aboutsummaryrefslogtreecommitdiff
path: root/src/std.s
blob: bfdb547f8797474c12a7b4160a0e69215c8a5078 (plain)
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