diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt index aa5d0ca52..0e9812e64 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt @@ -707,11 +707,8 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } private fun inplacemodificationByteVariableWithValue(name: String, dt: DataType, operator: String, value: PtExpression) { - // TODO optimize: don't use scratch var if possible - val tmpVar = if(name!="P8ZP_SCRATCH_B1") "P8ZP_SCRATCH_B1" else "P8ZP_SCRATCH_REG" - asmgen.assignExpressionToVariable(value, tmpVar, value.type) - asmgen.out(" lda $name") - inplacemodificationRegisterAwithVariable(operator, tmpVar, dt in SignedDatatypes) + asmgen.assignExpressionToRegister(value, RegisterOrPair.A, dt in SignedDatatypes) + inplacemodificationRegisterAwithVariableWithSwappedOperands(operator, name, dt in SignedDatatypes) asmgen.out(" sta $name") } @@ -722,15 +719,16 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } private fun inplacemodificationRegisterAwithVariable(operator: String, variable: String, signed: Boolean) { + // A = A variable when (operator) { "+" -> asmgen.out(" clc | adc $variable") "-" -> asmgen.out(" sec | sbc $variable") "*" -> asmgen.out(" ldy $variable | jsr math.multiply_bytes") "/" -> { if(signed) - asmgen.out(" ldy $variable | jsr math.divmod_b_asm | tya") + asmgen.out(" ldy $variable | jsr math.divmod_b_asm | tya") else - asmgen.out(" ldy $variable | jsr math.divmod_ub_asm | tya") + asmgen.out(" ldy $variable | jsr math.divmod_ub_asm | tya") } "%" -> { if(signed) @@ -881,6 +879,164 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } } + private fun inplacemodificationRegisterAwithVariableWithSwappedOperands(operator: String, variable: String, signed: Boolean) { + // A = variable A + + if(operator in AssociativeOperators) + return inplacemodificationRegisterAwithVariable(operator, variable, signed) // just reuse existing code for associative operators + + // now implement the non-assiciative operators... + when (operator) { + "-" -> { + // TODO optimize: don't use scratch var + val tmpVar = if(variable!="P8ZP_SCRATCH_B1") "P8ZP_SCRATCH_B1" else "P8ZP_SCRATCH_REG" + asmgen.out(" sta $tmpVar | lda $variable | sec | sbc $tmpVar") + } + "/" -> { + if(signed) + asmgen.out(" tay | lda $variable | jsr math.divmod_b_asm | tya") + else + asmgen.out(" tay | lda $variable | jsr math.divmod_ub_asm | tya") + } + "%" -> { + if(signed) + throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead") + asmgen.out(" tay | lda $variable | jsr math.divmod_ub_asm") + } + "<<" -> { + asmgen.out(""" + tay + beq + + lda $variable +- asl a + dey + bne - ++""") + } + ">>" -> { + if(!signed) { + asmgen.out(""" + tay + beq + + lda $variable +- lsr a + dey + bne - ++""") + } else { + asmgen.out(""" + tay + beq + + lda $variable + sta P8ZP_SCRATCH_B1 +- asl a + ror P8ZP_SCRATCH_B1 + lda P8ZP_SCRATCH_B1 + dey + bne - ++""") + } + } + "<" -> { + if(!signed) { + TODO("swap operand order") + asmgen.out(""" + tay + lda #0 + cpy $variable + rol a + eor #1""") + } + else { + TODO("swap operand order") + // see http://www.6502.org/tutorials/compare_beyond.html + asmgen.out(""" + sec + sbc $variable + bvc + + eor #$80 ++ bmi + + lda #0 + beq ++ ++ lda #1 ++""") + } + } + "<=" -> { + if(!signed) { + TODO("swap operand order") + asmgen.out(""" + tay + lda #0 + ldy $variable + rol a""") + } else { + TODO("swap operand order") + // see http://www.6502.org/tutorials/compare_beyond.html + asmgen.out(""" + clc + sbc $variable + bvc + + eor #$80 ++ bmi + + lda #0 + beq ++ ++ lda #1 ++""") + } + } + ">" -> { + if(!signed) { + TODO("swap operand order") + asmgen.out(""" + tay + lda #0 + cpy $variable + beq + + rol a ++""") + } else { + TODO("swap operand order") + // see http://www.6502.org/tutorials/compare_beyond.html + asmgen.out(""" + clc + sbc $variable + bvc + + eor #$80 ++ bpl + + lda #0 + beq ++ ++ lda #1 ++""") + } + } + ">=" -> { + if(!signed) { + TODO("swap operand order") + asmgen.out(""" + tay + lda #0 + cpy $variable + rol a""") + } else { + TODO("swap operand order") + // see http://www.6502.org/tutorials/compare_beyond.html + asmgen.out(""" + sec + sbc $variable + bvc + + eor #$80 ++ bpl + + lda #0 + beq ++ ++ lda #1 ++""") + } + } + else -> throw AssemblyError("invalid operator for in-place modification $operator") + } + } + private fun inplacemodificationByteVariableWithLiteralval(name: String, dt: DataType, operator: String, value: Int) { // note: this contains special optimized cases because we know the exact value. Don't replace this with another routine. when (operator) { diff --git a/compiler/res/prog8lib/math.asm b/compiler/res/prog8lib/math.asm index 54087c48d..a7c876992 100644 --- a/compiler/res/prog8lib/math.asm +++ b/compiler/res/prog8lib/math.asm @@ -58,6 +58,7 @@ multiply_words .proc ; -- multiply two 16-bit words into a 32-bit result (signed and unsigned) ; input: A/Y = first 16-bit number, cx16.R0 = second 16-bit number ; output: multiply_words.result == cx16.R0:R1, 4-bytes/32-bits product, LSB order (low-to-high) low 16 bits also in AY. + ; TODO: should not use R0 and R1 at all !!! result needs 4 consecutive bytes, so it can't be in zeropage at all... ; mult62.a ; based on Dr Jefyll, http://forum.6502.org/viewtopic.php?f=9&t=689&start=0#p19958 diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 96dba71d7..b846a5398 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,6 +1,11 @@ TODO ==== +- fix: amiga example with noopt draws wrong lines, caused by "2x faster word multiplication routine" because it trashes r0 and r1 now + multiply_words in math.asm needs fixing. + +- fix: test all other things with noopt once again! (examples/c64 are all ok) +- fix: search for TODO("swap operand order") - optimize: search for TODO optimize: don't use scratch var - prefix prog8 subroutines with p8s_ instead of p8_ to not let them clash with variables in the asm? - allow 'chained' array indexing for expressions: value = ptrarray[0][0] diff --git a/examples/test.p8 b/examples/test.p8 index 05a038515..91a8d6a6c 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,14 +1,17 @@ %import textio -%import math %zeropage basicsafe main { sub start() { - ubyte index + ubyte index = 100 ubyte[] t_index = [1,2,3,4,5] ubyte nibble = 0 - index -= t_index[4] + index += t_index[4] + index += t_index[nibble] + nibble++ + index -= t_index[3] index -= t_index[nibble] + txt.print_ub(index) ; 100 } }