-
Notifications
You must be signed in to change notification settings - Fork 0
/
myc_printf.mips
131 lines (112 loc) · 3.29 KB
/
myc_printf.mips
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
l0:
subu $sp, $sp, 36
sw $ra, 32($sp)
sw $fp, 28($sp)
sw $s0, 24($sp)
sw $s1, 20($sp)
sw $s2, 16($sp)
sw $s3, 12($sp)
sw $s4, 8($sp)
sw $s5, 4($sp)
sw $s6, 0($sp)
addu $fp, $sp, 36
# grab the arguments:
move $s0, $a0 # fmt string
move $s1, $a1 # arg1 (optional)
move $s2, $a2 # arg2 (optional)
move $s3, $a3 # arg3 (optional)
lw $t0, 0($gp) # arg4 (optional)
lw $t1, 4($gp) # arg5 (optional)
lw $t2, 8($gp) # arg6 (optional)
li $s4, 0 # set # of formats = 0
la $s6, printf_buf # set s6 = base of printf buffer.
printf_loop: # process each character in the fmt:
lb $s5, 0($s0) # get the next character, and then
addu $s0, $s0, 1 # bump up $s0 to the next character.
beq $s5, '%', printf_fmt # if the fmt character, then do fmt.
beq $0, $s5, printf_end # if zero, then go to end.
printf_putc:
sb $s5, 0($s6) # otherwise, just put this char
sb $0, 1($s6) # into the printf buffer,
move $a0, $s6 # and then print it with the
li $v0, 4 # print_str syscall
syscall
b printf_loop # loop on.
printf_fmt:
lb $s5, 0($s0) # see what the fmt character is,
addu $s0, $s0, 1 # and bump up the pointer.
beq $s4, 6, printf_loop # if we've already processed 6 args,
# then *ignore* this fmt.
beq $s5, 'd', printf_int # if 'd', print as a decimal integer.
beq $s5, 's', printf_str # if 's', print as a string.
beq $s5, 'c', printf_char # if 'c', print as a ASCII char.
beq $s5, '0', printf_prefix # if '0', print as a '0'-prefix dectimal integer.
beq $s5, '.', printf_prefix # if '.', print as a '.'-prefix dectimal integer.
beq $s5, '%', printf_perc # if '%', print a '%'
b printf_loop # otherwise, just continue.
printf_shift_args: # shift over the fmt args,
move $s1, $s2 # $s1 = $s2
move $s2, $s3 # $s2 = $s3
move $s3, $t0 # $s3 = $t0
move $t0, $t1 # $t0 = $t1
move $t1, $t2 # $t1 = $t2
add $s4, $s4, 1 # increment # of args processed.
b printf_loop # and continue the main loop.
printf_prefix: # deal with a %0
lb $s5, 0($s0)
add $s0, $s0, 1
li $s7, 1
printf_prefix_loop_1:
mul $s7, $s7, 10
sub $s5, $s5, 1
bgt $s5, '1', printf_prefix_loop_1
printf_prefix_loop_2:
move $a0, $s1
div $a0, $a0, $s7
rem $a0, $a0, 10
li $v0, 1
syscall
div $s7, $s7, 10
bge $s7, 1, printf_prefix_loop_2
lb $s5, 0($s0)
addu $s0, $s0, 1
b printf_shift_args # branch to printf_shift_args
printf_int: # deal with a %d:
move $a0, $s1 # do a print_int syscall of $s1.
li $v0, 1
syscall
b printf_shift_args # branch to printf_shift_args
printf_str: # deal with a %s:
move $a0, $s1 # do a print_string syscall of $s1.
li $v0, 4
syscall
b printf_shift_args # branch to printf_shift_args
printf_char: # deal with a %c:
sb $s1, 0($s6) # fill the buffer in with byte $s1,
sb $0, 1($s6) # and then a null.
move $a0, $s6 # and then do a print_str syscall
li $v0, 4 # on the buffer.
syscall
b printf_shift_args # branch to printf_shift_args
printf_perc: # deal with a %%:
li $s5, '%' # (this is redundant)
sb $s5, 0($s6) # fill the buffer in with byte %,
sb $0, 1($s6) # and then a null.
move $a0, $s6 # and then do a print_str syscall
li $v0, 4 # on the buffer.
syscall
b printf_loop # branch to printf_loop
printf_end:
lw $ra, 32($sp) # restore the prior environment:
lw $fp, 28($sp)
lw $s0, 24($sp)
lw $s1, 20($sp)
lw $s2, 16($sp)
lw $s3, 12($sp)
lw $s4, 8($sp)
lw $s5, 4($sp)
lw $s6, 0($sp)
addu $sp, $sp, 36 # release the stack frame.
jr $ra # return.
.data 0x10020000
printf_buf: .space 2