diff --git a/docs/libraries.md b/docs/libraries.md new file mode 100644 index 0000000..9bfc6f2 --- /dev/null +++ b/docs/libraries.md @@ -0,0 +1,16 @@ +# Included libraries + +I've started to implement some sort of standard library, following closely to [GNU's glibc](https://www.gnu.org/software/libc/). + +You can include the libraries by adding them as arguments (before your main assembly file): + +``` +> python3 -m riscemu examples/lib/libstring.asm example.asm +[MMU] Successfully loaded: LoadedExecutable[examples/lib/libstring.asm](base=0x00000100, size=64bytes, sections=text, run_ptr=0x00000100) +[MMU] Successfully loaded: LoadedExecutable[example.asm](base=0x00000140, size=168bytes, sections=data text, run_ptr=0x000001D0) +[CPU] Allocated 524288 bytes of stack +[CPU] Started running from 0x000001D0 (example.asm) +``` + +These libraries are no where near a stable state, so documentation will be scarce. Your best bet would be to `grep` for functionality. Sorry! + diff --git a/examples/lib/libstring.asm b/examples/lib/libstring.asm index e69de29..a95dafe 100644 --- a/examples/lib/libstring.asm +++ b/examples/lib/libstring.asm @@ -0,0 +1,154 @@ +; string operations in RISC-V Assembly +; All function restore all registers after use (even caller-saved ones) + +.global NULL +; A global constant, points to the empty string + + +.global strlen +; size_t libstr_strlen(char* str) +; return the length of str + + +.global strncpy +; char *strncpy(char *dest, const char *src, size_t n) +; copy n bytes from source into dest. If source ends before n bytes, the rest is filled with null-bytes +; returns pointer to dest + + +.global strcpy +; char *strncpy(char *dest, const char *src) +; copy string src into dest, including null terminator +; returns pointer to dest + + +.global memchr +; void *memchr(const void *str, char c, size_t n) +; search vor the first occurance of c in str +; returns a pointer to the first occurance, or NULL + + +.global memset +; void *memset(void *str, char c, size_t n) +; copies the character c to the first n characters of str. + + +;.global memcmp +;.global memcpy +;.global strcat + +; Create NullPtr constant +.set NULL, 0x00 + + + .text +strlen: +; size_t strlen(char* str) + ; push s1, s2 to the stack + sw s1, sp, -4 + sw s2, sp, -8 + ; since no subroutines are called, we don't need to increment or decrement the sp + addi s2, zero, -1 ; length (since null byte is counted by this method, we return len - 1) +__strlen_loop: + lb s1, a0, 0 ; read character + addi s2, s2, 1 ; increment number bytes read + addi a0, a0, 1 + bne s1, zero, __strlen_loop + ; we are done, set return value in a0 + add a0, zero, s2 + ; pop s1, s2, from stack + lw s1, sp, -4 + lw s2, sp, -8 + ret + +strncpy: +; char *strncpy(char *dest, const char *src, size_t n) +; copy size bytes from source to dest + sw s1, sp, -4 ; push s1 to the stack + sw s2, sp, -8 ; push s1 to the stack + add s1, a0, zero ; save dest pointer for return +__strncpy_loop: + beq a2, zero, __strncpy_end + ; copy byte + lb s2, a1, 0 ; read first byte from src + sb s2, a0, 0 ; write first byte to dest + ; increment pointers + addi a0, a0, 1 + addi a1, a1, 1 + ; one less byte to copy + addi a2, a2, -1 + ; if we read the terminating byte, jump to fill code + beq s2, zero, __strncpy_fill + ; otherwise continue copying + j __strncpy_loop +__strncpy_fill: + ; fill remaining space with 0 bytes + ; if no bytes left, stop filling + beq a2, zero, __strncpy_end + sb zero, a0, 0 + addi a0, a0, 1 + addi a2, a2, -1 + j __strncpy_fill +__strncpy_end: + ; set return value + add a0, zero, s1 + ; pop s1, s2 from stack + lw s1, sp, -4 + lw s2, sp, -8 + ret + + +strcpy: +; char *strncpy(char *dest, const char *src) + sw s1, sp, -4 ; push s1 to the stack + sw s2, sp, -8 ; push s1 to the stack + add s1, a0, zero ; save dest pointer for return +__strcpy_loop: + ; copy byte + lb s2, a1, 0 ; read first byte from src + sb s2, a0, 0 ; write first byte to dest + ; increment pointers + addi a0, a0, 1 + addi a1, a1, 1 + bne s2, zero, __strcpy_loop + ; we are done copying, return + ; set return value + add a0, zero, s1 + ; pop s1, s2 from stack + lw s1, sp, -4 + lw s2, sp, -8 + ret + +memchr: +; void *memchr(const void *str, char c, size_t n) + sw s1, sp, -4 ; push s1 to the stack +__memchr_loop: + beq a2, zero, __memchr_ret_null + lb s1, a0, 0 + addi a0, a0, 1 ; let a0 point to the next byte + addi a2, a2, -1 ; decrement bytes to copy by 1 + bne s1, s2, __memchr_loop + ; return pointer to prev byte (as the prev byte actually matched a1) + addi a0, a0, -1 + ; pop s1, s2 from stack + lw s1, sp, -4 + ret +__memchr_ret_null: + ; nothing found, return nullptr + addi a0, zero, NULL + lw s1, sp, -4 + ret + + +memset: +; void *memset(void *str, char c, size_t n) +__memset_loop: + beq a2, zero, __memset_ret + sb a1, a0, 0 + addi a0, a0, 1 + addi a2, a2, -1 + j __memset_loop +__memset_ret: + ret + +