58 Commits
Author SHA1 Message Date
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
6 changed files with 254 additions and 33 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.
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.
You also need to include [[globals.asm]] as the first line in your assembly file.
If you just want to use the standard library [[src/stdlib.asm]] is your main header, include it after your code.
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
+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 imath
pub include array
pub include console
pub include mem
; Needs to be last!
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