diff options
Diffstat (limited to 'src/std.s')
-rw-r--r-- | src/std.s | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/src/std.s b/src/std.s new file mode 100644 index 0000000..bfdb547 --- /dev/null +++ b/src/std.s @@ -0,0 +1,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 |