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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
|
.section .data
;;;# Constants
.equ SYS_WRITE, 64
.equ SYS_BRK, 214
.equ STDOUT, 1
.equ NULL, 0
.section .text
;;;# size_t strlen(char *buf)
;;;# returns the lenght of buf
;;;# (buf must be a NULL-terminated)
;;;# returns 0 when buf is empty
.globl strlen
;;;# int puts(char *buf)
;;;# does a sys_write on buf
;;;# (buf must be a NULL-terminated)
;;;# returns the amount of charaters written
;;;# < 0 on fail
.globl puts
;;;# int putc(char ch)
;;;# does a sys_write on ch
;;;# returns 1 on success
.globl putc
;;;# int printf(char *buf, ...)
;;;# does what libc printf does
;;;# (buf must be NULL-terminated)
;;;# (the variadic args are on the stack
;;;# with the first begin at 0(sp))
;;;# returns the amount of characters written
;;;# < 0 on fail
.globl printf
;;;# strlen
strlen:
mv t0, a0 ;# copy buf addr
li t3, NULL ;# NULL
strlen_loop:
lb t2, 0(t0) ;# load cur char
beq t2, t3, strlen_end ;# end loop when its \0
addi t0, t0, 1 ;# next element in the array
j strlen_loop
strlen_end:
sub a0, t0, a0 ;# get the amount of elements
ret
;;;# puts
puts:
mv a1, a0 ;# copy buf
addi sp, sp, -4 ;# save ra
sw ra, 0(sp) ;#
call strlen
mv a2, a0 ;# move the len into a2
lw ra, 0(sp) ;# load ra
addi sp, sp, 4 ;#
li a7, SYS_WRITE
li a0, STDOUT
ecall
ret
;;;# putc
putc:
addi sp, sp, -1 ;# save the char on the stack
sb a0, 0(sp) ;# so it is an address
li a7, SYS_WRITE ;#
li a0, STDOUT ;#
mv a1, sp ;# do of write syscall
li a2, 1 ;#
ecall ;#
addi sp, sp, 1 ;# restore the stack
ret
;;;# printf
printf:
;;# using t6 and t5 like saved registers since i can't
;;# use the stack normally because of the variadic args
mv t6, zero ;# the character counter
mv t5, a0 ;# the fmt string
printf_loop:
lb t4, 0(t5) ;# load the next char
li t3, NULL ;# branch to end on null
beq t4, t3, printf_end ;#
li t3, '%' ;# branch on %
beq t4, t3, printf_on_fmt ;#
li t3, '\' ;# branch on escape character
beq t4, t3, printf_on_esc ;#
li a0, STDOUT ;#
mv a1, t5 ;# the character must be normal
li a2, 1 ;# so we just write it
li a7, SYS_WRITE ;#
ecall ;#
addi t6, t6, 1 ;# we wrote one more byte
printf_loop_again:
addi t5, t5, 1 ;# go to the next char
j printf_loop
printf_end:
mv a0, t6 ;# return the amount of written bytes
ret
;;;# each branch pops the data from the stack,
;;;# then it prints it and increases the byte counter (t6)
printf_on_fmt:
addi t5, t5, 1 ;# go to the next char
lb t4, 0(t5) ;# load the next char
li t3, NULL
beq t4, t3, printf_end ;# branch to end on null
li t3, '%'
beq t4, t3, printf_perc ;# print '%' on '%'
li t3, 's'
beq t4, t3, printf_string ;# print string on 's'
li t3, 'd'
beq t4, t3, printf_dec_num ;# print decimal on 'd'
j printf_loop_again ;# no such program character
;;;# each branch sets a0 to a char, then the char is written
printf_on_esc:
addi t5, t5, 1 ;# go to the next char
lb t4, 0(t5) ;# load the next char
li t3, NULL
beq t4, t3, printf_end ;# branch to end on null
li t3, '\'
beq t4, t3, printf_esc_slsh ;# putc slash
li t3, 'n'
beq t4, t3, printf_esc_nl ;# putc \n
printf_on_esc_ret:
addi sp, sp, -4 ;# push ra to the stack
sw ra, 0(sp) ;#
call putc
lw ra, 0(sp) ;# pop ra from the stack
addi sp, sp, 4 ;#
add t6, t6, a0 ;# add amount of printed chars
j printf_loop_again
printf_esc_slsh:
li a0, '\'
j printf_on_esc_ret
printf_esc_nl:
li a0, 0xA
j printf_on_esc_ret
printf_perc:
addi sp, sp, -4 ;# push ra to the stack
sw ra, 0(sp) ;#
li a0, '%' ;# putc '%'
call putc ;#
lw ra, 0(sp) ;# pop ra from the stack
addi sp, sp, 4 ;#
add t6, t6, a0 ;# add amount of printed chars
j printf_loop_again
printf_string:
lw a0, 0(sp) ;# get the string from the stack
sw ra, 0(sp) ;# save ra to stack
call puts
lw ra, 0(sp) ;# pop ra from the stack
addi sp, sp, 4 ;#
add t6, t6, a0 ;# add amount of printed chars
j printf_loop_again
printf_dec_num:
addi t0, zero, 10 ;# divisor
mv t2, zero ;# counter
lw t3, 0(sp) ;# pop the number from the stack
addi sp, sp, 4 ;#
printf_dec_num_loop:
remu t1, t3, t0 ;# get the last digit
addi t2, t2, 1 ;# inc the counter
addi t1, t1, '0' ;# turns digit into a char
addi sp, sp, -1 ;# one byte on stack
sb t1, 0(sp) ;# save on stack
divu t3, t3, t0 ;# remove the last digit
bne t3, zero, printf_dec_num_loop ;# loop again when the number is not 0
li a0, STDOUT ;#
mv a1, sp ;# do a write syscall
mv a2, t2 ;# on the string in the stack
li a7, SYS_WRITE ;#
ecall ;#
add sp, sp, t2 ;# clear the stack
add t6, t6, t2 ;# add to the char counter
j printf_loop_again
|