# This Source Code Form is subject to the terms of the Mozilla Public License, # v. 2.0. If a copy of the MPL was not distributed with this file, You can # obtain one at https://mozilla.org/MPL/2.0/. .global write_s, write_c, write_i, _print_i .global memcmp, memchr, memmem, memcpy .section .text # a0 - First pointer. # a1 - Second pointer. # a2 - The length to compare. # # Returns 0 in a0 if memory regions are equal. .type memcmp, @function memcmp: mv t0, a0 li a0, 0 .Lmemcmp_loop: beqz a2, .Lmemcmp_end lbu t1, (t0) lbu t2, (a1) sub a0, t1, t2 bnez a0, .Lmemcmp_end addi t0, t0, 1 addi a1, a1, 1 addi a2, a2, -1 j .Lmemcmp_loop .Lmemcmp_end: ret # Prints a string. # # Parameters: # a0 - String pointer. # a1 - Length of the string. .type write_s, @function write_s: # Prologue. addi sp, sp, -32 sw ra, 28(sp) sw s0, 24(sp) addi s0, sp, 32 sw s1, 20(sp) sw s2, 16(sp) mv s1, a1 mv s2, a0 .Lwrite_s_if: beqz s1, .Lwrite_s_end lw a0, (s2) call write_c addi s1, s1, -1 addi s2, s2, 1 j .Lwrite_s_if .Lwrite_s_end: lw s1, 20(sp) lw s2, 16(sp) # Epilogue. lw ra, 28(sp) lw s0, 24(sp) addi sp, sp, 32 ret # Writes a number to a string buffer. # # t0 - Local buffer. # t1 - Constant 10. # t2 - Current character. # t3 - Whether the number is negative. # # Parameters: # a0 - Whole number. # a1 - Buffer pointer. # # Sets a0 to the length of the written number. .type _print_i, @function _print_i: addi sp, sp, -32 sw ra, 28(sp) sw s0, 24(sp) addi s0, sp, 32 li t1, 10 addi t0, s0, -9 li t3, 0 bgez a0, .Lprint_i_digit10 li t3, 1 neg a0, a0 .Lprint_i_digit10: rem t2, a0, t1 addi t2, t2, '0' sb t2, 0(t0) div a0, a0, t1 addi t0, t0, -1 bne zero, a0, .Lprint_i_digit10 beq zero, t3, .Lprint_i_write_call addi t2, zero, '-' sb t2, 0(t0) addi t0, t0, -1 .Lprint_i_write_call: mv a0, a1 addi a1, t0, 1 sub a2, s0, t0 addi a2, a2, -9 sw a2, 0(sp) call memcpy lw a0, 0(sp) lw ra, 28(sp) lw s0, 24(sp) addi sp, sp, 32 ret # Writes a number to the standard output. # # Parameters: # a0 - Whole number. .type write_i, @function write_i: addi sp, sp, -32 sw ra, 28(sp) sw s0, 24(sp) addi s0, sp, 32 addi a1, sp, 0 call _print_i mv a1, a0 addi a0, sp, 0 call write_s lw ra, 28(sp) lw s0, 24(sp) addi sp, sp, 32 ret # Prints a character from a0. # # Arguments: # a0 - Character. .type write_c, @function write_c: li a1, 0 li a2, 0 li a3, 0 li a4, 0 li a5, 0 li a6, 0 li a7, 1 # sbi_console_putchar. ecall ret # Searches for the occurences of a character in the given memory block. # # Parameters: # a0 - Memory block. # a1 - Needle. # a2 - Memory size. # # Sets a0 to the pointer to the found character or to null if the character # doesn't occur in the memory block. .type memchr, @function memchr: .Lmemchr_loop: beqz a2, .Lmemchr_nil # Exit if the length is 0. lbu t0, (a0) # Load the character from the memory block. beq t0, a1, .Lmemchr_end # Exit if the character was found. # Otherwise, continue with the next character. addi a0, a0, 1 addi a2, a2, -1 j .Lmemchr_loop .Lmemchr_nil: li a0, 0 .Lmemchr_end: ret # Locates a substring. # # Parameters: # a0 - Haystack. # a1 - Haystack size. # a2 - Needle. # a3 - Needle size. # # Sets a0 to the pointer to the beginning of the substring in memory or to 0 # if the substring doesn't occur in the block. .type memmem, @function memmem: # Prologue. addi sp, sp, -24 sw ra, 20(sp) sw s0, 16(sp) addi s0, sp, 24 # Save preserved registers. They are used to keep arguments. sw s1, 12(sp) sw s2, 8(sp) sw s3, 4(sp) sw s4, 0(sp) mv s1, a0 mv s2, a1 mv s3, a2 mv s4, a3 .Lmemmem_loop: blt s2, s3, .Lmemmem_nil # Exit if the needle length is greater than memory. mv a0, s1 mv a1, s3 mv a2, s4 call memcmp mv t0, a0 # memcmp result. mv a0, s1 # Memory pointer for the case the substring was found. beqz t0, .Lmemmem_end addi s1, s1, 1 add s2, s2, -1 j .Lmemmem_loop .Lmemmem_nil: li a0, 0 .Lmemmem_end: # Restore the preserved registers. lw s1, 12(sp) lw s2, 8(sp) lw s3, 4(sp) lw s4, 0(sp) # Epilogue. lw ra, 20(sp) lw s0, 16(sp) add sp, sp, 24 ret # Copies memory. # # Parameters: # a0 - Destination. # a1 - Source. # a2 - Size. # # Preserves a0. .type memcpy, @function memcpy: mv t0, a0 .Lmemcpy_loop: beqz a2, .Lmemcpy_end lbu t1, (a1) sb t1, (a0) addi a0, a0, 1 addi a1, a1, 1 addi a2, a2, -1 j .Lmemcpy_loop .Lmemcpy_end: mv a0, t0 ret