mirror of
https://github.com/irmen/prog8.git
synced 2024-12-23 09:32:43 +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 -> {
|
||||
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!!
|
||||
when (value.address) {
|
||||
is PtNumber -> {
|
||||
@ -304,10 +298,10 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
if(asmgen.tryOptimizedPointerAccessWithA(addrExpr, false)) {
|
||||
assignRegisterByte(assign.target, CpuRegister.A, false, true)
|
||||
} else {
|
||||
assignViaExprEval(value.address)
|
||||
assignByteFromAddressExpression(value.address, assign.target)
|
||||
}
|
||||
}
|
||||
else -> assignViaExprEval(value.address)
|
||||
else -> assignByteFromAddressExpression(value.address, assign.target)
|
||||
}
|
||||
}
|
||||
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?) {
|
||||
when(val value = assign.source.expression!!) {
|
||||
is PtAddressOf -> {
|
||||
@ -3746,17 +3758,8 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
|
||||
fun storeViaExprEval() {
|
||||
when(addressExpr) {
|
||||
is PtNumber, is PtIdentifier -> {
|
||||
assignExpressionToVariable(addressExpr, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
||||
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)
|
||||
}
|
||||
is PtNumber, is PtIdentifier -> storeByteInAToAddressExpression(addressExpr, false)
|
||||
else -> storeByteInAToAddressExpression(addressExpr, true)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -25,17 +25,19 @@ smallringbuffer {
|
||||
buffer[head] = value
|
||||
head++
|
||||
fill++
|
||||
return true
|
||||
}
|
||||
|
||||
sub putw(uword value) -> bool {
|
||||
; -- store a word in the buffer, returns success
|
||||
if fill>=254
|
||||
return false
|
||||
fill+=2
|
||||
fill += 2
|
||||
buffer[head] = lsb(value)
|
||||
head++
|
||||
buffer[head] = msb(value)
|
||||
head++
|
||||
return true
|
||||
}
|
||||
|
||||
sub get() -> ubyte {
|
||||
@ -56,7 +58,7 @@ smallringbuffer {
|
||||
sys.clear_carry()
|
||||
return 0
|
||||
}
|
||||
fill-=2
|
||||
fill -= 2
|
||||
tail++
|
||||
cx16.r0L = buffer[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)
|
||||
|
@ -866,6 +866,7 @@ io_error:
|
||||
|
||||
sub f_seek(uword pos_hiword, uword pos_loword) {
|
||||
; -- 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]
|
||||
command[1] = READ_IO_CHANNEL ; f_open uses this secondary address
|
||||
command[2] = lsb(pos_loword)
|
||||
|
@ -3,6 +3,8 @@ TODO
|
||||
|
||||
See open issues on github.
|
||||
|
||||
Optimize code in assignByteFromAddressExpression() and storeByteInAToAddressExpression()
|
||||
|
||||
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 % ?)
|
||||
@ -75,9 +77,8 @@ Compiler:
|
||||
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.
|
||||
- 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?
|
||||
- implement split words arrays all()
|
||||
|
||||
|
||||
Libraries:
|
||||
|
@ -1,42 +1,27 @@
|
||||
%import buffers
|
||||
%import textio
|
||||
%option no_sysinit
|
||||
%zeropage basicsafe
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
ubyte @shared b1 = %10101010
|
||||
ubyte @shared b2 = %00001111
|
||||
uword @shared ptr = $2000
|
||||
uword @shared index = 1000
|
||||
|
||||
b1 &= ~b2
|
||||
txt.print_ubbin(b1, true)
|
||||
txt.nl()
|
||||
b1 |= b2
|
||||
txt.print_ubbin(b1, true)
|
||||
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())
|
||||
cx16.r0L = @(ptr+index)
|
||||
cx16.r1L = ptr[index]
|
||||
@(ptr+index) = cx16.r0L
|
||||
ptr[index] = cx16.r1L
|
||||
; txt.print_ub(ptr[index])
|
||||
; txt.nl()
|
||||
;
|
||||
; smallringbuffer.putw(12345)
|
||||
; txt.print_uw(smallringbuffer.getw())
|
||||
; ptr[index] = 123
|
||||
; txt.print_ub(ptr[index])
|
||||
; txt.nl()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
;
|
||||
;main {
|
||||
; sub start() {
|
||||
|
Loading…
Reference in New Issue
Block a user