aboutsummaryrefslogtreecommitdiff
path: root/src/std.s
diff options
context:
space:
mode:
Diffstat (limited to 'src/std.s')
-rw-r--r--src/std.s210
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