From dd2c436dc6f9dcb9606297c3cd1db25577dcc231 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 24 Jan 2021 14:03:01 +0100 Subject: [PATCH] tweaked repeat --- .../compiler/target/c64/codegen/AsmGen.kt | 61 ++++++++++++++----- docs/source/todo.rst | 4 +- examples/test.p8 | 8 ++- syntax-files/IDEA/Prog8.xml | 2 +- 4 files changed, 55 insertions(+), 20 deletions(-) diff --git a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt index 7550640ca..cb2a988c0 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt @@ -966,12 +966,10 @@ internal class AsmGen(private val program: Program, val name = asmVariableName(stmt.iterations as IdentifierReference) when(vardecl.datatype) { DataType.UBYTE, DataType.BYTE -> { - out(" lda $name") - repeatByteCountInA(null, repeatLabel, endLabel, stmt.body) + repeatByteCountVar(name, repeatLabel, endLabel, stmt.body) } DataType.UWORD, DataType.WORD -> { - out(" lda $name | ldy $name+1") - repeatWordCountInAY(null, repeatLabel, endLabel, stmt.body) + repeatWordCountVar(name, repeatLabel, endLabel, stmt.body) } else -> throw AssemblyError("invalid loop variable datatype $vardecl") } @@ -1001,6 +999,7 @@ internal class AsmGen(private val program: Program, if(constIterations==0) return // note: A/Y must have been loaded with the number of iterations already! + // TODO can be even more optimized by iterating over pages val counterVar = makeLabel("repeatcounter") out(""" sta $counterVar @@ -1035,22 +1034,54 @@ $counterVar .word 0""") val counterVar = makeLabel("repeatcounter") if(constIterations==null) out(" beq $endLabel") - out(""" - sta $counterVar -$repeatLabel""") + out(" sta $counterVar") + out(repeatLabel) translate(body) out(""" dec $counterVar bne $repeatLabel - beq $endLabel""") - if(constIterations!=null && constIterations>=16 && zeropage.available() > 0) { - // allocate count var on ZP - val zpAddr = zeropage.allocate(counterVar, DataType.UBYTE, body.position, errors) - out("""$counterVar = $zpAddr ; auto zp UBYTE""") - } else { - out(""" + beq $endLabel $counterVar .byte 0""") - } + out(endLabel) + } + + private fun repeatByteCountVar(repeatCountVar: String, repeatLabel: String, endLabel: String, body: AnonymousScope) { + // note: cannot use original counter variable because it should retain its original value + val counterVar = makeLabel("repeatcounter") + out(" lda $repeatCountVar | beq $endLabel | sta $counterVar") + out(repeatLabel) + translate(body) + out(" dec $counterVar | bne $repeatLabel") + // inline countervar: + out(""" + beq $endLabel +$counterVar .byte 0""") + out(endLabel) + } + + private fun repeatWordCountVar(repeatCountVar: String, repeatLabel: String, endLabel: String, body: AnonymousScope) { + // TODO can be even more optimized by iterating over pages + // note: cannot use original counter variable because it should retain its original value + val counterVar = makeLabel("repeatcounter") + out(""" + lda $repeatCountVar + sta $counterVar + ora $repeatCountVar+1 + beq $endLabel + lda $repeatCountVar+1 + sta $counterVar+1""") + out(repeatLabel) + translate(body) + out(""" + lda $counterVar + bne + + dec $counterVar+1 ++ dec $counterVar + lda $counterVar + ora $counterVar+1 + bne $repeatLabel + beq $endLabel +$counterVar .word 0""") out(endLabel) } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 7f2560641..7ad210537 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -2,15 +2,13 @@ TODO ==== -- add any2(), all2(), max2(), min2(), reverse2(), sum2(), sort2() that take (array, startindex, length) arguments - optimize for loop iterations better to allow proper inx, cpx #value, bne loop instructions (like repeat loop) -- why is there a beq _prog8_label_2_repeatend at the end of repeat loops? seems unused - optimize swap of two memread values with index, using the same pointer expression/variable, like swap(@(ptr+1), @(ptr+2)) - implement the linked_list millfork benchmark -- use the 65c02 bit clear/set/test instructions for single-bit operations - implement highres 4 color mode in gfx2 - make a retro Amiga Workbench "simulator" using that new gfx mode +- use the 65c02 bit clear/set/test instructions for single-bit operations - add a flood fill routine to gfx2 - can we get rid of the --longOptionName command line options and only keep the short versions? https://github.com/Kotlin/kotlinx-cli/issues/50 - add a f_seek() routine for the Cx16 that uses its seek dos api? diff --git a/examples/test.p8 b/examples/test.p8 index b9def49a5..888d18323 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -5,6 +5,12 @@ main { sub start() { - txt.print("hello\n") + uword xx + uword iter = 256 + repeat iter { + xx++ + } + + txt.print_uw(xx) } } diff --git a/syntax-files/IDEA/Prog8.xml b/syntax-files/IDEA/Prog8.xml index 453d93906..2a92bb898 100644 --- a/syntax-files/IDEA/Prog8.xml +++ b/syntax-files/IDEA/Prog8.xml @@ -11,7 +11,7 @@