From 40e4272cddaede082ef73469fa53623d65314490 Mon Sep 17 00:00:00 2001 From: PleegWat Date: Tue, 8 Sep 2026 17:00:26 +0200 Subject: [PATCH] Int to string conversion Initially only binary output --- src/errno.asm | 5 ++- src/int_to_string.asm | 66 ++++++++++++++++++++++++++++++++++++ src/stdlib.asm | 2 ++ src/string.asm | 33 ++++++++++++++++++ tests/int_to_string_test.asm | 49 ++++++++++++++++++++++++++ 5 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 src/int_to_string.asm create mode 100644 src/string.asm create mode 100644 tests/int_to_string_test.asm diff --git a/src/errno.asm b/src/errno.asm index 5d06c89..287553d 100755 --- a/src/errno.asm +++ b/src/errno.asm @@ -21,7 +21,10 @@ pub const SCREEN_INVALID_WIDTH = 0x0003 pub const SCREEN_FB_TOO_SMALL = 0x0005 pub const SCREEN_OUTSIDE_FB = 0x0007 +pub const INTTOSTR_BAD_BASE = 0x0101 +pub const INTTOSTR_BAD_BUFFER = 0x0103 + pub const MAGIC_BAD = 0x8001 ; Extended error codes, these would require loading a 32 bit value. -pub const EXT_OK = 0x00000000 \ No newline at end of file +pub const EXT_OK = 0x00000000 diff --git a/src/int_to_string.asm b/src/int_to_string.asm new file mode 100644 index 0000000..3b30768 --- /dev/null +++ b/src/int_to_string.asm @@ -0,0 +1,66 @@ +include errno + +; Convert integer to string +; Arguments: +; r1 - Integer +; r2 - Start of buffer +; r3 - Buffer length +; r4 - Base (2, 8, 10, or 16) +; Result: +; none +; Clobbers: +; Based on specialization +pub auto: +cmp r4, 2 +je bin +mov flags, errno.INTTOSTR_BAD_BASE +jmp r13 + +; Convert integer to binary string +; Arguments: +; r1 - Integer +; r2 - Start of buffer (assumed 'big enough') +; r3 - Buffer length (ignored) +; Result: +; none +; Clobbers: +; flags +; r4 - counter +; r5 - result character +pub bin: +mov r4, 31 +cmp r2, 2 +jl badbuffer + +bin_find_one: +lsr r5, r1, r4 ; Select bit and advance counter +and r5, r5, 1 +sub r4, r4, 1 + +cmp r4, 0 ; Start printing if last bit ... +jl bin_print +cmp r5, zr ; .. or if nonzero +je bin_find_one + +add flags, r4, 3 ; Check buffer size +cmp flags, r3 +ja badbuffer + +bin_print: +add r5, r5, 0x30 ; '0' ; Add digit to buffer +store_8 [r2], r5 +add r2, r2, 1 +cmp r4, 0 ; Done if last bit +jl done +lsr r5, r1, r4 ; Select bit and advance counter +and r5, r5, 1 +sub r4, r4, 1 +jmp bin_print + +badbuffer: +mov flags, errno.INTTOSTR_BAD_BUFFER +jmp r13 + +done: +store_8 [r2], zr +jmp r13 diff --git a/src/stdlib.asm b/src/stdlib.asm index ee6477d..ad85881 100644 --- a/src/stdlib.asm +++ b/src/stdlib.asm @@ -3,7 +3,9 @@ pub include imath pub include array pub include console pub include mem +pub include string pub include string_to_int +pub include int_to_string ; Needs to be last! pub include LUTs diff --git a/src/string.asm b/src/string.asm new file mode 100644 index 0000000..26c99ec --- /dev/null +++ b/src/string.asm @@ -0,0 +1,33 @@ +; Compare two strings +; Arguments: +; r1 - Pointer to string 1 +; r2 - Pointer to string 2 +; Result: +; r1: +; - `0` if both segments are equal. +; - `<0` if the first segment is less than the second segment. +; - `>0` if the first segment is greater than the second segment. +; flags - Compare result +; Clobbers: +; r3 - last byte of r1 tested +; r4 - last byte of r2 tested +pub compare: +load_8 r3, [r1] +add r1, r1, 1 +load_8 r4, [r2] +add r2, r2, 1 +cmp zr, r3 ; End of string 1 +je done +cmp zr, r4 ; End of string 2 +je done +cmp r3, r4 +je compare ; Loop, tail recursion, what's the difference +done: +cmp r3, r4 +; `flags` is the comparison result in the format of `cmp`. Convert it to the desired format. +; 00 => 0x40000000 > 0 +; 01 => 0x00000000 = 0 +; 10 => 0xC0000000 < 0 +xor r1, flags, 1 +lsl r1, r1, 30 +jmp r13 diff --git a/tests/int_to_string_test.asm b/tests/int_to_string_test.asm new file mode 100644 index 0000000..2da2da9 --- /dev/null +++ b/tests/int_to_string_test.asm @@ -0,0 +1,49 @@ +; test harness for int_to_string +; Registers: +; r8 - test address +; r9 - test method +; r12 - end of tests address +li r8, tests +li r12, end_of_tests +next_test: +; Set up arguments and run test +load_32 r1, [r8] ; Input value +li r2, scratch ; Output buffer +mov r3, 64 ; Output buffer size +add r4, r8, 4 ; Base +load_8 r4, [r4] +mov r13, itoa_test_ret ; return address +jmp stdlib.int_to_string.auto +itoa_test_ret: + +; Strcmp to check results +add r1, r8, 5 ; expected output +li r2, scratch ; actual output +mov r13, itoa_strcmp_ret +jmp stdlib.string.compare +itoa_strcmp_ret: + +; Verify results +halt.ne + +; Next test +add r8, r8, 0x40 +cmp r8, r12 +jl next_test + +; Done +halt + +include ../src/stdlib + +@0x20000 +tests: +; inlen is the number of input bytes the function is expected to consume +; addr int base result +@0x20000 U32 0b0 U8 2 "0\0" +@0x20040 U32 0xFFFFFFFF U8 2 "11111111111111111111111111111111\0" +@0x20080 U32 0b101010 U8 2 "101010\0" +@0x200c0 +end_of_tests: +scratch: U1024 0 +