diff --git a/compiler/src/prog8/compiler/target/c64/codegen/ForLoopsAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/ForLoopsAsmGen.kt index 23e4cf5f0..37377767b 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/ForLoopsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/ForLoopsAsmGen.kt @@ -14,10 +14,6 @@ import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_LO_PLUS1_HEX import prog8.compiler.toHex import kotlin.math.absoluteValue -// todo choose more efficient comparisons to avoid needless lda's -// todo optimized code for step == 2 or -2 -// todo allocate loop counter variable dynamically, preferrably on zeropage - internal class ForLoopsAsmGen(private val program: Program, private val asmgen: AsmGen) { internal fun translate(stmt: ForLoop) { @@ -41,8 +37,6 @@ internal class ForLoopsAsmGen(private val program: Program, private val asmgen: } private fun translateForOverNonconstRange(stmt: ForLoop, iterableDt: DataType, range: RangeExpr) { - // TODO more optimized code possible now that continue is gone? - val loopLabel = asmgen.makeLabel("for_loop") val endLabel = asmgen.makeLabel("for_end") asmgen.loopEndLabels.push(endLabel) @@ -66,13 +60,13 @@ $loopLabel""") asmgen.translate(stmt.body) asmgen.out(""" lda $varname - cmp $ESTACK_LO_PLUS1_HEX,x + cmp $ESTACK_LO_PLUS1_HEX,x TODO modifying code beq $endLabel $incdec $varname jmp $loopLabel $endLabel inx""") - } - else { + + } else { // bytes, step >= 2 or <= -2 @@ -93,7 +87,7 @@ $loopLabel""") clc adc #$stepsize sta $varname - cmp $ESTACK_LO_PLUS1_HEX,x + cmp $ESTACK_LO_PLUS1_HEX,x TODO modifying code bcc $loopLabel beq $loopLabel""") } else { @@ -101,7 +95,7 @@ $loopLabel""") sec sbc #${stepsize.absoluteValue} sta $varname - cmp $ESTACK_LO_PLUS1_HEX,x + cmp $ESTACK_LO_PLUS1_HEX,x TODO modifying code bcs $loopLabel""") } asmgen.out(""" @@ -123,10 +117,10 @@ $endLabel inx""") asmgen.translate(stmt.body) asmgen.out(""" lda $varname+1 - cmp $ESTACK_HI_PLUS1_HEX,x + cmp $ESTACK_HI_PLUS1_HEX,x TODO modifying code bne + lda $varname - cmp $ESTACK_LO_PLUS1_HEX,x + cmp $ESTACK_LO_PLUS1_HEX,x TODO modifying code beq $endLabel""") if(stepsize==1) { asmgen.out(""" @@ -166,12 +160,12 @@ $endLabel inx""") lda $varname+1 adc #>$stepsize sta $varname+1 - lda $ESTACK_HI_PLUS1_HEX,x + lda $ESTACK_HI_PLUS1_HEX,x TODO modifying code cmp $varname+1 bcc $endLabel bne $loopLabel lda $varname - cmp $ESTACK_LO_PLUS1_HEX,x + cmp $ESTACK_LO_PLUS1_HEX,x TODO modifying code bcc $endLabel bcs $loopLabel $endLabel inx""") @@ -184,9 +178,9 @@ $endLabel inx""") lda $varname+1 adc #>$stepsize sta $varname+1 - lda $ESTACK_LO_PLUS1_HEX,x + lda $ESTACK_LO_PLUS1_HEX,x TODO modifying code cmp $varname - lda $ESTACK_HI_PLUS1_HEX,x + lda $ESTACK_HI_PLUS1_HEX,x TODO modifying code sbc $varname+1 bvc + eor #$80 @@ -214,11 +208,11 @@ $endLabel inx""") lda $varname+1 sbc #>${stepsize.absoluteValue} sta $varname+1 - cmp $ESTACK_HI_PLUS1_HEX,x + cmp $ESTACK_HI_PLUS1_HEX,x TODO modifying code bcc $endLabel bne $loopLabel lda $varname - cmp $ESTACK_LO_PLUS1_HEX,x + cmp $ESTACK_LO_PLUS1_HEX,x TODO modifying code bcs $loopLabel $endLabel inx""") } else { @@ -232,9 +226,9 @@ $endLabel inx""") sbc #>${stepsize.absoluteValue} sta $varname+1 pla - cmp $ESTACK_LO_PLUS1_HEX,x + cmp $ESTACK_LO_PLUS1_HEX,x TODO modifying code lda $varname+1 - sbc $ESTACK_HI_PLUS1_HEX,x + sbc $ESTACK_HI_PLUS1_HEX,x TODO modifying code bvc + eor #$80 + bpl $loopLabel @@ -250,7 +244,6 @@ $endLabel inx""") } private fun translateForOverIterableVar(stmt: ForLoop, iterableDt: DataType, ident: IdentifierReference) { - // TODO more optimized code possible now that continue is gone? val loopLabel = asmgen.makeLabel("for_loop") val endLabel = asmgen.makeLabel("for_end") asmgen.loopEndLabels.push(endLabel) @@ -275,9 +268,9 @@ $loopLabel lda ${65535.toHex()} ; modified $endLabel""") } DataType.ARRAY_UB, DataType.ARRAY_B -> { - // TODO: optimize loop code when the length of the array is < 256 + // TODO: optimize loop code when the length of the array is < 256 (i.e. always) val length = decl.arraysize!!.size()!! - val counterLabel = asmgen.makeLabel("for_counter") + val counterLabel = asmgen.makeLabel("for_counter") // todo allocate dynamically, zero page preferred if iterations >= 8 val modifiedLabel = asmgen.makeLabel("for_modified") asmgen.out(""" lda #<$iterableName @@ -294,14 +287,14 @@ $modifiedLabel lda ${65535.toHex()},y ; modified""") iny cpy #${length and 255} beq $endLabel - jmp $loopLabel + bne $loopLabel $counterLabel .byte 0 $endLabel""") } DataType.ARRAY_W, DataType.ARRAY_UW -> { - // TODO: optimize loop code when the length of the array is < 256 + // TODO: optimize loop code when the length of the array is < 256 (i.e. always) val length = decl.arraysize!!.size()!! * 2 - val counterLabel = asmgen.makeLabel("for_counter") + val counterLabel = asmgen.makeLabel("for_counter") // todo allocate dynamically, zero page preferred if iterations >= 8 val modifiedLabel = asmgen.makeLabel("for_modified") val modifiedLabel2 = asmgen.makeLabel("for_modified2") val loopvarName = asmgen.asmIdentifierName(stmt.loopVar) @@ -327,7 +320,7 @@ $modifiedLabel2 lda ${65535.toHex()},y ; modified iny cpy #${length and 255} beq $endLabel - jmp $loopLabel + bne $loopLabel $counterLabel .byte 0 $endLabel""") } @@ -343,179 +336,117 @@ $endLabel""") if (range.isEmpty() || range.step==0) throw AssemblyError("empty range or step 0") if(iterableDt==DataType.ARRAY_B || iterableDt==DataType.ARRAY_UB) { - if(range.step==1 && range.first>=0 && range.last <= 255 && range.last>range.first) return translateForSimpleByteRangeAsc(stmt, range) - if(range.step==-1 && range.first<=255 && range.first >=0 && range.lastrange.first) return translateForSimpleByteRangeAsc(stmt, range) + if(range.step==-1 && range.last=0 && range.last <= 255 && range.last>range.first) return translateForSimpleWordRange255Asc(stmt, range) - if(range.step==-1 && range.first<=255 && range.first >=0 && range.last=0 && range.last <= 65535 && range.last>range.first) return translateForSimpleWordRange65535Asc(stmt, range) - if(range.step==-1 && range.first<=65535 && range.first >=0 && range.lastrange.first) return translateForSimpleWordRangeAsc(stmt, range) + if(range.step==-1 && range.last { - // loop over byte range via loopvar, step > 1 or < -1 - val counterLabel = asmgen.makeLabel("for_counter") + // loop over byte range via loopvar, step >= 2 or <= -2 val varname = asmgen.asmIdentifierName(stmt.loopVar) - when { - range.step==1 || range.step==-1 -> { - throw AssemblyError("step 1 and -1 should have been handled specifically") - } - range.step >= 2 -> { - // step >= 2 - asmgen.out(""" - lda #${(range.last-range.first) / range.step + 1} - sta $counterLabel - lda #${range.first} - sta $varname + asmgen.out(""" + lda #${range.first} + sta $varname $loopLabel""") - asmgen.translate(stmt.body) - asmgen.out(""" - dec $counterLabel - beq $endLabel - lda $varname - clc - adc #${range.step} - sta $varname - jmp $loopLabel -$counterLabel .byte 0 -$endLabel""") + asmgen.translate(stmt.body) + when (range.step) { + 0, 1, -1 -> { + throw AssemblyError("step 0, 1 and -1 should have been handled specifically $stmt") + } + 2 -> { + if(range.last==255) { + asmgen.out(""" + inc $varname + beq $endLabel + inc $varname + bne $loopLabel""") + } else { + asmgen.out(""" + lda $varname + cmp #${range.last} + beq $endLabel + inc $varname + inc $varname + jmp $loopLabel""") + } + } + -2 -> { + when (range.last) { + 0 -> asmgen.out(""" + lda $varname + beq $endLabel + dec $varname + dec $varname + jmp $loopLabel""") + 1 -> asmgen.out(""" + dec $varname + beq $endLabel + dec $varname + bne $loopLabel""") + else -> asmgen.out(""" + lda $varname + cmp #${range.last} + beq $endLabel + dec $varname + dec $varname + jmp $loopLabel""") + } } else -> { - // step <= -2 + // step <= -3 or >= 3 asmgen.out(""" - lda #${(range.first-range.last) / range.step.absoluteValue + 1} - sta $counterLabel - lda #${range.first} - sta $varname -$loopLabel""") - asmgen.translate(stmt.body) - asmgen.out(""" - dec $counterLabel - beq $endLabel - lda $varname - sec - sbc #${range.step.absoluteValue} - sta $varname - jmp $loopLabel -$counterLabel .byte 0 -$endLabel""") + lda $varname + cmp #${range.last} + beq $endLabel + clc + adc #${range.step} + sta $varname + jmp $loopLabel""") } } + asmgen.out(endLabel) } DataType.ARRAY_W, DataType.ARRAY_UW -> { - // loop over word range via loopvar, step > 1 or < -1 + // loop over word range via loopvar, step >= 2 or <= -2 val varname = asmgen.asmIdentifierName(stmt.loopVar) - when { - range.step==1 || range.step==-1 -> { - throw AssemblyError("step 1 and -1 should have been handled specifically") - } -// range.step == 1 -> { -// // word, step = 1 -// val lastValue = range.last+1 -// asmgen.out(""" -// lda #<${range.first} -// ldy #>${range.first} -// sta $varname -// sty $varname+1 -//$loopLabel""") -// asmgen.translate(stmt.body) -// asmgen.out(""" -// inc $varname -// bne + -// inc $varname+1 -//+ lda $varname -// cmp #<$lastValue -// bne + -// lda $varname+1 -// cmp #>$lastValue -// beq $endLabel -//+ jmp $loopLabel -//$endLabel""") -// } -// range.step == -1 -> { -// // word, step = 1 -// val lastValue = range.last-1 -// asmgen.out(""" -// lda #<${range.first} -// ldy #>${range.first} -// sta $varname -// sty $varname+1 -//$loopLabel""") -// asmgen.translate(stmt.body) -// asmgen.out(""" -// lda $varname -// bne + -// dec $varname+1 -//+ dec $varname -// lda $varname -// cmp #<$lastValue -// bne + -// lda $varname+1 -// cmp #>$lastValue -// beq $endLabel -//+ jmp $loopLabel -//$endLabel""") -// } - range.step >= 2 -> { - // word, step >= 2 - // note: range.last has already been adjusted by kotlin itself to actually be the last value of the sequence - val lastValue = range.last+range.step - asmgen.out(""" - lda #<${range.first} - ldy #>${range.first} - sta $varname - sty $varname+1 -$loopLabel""") - asmgen.translate(stmt.body) - asmgen.out(""" - clc - lda $varname - adc #<${range.step} - sta $varname - lda $varname+1 - adc #>${range.step} - sta $varname+1 - lda $varname - cmp #<$lastValue - bne + - lda $varname+1 - cmp #>$lastValue - beq $endLabel -+ jmp $loopLabel -$endLabel""") + when (range.step) { + 0, 1, -1 -> { + throw AssemblyError("step 0, 1 and -1 should have been handled specifically $stmt") } else -> { - // step <= -2 + // word, step >= 2 or <= -2 // note: range.last has already been adjusted by kotlin itself to actually be the last value of the sequence - val lastValue = range.last+range.step asmgen.out(""" - lda #<${range.first} - ldy #>${range.first} - sta $varname - sty $varname+1 + lda #<${range.first} + ldy #>${range.first} + sta $varname + sty $varname+1 $loopLabel""") asmgen.translate(stmt.body) asmgen.out(""" - sec - lda $varname - sbc #<${range.step.absoluteValue} - sta $varname - lda $varname+1 - sbc #>${range.step.absoluteValue} - sta $varname+1 - lda $varname - cmp #<$lastValue - bne + - lda $varname+1 - cmp #>$lastValue - beq $endLabel -+ jmp $loopLabel + lda $varname + cmp #<${range.last} + bne + + lda $varname+1 + cmp #>${range.last} + bne + + beq $endLabel ++ lda $varname + clc + adc #<${range.step} + sta $varname + lda $varname+1 + adc #>${range.step} + sta $varname+1 + jmp $loopLabel $endLabel""") } } @@ -530,28 +461,23 @@ $endLabel""") val endLabel = asmgen.makeLabel("for_end") asmgen.loopEndLabels.push(endLabel) val varname = asmgen.asmIdentifierName(stmt.loopVar) - if (range.last == 255) { - asmgen.out(""" + asmgen.out(""" lda #${range.first} sta $varname $loopLabel""") - asmgen.translate(stmt.body) + asmgen.translate(stmt.body) + if (range.last == 255) { asmgen.out(""" inc $varname bne $loopLabel $endLabel""") } else { - asmgen.out(""" - lda #${range.first} - sta $varname -$loopLabel""") - asmgen.translate(stmt.body) asmgen.out(""" lda $varname cmp #${range.last} beq $endLabel inc $varname - bne $loopLabel + jmp $loopLabel $endLabel""") } asmgen.loopEndLabels.pop() @@ -562,13 +488,13 @@ $endLabel""") val endLabel = asmgen.makeLabel("for_end") asmgen.loopEndLabels.push(endLabel) val varname = asmgen.asmIdentifierName(stmt.loopVar) - when (range.last) { - 0 -> { - asmgen.out(""" + asmgen.out(""" lda #${range.first} sta $varname $loopLabel""") - asmgen.translate(stmt.body) + asmgen.translate(stmt.body) + when (range.last) { + 0 -> { asmgen.out(""" lda $varname beq $endLabel @@ -577,48 +503,78 @@ $loopLabel""") $endLabel""") } 1 -> { - asmgen.out(""" - lda #${range.first} - sta $varname -$loopLabel""") - asmgen.translate(stmt.body) asmgen.out(""" dec $varname - bne $loopLabel + jmp $loopLabel $endLabel""") } else -> { - asmgen.out(""" - lda #${range.first} - sta $varname -$loopLabel""") - asmgen.translate(stmt.body) asmgen.out(""" lda $varname cmp #${range.last} beq $endLabel dec $varname - bne $loopLabel + jmp $loopLabel $endLabel""") } } asmgen.loopEndLabels.pop() } - private fun translateForSimpleWordRange255Asc(stmt: ForLoop, range: IntProgression) { - TODO("Not yet implemented") + private fun translateForSimpleWordRangeAsc(stmt: ForLoop, range: IntProgression) { + val loopLabel = asmgen.makeLabel("for_loop") + val endLabel = asmgen.makeLabel("for_end") + asmgen.loopEndLabels.push(endLabel) + val varname = asmgen.asmIdentifierName(stmt.loopVar) + asmgen.out(""" + lda #<${range.first} + ldy #>${range.first} + sta $varname + sty $varname+1 +$loopLabel""") + asmgen.translate(stmt.body) + asmgen.out(""" + lda $varname + cmp #<${range.last} + bne + + lda $varname+1 + cmp #>${range.last} + bne + + beq $endLabel ++ inc $varname + bne $loopLabel + inc $varname+1 + jmp $loopLabel +$endLabel""") + asmgen.loopEndLabels.pop() } - private fun translateForSimpleWordRange255Desc(stmt: ForLoop, range: IntProgression) { - TODO("Not yet implemented") + private fun translateForSimpleWordRangeDesc(stmt: ForLoop, range: IntProgression) { + val loopLabel = asmgen.makeLabel("for_loop") + val endLabel = asmgen.makeLabel("for_end") + asmgen.loopEndLabels.push(endLabel) + val varname = asmgen.asmIdentifierName(stmt.loopVar) + asmgen.out(""" + lda #<${range.first} + ldy #>${range.first} + sta $varname + sty $varname+1 +$loopLabel""") + asmgen.translate(stmt.body) + asmgen.out(""" + lda $varname + cmp #<${range.last} + bne + + lda $varname+1 + cmp #>${range.last} + bne + + beq $endLabel ++ lda $varname + bne + + dec $varname+1 ++ dec $varname + jmp $loopLabel +$endLabel""") + asmgen.loopEndLabels.pop() } - - private fun translateForSimpleWordRange65535Asc(stmt: ForLoop, range: IntProgression) { - TODO("Not yet implemented") - } - - private fun translateForSimpleWordRange65535Desc(stmt: ForLoop, range: IntProgression) { - TODO("Not yet implemented") - } - } diff --git a/examples/test.p8 b/examples/test.p8 index 07b5ff881..fe3f7b915 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -6,93 +6,82 @@ main { sub start() { - ubyte counterb - uword counterw + byte counterb + word counterw - - for counterb in 0 to 10 { - c64scr.print_ub(counterb) + for counterb in -10 to 11 { + c64scr.print_b(counterb) c64.CHROUT(',') } c64.CHROUT('\n') - for counterb in 10 to 30 { - c64scr.print_ub(counterb) + for counterb in 11 to -10 step -1 { + c64scr.print_b(counterb) c64.CHROUT(',') } c64.CHROUT('\n') - for counterb in 250 to 255 { - c64scr.print_ub(counterb) + for counterb in -10 to 11 step 2 { + c64scr.print_b(counterb) c64.CHROUT(',') } c64.CHROUT('\n') - for counterb in 10 to 0 step -1 { - c64scr.print_ub(counterb) + for counterb in 11 to -10 step -2 { + c64scr.print_b(counterb) c64.CHROUT(',') } c64.CHROUT('\n') - for counterb in 10 to 1 step -1 { - c64scr.print_ub(counterb) + for counterb in -10 to 11 step 3 { + c64scr.print_b(counterb) c64.CHROUT(',') } c64.CHROUT('\n') - for counterb in 30 to 10 step -1 { - c64scr.print_ub(counterb) + for counterb in 11 to -10 step -3 { + c64scr.print_b(counterb) + c64.CHROUT(',') + } + c64.CHROUT('\n') + c64.CHROUT('\n') + c64.CHROUT('\n') + + for counterw in -10 to 11 { + c64scr.print_w(counterw) c64.CHROUT(',') } c64.CHROUT('\n') - for counterb in 255 to 250 step -1 { - c64scr.print_ub(counterb) - c64.CHROUT(',') - } - c64.CHROUT('\n') - c64.CHROUT('\n') - - for counterw in 0 to 10 { - c64scr.print_uw(counterw) + for counterw in 11 to -10 step -1 { + c64scr.print_w(counterw) c64.CHROUT(',') } c64.CHROUT('\n') - for counterw in 10 to 30 { - c64scr.print_uw(counterw) + for counterw in -10 to 11 step 2 { + c64scr.print_w(counterw) c64.CHROUT(',') } c64.CHROUT('\n') - for counterw in 250 to 255 { - c64scr.print_uw(counterw) + for counterw in 11 to -10 step -2 { + c64scr.print_w(counterw) c64.CHROUT(',') } c64.CHROUT('\n') - for counterw in 10 to 0 step -1 { - c64scr.print_uw(counterw) + for counterw in -10 to 11 step 3 { + c64scr.print_w(counterw) c64.CHROUT(',') } c64.CHROUT('\n') - for counterw in 10 to 1 step -1 { - c64scr.print_uw(counterw) + for counterw in 11 to -10 step -3 { + c64scr.print_w(counterw) c64.CHROUT(',') } c64.CHROUT('\n') - for counterw in 30 to 10 step -1 { - c64scr.print_uw(counterw) - c64.CHROUT(',') - } - c64.CHROUT('\n') - - for counterw in 255 to 250 step -1 { - c64scr.print_uw(counterw) - c64.CHROUT(',') - } - c64.CHROUT('\n') } }