mirror of
https://github.com/irmen/prog8.git
synced 2024-12-24 16:29:21 +00:00
ringbuffer and pointer optimization todo
This commit is contained in:
parent
78c7ee247a
commit
9046fe8d3a
@ -284,12 +284,6 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
SourceStorageKind.MEMORY -> {
|
SourceStorageKind.MEMORY -> {
|
||||||
fun assignViaExprEval(expression: PtExpression) {
|
|
||||||
assignExpressionToVariable(expression, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
|
||||||
asmgen.loadAFromZpPointerVar("P8ZP_SCRATCH_W2", false)
|
|
||||||
assignRegisterByte(assign.target, CpuRegister.A, false, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
val value = assign.source.memory!!
|
val value = assign.source.memory!!
|
||||||
when (value.address) {
|
when (value.address) {
|
||||||
is PtNumber -> {
|
is PtNumber -> {
|
||||||
@ -304,10 +298,10 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
if(asmgen.tryOptimizedPointerAccessWithA(addrExpr, false)) {
|
if(asmgen.tryOptimizedPointerAccessWithA(addrExpr, false)) {
|
||||||
assignRegisterByte(assign.target, CpuRegister.A, false, true)
|
assignRegisterByte(assign.target, CpuRegister.A, false, true)
|
||||||
} else {
|
} else {
|
||||||
assignViaExprEval(value.address)
|
assignByteFromAddressExpression(value.address, assign.target)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> assignViaExprEval(value.address)
|
else -> assignByteFromAddressExpression(value.address, assign.target)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SourceStorageKind.EXPRESSION -> {
|
SourceStorageKind.EXPRESSION -> {
|
||||||
@ -319,6 +313,24 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun assignByteFromAddressExpression(address: PtExpression, target: AsmAssignTarget) {
|
||||||
|
// TODO optimize this into more efficient code, using indexed register ,Y instead of explicitly calculating the full pointer value, or use self=modifying code and just use absolute addressing.
|
||||||
|
// see: https://discord.com/channels/547559626024157184/629863245934755860/1262873088782110750
|
||||||
|
assignExpressionToVariable(address, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
||||||
|
asmgen.loadAFromZpPointerVar("P8ZP_SCRATCH_W2", false)
|
||||||
|
assignRegisterByte(target, CpuRegister.A, false, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun storeByteInAToAddressExpression(addressExpr: PtExpression, saveA: Boolean) {
|
||||||
|
// TODO optimize this into more efficient code, using indexed register ,Y instead of explicitly calculating the full pointer value, or use self=modifying code and just use absolute addressing.
|
||||||
|
// see: https://discord.com/channels/547559626024157184/629863245934755860/1262873088782110750
|
||||||
|
if(saveA) asmgen.out(" pha")
|
||||||
|
assignExpressionToVariable(addressExpr, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
||||||
|
if(saveA) asmgen.out(" pla")
|
||||||
|
asmgen.storeAIntoZpPointerVar("P8ZP_SCRATCH_W2", false)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun assignExpression(assign: AsmAssignment, scope: IPtSubroutine?) {
|
private fun assignExpression(assign: AsmAssignment, scope: IPtSubroutine?) {
|
||||||
when(val value = assign.source.expression!!) {
|
when(val value = assign.source.expression!!) {
|
||||||
is PtAddressOf -> {
|
is PtAddressOf -> {
|
||||||
@ -3746,17 +3758,8 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
|
|
||||||
fun storeViaExprEval() {
|
fun storeViaExprEval() {
|
||||||
when(addressExpr) {
|
when(addressExpr) {
|
||||||
is PtNumber, is PtIdentifier -> {
|
is PtNumber, is PtIdentifier -> storeByteInAToAddressExpression(addressExpr, false)
|
||||||
assignExpressionToVariable(addressExpr, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
else -> storeByteInAToAddressExpression(addressExpr, true)
|
||||||
asmgen.storeAIntoZpPointerVar("P8ZP_SCRATCH_W2", false)
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
// same as above but we need to save the A register
|
|
||||||
asmgen.out(" pha")
|
|
||||||
assignExpressionToVariable(addressExpr, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
|
||||||
asmgen.out(" pla")
|
|
||||||
asmgen.storeAIntoZpPointerVar("P8ZP_SCRATCH_W2", false)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
; any() and all() checks on arrays/memory buffers
|
; any() and all() checks on arrays/memory buffers.
|
||||||
|
; These were builtin functions in older versions of the language.
|
||||||
|
|
||||||
%option no_symbol_prefixing, ignore_unused
|
%option no_symbol_prefixing, ignore_unused
|
||||||
|
|
||||||
|
@ -25,17 +25,19 @@ smallringbuffer {
|
|||||||
buffer[head] = value
|
buffer[head] = value
|
||||||
head++
|
head++
|
||||||
fill++
|
fill++
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
sub putw(uword value) -> bool {
|
sub putw(uword value) -> bool {
|
||||||
; -- store a word in the buffer, returns success
|
; -- store a word in the buffer, returns success
|
||||||
if fill>=254
|
if fill>=254
|
||||||
return false
|
return false
|
||||||
fill+=2
|
fill += 2
|
||||||
buffer[head] = lsb(value)
|
buffer[head] = lsb(value)
|
||||||
head++
|
head++
|
||||||
buffer[head] = msb(value)
|
buffer[head] = msb(value)
|
||||||
head++
|
head++
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
sub get() -> ubyte {
|
sub get() -> ubyte {
|
||||||
@ -56,7 +58,7 @@ smallringbuffer {
|
|||||||
sys.clear_carry()
|
sys.clear_carry()
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
fill-=2
|
fill -= 2
|
||||||
tail++
|
tail++
|
||||||
cx16.r0L = buffer[tail]
|
cx16.r0L = buffer[tail]
|
||||||
tail++
|
tail++
|
||||||
@ -67,5 +69,84 @@ smallringbuffer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
; TODO ringbuffer (FIFO queue) using more than 1 page of ram (maybe even banked ram on the x16)
|
ringbuffer {
|
||||||
|
; -- A ringbuffer (FIFO queue) that occupies a single page in memory, containing 8 KB maximum.
|
||||||
|
; You can store and retrieve words too.
|
||||||
|
|
||||||
|
uword fill
|
||||||
|
uword head
|
||||||
|
uword tail
|
||||||
|
uword buffer_ptr = memory("ringbuffer", 8192, 0)
|
||||||
|
|
||||||
|
sub init() {
|
||||||
|
; -- (re)initialize the ringbuffer, you must call this before using the other routines
|
||||||
|
head = fill = 0
|
||||||
|
tail = 8191
|
||||||
|
}
|
||||||
|
|
||||||
|
sub put(ubyte value) -> bool {
|
||||||
|
; -- store a byte in the buffer, returns success
|
||||||
|
if fill==8192
|
||||||
|
return false
|
||||||
|
buffer_ptr[head] = value
|
||||||
|
inc_head()
|
||||||
|
fill++
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
sub putw(uword value) -> bool {
|
||||||
|
; -- store a word in the buffer, returns success
|
||||||
|
if fill>=8191
|
||||||
|
return false
|
||||||
|
fill += 2
|
||||||
|
buffer_ptr[head] = lsb(value)
|
||||||
|
inc_head()
|
||||||
|
buffer_ptr[head] = msb(value)
|
||||||
|
inc_head()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get() -> ubyte {
|
||||||
|
; -- retrieves a byte from the buffer. Also sets Carry flag: set=success, clear=buffer was empty
|
||||||
|
if fill==0 {
|
||||||
|
sys.clear_carry()
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
fill--
|
||||||
|
inc_tail()
|
||||||
|
cx16.r0L = buffer_ptr[tail]
|
||||||
|
sys.set_carry()
|
||||||
|
return cx16.r0L
|
||||||
|
}
|
||||||
|
|
||||||
|
sub getw() -> uword {
|
||||||
|
; -- retrieves a word from the buffer. Also sets Carry flag: set=success, clear=buffer was empty
|
||||||
|
if fill<2 {
|
||||||
|
sys.clear_carry()
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
fill -= 2
|
||||||
|
inc_tail()
|
||||||
|
cx16.r0L = buffer_ptr[tail]
|
||||||
|
inc_tail()
|
||||||
|
cx16.r0H = buffer_ptr[tail]
|
||||||
|
sys.set_carry()
|
||||||
|
return cx16.r0
|
||||||
|
}
|
||||||
|
|
||||||
|
sub inc_head() {
|
||||||
|
head++
|
||||||
|
if msb(head)==$20
|
||||||
|
head=0
|
||||||
|
}
|
||||||
|
|
||||||
|
sub inc_tail() {
|
||||||
|
tail++
|
||||||
|
if msb(tail)==$20
|
||||||
|
tail=0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
; TODO ringbuffer (FIFO queue) should use banked ram on the X16, but still work on virtual
|
||||||
; TODO stack (LIFO queue) using more than 1 page of ram (maybe even banked ram on the x16)
|
; TODO stack (LIFO queue) using more than 1 page of ram (maybe even banked ram on the x16)
|
||||||
|
@ -866,6 +866,7 @@ io_error:
|
|||||||
|
|
||||||
sub f_seek(uword pos_hiword, uword pos_loword) {
|
sub f_seek(uword pos_hiword, uword pos_loword) {
|
||||||
; -- seek in the reading file opened with f_open, to the given 32-bits position
|
; -- seek in the reading file opened with f_open, to the given 32-bits position
|
||||||
|
; Note: this will not work if you have already read the last byte of the file! Then you must close and reopen the file first.
|
||||||
ubyte[6] command = ['p',0,0,0,0,0]
|
ubyte[6] command = ['p',0,0,0,0,0]
|
||||||
command[1] = READ_IO_CHANNEL ; f_open uses this secondary address
|
command[1] = READ_IO_CHANNEL ; f_open uses this secondary address
|
||||||
command[2] = lsb(pos_loword)
|
command[2] = lsb(pos_loword)
|
||||||
|
@ -3,6 +3,8 @@ TODO
|
|||||||
|
|
||||||
See open issues on github.
|
See open issues on github.
|
||||||
|
|
||||||
|
Optimize code in assignByteFromAddressExpression() and storeByteInAToAddressExpression()
|
||||||
|
|
||||||
Re-generate the skeletons doc files.
|
Re-generate the skeletons doc files.
|
||||||
|
|
||||||
optimize signed byte/word division by powers of 2 (and shift right?), it's now using divmod routine. (also % ?)
|
optimize signed byte/word division by powers of 2 (and shift right?), it's now using divmod routine. (also % ?)
|
||||||
@ -75,9 +77,8 @@ Compiler:
|
|||||||
But all library code written in asm uses .proc already..... (textual search/replace when writing the actual asm?)
|
But all library code written in asm uses .proc already..... (textual search/replace when writing the actual asm?)
|
||||||
Once new codegen is written that is based on the IR, this point is mostly moot anyway as that will have its own dead code removal on the IR level.
|
Once new codegen is written that is based on the IR, this point is mostly moot anyway as that will have its own dead code removal on the IR level.
|
||||||
- Zig-like try-based error handling where the V flag could indicate error condition? and/or BRK to jump into monitor on failure? (has to set BRK vector for that) But the V flag is also set on certain normal instructions
|
- Zig-like try-based error handling where the V flag could indicate error condition? and/or BRK to jump into monitor on failure? (has to set BRK vector for that) But the V flag is also set on certain normal instructions
|
||||||
- Zig-like defer to execute a statement/anonymousscope when subroutine exits? (problem is, we have jump insructions and inline asm , where we lose track of when exactly the subroutine exits...)
|
- Zig-like defer to execute a statement/anonymousscope when subroutine exits? (problem is, we have jump instructions and inline asm , where we lose track of when exactly the subroutine exits...)
|
||||||
- generate WASM to eventually run prog8 on a browser canvas? Use binaryen toolkit and/or my binaryen kotlin library?
|
- generate WASM to eventually run prog8 on a browser canvas? Use binaryen toolkit and/or my binaryen kotlin library?
|
||||||
- implement split words arrays all()
|
|
||||||
|
|
||||||
|
|
||||||
Libraries:
|
Libraries:
|
||||||
|
@ -1,42 +1,27 @@
|
|||||||
|
%import buffers
|
||||||
%import textio
|
%import textio
|
||||||
%option no_sysinit
|
%option no_sysinit
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
|
|
||||||
main {
|
main {
|
||||||
sub start() {
|
sub start() {
|
||||||
ubyte @shared b1 = %10101010
|
uword @shared ptr = $2000
|
||||||
ubyte @shared b2 = %00001111
|
uword @shared index = 1000
|
||||||
|
|
||||||
b1 &= ~b2
|
cx16.r0L = @(ptr+index)
|
||||||
txt.print_ubbin(b1, true)
|
cx16.r1L = ptr[index]
|
||||||
txt.nl()
|
@(ptr+index) = cx16.r0L
|
||||||
b1 |= b2
|
ptr[index] = cx16.r1L
|
||||||
txt.print_ubbin(b1, true)
|
; txt.print_ub(ptr[index])
|
||||||
txt.nl()
|
|
||||||
|
|
||||||
b1 = %11001100
|
|
||||||
b2 = %11110000
|
|
||||||
|
|
||||||
b1 &= ~b2
|
|
||||||
txt.print_ubbin(b1, true)
|
|
||||||
txt.nl()
|
|
||||||
b1 |= b2
|
|
||||||
txt.print_ubbin(b1, true)
|
|
||||||
txt.nl()
|
|
||||||
|
|
||||||
; smallringbuffer.init()
|
|
||||||
;
|
|
||||||
; smallringbuffer.put(123)
|
|
||||||
; txt.print_ub(smallringbuffer.get())
|
|
||||||
; txt.nl()
|
; txt.nl()
|
||||||
;
|
; ptr[index] = 123
|
||||||
; smallringbuffer.putw(12345)
|
; txt.print_ub(ptr[index])
|
||||||
; txt.print_uw(smallringbuffer.getw())
|
|
||||||
; txt.nl()
|
; txt.nl()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;
|
;
|
||||||
;main {
|
;main {
|
||||||
; sub start() {
|
; sub start() {
|
||||||
|
Loading…
Reference in New Issue
Block a user