aboutsummaryrefslogtreecommitdiff
path: root/arch/riscv/usr/string.S
diff options
context:
space:
mode:
authorMiquel Sabaté Solà <mikisabate@gmail.com>2024-08-28 22:25:56 +0200
committerMiquel Sabaté Solà <mikisabate@gmail.com>2024-12-05 16:02:49 +0100
commitab03d3be21f229be8c28dba292d5da237a929a73 (patch)
tree8bc53e3031f644532fec255bb392a90cd4ad59fb /arch/riscv/usr/string.S
parent1a36e6211674f1a39c7cc0ddff705357a4add65a (diff)
downloadfarga-ab03d3be21f229be8c28dba292d5da237a929a73.tar.gz
farga-ab03d3be21f229be8c28dba292d5da237a929a73.zip
Restructure the whole thing
It will be something more than just messing around with RISC-V stuff. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
Diffstat (limited to 'arch/riscv/usr/string.S')
-rw-r--r--arch/riscv/usr/string.S93
1 files changed, 93 insertions, 0 deletions
diff --git a/arch/riscv/usr/string.S b/arch/riscv/usr/string.S
new file mode 100644
index 0000000..0f3bcc1
--- /dev/null
+++ b/arch/riscv/usr/string.S
@@ -0,0 +1,93 @@
+.text
+
+.globl reverse_string
+.type reverse_string, @function
+
+// char * reverse_string(char *str);
+reverse_string:
+ // Return early on null pointer.
+ beq a0, zero, end
+
+ // Preserve the original pointer.
+ addi sp, sp, -8
+ sd a0, 0(sp)
+
+ // Set `t0` to point to the end of the string.
+ add t0, a0, zero
+set_end_ptr:
+ lbu t2, 0(t0)
+ beq t2, zero, end_ptr_done
+ addi t0, t0, 1
+ j set_end_ptr
+
+ // We are done iterating, if `a0` and `t0` are equal, then there's nothing
+ // to be done and we can return early. Otherwise decrement `t0` so it points
+ // to the byte right before the null termination.
+end_ptr_done:
+ beq a0, t0, reverse_done
+ addi t0, t0, -1
+
+reverse_loop:
+ // Swap values between the two pointers.
+ lb t1, 0(a0)
+ lb t2, 0(t0)
+ sb t1, 0(t0)
+ sb t2, 0(a0)
+
+ // Move pointers and check whether the pointers have already crossed. If
+ // they have not crossed yet there is still looping to be done. Otherwise
+ // we are done.
+ addi a0, a0, 1
+ addi t0, t0, -1
+ bltu a0, t0, reverse_loop
+
+reverse_done:
+ // Restore things back and return to the caller.
+ ld a0, 0(sp)
+ addi sp, sp, 8
+end:
+ jr ra
+
+.globl is_palindrome
+.type is_palindrome, @function
+
+// bool is_palindrome(char *str);
+is_palindrome:
+ // Return early on null pointer.
+ beq a0, zero, palindrome_no
+
+ // Set `t0` to point to the end of the string.
+ add t0, a0, zero
+pal_set_end_ptr:
+ lbu t2, 0(t0)
+ beq t2, zero, pal_end_ptr_done
+ addi t0, t0, 1
+ j pal_set_end_ptr
+
+ // We are done iterating, if `a0` and `t0` are equal, then there's nothing
+ // to be done and we can return early. Otherwise decrement `t0` so it points
+ // to the byte right before the null termination.
+pal_end_ptr_done:
+ beq a0, t0, palindrome_no
+ addi t0, t0, -1
+
+pal_loop:
+ // Swap values between the two pointers.
+ lb t1, 0(a0)
+ lb t2, 0(t0)
+ bne t1, t2, palindrome_no
+
+ // Move pointers and check whether the pointers have already crossed. If
+ // they have not crossed yet there is still looping to be done. Otherwise
+ // we are done.
+ addi a0, a0, 1
+ addi t0, t0, -1
+ bleu a0, t0, pal_loop
+
+palindrome_yes:
+ li a0, 1
+ jr ra
+
+palindrome_no:
+ li a0, 0
+ jr ra