-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
lib/ce reviewed, useable items moved to lib/agon
lib/ce reviewed, useable items moved to lib/agon - other disabled in linker_script
- Loading branch information
Showing
13 changed files
with
899 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
; --- | ||
; uint32_t atomic_load_32(volatile uint32_t *p) | ||
; --- | ||
assume adl=1 | ||
|
||
section .text | ||
public _atomic_load_32 | ||
_atomic_load_32: | ||
pop hl | ||
ex (sp),iy | ||
push hl | ||
ld c,0 | ||
retry: | ||
; Wait for a different (increasing) amount of time before each retry to prevent | ||
; getting caught in an endless loop of the value changing between reads with a | ||
; fixed period equal to the amount of time it takes for each retry | ||
inc c | ||
ld b,c | ||
wait: | ||
djnz wait | ||
; Read the value twice. | ||
lea hl,iy+3 | ||
; Time between first and last byte read: | ||
ld de,(iy) ; 2R | ||
ld a,(hl) ; + 1F+1R | ||
cp a,(hl) ; + 1F+1R | ||
ld hl,(iy) ; + 3F+3R | ||
; = 5F+7R | ||
; = 48cc (assuming F = R = 3) | ||
; = 1us (assuming 48MHz clock speed) | ||
; Don't need to worry about DMA, just | ||
; retry until not interrupted by DMA | ||
; Retry if the values read differ. | ||
; | ||
; If the values differ, then the underlying value changed between reading the | ||
; first byte of the first 32-bit read and the last byte of the second 32-bit | ||
; read: | ||
; * If a change occurs between the two 32-bit reads, then both values read | ||
; remain valid. | ||
; * If a change occurs in the middle of one of the 32-bit reads: | ||
; * If the bytes already read change but the bytes yet to read do not | ||
; change, then the value read is the valid value before the change. | ||
; * If the bytes already read do not change but the yet still to read | ||
; change, then the value read is the valid value after the change. | ||
; * If the bytes already read and the bytes yet to read change, then the | ||
; value read is an invalid mix of the values before and after the change. | ||
; | ||
; Without reading the value again, there is not enough information to determine | ||
; if the third case occurred. If it did occur, then one of the values is | ||
; invalid. But there is also not enough information to determine which is | ||
; invalid, and therefore which is valid. So reading the value must be retried. | ||
; | ||
; (Furthermore, if a change occurs in the middle of both 32-bit reads and the | ||
; bytes already read change in both, then both values read become invalid.) | ||
jr nz,retry | ||
sbc hl,de | ||
jr nz,retry | ||
; Values don't differ, good to go. | ||
add hl,de | ||
ld e,a ; euhl = value read | ||
ret |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
; --- | ||
; uint32_t atomic_load_decreasing_32(volatile uint32_t *p) | ||
; --- | ||
assume adl=1 | ||
|
||
section .text | ||
public _atomic_load_decreasing_32 | ||
_atomic_load_decreasing_32: | ||
pop hl | ||
ex (sp),iy | ||
push hl | ||
; Temporarily disable interrupts. | ||
ld a,i | ||
di | ||
; Read the value twice. | ||
; first value read = cude, second value read = auhl | ||
; Time between first and last byte read: | ||
ld de,(iy) ; 2R | ||
ld c,(iy+3) ; + 3F+1R | ||
ld hl,(iy) ; + 3F+3R | ||
ld a,(iy+3) ; + 3F+1R | ||
; = 9F+7R | ||
; = 56cc (assuming F = R = 3) | ||
; ~ 1.17us (assuming 48MHz clock speed) | ||
; + approximate worst-case LCD + USB DMA | ||
; ~ 5us | ||
; Re-enable interrupts if they were previously enabled. | ||
jp po,no_ei | ||
ei | ||
no_ei: | ||
; Compare and return the greater of the two values read. | ||
; | ||
; If the values differ, then the underlying value changed between reading the | ||
; first byte of the first 32-bit read and the last byte of the second 32-bit | ||
; read: | ||
; * If a change occurs between the two 32-bit reads, then both values read | ||
; remain valid. | ||
; * If a change occurs in the middle of one of the 32-bit reads: | ||
; * If the bytes already read change but the bytes yet to read do not | ||
; change, then the value read is the valid value before the change. | ||
; * If the bytes already read do not change but the yet still to read | ||
; change, then the value read is the valid value after the change. | ||
; * If the bytes already read and the bytes yet to read change, then the | ||
; value read is an invalid mix of the values before and after the change. | ||
; | ||
; If the final case did not occur, then both values read are valid. | ||
; | ||
; If the final case occurred for only the second value read, then due to reading | ||
; bytes in little-endian order, one to three upper bytes will reflect the | ||
; decreased value after the change. Regardless of the lower bytes, the valid, | ||
; first value read will be greater than the invalid, second value read. | ||
; | ||
; If the final case occurred for only the first value read, then due to reading | ||
; bytes in little-endian order, one to three upper bytes will reflect the | ||
; decreased value after the change, while the remaining one to three lower bytes | ||
; will reflect the value before the change. If it is assumed that the value | ||
; decreased by less than 256, then the upper bytes must have decreased through | ||
; borrow and the lower bytes of the valid, second value read will be greater | ||
; than the lower bytes of the invalid, first value read. And because the full | ||
; second value read will reflect the the decreased value after the change, and | ||
; therefore the two values read will only differ in the lower bytes, it follows | ||
; that the full, valid, second valid read will be greater than the full, | ||
; invalid, first value read. (Note that this assertion can be extended to | ||
; include 256 because only one byte would change, making this whole case | ||
; unreachable.) | ||
; | ||
; If the final case occurred for both values read, then both are invalid. There | ||
; is no reasonable way to detect this, so it is assumed that this did not occur. | ||
; | ||
; Combining all of these cases and assumptions, the greater of the two values | ||
; read will always be valid. | ||
or a,a | ||
sbc hl,de | ||
sbc a,c ; auhl = second value read | ||
; - first value read | ||
jr c,swap | ||
; second value read >= first value read | ||
; ==> second value read is valid | ||
add hl,de | ||
adc a,c | ||
ld e,a ; euhl = second value read | ||
ret | ||
|
||
swap: | ||
; second value read < first value read | ||
; ==> first value read is valid | ||
ex de,hl | ||
ld e,c ; euhl = first value read | ||
ret |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
; --- | ||
; uint32_t atomic_load_increasing_32(volatile uint32_t *p) | ||
; --- | ||
assume adl=1 | ||
|
||
section .text | ||
public _atomic_load_increasing_32 | ||
_atomic_load_increasing_32: | ||
; CC: 202 + 9 * read_1_invalid + 3 * ie | ||
; Timing assumes fetching from RAM (4cc) and reading from non-RAM (3cc). | ||
|
||
; Read the argument. | ||
pop hl | ||
ex (sp),iy ; iy = p | ||
push hl | ||
; ^ 48 cc | ||
; Temporarily disable interrupts. | ||
ld a,i | ||
di | ||
; ^ 12 cc | ||
; Read from the pointer twice: first into cude, second into auhl. | ||
; Time between first and last byte read: | ||
ld de,(iy) ; 2R | ||
; ^ 21 cc | ||
; 48 + 12 + 21 - 6 = 75 cc until first value captured if valid | ||
ld c,(iy+3) ; + 3F + 1R | ||
ld hl,(iy) ; + 3F + 3R | ||
; ^ 36 cc | ||
; 48 + 12 + 21 + 36 - 5 = 112 cc until second value captured if valid | ||
ld a,(iy+3) ; + 3F + 1R | ||
; == 9F + 7R | ||
; == 57 cc | ||
; + 9 * 19 cc = 171 cc (worst-case DMA) | ||
; = 228 cc | ||
; ^ 15 cc | ||
; Re-enable interrupts if they were previously enabled. | ||
jp po,no_ei | ||
ei | ||
no_ei: | ||
; ^ 17 + 3 * ie cc | ||
; Compare and return the lesser of the two values read. | ||
; | ||
; If the values are the same, then the underlying value must not have changed | ||
; during the reads, so both values are valid. | ||
; | ||
; If the values differ, then the underlying value changed between reading the | ||
; first byte of the first 32-bit read and the last byte of the second 32-bit | ||
; read: | ||
; * If a change occurs between the two 32-bit reads, then both values read | ||
; remain valid. | ||
; * If a change occurs in the middle of one of the 32-bit reads: | ||
; * If the bytes already read change but the bytes yet to read do not | ||
; change, then the value read is the valid value before the change. | ||
; * If the bytes already read do not change but the yet still to read | ||
; change, then the value read is the valid value after the change. | ||
; * If the bytes already read and the bytes yet to read change, then the | ||
; value read is an invalid mix of the values before and after the change. | ||
; | ||
; If the final case did not occur, then both values read are valid. | ||
; | ||
; If the final case occurred for only the second value read, then due to reading | ||
; bytes in little-endian order, one to three upper bytes will reflect the | ||
; increased value after the change. Regardless of the lower bytes, the valid, | ||
; first value read will be less than the invalid, second value read. | ||
; | ||
; If the final case occurred for only the first value read, then due to reading | ||
; bytes in little-endian order, one to three upper bytes will reflect the | ||
; increased value after the change, while the remaining one to three lower bytes | ||
; will reflect the value before the change. If it is assumed that the value | ||
; increased by less than 256, then the upper bytes must have increased through | ||
; carry and the lower bytes of the valid, second value read will be less than | ||
; the lower bytes of the invalid, first value read. And because the full second | ||
; value read will reflect the the increased value after the change, and | ||
; therefore the two values read will only differ in the lower bytes, it follows | ||
; that the full, valid, second valid read will be less than the full, invalid, | ||
; first value read. (Note that this assertion can be extended to include 256 | ||
; because only one byte would change, making this whole case unreachable.) | ||
; | ||
; If the final case occurred for both values read, then both are invalid. There | ||
; is no reasonable way to detect this, so it is assumed that this did not occur. | ||
; | ||
; Combining all of these cases and assumptions, the lesser of the two values | ||
; read will always be valid. | ||
or a,a | ||
sbc hl,de | ||
sbc a,c ; auhl = second value read | ||
; - first value read | ||
; ^ 16 cc | ||
jr c,no_swap | ||
; second value read >= first value read | ||
; ==> first value read is valid | ||
ex de,hl | ||
ld e,c ; euhl = first value read | ||
ret | ||
; ^ 37 cc | ||
|
||
no_swap: | ||
; second value read < first value read | ||
; ==> second value read is valid | ||
add hl,de | ||
adc a,c | ||
ld e,a ; euhl = second value read | ||
ret | ||
; ^ 46 cc (including conditional jr into) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
; void delay(uint16_t millis); | ||
|
||
assume adl=1 | ||
|
||
if 0 | ||
; Minimal caller code (for timing calculation). | ||
call _delay | ||
; ^ 22 cc | ||
end if | ||
|
||
section .text | ||
public _delay | ||
_delay: | ||
; Timing assumes fetching from RAM (4cc) and the first timer read being valid. | ||
|
||
; Get millis. | ||
pop de | ||
ex (sp), hl ; hl = millis | ||
push de | ||
; ^ 48 cc | ||
; Abort ASAP if millis == 0. | ||
ld a, l | ||
or a, h | ||
ret z | ||
; ^ 13 cc | ||
; Get the start time ASAP. | ||
push hl | ||
call _clock ; euhl = start | ||
; ^ 32 + cc(_clock) cc | ||
; 22 + 48 + 13 + 32 + 48 + 75 = 238 cc until start time captured | ||
ex (sp), hl ; hl = millis | ||
push de | ||
; Convert millis to clock ticks. | ||
dec.s hl | ||
xor a, a ; a = 0 | ||
ld e, a ; euhl = millis - 1 | ||
.multiplier_fp := (256 * 32768 + 1000 - 1) / 1000 | ||
assert .multiplier_fp shr 24 = 0 | ||
ld bc, .multiplier_fp ; aubc = ceil(256 * 32768 / 1e3) | ||
assert ($FFFF * .multiplier_fp) shr 32 = 0 | ||
call __lmulu ; euhl = (millis - 1) * | ||
; ceil(256 * 32768 / 1e3) | ||
; https://docs.google.com/spreadsheets/d/1mZwDn6rEw3-uSQPuy48Ez0UWIvnggLiJxWft4u4OtcU/edit?usp=sharing | ||
.correction_fp := 413 | ||
ld bc, .multiplier_fp + .correction_fp | ||
add hl, bc | ||
adc a, e ; auhl = millis * | ||
; ceil(256 * 32768 / 1e3) + | ||
; correction_fp | ||
push af | ||
inc sp | ||
push hl | ||
inc sp | ||
pop hl ; uhl = (millis * | ||
; ceil(256 * 32768 / 1e3) + | ||
; correction_fp) / | ||
; 256 | ||
; = ticks + correction | ||
inc sp | ||
xor a, a ; auhl = ticks + correction | ||
; Join common code for the rest. | ||
jp ___sleep_common.3 | ||
|
||
|
||
public _msleep | ||
_msleep := _delay | ||
|
||
|
||
extern ___sleep_common.3 | ||
extern __lmulu | ||
extern _clock |
Oops, something went wrong.