64 Commits
Author SHA1 Message Date
Micha_i ff5e1be8fd Merge branch 'main' into fast-math 2026-09-04 23:11:37 +02:00
Michał Isalski b97e17fa84 Changed mul_low algorithm to radix-16-1 algorithm with swap 2026-09-04 23:08:06 +02:00
ShatteredMINT 50f7040f59 Merge pull request 'Add mem.compare, mem.copy, mem.fill32, unsafe_mem.compare' (#13) from Mutex/symphony_stdlib:mem_ops into main
Reviewed-on: #13
2026-09-04 21:55:22 +02:00
ShatteredMINT 57934309c2 Merge branch 'main' into mem_ops 2026-09-04 21:53:34 +02:00
ShatteredMINT 32a157e87d Merge pull request 'Changed mul_low algorithm to radix-4 multiplication' (#16) from Micha_i/symphony_stdlib:fast-math into main
Reviewed-on: #16
2026-09-04 08:21:49 +02:00
Michał Isalski a00c7f2a84 Changed mul_low algorithm to radix-4 multiplication 2026-09-04 00:11:33 +02:00
MutexRaceCondition ae0684f98a Merged main into mem_ops 2026-09-03 21:15:08 +02:00
MutexRaceCondition 257735d776 Remove leftover files 2026-09-03 21:01:07 +02:00
MutexRaceCondition 809f6e35d5 Merged with main 2026-09-03 20:58:17 +02:00
ShatteredMINT c83269fcf7 fix path to stdlib.asm 2026-09-03 20:35:41 +02:00
ShatteredMINT 6bf0c0a4fc add examples directory 2026-09-03 20:34:56 +02:00
ShatteredMINT 697445feec add tests folder 2026-09-03 20:34:16 +02:00
ShatteredMINT 7c49c5212e move assembly files into src directory 2026-09-03 20:32:40 +02:00
ShatteredMINT 6ff1a43c32 Merge pull request 'Added find_index array function' (#9) from Micha_i/symphony_stdlib:array-functions into main
Reviewed-on: #9
2026-09-03 20:30:09 +02:00
Michał Isalski b5249a43b9 Merge branch 'main' into array-functions 2026-09-03 20:29:24 +02:00
MutexRaceCondition 655ce0237e Fixed unsafe_mem.compare not working correctly when both input pointers are the same 2026-09-03 18:48:57 +02:00
MutexRaceCondition a1e19112c5 Specialised unsafe.asm to unsafe_mem.asm, and renamed unsafe.memcmp to unsafe.compare 2026-09-03 15:22:40 +02:00
MutexRaceCondition 3d874cebbd Merged with main 2026-09-03 15:17:00 +02:00
MutexRaceCondition 4aca17aa40 Moved memory operations into mem.asm (and renamed them) 2026-09-03 15:15:54 +02:00
ShatteredMINT 0188969dab Merge pull request 'Added read_line console function' (#10) from Micha_i/symphony_stdlib:console-functions into main
Reviewed-on: #10
2026-09-03 14:56:12 +02:00
Micha_i 5c9a33c24d Merge branch 'main' into array-functions 2026-09-03 09:04:11 +02:00
Micha_i e4edb56d08 Merge branch 'main' into console-functions 2026-09-03 09:04:03 +02:00
Michał Isalski aa8eef7b1f Fixed at-address 2026-09-02 22:56:24 +02:00
ShatteredMINT 37d0e556d2 Merge pull request 'clean up confusion about function template' (#14) from meta-documentation into main
Reviewed-on: #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
Michał Isalski 870b6ebc39 Merge branch 'main' into console-functions 2026-09-02 20:41:38 +02:00
Michał Isalski 1e4ad8f64c Merge branch 'main' into array-functions 2026-09-02 20:40:49 +02:00
MutexRaceCondition 7b43e75a9d Added memcmp, memcpy, memset32, unsafe.memcmp 2026-09-02 19:41:56 +02:00
Michal Isalski ca1ba67fd8 Added a shift conversion LUT and finished read_line (except Writeback) 2026-09-02 13:20:55 +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: #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
Michał Isalski f9bb69f1f5 Added storing shift status 2026-09-02 02:03:00 +02:00
ShatteredMINT 9816111f38 clarify stack arguments 2026-09-01 14:08:20 +02:00
Michal Isalski 20e1f17181 Fixed swapped pop instructions 2026-09-01 13:52:45 +02:00
Michal Isalski 625f01166a Made find_index conform to new doc guidelines 2026-09-01 13:52:26 +02:00
ShatteredMINT f2e5c830b3 explain inline comment 2026-09-01 13:48:12 +02:00
Michal Isalski 65caf8aff9 Made read_line compliant to new doc guidelines 2026-09-01 13:47:09 +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
Michal Isalski 1dca814388 One instruction less by using another register 2026-09-01 10:54:29 +02:00
Michal Isalski 9dfb8248a6 Added handling for skipping non-renderable characters
Added handling for backspace character
2026-09-01 10:51:31 +02:00
Michał Isalski 4b962a1f87 Added read_line function 2026-09-01 00:38:37 +02:00
Michał Isalski e6a0739e95 pleegwat's code review fixes 2026-08-31 23:57:55 +02:00
Michał Isalski 1885f304ad Merge branch 'array-functions' of https://gitea.shatteredmint.net/Micha_i/symphony_stdlib into array-functions 2026-08-31 23:55:16 +02:00
Michał Isalski 63b37ab094 Added comment about predicate context 2026-08-31 23:06:59 +02:00
Michał Isalski 6981ff027d Tested and fixed stride->shift conversion missing 2026-08-31 23:06:59 +02:00
Michal Isalski 88c91a8eec Reduced operations to get -1 in register 2026-08-31 23:06:59 +02:00
Michal Isalski a02f0646b4 Fixed the predicate return address 2026-08-31 23:06:59 +02:00
Michal Isalski 7abfcabd73 Added find_index array function 2026-08-31 23:06:59 +02:00
Michał Isalski b476b8aaa3 Added comment about predicate context 2026-08-31 23:06:40 +02:00
Michał Isalski bddb153d9b Tested and fixed stride->shift conversion missing 2026-08-31 23:03:23 +02:00
Michal Isalski 29103d4335 Reduced operations to get -1 in register 2026-08-31 15:30:11 +02:00
Michal Isalski 837e8ba0a6 Fixed the predicate return address 2026-08-31 13:52:27 +02:00
Michal Isalski 6ca77970b8 Added find_index array function 2026-08-31 13:44:07 +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
7 changed files with 299 additions and 47 deletions
-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 -2
View File
@@ -3,8 +3,7 @@
This is a standard library for symphony. 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 [[src/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
+44 -13
View File
@@ -4,22 +4,53 @@
; r2 - The second value ; r2 - The second value
; Result: ; Result:
; r1 - The lower 32 bits of the result ; r1 - The lower 32 bits of the result
; Clobbers: r2, r3, r4, r5 ; Clobbers: r2, r3, r4, r5, r6
pub mul_low: pub mul_low:
mov r3, 0 ; result cmp r1, r2
mov r4, 31 ; loop counter jbe mul_low_noswap
xor r1, r2, r1
xor r2, r1, r2
xor r1, r2, r1
; Passthrough
mul_low_loop: ; Multiplies r1 and r2, returning the lower part of the result
asr r5, r2, 31 ; This method assumes r1 is smaller than r2, which results in faster execution
and r5, r5, r1 ; Arguments:
lsl r5, r5, r4 ; r1 - The first value
add r3, r3, r5 ; r2 - The second value
lsl r2, r2, 1 ; Result:
sub r4, r4, 1 ; r1 - The lower 32 bits of the result
cmp r4, 0 ; Clobbers: r2, r3, r4, r5, r6
jge mul_low_loop pub mul_low_noswap:
mov r1, r3 mov r4, 0 ; r4 has the result
mov r6, mul_loop_end
add r3, r2, r2
mul_loop:
and r5, r1, 14 ; Taking the first four bits, discarding the odd
lsl r5, r5, 1 ; 0000 - 0, 0001 - 2, 0010 - 4, 0011 - 8, etc.
sub r5, r6, r5
jmp r5
add r4, r4, r3
add r4, r4, r3
add r4, r4, r3
add r4, r4, r3
add r4, r4, r3
add r4, r4, r3
add r4, r4, r3
mul_loop_end:
mov flags, r1
jne mul_skip_one
add r4, r4, r2
mul_skip_one:
lsl r2, r2, 4
lsl r3, r3, 4
lsr r1, r1, 4
cmp r1, zr
jne mul_loop
mov r1, r4
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
+174
View File
@@ -0,0 +1,174 @@
; int compare(uint8_t* a, uint8_t* b, size_t count);
; Compares two memory segment of equal length lexicographically.
;
; Arguments:
; - `r1`: A pointer to the first memory segment.
; - `r2`: A pointer to the second memory segment.
; - `r3`: The size of both memory segments.
; Results:
; - `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.
;
pub compare:
; Exclusive end point of the first segment.
add r3, r3, r1
sub r3, r3, 4
_compare__loop:
load_32 r4, [r1]
add r1, r1, 4
load_32 r5, [r2]
add r2, r2, 4
; Comparing two sequences of 4 bytes lexicographically is equivalent to
; comparing the corresponding big endian 32 bit words.
cmp r4, r5
jne _compare__break
; Check if there are enough bytes left to continue with the vectorized loop.
cmp r1, r3
jbe _compare__loop
; `r3 + 4 - r1 = <remaining byte count> = r3 - r1 mod 4`
sub flags, r3, r1
; Check if one of the lowest 2 bits is non-zero
jbe _compare__rem
; If not, we are done. Both segments are equal.
mov r1, 0
jmp r13
_compare__break:
; `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
_compare__rem:
; Compute `S = 8*(4 - <remaining byte count>)` and
; [r1] >> S, [r2] >> S
mov r3, 8
load_32 r4, [r1]
sub r3, r3, flags
load_32 r5, [r2]
lsl r3, r3, 3
lsr r4, r4, r3
lsr r5, r5, r3
; Compare both values, now with garbage bytes removed.
cmp r4, r5
jmp _compare__break
; void copy(void* src, void* dest, size_t count);
; Copies `count` bytes from `src` to `dest`. The two memory segments must not overlap.
;
; Arguments:
; - `r1`: Pointer to the memory segment to be copied.
; - `r2`: Pointer to the memory segment to be copied into.
; - `r3`: Byte size of both the `src` and `dest` segments.
;
pub copy:
; Exclusive end point of the source segment.
add r3, r1, r3
; Last index from where we can safely copy 8 bytes per loop iteration.
sub r3, r3, 8
jmp _copy__loop_entry
_copy__loop:
; Copy 8 bytes from `src` to `dest`.
load_32 flags, [r1]
add r1, r1, 4
store_32 [r2], flags
add r2, r2, 4
load_32 flags, [r1]
add r1, r1, 4
store_32 [r2], flags
add r2, r2, 4
_copy__loop_entry:
; Check if we can process more data in the vectorized loop.
cmp r1, r3
jbe _copy__loop
; The remaining amount of bytes `R` is `R = r3 + 8 - r1 = r3 - r1 mod 8`.
sub flags, r3, r1
; Test if `R` is not a multiple of `4`, i.e. the lowest 2 bits are non-zero.
jbe _copy__rem
; `R` is a multiple of `4`. Special case this.
; Check if `R` is `0`, i.e. the third bit is also 0. In that case, we are already done.
; There are no conditional indirect jumps, so we can't return immediately.
jge _copy__ret
; `R = 4`. No need to update `r1` or `r2`, we don't need them anymore.
load_32 flags, [r1]
store_32 [r2], flags
_copy__ret:
; Return
jmp r13
_copy__rem:
; Optimize the remaining cases for code size.
; End point of the source segment.
add r3, r3, 8
; We already handled the case `R = 0` earlier,
; so no bounds check needed for the first iteration.
_copy__rem_loop:
; Copy 1 byte.
load_8 flags, [r1]
add r1, r1, 1
store_8 [r2], flags
add r2, r2, 1
; Check if we are still within the bounds.
cmp r1, r3
jb _copy__rem_loop
jmp r13
; void fill32(uint8_t* dest, size_t count, uint32_t value);
; Fills `count` bytes in `dest` with `value`. If `count` is not a multiple of 4,
; the least significant bytes of `value` are cut off for the last entry.
;
; Arguments:
; - `r1`: A pointer to the destination segment.
; - `r2`: The size of the destination segment.
; - `r3`: The 32 bit value that the segment is filled with.
;
pub fill32:
; Exclusive end point of the destination segment.
add r2, r1, r2
; Last index from where we can safely write 8 bytes per loop iteration.
sub r2, r2, 8
jmp _fill32__entry
_fill32__loop:
; Set 8 bytes per loop iteraion.
store_32 [r1], r3
add r1, r1, 4
store_32 [r1], r3
add r1, r1, 4
_fill32__entry:
; Check if we can process more data in the vectorized loop.
cmp r1, r2
jbe _fill32__loop
; The remaining amount of bytes `R` is `R = r2 + 8 - r1 = r2 - r1 mod 8`.
sub flags, r2, r1
; Check if the third bit of the remainder is cleared.
jge _fill32__r4
; Otherwise set 4 bytes.
store_32 [r1], r3
add r1, r1, 4
_fill32__r4:
; Check if the two least significant bits of the remainder are zero.
ja _fill32__ret
; Handle the remaining bytes `R` individually, in reverse order.
add r2, r2, 4
; `r1 + 4 - r2 = 4 - R`.
sub flags, r1, r2
; Exclusive end point of the destination segment.
add r2, r2, 4
; Shift out the least significant `8*(4 - R)` bits of the value.
lsl flags, flags, 3
lsr r3, r3, flags
jmp _fill32__loop2_entry
_fill32__loop2:
sub r2, r2, 1
; Write the least significant byte of the value...
store_8 [r2], r3
; and then shift it out.
lsr r3, r3, 8
_fill32__loop2_entry:
cmp r1, r2
jb _fill32__loop2
_fill32__ret:
jmp r13
+2
View File
@@ -1,6 +1,8 @@
pub include bit pub include bit
pub include imath pub include imath
pub include array
pub include console pub include console
pub include mem
; Needs to be last! ; Needs to be last!
pub include LUTs pub include LUTs
+77
View File
@@ -0,0 +1,77 @@
; int compare(uint8_t* a, uint8_t* b, size_t count);
; Compares two memory segment of equal length lexicographically.
; Temporarily modifies the byte at address `a + count`.
;
; Arguments:
; - `r1`: A pointer to the first memory segment.
; - `r2`: A pointer to the second memory segment.
; - `r3`: The size of both memory segments.
; Results:
; - `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.
pub compare:
cmp r1, r2
je _compare__is_eq
; Exclusive end point of the second segment.
add r4, r3, r2
; Exclusive end point of the first segment.
add r3, r3, r1
load_8 r6, [r3]
load_8 flags, [r4]
; Check if the first bytes behind the sequences are equal.
cmp flags, r6
jne _compare__loop
; Change the byte directly behind the first segment.
xor r4, r6, 1
; This would be problematic if someone calls compare with a first segment
; whose end point overlaps the program memory of this function.
store_8 [r3], r4
_compare__loop:
load_32 r4, [r1]
add r1, r1, 4
load_32 r5, [r2]
add r2, r2, 4
; Comparing two sequences of 4 bytes lexicographically is equivalent to
; comparing the corresponding big endian 32 bit words.
cmp r4, r5
je _compare__loop
; We overshot in the loop; decrement r1 again. (Only by 2, we backtrack the rest if necessary later)
sub r1, r1, 2
; Restore the byte we changed.
store_8 [r3], r6
; We encountered two different words. Figure out what byte they differ on.
xor r4, r4, r5
; Store the flags for later, to figure out the return value.
mov r5, flags
; Check if at least one of the two most significant bytes is not 0.
cmp r4, 0xffff
jbe _compare__low2
; If it is, backtrack the remaining 2 indices.
; Shift the most significant bytes to the least significant ones.
sub r1, r1, 2
lsr r4, r4, 16
_compare__low2:
; r1 now points to a non-zero 16 bit value.
; If the 16 bit value at r1-2 is in-bounds, then it is 0.
; Check if the most significant byte of the 16 bit value is 0.
cmp r4, 0xff
ja _compare__low1
; If it is, our target is the least significant byte.
add r1, r1, 1
_compare__low1:
; Otherwise, the target is that non-zero byte.
; Check if the target is out of bounds, i.e. the loop terminated through the "bounds check".
cmp r1, r3
jae _compare__is_eq
; r5 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, r5, 1
lsl r1, r1, 30
jmp r13
_compare__is_eq:
mov r1, 0
jmp r13