diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt index ea7757e07..9a2c3757d 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt @@ -1420,6 +1420,9 @@ $repeatLabel""") sta $asmvar+2 sta $asmvar+3""") } + BaseDataType.UWORD -> { + out(" lda #0 | sta $asmvar+2 | sta $asmvar+3") + } BaseDataType.WORD -> { out(""" lda $asmvar+1 diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/IfElseAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/IfElseAsmGen.kt index e0bbcba90..29f1d986e 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/IfElseAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/IfElseAsmGen.kt @@ -1263,7 +1263,23 @@ _jump jmp (${target.asmLabel}) } private fun longEqualsZero(value: PtExpression, notEquals: Boolean, jump: PtJump?, stmt: PtIfElse) { - TODO("long == 0") + asmgen.assignExpressionToRegister(value, RegisterOrPair.R0R1_32, value.type.isSigned) + asmgen.out(""" + lda cx16.r0 + ora cx16.r0+1 + ora cx16.r0+2 + ora cx16.r0+3""") + if(notEquals) { + if (jump != null) + translateJumpElseBodies("bne", "beq", jump, stmt.elseScope) + else + translateIfElseBodies("bne", stmt) + } else { + if (jump != null) + translateJumpElseBodies("beq", "bne", jump, stmt.elseScope) + else + translateIfElseBodies("beq", stmt) + } } private fun longLessZero(value: PtExpression, lessEquals: Boolean, jump: PtJump?, stmt: PtIfElse) { @@ -1374,7 +1390,72 @@ _jump jmp (${target.asmLabel}) jump: PtJump?, stmt: PtIfElse ) { - TODO("long == value") + // TODO this can be optimized somewhat more when the left operand is a variable as well + // we only optimize for a const right value for now + + val constRight = right.asConstInteger() + val variableRight = (right as? PtIdentifier)?.name + if(constRight!=null) { + asmgen.assignExpressionToRegister(left, RegisterOrPair.R0R1_32, left.type.isSigned) + val hex = constRight.toUInt().toString(16).padStart(8, '0') + asmgen.out(""" + lda cx16.r0 + cmp #$${hex.substring(6,8)} + bne + + lda cx16.r0+1 + cmp #$${hex.substring(4, 6)} + bne + + lda cx16.r0+2 + cmp #$${hex.substring(2, 4)} + bne + + lda cx16.r0+3 + cmp #$${hex.take(2)} ++""") + } else if(variableRight!=null) { + require(right.type.isLong) + asmgen.assignExpressionToRegister(left, RegisterOrPair.R0R1_32, left.type.isSigned) + asmgen.out(""" + lda cx16.r0 + cmp $variableRight + bne + + lda cx16.r0+1 + cmp $variableRight+1 + bne + + lda cx16.r0+2 + cmp $variableRight+2 + bne + + lda cx16.r0+3 + cmp $variableRight+3 ++""") + } else { + asmgen.assignExpressionToRegister(left, RegisterOrPair.R2R3_32, left.type.isSigned) + asmgen.assignExpressionToRegister(right, RegisterOrPair.R0R1_32, right.type.isSigned) + asmgen.out(""" + lda cx16.r0 + cmp cx16.r2 + bne + + lda cx16.r0+1 + cmp cx16.r2+1 + bne + + lda cx16.r0+2 + cmp cx16.r2+2 + bne + + lda cx16.r0+3 + cmp cx16.r2+3 ++""") + } + + if(notEquals) { + if (jump != null) + translateJumpElseBodies("bne", "beq", jump, stmt.elseScope) + else + translateIfElseBodies("bne", stmt) + } else { + if (jump != null) + translateJumpElseBodies("beq", "bne", jump, stmt.elseScope) + else + translateIfElseBodies("beq", stmt) + } } private fun wordEqualsValue( diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index 82bdcb37d..4855f3cc4 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -3171,7 +3171,24 @@ $endLabel""") else -> throw AssemblyError("wrong dt ${target.position}") } } - TargetStorageKind.ARRAY -> TODO("assign long to array ${target.position}") + TargetStorageKind.ARRAY -> { + require(sourceDt.isLong) + val deref = target.array!!.pointerderef + if(deref!=null) { + pointergen.assignLongVar(IndexedPtrTarget(target), varName) + return + } + asmgen.loadScaledArrayIndexIntoRegister(target.array, CpuRegister.Y) + asmgen.out(""" + lda $varName + sta ${target.asmVarname},y + lda $varName+1 + sta ${target.asmVarname}+1,y + lda $varName+2 + sta ${target.asmVarname}+2,y + lda $varName+3 + sta ${target.asmVarname}+3,y""") + } TargetStorageKind.MEMORY -> throw AssemblyError("memory is bytes not long ${target.position}") TargetStorageKind.REGISTER -> { require(target.register in combinedLongRegisters) @@ -4231,7 +4248,7 @@ $endLabel""") TargetStorageKind.ARRAY -> { val deref = target.array!!.pointerderef if(deref!=null) { - pointergen.assignWord(IndexedPtrTarget(target), long) + pointergen.assignLong(IndexedPtrTarget(target), long) return } asmgen.loadScaledArrayIndexIntoRegister(target.array, CpuRegister.Y) @@ -4247,7 +4264,20 @@ $endLabel""") sta ${target.asmVarname}+3,y""") } TargetStorageKind.MEMORY -> throw AssemblyError("memory is bytes not long ${target.position}") - TargetStorageKind.REGISTER -> TODO("32 bits register assign? (we have no 32 bits registers right now) ${target.position}") + TargetStorageKind.REGISTER -> { + require(target.register in combinedLongRegisters) + val regstart = target.register!!.name.take(2).lowercase() + val hex = long.toUInt().toString(16).padStart(8, '0') + asmgen.out(""" + lda #$${hex.substring(6,8)} + sta cx16.$regstart + lda #$${hex.substring(4,6)} + sta cx16.$regstart+1 + lda #$${hex.substring(2,4)} + sta cx16.$regstart+2 + lda #$${hex.take(2)} + sta cx16.$regstart+3""") + } TargetStorageKind.POINTER -> throw AssemblyError("can't assign long to pointer, pointers are 16 bits ${target.position}") TargetStorageKind.VOID -> { /* do nothing */ } } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt index fb55d5f7f..1bc3be27b 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt @@ -111,7 +111,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, SourceStorageKind.LITERALBOOLEAN -> inplacemodificationLongWithLiteralval(target.asmVarname, operator, value.boolean!!.asInt()) SourceStorageKind.LITERALNUMBER -> inplacemodificationLongWithLiteralval(target.asmVarname, operator, value.number!!.number.toInt()) SourceStorageKind.VARIABLE -> inplacemodificationLongWithVariable(target.asmVarname, operator, value.asmVarname) - SourceStorageKind.EXPRESSION -> TODO("inplace modify long with expression ${target.position}") + SourceStorageKind.EXPRESSION -> inplacemodificationLongWithExpression(target.asmVarname, operator, value.expression!!) SourceStorageKind.REGISTER -> TODO("32 bits register inplace modification? ${target.position}") SourceStorageKind.ARRAY -> TODO("inplace modify long with array ${target.position}") SourceStorageKind.MEMORY -> TODO("memread into long ${target.position}") @@ -553,6 +553,11 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } } + internal fun inplacemodificationLongWithExpression(targetVar: String, operator: String, value: PtExpression) { + assignmentAsmGen.assignExpressionToRegister(value, RegisterOrPair.R0R1_32, value.type.isSigned) + inplacemodificationLongWithVariable(targetVar, operator, "cx16.r0") + } + internal fun inplacemodificationLongWithVariable(targetVar: String, operator: String, sourceVar: String) { when(operator) { "+" -> { diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/PointerAssignmentsGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/PointerAssignmentsGen.kt index 200c15635..2325e03c6 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/PointerAssignmentsGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/PointerAssignmentsGen.kt @@ -446,6 +446,10 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri TODO("array ptr assign word var ${target.position}") } + internal fun assignLongVar(target: IndexedPtrTarget, varName: String) { + TODO("array ptr assign long var ${target.position}") + } + internal fun operatorDereference(binExpr: PtBinaryExpression): Triple { // the only case we support here is: a.b.c[i] . value // returns the ZP var to use as a pointer, and a Y register offset (which can be zero), and finally the datatype of the field diff --git a/docs/source/todo.rst b/docs/source/todo.rst index b069497ae..40b024b17 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,11 +1,14 @@ TODO ==== +CHECK THAT >> and << work correctly for negative longs +implement the bitwise & | ^ operations as expressions on longs (all types args) + + LONG TYPE --------- - call convention: return long -> return it in R0+R1.... because AY is only 16 bits... - call convention: long param -> passed as regular variable NOT via R0:R1? asmsubs don't have syntax for this so use explicit separate msw() and lsw() arguments... Or introduce new syntax for R0+R1 combo's? -- implement the bitwise & | ^ operations as expressions on longs (all types args) - make sure == and != work with longs against byte and words as well signed and unsigned - how hard is it to also implement the other comparison operators on longs? - implement rol() and ror() on longs (also roxl and roxr) @@ -173,6 +176,7 @@ Optimizations ------------- - more optimized operator handling of different types, for example uword a ^ byte b now does a type cast of b to word first +- optimize longEqualsValue() for const and variable operands to not assign needlessly to R0-R3. - Port benchmarks from https://thred.github.io/c-bench-64/ to prog8 and see how it stacks up. - Since fixing the missing zp-var initialization, programs grew in size again because STZ's reappeared. Can we add more intelligent (and correct!) optimizations to remove those STZs that might be redundant again? - in Identifier: use typedarray of strings instead of listOf? Other places? diff --git a/examples/test.p8 b/examples/test.p8 index 2b1144521..4ad625d01 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -9,6 +9,37 @@ main { lv1 = $11223344 lv2 = $33883388 + + txt.print_bool(lv1==0) + txt.spc() + txt.print_bool(lv1==1) + txt.spc() + txt.print_bool(lv1==$11000000) + txt.spc() + txt.print_bool(lv1==$11223344) + txt.nl() + txt.print_bool(lv1==lv2) + txt.spc() + lv2 = lv1 + txt.print_bool(lv1==lv2) + txt.nl() + + + lv2 = $33883388 + txt.print_bool(lv1!=0) + txt.spc() + txt.print_bool(lv1!=1) + txt.spc() + txt.print_bool(lv1!=$11000000) + txt.spc() + txt.print_bool(lv1!=$11223344) + txt.nl() + txt.print_bool(lv1!=lv2) + txt.spc() + lv2 = lv1 + txt.print_bool(lv1!=lv2) + txt.nl() + txt.print_ulhex(lv1, false) txt.nl() lv1 = ~lv1 @@ -59,11 +90,7 @@ main { b1 = lv1 != cx16.r0 b2 = lv2 != cx16.r0s b1 = lv1 != lv2 - } -} -/* - sub start2() { txt.print_l(mklong2($a000,$bbbb)) txt.spc() txt.print_ulhex(mklong2($a000,$bbbb), true) @@ -88,16 +115,16 @@ main { txt.nl() long @shared lv = 111111111 - long @shared lv2 = 1000000 + lv2 = 1000000 word @shared ww = 1000 byte @shared bb = 1 long @shared result = lv + lv2 txt.print_l(result) txt.spc() - result = lv + (ww as long) ; TODO automatic cast + result = lv + ww txt.print_l(result) txt.spc() - result = lv + (bb as long) ; TODO automatic cast + result = lv + bb txt.print_l(result) txt.nl() txt.print_l(lv) @@ -109,79 +136,19 @@ main { txt.print_l(lv + 1000000) txt.nl() -; long[] array = [-1999888777, -999, 42, 0, 77, 123456, 999999999] -; long xx -; for xx in array { -; txt.print_uw(msw(xx)) -; txt.spc() -; txt.print_uw(lsw(xx)) -; txt.nl() -; } -; txt.nl() -; array[2] = 0 -; array[3] = 222222222 -; array[4] = bignum -; array[5]++ -; array[6]-- -; -; txt.print_l(-1999888777) -; txt.spc() -; txt.print_l(-999) -; txt.spc() -; txt.print_l(-42) -; txt.spc() -; txt.print_l(0) -; txt.spc() -; txt.print_l(bignum) -; txt.nl() -; txt.print_l(bignum2) -; txt.nl() -; txt.print_l(-bignum2) -; txt.nl() -; bignum2 = -bignum2 -; bignum2++ -; bignum2++ -; txt.print_l(bignum2) -; txt.nl() -; bignum2-- -; bignum2-- -; txt.print_l(bignum2) -; txt.spc() -; txt.print_l(bignum) -; txt.nl() -; txt.nl() -; bignum2 += bignum -; txt.print_l(bignum2) -; txt.nl() -; bignum2 -= bignum -; txt.print_l(bignum2) -; txt.nl() - -; ^^Node test = [] -; -; bignum++ -; bignum2-- - -; txt.print_l(bignum) -; txt.spc() -; txt.print_l(bignum2) -; txt.nl() -; -; str output = "...................." -; txt.print_l(bignum) -; txt.spc() -; txt.print(conv.str_l(bignum)) -; txt.nl() -; -; bignum = 999999 -; bignum-- ; TODO this works in the current VM... -; bignum = -888888 -; -; test.counter = 0 -; test.counter ++ ; TODO ... why doesn't this? (requires plusMinusMultAnyLong routine) -; test.counter = bignum2 -; test.counter -- + long[] array = [-1999888777, -999, 42, 0, 77, 123456, 999999999] + long xx + for xx in array { + txt.print_uw(msw(xx)) + txt.spc() + txt.print_uw(lsw(xx)) + txt.nl() + } + txt.nl() + array[2] = 0 + array[3] = 222222222 + array[4] = lv1 + array[5]++ + array[6]-- } -*/ - -;} +}