diff --git a/compiler/res/prog8lib/prog8_lib.asm b/compiler/res/prog8lib/prog8_lib.asm index f1907502c..e77778c62 100644 --- a/compiler/res/prog8lib/prog8_lib.asm +++ b/compiler/res/prog8lib/prog8_lib.asm @@ -21,6 +21,7 @@ read_byte_from_address_on_stack .proc write_byte_to_address_on_stack .proc ; -- write the byte in A to the memory address on the top of the stack (stack remains unchanged) + ; TODO get rid of this by not evaluating the adress onto the stack, but directly into AY or SCRATCH_W2 ldy P8ESTACK_LO+1,x sty P8ZP_SCRATCH_W2 ldy P8ESTACK_HI+1,x diff --git a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt index 717eecc71..426cea304 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt @@ -184,7 +184,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, else -> { if(asmgen.options.slowCodegenWarnings) println("warning: slow stack evaluation used (1): ${memory.addressExpression::class.simpleName} at ${memory.addressExpression.position}") // TODO optimize... - asmgen.translateExpression(memory.addressExpression) + asmgen.translateExpression(memory.addressExpression) // TODO directly into P8ZP_SCRATCH_W2 asmgen.out(" jsr prog8_lib.read_byte_from_address_on_stack | sta P8ZP_SCRATCH_B1") val zp = CompilationTarget.instance.machine.zeropage when { @@ -420,30 +420,42 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, private fun inplaceModification_byte_value_to_variable(name: String, dt: DataType, operator: String, value: Expression) { // this should be the last resort for code generation for this, // because the value is evaluated onto the eval stack (=slow). - if(asmgen.options.slowCodegenWarnings) - println("warning: slow stack evaluation used (5): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO - asmgen.translateExpression(value) when (operator) { // note: ** (power) operator requires floats. - "+" -> asmgen.out(" lda $name | clc | adc P8ESTACK_LO+1,x | sta $name") - "-" -> asmgen.out(" lda $name | sec | sbc P8ESTACK_LO+1,x | sta $name") - "*" -> asmgen.out(" lda P8ESTACK_LO+1,x | ldy $name | jsr math.multiply_bytes | sta $name") + "+" -> { + if(asmgen.options.slowCodegenWarnings) + println("warning: slow stack evaluation used (5): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO + asmgen.translateExpression(value) + asmgen.out(" lda $name | clc | adc P8ESTACK_LO+1,x | sta $name | inx") + } + "-" -> { + if(asmgen.options.slowCodegenWarnings) + println("warning: slow stack evaluation used (5): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO + asmgen.translateExpression(value) + asmgen.out(" lda $name | sec | sbc P8ESTACK_LO+1,x | sta $name | inx") + } + "*" -> { + asmgen.translateExpression(value) // TODO directly into A + asmgen.out(" lda P8ESTACK_LO+1,x | ldy $name | jsr math.multiply_bytes | sta $name | inx") + } "/" -> { + asmgen.translateExpression(value) // TODO directly into Y if(dt==DataType.UBYTE) - asmgen.out(" lda P8ESTACK_LO+1,x | tay | lda $name | jsr math.divmod_ub_asm | sty $name") + asmgen.out(" lda P8ESTACK_LO+1,x | tay | lda $name | jsr math.divmod_ub_asm | sty $name | inx") else - asmgen.out(" lda P8ESTACK_LO+1,x | tay | lda $name | jsr math.divmod_b_asm | sty $name") + asmgen.out(" lda P8ESTACK_LO+1,x | tay | lda $name | jsr math.divmod_b_asm | sty $name | inx") } "%" -> { if(dt==DataType.BYTE) throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead") - asmgen.out(" lda P8ESTACK_LO+1,x | tay | lda $name | jsr math.divmod_ub_asm | sta $name") + if(asmgen.options.slowCodegenWarnings) + println("warning: slow stack evaluation used (5): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO + asmgen.translateExpression(value) + asmgen.out(" lda P8ESTACK_LO+1,x | tay | lda $name | jsr math.divmod_ub_asm | sta $name | inx") } "<<" -> { - asmgen.translateExpression(value) // todo directly into Y + asmgen.assignExpressionToRegister(value, RegisterOrPair.Y) asmgen.out(""" - inx - ldy P8ESTACK_LO,x beq + - asl $name dey @@ -451,11 +463,9 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, +""") } ">>" -> { - asmgen.translateExpression(value) // todo directly into Y + asmgen.assignExpressionToRegister(value, RegisterOrPair.Y) if(dt==DataType.UBYTE) { asmgen.out(""" - inx - ldy P8ESTACK_LO,x beq + - lsr $name dey @@ -463,8 +473,6 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, +""") } else { asmgen.out(""" - inx - ldy P8ESTACK_LO,x beq + - lda $name asl a @@ -474,12 +482,26 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, +""") } } - "&" -> asmgen.out(" lda $name | and P8ESTACK_LO+1,x | sta $name") - "^" -> asmgen.out(" lda $name | eor P8ESTACK_LO+1,x | sta $name") - "|" -> asmgen.out(" lda $name | ora P8ESTACK_LO+1,x | sta $name") + "&" -> { + if(asmgen.options.slowCodegenWarnings) + println("warning: slow stack evaluation used (5): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO + asmgen.translateExpression(value) + asmgen.out(" lda $name | and P8ESTACK_LO+1,x | sta $name | inx") + } + "^" -> { + if(asmgen.options.slowCodegenWarnings) + println("warning: slow stack evaluation used (5): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO + asmgen.translateExpression(value) + asmgen.out(" lda $name | eor P8ESTACK_LO+1,x | sta $name | inx") + } + "|" -> { + if(asmgen.options.slowCodegenWarnings) + println("warning: slow stack evaluation used (5): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO + asmgen.translateExpression(value) + asmgen.out(" lda $name | ora P8ESTACK_LO+1,x | sta $name | inx") + } else -> throw AssemblyError("invalid operator for in-place modification $operator") } - asmgen.out(" inx") } private fun inplaceModification_byte_variable_to_variable(name: String, dt: DataType, operator: String, ident: IdentifierReference) { @@ -1100,15 +1122,13 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, private fun inplaceModification_word_value_to_variable(name: String, dt: DataType, operator: String, value: Expression) { // this should be the last resort for code generation for this, // because the value is evaluated onto the eval stack (=slow). - if(asmgen.options.slowCodegenWarnings) - println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO - asmgen.translateExpression(value) val valueiDt = value.inferType(program) if(!valueiDt.isKnown) throw AssemblyError("unknown dt") val valueDt = valueiDt.typeOrElse(DataType.STRUCT) + // TODO can use registers instead of stack value? fun multiplyWord() { asmgen.out(""" lda P8ESTACK_LO+1,x @@ -1125,6 +1145,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, """) } + // TODO can use registers instead of stack value? fun divideWord() { if (dt == DataType.WORD) { asmgen.out(""" @@ -1153,6 +1174,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, } } + // TODO can use registers instead of stack value? fun remainderWord() { if(dt==DataType.WORD) throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead") @@ -1177,6 +1199,9 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, when (operator) { // note: ** (power) operator requires floats. "+" -> { + if(asmgen.options.slowCodegenWarnings) + println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO + asmgen.translateExpression(value) if(valueDt==DataType.UBYTE) asmgen.out(""" lda $name @@ -1198,8 +1223,12 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, tya adc $name+1 sta $name+1""") + asmgen.out(" inx") } "-" -> { + if(asmgen.options.slowCodegenWarnings) + println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO + asmgen.translateExpression(value) if(valueDt==DataType.UBYTE) asmgen.out(""" lda $name @@ -1223,23 +1252,39 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, lda $name+1 sbc P8ZP_SCRATCH_B1 sta $name+1""") + asmgen.out(" inx") } "*" -> { // stack contains (u) byte value, sign extend that and proceed with regular 16 bit operation + if(asmgen.options.slowCodegenWarnings) + println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO + asmgen.translateExpression(value) asmgen.signExtendStackLsb(valueDt) multiplyWord() + asmgen.out(" inx") } "/" -> { // stack contains (u) byte value, sign extend that and proceed with regular 16 bit operation + if(asmgen.options.slowCodegenWarnings) + println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO + asmgen.translateExpression(value) asmgen.signExtendStackLsb(valueDt) divideWord() + asmgen.out(" inx") } "%" -> { // stack contains (u) byte value, sign extend that and proceed with regular 16 bit operation + if(asmgen.options.slowCodegenWarnings) + println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO + asmgen.translateExpression(value) asmgen.signExtendStackLsb(valueDt) remainderWord() + asmgen.out(" inx") } "<<" -> { + if(asmgen.options.slowCodegenWarnings) + println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO + asmgen.translateExpression(value) // TODO directly into Y asmgen.out(""" ldy P8ESTACK_LO+1,x beq + @@ -1248,9 +1293,13 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, dey bne - +""") + asmgen.out(" inx") } ">>" -> { - if(dt==DataType.UWORD) { + if(asmgen.options.slowCodegenWarnings) + println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO + asmgen.translateExpression(value) // TODO directly into Y + if(dt==DataType.UWORD) asmgen.out(""" ldy P8ESTACK_LO+1,x beq + @@ -1258,8 +1307,8 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, ror $name dey bne - -+""") } - else { ++""") + else asmgen.out(""" ldy P8ESTACK_LO+1,x beq + @@ -1270,15 +1319,31 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, dey bne - +""") - } + asmgen.out(" inx") } "&" -> { + if(asmgen.options.slowCodegenWarnings) + println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO + asmgen.translateExpression(value) // TODO directly into A asmgen.out(" lda P8ESTACK_LO+1,x | and $name | sta $name") if(dt in WordDatatypes) asmgen.out(" lda #0 | sta $name+1") + asmgen.out(" inx") + } + "^" -> { + if(asmgen.options.slowCodegenWarnings) + println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO + asmgen.translateExpression(value) // TODO directly into A + asmgen.out(" lda P8ESTACK_LO+1,x | eor $name | sta $name") + asmgen.out(" inx") + } + "|" -> { + if(asmgen.options.slowCodegenWarnings) + println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO + asmgen.translateExpression(value) // TODO directly into A + asmgen.out(" lda P8ESTACK_LO+1,x | ora $name | sta $name") + asmgen.out(" inx") } - "^" -> asmgen.out(" lda P8ESTACK_LO+1,x | eor $name | sta $name") - "|" -> asmgen.out(" lda P8ESTACK_LO+1,x | ora $name | sta $name") else -> throw AssemblyError("invalid operator for in-place modification $operator") } } @@ -1286,24 +1351,63 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, // the value is a proper 16-bit word, so use both bytes of it. when (operator) { // note: ** (power) operator requires floats. - "+" -> asmgen.out(" lda $name | clc | adc P8ESTACK_LO+1,x | sta $name | lda $name+1 | adc P8ESTACK_HI+1,x | sta $name+1") - "-" -> asmgen.out(" lda $name | sec | sbc P8ESTACK_LO+1,x | sta $name | lda $name+1 | sbc P8ESTACK_HI+1,x | sta $name+1") - "*" -> multiplyWord() - "/" -> divideWord() - "%" -> remainderWord() + "+" -> { + if(asmgen.options.slowCodegenWarnings) + println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO + asmgen.translateExpression(value) + asmgen.out(" lda $name | clc | adc P8ESTACK_LO+1,x | sta $name | lda $name+1 | adc P8ESTACK_HI+1,x | sta $name+1 | inx") + } + "-" -> { + if(asmgen.options.slowCodegenWarnings) + println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO + asmgen.translateExpression(value) + asmgen.out(" lda $name | sec | sbc P8ESTACK_LO+1,x | sta $name | lda $name+1 | sbc P8ESTACK_HI+1,x | sta $name+1 | inx") + } + "*" -> { + if(asmgen.options.slowCodegenWarnings) + println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO + asmgen.translateExpression(value) + multiplyWord() + asmgen.out(" inx") + } + "/" -> { + if(asmgen.options.slowCodegenWarnings) + println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO + asmgen.translateExpression(value) + divideWord() + asmgen.out(" inx") + } + "%" -> { + if(asmgen.options.slowCodegenWarnings) + println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO + asmgen.translateExpression(value) + remainderWord() + asmgen.out(" inx") + } "<<", ">>" -> throw AssemblyError("shift by a word value not supported, max is a byte") - "&" -> asmgen.out(" lda $name | and P8ESTACK_LO+1,x | sta $name | lda $name+1 | and P8ESTACK_HI+1,x | sta $name+1") - "^" -> asmgen.out(" lda $name | eor P8ESTACK_LO+1,x | sta $name | lda $name+1 | eor P8ESTACK_HI+1,x | sta $name+1") - "|" -> asmgen.out(" lda $name | ora P8ESTACK_LO+1,x | sta $name | lda $name+1 | ora P8ESTACK_HI+1,x | sta $name+1") + "&" -> { + if(asmgen.options.slowCodegenWarnings) + println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO + asmgen.translateExpression(value) + asmgen.out(" lda $name | and P8ESTACK_LO+1,x | sta $name | lda $name+1 | and P8ESTACK_HI+1,x | sta $name+1 | inx") + } + "^" -> { + if(asmgen.options.slowCodegenWarnings) + println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO + asmgen.translateExpression(value) + asmgen.out(" lda $name | eor P8ESTACK_LO+1,x | sta $name | lda $name+1 | eor P8ESTACK_HI+1,x | sta $name+1 | inx") + } + "|" -> { + if(asmgen.options.slowCodegenWarnings) + println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO + asmgen.translateExpression(value) + asmgen.out(" lda $name | ora P8ESTACK_LO+1,x | sta $name | lda $name+1 | ora P8ESTACK_HI+1,x | sta $name+1 | inx") + } else -> throw AssemblyError("invalid operator for in-place modification $operator") } } - else -> { - throw AssemblyError("can only use integer datatypes here") - } + else -> throw AssemblyError("can only use integer datatypes here") } - - asmgen.out(" inx") } private fun inplaceModification_float_value_to_variable(name: String, operator: String, value: Expression, scope: Subroutine) { @@ -1594,7 +1698,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, else -> { if(asmgen.options.slowCodegenWarnings) println("warning: slow stack evaluation used (6): ${mem.addressExpression::class.simpleName} at ${mem.addressExpression.position}") // TODO - asmgen.translateExpression(mem.addressExpression) + asmgen.translateExpression(mem.addressExpression) // TODO directly into P8ZP_SCRATCH_W2 asmgen.out(""" jsr prog8_lib.read_byte_from_address_on_stack beq + @@ -1664,7 +1768,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, else -> { if(asmgen.options.slowCodegenWarnings) println("warning: slow stack evaluation used (7): ${memory.addressExpression::class.simpleName} at ${memory.addressExpression.position}") // TODO - asmgen.translateExpression(memory.addressExpression) + asmgen.translateExpression(memory.addressExpression) // TODO directly into P8ZP_SCRATCH_W2 asmgen.out(""" jsr prog8_lib.read_byte_from_address_on_stack eor #255 diff --git a/examples/test.p8 b/examples/test.p8 index 57ef6bd6e..23261306e 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -6,12 +6,17 @@ main { sub start() { - ubyte ub = 4 + ubyte ub = 2 ubyte ub2 = 8 uword uw = 5 - ub = uw*3 as ubyte - txt.print_ub(ub) + ub2 <<= (ub-1) + txt.print_ub(ub2) + txt.chrout('\n') + + ub2 >>= (ub-1) + txt.print_ub(ub2) + txt.chrout('\n') testX() }