26 Commits
Author SHA1 Message Date
PleegWat 3968179026 Optimize digit parse loops 2026-09-04 23:07:21 +02:00
PleegWat f18199c5d0 Only allow 0o prefix for octal, not just 0 2026-09-03 16:45:04 +02:00
PleegWat b4af75a18e Handle negative in radix-specific preludes 2026-09-03 14:31:54 +02:00
PleegWat 836b977fc9 Implement negative number parsing 2026-09-03 13:42:11 +02:00
PleegWat 2c6e025dff Refactor tests to use data structs
Rather than a pointer to the end of the parseable string, we now store
the number of bytes we expect to be parsed. Current code allows for 11
bytes of string data which should suffice for most usecases.
2026-09-03 11:34:01 +02:00
PleegWat 9ff0a3192c Fix binary parsing and more tests 2026-09-02 21:33:58 +02:00
PleegWat fd5469aafc Add some cases, fix an octal bug 2026-09-02 21:28:29 +02:00
PleegWat e8cf5ae35f Initial version of atoi
Functions to convert strings to integers in various bases
2026-09-02 21:22:04 +02:00
ShatteredMINT 37d0e556d2 Merge pull request 'clean up confusion about function template' (#14) from meta-documentation into main
Reviewed-on: TCShenanigans/symphony_stdlib#14
2026-09-02 20:49:38 +02:00
ShatteredMINT 26d3a4d4f4 clean up confusion about function template 2026-09-02 20:49:22 +02:00
ShatteredMINT 786adfdb1c Merge pull request 'Changed docs of math functions to conform to new guidelines' (#12) from Micha_i/symphony_stdlib:math-functions-docs into main
Reviewed-on: TCShenanigans/symphony_stdlib#12
2026-09-02 11:46:14 +02:00
Michał Isalski 84636799b6 Changed docs of math functions to conform to new guidelines 2026-09-02 11:44:30 +02:00
ShatteredMINT aa2cbe4ad8 Merge pull request 'Add basic meta documentation' (#11) from meta-documentation into main
Documentation efforts are ongoing but this should be good enough for now
2026-09-02 11:39:25 +02:00
ShatteredMINT 8301d5988a create teaching directory 2026-09-02 11:32:46 +02:00
ShatteredMINT dbd4865f14 change stack start 2026-09-02 11:31:52 +02:00
ShatteredMINT 8f1b970a2f remove mention of non existent file 2026-09-02 11:31:33 +02:00
ShatteredMINT ddca02d8a8 relax r7 requirement for result stack 2026-09-02 11:21:03 +02:00
ShatteredMINT a3d6cb64b5 remove duplicate documentation from stdlib.asm 2026-09-02 11:17:18 +02:00
ShatteredMINT 9816111f38 clarify stack arguments 2026-09-01 14:08:20 +02:00
ShatteredMINT f2e5c830b3 explain inline comment 2026-09-01 13:48:12 +02:00
ShatteredMINT 60e7b6209f basic contribution guidelines 2026-09-01 13:21:17 +02:00
ShatteredMINT 33b7886e70 add arrays to readme 2026-09-01 13:07:13 +02:00
ShatteredMINT daf4168129 format calling convention 2026-08-31 10:17:25 +02:00
ShatteredMINT 4bce47209a fix remaining links 2026-08-31 10:12:57 +02:00
ShatteredMINT af5a750031 link test 2026-08-31 10:10:10 +02:00
ShatteredMINT 8e0fdf0d28 start readme 2026-08-31 10:08:44 +02:00
8 changed files with 275 additions and 42 deletions
+2 -2
View File
@@ -16,8 +16,8 @@ All functions in the standard library should follow the following outline:
; Arguments: <which register contains what argument> ; Arguments: <which register contains what argument>
; Result: <what is the result, and where is it stored> ; Result: <what is the result, and where is it stored>
; Clobbers: <list of registers that are clobbered> ; Clobbers: <list of registers that are clobbered>
fn_label: <;SHOULD BE INLINED> <label>: <;SHOULD BE INLINED>
CODE <CODE>
``` ```
-21
View File
@@ -1,21 +0,0 @@
# Memory Map
To not have to allocate a ton of things at run time the Standard Library uses a static memory map for some purposes
## Overview
| Start | Use |
| ---- | ---- |
| `0x0` | Reset Vector |
| `0x16` | Zero Page |
| `0x100` | User Code |
| `?` | Library Code |
| `0x1_0000` | LUTs |
| `?` | heap |
| `0xXXF0_0000` | Stack |
| `0xXXFF_0000` | quick access |
## Zero Page
Some values are needed not often enough to get their own special register, but often enough that it makes sense to keep them at a quickly accessible location.
This is what the zero page is for. its position in memory allows us to load them into a register with a single instruction.
-1
View File
@@ -4,7 +4,6 @@ This is a standard library for symphony.
It is both intended as a practical toolkit to develop more complex software as well as a teaching resource. It is both intended as a practical toolkit to develop more complex software as well as a teaching resource.
If you just want to use the standard library [[stdlib.asm]] is your main header, include it after your code. If you just want to use the standard library [[stdlib.asm]] is your main header, include it after your code.
You also need to include [[globals.asm]] as the first line in your assembly file.
If you are using it as a learning resource have a look at the [teaching folder](teaching). If you are using it as a learning resource have a look at the [teaching folder](teaching).
-10
View File
@@ -1,10 +0,0 @@
jmp 0x100
@0x10
screen:
frambuffer_ptr: U32 0x0
size: U32 0x0
position_xy: U32 0x0
mode: U32 0x0
@0x100
+29 -8
View File
@@ -1,8 +1,15 @@
; Multiplies r1 and r2, returning the lower part of the result
; Arguments:
; r1 - The first value
; r2 - The second value
; Result:
; r1 - The lower 32 bits of the result
; Clobbers: r2, r3, r4, r5
pub mul_low: pub mul_low:
mov r3, 0 ; result mov r3, 0 ; result
mov r4, 31 ; loop counter mov r4, 31 ; loop counter
mull_loop: mul_low_loop:
asr r5, r2, 31 asr r5, r2, 31
and r5, r5, r1 and r5, r5, r1
lsl r5, r5, r4 lsl r5, r5, r4
@@ -10,14 +17,18 @@ pub mul_low:
lsl r2, r2, 1 lsl r2, r2, 1
sub r4, r4, 1 sub r4, r4, 1
cmp r4, 0 cmp r4, 0
jge mull_loop jge mul_low_loop
mov r1, r3 mov r1, r3
jmp r13 jmp r13
; Calculates the absolute value of the value provided in the r1 register ; Calculates the absolute value of the value provided in the r1 register
; Based on Stanford's BitHacks ; Arguments:
; Clobbers r2 ; r1 - The value for which we want the absolute value
; Result:
; r1 - The calculated absolute value
; Clobbers: r2
; Info: Based on Stanford's BitHacks
pub abs: ; SHOULD BE INLINED pub abs: ; SHOULD BE INLINED
; mask = v >> 31 ; mask = v >> 31
asr r2, r1, 31 asr r2, r1, 31
@@ -28,8 +39,13 @@ pub abs: ; SHOULD BE INLINED
jmp r13 jmp r13
; Calculates the minimum value of the two values provided in the r1 and r2 registers ; Calculates the minimum value of the two values provided in the r1 and r2 registers
; Based on Stanford's BitHacks ; Arguments:
; Clobbers flags ; r1 - The first value
; r2 - The second value
; Result:
; r1 - The smaller value
; Clobbers: Nothing
; Info: Based on Stanford's BitHacks
pub min: ; SHOULD BE INLINED pub min: ; SHOULD BE INLINED
; x < y ; x < y
cmp r1, r2 cmp r1, r2
@@ -45,8 +61,13 @@ pub min: ; SHOULD BE INLINED
jmp r13 jmp r13
; Calculates the maximum value of the two values provided in the r1 and r2 registers ; Calculates the maximum value of the two values provided in the r1 and r2 registers
; Based on Stanford's BitHacks ; Arguments:
; Clobbers r2 and flags ; r1 - The first value
; r2 - The second value
; Result:
; r1 - The smaller value
; Clobbers: r2
; Info: Based on Stanford's BitHacks
pub max: ; SHOULD BE INLINED pub max: ; SHOULD BE INLINED
; x < y ; x < y
cmp r1, r2 cmp r1, r2
+1
View File
@@ -1,2 +1,3 @@
pub include bit pub include bit
pub include imath pub include imath
pub include strint
+188
View File
@@ -0,0 +1,188 @@
; Internal register assignments:
; r1 - Partially parsed output integer
; r2 - Parsing position
; r3 - Character being parsed
; r4 - Set to -1 if the input is negative
; Convert string to integer
; Arguments:
; r1 - Pointer to string
; Result:
; r1 - Parsed integer
; r2 - Pointer to first rejected input byte
; Clobbers:
; flags
; r3 - last character read
; r4 - Negative marker
; Note: Unless the input is "0", tail-calls into a base-specific specialization.
pub atoi:
mov r2, r1
mov r1, 0
mov r4, 0
load_8 r3, [r2]
cmp r3, 0x2D ; '-'
jne atoi_positive
sub r4, zr, 1 ; Set r4 to -1
add r2, r2, 1
atoi_positive:
load_16 r3, [r2] ; 2-byte prefix "0b", "0o", "0x", etc.
or r3, r3, 0x20 ; 2nd char to lower case
add r2, r2, 2
cmp r3, 0x3062 ; "0b"
je atoi_bin_loop
cmp r3, 0x306F ; "0o"
je atoi_oct_loop
cmp r3, 0x3078 ; "0x"
je atoi_hex_loop
sub r2, r2, 2 ; no matching prefix, move pointer back
jmp atoi_dec_loop
; Epilogue
atoi_done:
add r1, r1, r4 ; If r4 is -1, negate r1. Else it's 0 and no effect.
xor r1, r1, r4
mov flags, 0 ; No error
jmp r13
; Convert decimal string to integer
; Arguments:
; r1 - Pointer to string
; Result:
; r1 - Parsed integer
; r2 - Pointer to first rejected input byte
; Clobbers:
; flags
; r3 - last character read
; r4 - Negative marker
pub atoi_dec:
mov r2, r1
mov r1, 0
mov r4, 0
load_8 r3, [r2]
cmp r3, 0x2D ; '-'
jne atoi_dec_positive
sub r4, zr, 1 ; Set r4 to -1
add r2, r2, 1
atoi_dec_loop:
load_8 r3, [r2]
atoi_dec_positive:
sub r3, r3, 0x30 ; '0'
cmp r3, 9
ja atoi_done
add r2, r2, 1
lsl flags, r1, 2 ; Use flags to help multiply by 10
add r1, r1, flags
lsl r1, r1, 1
add r1, r1, r3
jmp atoi_dec_loop
; Convert binary string to integer
; Arguments:
; r1 - Pointer to string
; Result:
; r1 - Parsed integer
; r2 - Pointer to first rejected input byte
; Clobbers:
; flags
; r3 - last character read
; r4 - Negative marker
pub atoi_bin:
mov r2, r1
mov r1, 0
mov r4, 0
load_8 r3, [r2]
cmp r3, 0x2D ; '-'
jne atoi_bin_positive
sub r4, zr, 1 ; Set r4 to -1
add r2, r2, 1
atoi_bin_positive:
load_16 r3, [r2] ; check for prefix
or r3, r3, 0x20 ; 2nd char to lower case
cmp r3, 0x3062 ; "0b"
jne atoi_bin_loop
add r2, r2, 2
atoi_bin_loop:
load_8 r3, [r2]
sub r3, r3, 0x30 ; '0'
cmp r3, 1
ja atoi_done
add r2, r2, 1
lsl r1, r1, 1
add r1, r1, r3
jmp atoi_bin_loop
; Convert octal string to integer
; Arguments:
; r1 - Pointer to string
; Result:
; r1 - Parsed integer
; r2 - Pointer to first rejected input byte
; Clobbers:
; flags
; r3 - last character read
; r4 - Negative marker
pub atoi_oct:
mov r2, r1
mov r1, 0
mov r4, 0
load_8 r3, [r2]
cmp r3, 0x2D ; '-'
jne atoi_oct_positive
sub r4, zr, 1 ; Set r4 to -1
add r2, r2, 1
atoi_oct_positive:
load_16 r3, [r2] ; check for prefix
or r3, r3, 0x20 ; 2nd char to lower case
cmp r3, 0x306F ; "0o"
jne atoi_oct_loop
add r2, r2, 2
atoi_oct_loop:
load_8 r3, [r2]
sub r3, r3, 0x30 ; '0'
cmp r3, 7
ja atoi_done
add r2, r2, 1
lsl r1, r1, 3
add r1, r1, r3
jmp atoi_oct_loop
; Convert hexadecimal string to integer
; Arguments:
; r1 - Pointer to string
; Result:
; r1 - Parsed integer
; r2 - Pointer to first rejected input byte
; Clobbers:
; flags
; r3 - last character read
; r4 - Negative marker
pub atoi_hex:
mov r2, r1
mov r1, 0
mov r4, 0
load_8 r3, [r2]
cmp r3, 0x2D ; '-'
jne atoi_hex_positive
sub r4, zr, 1 ; Set r4 to -1
add r2, r2, 1
atoi_hex_positive:
load_16 r3, [r2] ; check for prefix
or r3, r3, 0x20 ; 2nd char to lower case
cmp r3, 0x3078 ; "0x"
jne atoi_hex_loop
add r2, r2, 2
atoi_hex_loop:
load_8 r3, [r2]
sub r3, r3, 0x30 ; '0'
cmp r3, 10
jb atoi_hex_add
sub r3, r3, 0x11 ; 'A' - '0'
and r3, r3, 0xdf ; to lower case
cmp r3, 5 ; 0-5: 6 letters
ja atoi_done
add r3, r3, 10 ; Adjust for digits below
atoi_hex_add:
add r2, r2, 1
lsl r1, r1, 4
add r1, r1, r3
jmp atoi_hex_loop
+55
View File
@@ -0,0 +1,55 @@
; test harness for strint.atoi
; Registers:
; r8 - test address
; r9 - expected result
; r10 - actual length
; r11 - expected length
mov r8, tests
next_test:
; Set up arguments and run test
add r1, r8, 5 ; Start of test string
mov r13, atoi_test_ret
jmp stdlib.strint.atoi
atoi_test_ret:
; Load reference data
load_32 r9, [r8] ; Expected result
sub r10, r2, r8
sub r10, r10, 5 ; Actual string length
add r11, r8, 4 ; Address of expected length
load_8 r11, [r11] ; Expected length
; Verify results
cmp r1, r9
incorrect_result: jne incorrect_result
cmp r10, r11
incorrect_length: jne incorrect_length
; Next test
add r8, r8, 0x10
cmp r8, end_of_tests
jl next_test
; Done
success: jmp success
include stdlib
@0x1000
tests:
; inlen is the number of input bytes the function is expected to consume
; addr result inlen instr
@0x1000 U32 0 U8 0 "\0"
@0x1010 U32 0 U8 1 "0\0"
@0x1020 U32 1 U8 1 "1\0"
@0x1030 U32 2 U8 1 "2:\0"
@0x1040 U32 42 U8 2 "42\0"
@0x1050 U32 67 U8 2 "67lol\0"
@0x1060 U32 0x69a U8 5 "0x69a@\0"
@0x1070 U32 0x4B4 U8 5 "0x4B4g\0"
@0x1080 U32 0o23 U8 4 "0o239\0"
@0x1090 U32 0b1011 U8 6 "0b1011\0"
@0x10a0 U32 0b10001 U8 7 "0b100012\0"
@0x10b0 U32 0xFFFFFFEB U8 3 "-21\0" ; Yuk
@0x10c0
end_of_tests: