From e52725d564fbbb79f35bdb3b9c128ee6645ea0d8 Mon Sep 17 00:00:00 2001
From: Wesley Moore <wes@wezm.net>
Date: Tue, 11 Feb 2025 22:08:32 +1000
Subject: [PATCH] Add tests for add64

Currently the test harness isn't looping, so the test is failing.
---
 Makefile           |  7 +++-
 calc.s             | 20 +---------
 hex.s              |  1 +
 math.s             | 26 +++++++++++++
 tests/math_add64.s | 91 ++++++++++++++++++++++++++++++++++++++++++++++
 tests/test_math.sh |  7 ++++
 6 files changed, 131 insertions(+), 21 deletions(-)
 create mode 100644 math.s
 create mode 100644 tests/math_add64.s
 create mode 100644 tests/test_math.sh

diff --git a/Makefile b/Makefile
index 0e7d818..a41a7dc 100644
--- a/Makefile
+++ b/Makefile
@@ -14,10 +14,13 @@ check: tests
 hello.elf: hello.o
 	$(LD) -m elf32lriscv $^ -o $@
 
-calc.elf: mem.o hex.o debug.o calc.o
+calc.elf: mem.o hex.o debug.o math.o calc.o
 	$(LD) -m elf32lriscv -T link.ld $^ -o $@
 
-tests: tests/btohex.elf tests/tohex.elf
+tests: tests/btohex.elf tests/tohex.elf tests/math_add64.elf
+
+tests/math_add64.elf: hex.o math.o tests/math_add64.o
+	$(LD) -m elf32lriscv -T link.ld $^ -o $@
 
 tests/btohex.elf: mem.o hex.o debug.o tests/btohex.o
 	$(LD) -m elf32lriscv -T link.ld $^ -o $@
diff --git a/calc.s b/calc.s
index cff8a62..f3b8bd0 100644
--- a/calc.s
+++ b/calc.s
@@ -5,6 +5,7 @@
 .global _start
 
 .extern regdump
+.extern add64
 
 /* newlib system calls */
 .set SYSEXIT,  93
@@ -28,22 +29,3 @@ _start:
     li t0, SYSEXIT      # "exit" syscall
     add a0, x0, 0       # Use 0 return code
     ecall               # invoke syscall to terminate the program
-
-# 64-bit integer addition
-#   arguments:
-#       a0: x lower 32 bits
-#       a1: x upper 32 bits
-#       a2: y lower 32 bits
-#       a3: y upper 32 bits
-#   return:
-#       a0: x+y lower 32 bits
-#       a1: x+y upper 32 bits
-#
-add64:
-    add  a0, a0, a2  # add lower 32 bits
-    add  t0, a1, a3  # add upper 32 bits
-    sltu t1, a0, a2  # if lower 32-bit sum < a2 then set t1=1 (carry bit)
-    add  a1, t0, t1  # upper 32 bits of answer (upper sum + carry bit)
-    ret
-
-
diff --git a/hex.s b/hex.s
index afdc82c..3bf60a8 100644
--- a/hex.s
+++ b/hex.s
@@ -2,6 +2,7 @@
 .global tohex
 
 .section .rodata
+
 hexchars:
   .ascii "0123456789ABCDEF"
 
diff --git a/math.s b/math.s
new file mode 100644
index 0000000..2389918
--- /dev/null
+++ b/math.s
@@ -0,0 +1,26 @@
+.globl add64
+
+.text
+
+# > When primitive arguments twice the size of a pointer-word are passed on the
+# > stack, they are naturally aligned. When they are passed in the integer
+# > registers, they reside in an aligned even-odd register pair, with the even
+# > register holding the least-significant bits.
+
+# 64-bit integer addition
+#   arguments:
+#       a0: x lower 32 bits
+#       a1: x upper 32 bits
+#       a2: y lower 32 bits
+#       a3: y upper 32 bits
+#   return:
+#       a0: x+y lower 32 bits
+#       a1: x+y upper 32 bits
+#
+add64:
+    add  a0, a0, a2  # add lower 32 bits
+    add  t0, a1, a3  # add upper 32 bits
+    sltu t1, a0, a2  # if lower 32-bit sum < a2 then set t1=1 (carry bit)
+    add  a1, t0, t1  # upper 32 bits of answer (upper sum + carry bit)
+    ret
+
diff --git a/tests/math_add64.s b/tests/math_add64.s
new file mode 100644
index 0000000..cc4589c
--- /dev/null
+++ b/tests/math_add64.s
@@ -0,0 +1,91 @@
+# Test for add64
+
+.org 0
+# Provide program starting address to linker
+.global _start
+
+.extern add64
+.extern tohex
+
+/* newlib system calls */
+.set SYSEXIT,  93
+.set SYSWRITE, 64
+
+.section .rodata
+
+inputs:
+    .word 0x40000000   # 0.25
+    .word 1            # 1
+    .word 0x40000000   # 0.25
+    .word 2            # 2
+
+    .word 0x40000000   # 0.25
+    .word 1            # 1
+    .word 0x80000000   # 0.5
+    .word 2            # 2
+
+    .set inputs_end, .-inputs
+
+.section .bss
+
+buf: .skip 9
+
+.text
+
+_start:
+    li a0, '\n
+    la a1, buf
+    sb a0, 8(a1)        # append newline to buf
+
+    la s0, inputs       # init loop variables
+    la s1, inputs_end
+loop:
+    lw a0, 0(s0)        # a0: x lower 32 bits
+    lw a1, 4(s0)        # a1: x upper 32 bits
+    lw a2, 8(s0)        # a2: y lower 32 bits
+    lw a3, 12(s0)       # a3: y upper 32 bits
+    jal add64
+
+    # TODO: Format as an actual decimal
+    # print the result, hi = a1, lo = a0, a1.a0
+    # a0 is value, a1 is buf addr
+    addi sp, sp, -4
+    sw a0, 0(sp)        # stash a0 for later
+    mv a0, a1           # copy a1 to a0
+    la a1, buf
+    jal tohex
+
+    # print hi word
+    li t0, SYSWRITE     # "write" syscall
+    li a0, 1            # 1 = standard output (stdout)
+    la a1, buf          # load address of output string
+    li a2, 8            # length of output string
+    ecall               # invoke syscall to print the string
+
+    # print .
+    li t0, SYSWRITE     # "write" syscall
+    li a0, 1            # 1 = standard output (stdout)
+    la a1, buf          # load address of output string
+    li a2, '.
+    sb a2, 0(a1)
+    li a2, 1            # length of output string
+    ecall               # invoke syscall to print the string
+
+    # print lo word
+    lw a0, 0(sp)        # restore lo word
+    addi sp, sp, 4
+    la a1, buf
+    jal tohex
+
+    li t0, SYSWRITE     # "write" syscall
+    li a0, 1            # 1 = standard output (stdout)
+    la a1, buf          # load address of output string
+    li a2, 9            # length of output string
+    ecall               # invoke syscall to print the string
+
+    addi s0, s0, 16     # increment input pointer to next pair of 64-bit inputs
+    bltu s0, s1, loop   # if the input address is less than inputs_end, loop
+
+    li t0, SYSEXIT      # "exit" syscall
+    la a0, 0            # Use 0 return code
+    ecall               # invoke syscall to terminate the program
diff --git a/tests/test_math.sh b/tests/test_math.sh
new file mode 100644
index 0000000..83307d3
--- /dev/null
+++ b/tests/test_math.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+test_add64() {
+  result=$("${QEMU}" -B 0x80000000 -s 2k tests/math_add64.elf)
+
+  test $? -eq 0 && test "${result}" = "00000003.80000000\n00000003.C0000000" # 3.5, 3.75
+}