From 9c2bcab4a5feae00c78101c1f678c57abf116014 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Tue, 28 Oct 2025 20:10:10 +0100 Subject: [PATCH] fix more ptr/long issues --- .../src/prog8/codegen/cpu6502/AsmGen.kt | 23 ++-- .../cpu6502/assignment/AssignmentAsmGen.kt | 125 ++++++++++++------ compiler/test/TestPointers.kt | 40 +++++- docs/source/programming.rst | 6 +- examples/test.p8 | 62 +++------ 5 files changed, 151 insertions(+), 105 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt index b5c5c705a..cc0a867a3 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt @@ -844,7 +844,7 @@ class AsmGen6502Internal ( return } TargetStorageKind.POINTER -> { - TODO("assign to pointer ${target.position}") + pointerGen.assignByte(PtrTarget(target), 0) return } else -> { } @@ -854,7 +854,10 @@ class AsmGen6502Internal ( assignExpressionToRegister(value, RegisterOrPair.A) assignmentAsmGen.assignRegisterByte(target, CpuRegister.A, target.datatype.isSigned, false) } - target.datatype.isPointer -> TODO("assign expression to pointer ${target.position}") + target.datatype.isPointer -> { + assignExpressionToRegister(value, RegisterOrPair.AX) + pointerGen.assignWordReg(PtrTarget(target), RegisterOrPair.AX) + } target.datatype.isWord || target.datatype.isPassByRef -> { assignExpressionToRegister(value, RegisterOrPair.AY) translateNormalAssignment( @@ -882,7 +885,7 @@ class AsmGen6502Internal ( TargetStorageKind.ARRAY -> TODO("assign long to array ${target.position}") TargetStorageKind.MEMORY -> throw AssemblyError("memory is bytes not long ${target.position}") TargetStorageKind.REGISTER -> assignExpressionToRegister(value, target.register!!, true) - TargetStorageKind.POINTER -> TODO("assign long into pointer ${target.position}") + TargetStorageKind.POINTER -> pointerGen.assignLong(target.pointer!!, value.number.toInt()) TargetStorageKind.VOID -> { /* do nothing */ } } } else if(value is PtIdentifier && value.type.isLong) { @@ -905,7 +908,7 @@ class AsmGen6502Internal ( TargetStorageKind.ARRAY -> TODO("assign long to array ${target.position}") TargetStorageKind.MEMORY -> throw AssemblyError("memory is bytes not long ${target.position}") TargetStorageKind.REGISTER -> assignExpressionToRegister(value, target.register!!, true) - TargetStorageKind.POINTER -> TODO("assign long expression to pointer ${target.position}") + TargetStorageKind.POINTER -> pointerGen.assignLongVar(target.pointer!!, asmSymbolName(value)) TargetStorageKind.VOID -> { /* do nothing */ } } } else if(value is PtTypeCast && value.type.isLong) { @@ -920,7 +923,7 @@ class AsmGen6502Internal ( TargetStorageKind.ARRAY -> TODO("assign typecasted long to array ${target.position}") TargetStorageKind.MEMORY -> throw AssemblyError("memory is bytes not long ${target.position}") TargetStorageKind.REGISTER -> assignExpressionToRegister(value, target.register!!, true) - TargetStorageKind.POINTER -> TODO("assign long into pointer ${target.position}") + TargetStorageKind.POINTER -> TODO("assign typecasted long into pointer ${target.position}") TargetStorageKind.VOID -> { /* do nothing */ } } } else if(value.value.type.isWord) { @@ -945,9 +948,7 @@ class AsmGen6502Internal ( sta cx16.$startreg+1""") signExtendLongVariable("cx16.$startreg", value.value.type.base) } - TargetStorageKind.POINTER -> { - throw AssemblyError("assign typecasted long into pointer ${target.position}") - } + TargetStorageKind.POINTER -> TODO("assign typecasted long into pointer ${target.position}") TargetStorageKind.VOID -> { /* do nothing */ } } } else throw AssemblyError("weird casted type") @@ -956,6 +957,8 @@ class AsmGen6502Internal ( } } else if(target.kind == TargetStorageKind.REGISTER) { assignExpressionToRegister(value, target.register!!, true) + } else if(target.kind == TargetStorageKind.VARIABLE) { + assignExpressionToVariable(value, target.asmVarname, target.datatype) } else { TODO("assign long expression $value to a target ${target.kind} at ${target.position} - use simple expressions and temporary variables for now") } @@ -2264,7 +2267,7 @@ $repeatLabel""") } in Cx16VirtualRegisters -> { - val regname = regs.asScopedNameVirtualReg(DataType.UWORD) + val regname = regs.asScopedNameVirtualReg(DataType.UWORD).joinToString(".") out(""" lda $regname ldy #$offset @@ -2331,7 +2334,7 @@ $repeatLabel""") } in Cx16VirtualRegisters -> { - val regname = regs.asScopedNameVirtualReg(DataType.UWORD) + val regname = regs.asScopedNameVirtualReg(DataType.UWORD).joinToString(".") out(""" lda $regname ldy #0 diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index 7d79af3d2..13c69e05d 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -1746,46 +1746,6 @@ internal class AssignmentAsmGen( val left = expr.left val right = expr.right when(right) { - is PtIdentifier -> { - if(target.kind == TargetStorageKind.VARIABLE) { - asmgen.assignExpressionTo(left, target) - val rightsym = asmgen.asmVariableName(right) - asmgen.out(""" - lda #<$rightsym - ldy #>$rightsym - sta P8ZP_SCRATCH_W1 - sty P8ZP_SCRATCH_W1+1 - lda #<${target.asmVarname} - ldy #>${target.asmVarname}""") - if (expr.operator == "+") { - asmgen.out(" jsr prog8_lib.long_add_inplace") - } else { - asmgen.out(" jsr prog8_lib.long_sub_inplace") - } - return true - } else if(target.kind == TargetStorageKind.REGISTER) { - val startreg = target.register!!.startregname() - asmgen.assignExpressionTo(left, target) - val rightsym = asmgen.asmVariableName(right) - asmgen.out( - """ - lda #<$rightsym - ldy #>$rightsym - sta P8ZP_SCRATCH_W1 - sty P8ZP_SCRATCH_W1+1 - lda #cx16.$startreg""" - ) - if (expr.operator == "+") { - asmgen.out(" jsr prog8_lib.long_add_inplace") - } else { - asmgen.out(" jsr prog8_lib.long_sub_inplace") - } - return true - } else { - TODO("add/subtract long into ${target.kind} at ${target.position} - use simple expressions and temporary variables for now") - } - } is PtNumber -> { asmgen.assignExpressionTo(left, target) val hex = right.number.toLongHex() @@ -1856,10 +1816,90 @@ internal class AssignmentAsmGen( sta cx16.$startreg+3""") } return true + } else if(target.kind==TargetStorageKind.POINTER) { + // not an expression, no need to save R14/R15 + assignExpressionToRegister(expr, RegisterOrPair.R14R15_32, target.datatype.isSigned) + pointergen.assignLongVar(target.pointer!!, "cx16.r14") + return true } else { TODO("add/subtract long const into ${target.kind} ${target.position} - use simple expressions and temporary variables for now") } } + is PtIdentifier -> { + if(target.kind == TargetStorageKind.VARIABLE) { + asmgen.assignExpressionTo(left, target) + val rightsym = asmgen.asmVariableName(right) + asmgen.out(""" + lda #<$rightsym + ldy #>$rightsym + sta P8ZP_SCRATCH_W1 + sty P8ZP_SCRATCH_W1+1 + lda #<${target.asmVarname} + ldy #>${target.asmVarname}""") + if (expr.operator == "+") { + asmgen.out(" jsr prog8_lib.long_add_inplace") + } else { + asmgen.out(" jsr prog8_lib.long_sub_inplace") + } + return true + } else if(target.kind == TargetStorageKind.REGISTER) { + val startreg = target.register!!.startregname() + asmgen.assignExpressionTo(left, target) + val rightsym = asmgen.asmVariableName(right) + asmgen.out( + """ + lda #<$rightsym + ldy #>$rightsym + sta P8ZP_SCRATCH_W1 + sty P8ZP_SCRATCH_W1+1 + lda #cx16.$startreg""" + ) + if (expr.operator == "+") { + asmgen.out(" jsr prog8_lib.long_add_inplace") + } else { + asmgen.out(" jsr prog8_lib.long_sub_inplace") + } + return true + } else { + // isn't an expression, so no need to preserve R12-R15 + asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.R12R13_32, left.type.isSigned) + asmgen.assignExpressionToRegister(expr.right, RegisterOrPair.R14R15_32, left.type.isSigned) + if(expr.operator=="+") { + asmgen.out(""" + clc + lda cx16.r12 + adc cx16.r14 + sta cx16.r12 + lda cx16.r12+1 + adc cx16.r14+1 + sta cx16.r12+1 + lda cx16.r12+2 + adc cx16.r14+2 + sta cx16.r12+2 + lda cx16.r12+3 + adc cx16.r14+3 + sta cx16.r12+3""") + } else { + asmgen.out(""" + sec + lda cx16.r12 + sbc cx16.r14 + sta cx16.r12 + lda cx16.r12+1 + sbc cx16.r14+1 + sta cx16.r12+1 + lda cx16.r12+2 + sbc cx16.r14+2 + sta cx16.r12+2 + lda cx16.r12+3 + sbc cx16.r14+3 + sta cx16.r12+3""") + } + asmgen.assignRegister(RegisterOrPair.R12R13_32, target) + return true + } + } else -> { val targetreg = target.register if(targetreg==RegisterOrPair.R14R15_32) @@ -4050,7 +4090,10 @@ $endLabel""") sta cx16.$targetStartReg+3""") } } - TargetStorageKind.POINTER -> TODO("assign long to pointer ${target.position}") + TargetStorageKind.POINTER -> { + val startreg = pairedRegisters.startregname() + pointergen.assignLongVar(target.pointer!!, "cx16.$startreg") + } TargetStorageKind.VOID -> { /* do nothing */ } } } diff --git a/compiler/test/TestPointers.kt b/compiler/test/TestPointers.kt index db6165d10..bda7c5335 100644 --- a/compiler/test/TestPointers.kt +++ b/compiler/test/TestPointers.kt @@ -1258,7 +1258,7 @@ main { errors.errors[3] shouldContain "assigning this value to struct instance not supported" } - xtest("assigning struct instances") { + test("assigning struct instances") { val src=""" main { sub start() { @@ -1273,16 +1273,26 @@ main { lp2^^ = lp1^^ ; memcopy(lp1, lp2, 11) lp2[2] = lp1^^ ; memcopy(lp1, lp2 + 22, 11) - lp2[2]^^ = lp1^^ ; memcopy(lp1, lp2 + 22, 11) (same as above) TODO fix astchecker to allow this case + lp2[2]^^ = lp1^^ ; memcopy(lp1, lp2 + 22, 11) (same as above) lp2^^ = lp1[2] ; memcopy(lp1 + 22, lp2, 11) - lp2^^ = lp1[2]^^ ; memcopy(lp1 + 22, lp2, 11) (same as above) TODO fix astchecker to allow this case - lp2[3] = lp1[2] ; memcopy(lp1 + 22, lp2 + 33, 11) TODO fix astchecker to allow this case + lp2^^ = lp1[2]^^ ; memcopy(lp1 + 22, lp2, 11) (same as above) + ;;; lp2[3] = lp1[2] ; memcopy(lp1 + 22, lp2 + 33, 11) TODO fix astchecker to allow this case } }""" val errors = ErrorReporterForTests() val result = compileText(VMTarget(), false, src, outputDir, errors=errors)!! val st = result.compilerAst.entrypoint.statements - st.size shouldBe 99 + st.size shouldBe 11 + val memcopy1 = st[5] as FunctionCallStatement + val memcopy2 = st[6] as FunctionCallStatement + val memcopy3 = st[7] as FunctionCallStatement + val memcopy4 = st[8] as FunctionCallStatement + val memcopy5 = st[9] as FunctionCallStatement + memcopy1.target.nameInSource shouldBe listOf("sys", "memcopy") + memcopy2.target.nameInSource shouldBe listOf("sys", "memcopy") + memcopy3.target.nameInSource shouldBe listOf("sys", "memcopy") + memcopy4.target.nameInSource shouldBe listOf("sys", "memcopy") + memcopy5.target.nameInSource shouldBe listOf("sys", "memcopy") } test("a.b.c[i]^^.value as expression where pointer is struct") { @@ -2548,4 +2558,24 @@ main { be6.right shouldBe instanceOf() (a7.value as? ArrayIndexedExpression)?.indexer?.constIndex() shouldBe 0 } + + test("long pointer assignments") { + val src=""" +main { + sub start() { + long lvar = 999999 + ^^long lptr = 5000 + pokel(5000, 11223344) + + lptr^^ = 0 + lptr^^ = lvar + lptr^^ = 82348234+lvar + lvar = lptr^^+1111111 + } +}""" + compileText(VMTarget(), true, src, outputDir, writeAssembly = true) shouldNotBe null + compileText(C64Target(), true, src, outputDir, writeAssembly = true) shouldNotBe null + compileText(VMTarget(), false, src, outputDir, writeAssembly = true) shouldNotBe null + compileText(C64Target(), false, src, outputDir, writeAssembly = true) shouldNotBe null + } }) \ No newline at end of file diff --git a/docs/source/programming.rst b/docs/source/programming.rst index 3facf6968..51044756e 100644 --- a/docs/source/programming.rst +++ b/docs/source/programming.rst @@ -1238,10 +1238,8 @@ Otherwise the compiler will warn you about discarding the result of the call. Multiple return values ^^^^^^^^^^^^^^^^^^^^^^ Subroutines can return more than one value. -For example, ``asmsub`` routines (implemented in assembly code) or ``extsub`` routines -(referencing an external routine in ROM or elsewhere in RAM) can return multiple values spread -across different registers, and even the CPU's status register flags for boolean values. -Normal subroutines can also return multiple values. +``asmsub`` and ``extsub`` routines return their multiple values spread across different registers, +and can also efficiently use the CPU's status register flags for boolean returnvalues. You have to "multi assign" all return values of the subroutine call to something: write the assignment targets as a comma separated list, where the element's order corresponds to the order of the return values declared in the subroutine's signature. diff --git a/examples/test.p8 b/examples/test.p8 index 2a0e484e2..ca37babb5 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -2,56 +2,28 @@ %zeropage basicsafe main { - struct element { - ubyte type - long x - long y + struct Node { + ^^Node next } sub start() { - long @shared l1 = $e1fa84c6 - long @shared l2 = -1 - long @shared l3 = $ffffffff - long @shared l4 = $7fffffff - ^^long lptr = 20000 + ^^Node node = 6000 + long @shared lvar = 999999 + ^^long @shared lptr = 5000 + ^^bool bptr + ^^ubyte ubptr + pokel(5000, 11223344) - l1 ^= -1 - l2 ^= $ffffffff - l3 ^= $7fffffff - l3 ^= l4 + lptr^^ = 0 + lptr^^ = lvar + lptr^^ = 82348234+lvar + txt.print_l( lptr^^) + lvar = lptr^^+1111111 - lptr^^ = 82348234 - l2 = lptr^^ - l2 = 12345678 + ^^Node next = 8888 + node.next = next - txt.print_l(lptr^^) - txt.spc() - lptr^^ = 0 ; crash was fixed - txt.print_l(lptr^^) - txt.spc() - lptr^^ = l2 ; crash was fixed - txt.print_l(lptr^^) - txt.spc() - - lptr^^ = 82348234+l2 ; TODO fix crash - l3 = lptr^^+1 ; TODO fix crash - - -; cx16.r5L = 10 -; txt.print_l(cx16.r5L as long * $2000) -; txt.spc() -; txt.print_l(($2000 as long) * cx16.r5L) ; TODO fix long result? or wait till the long consts have landed? -; txt.nl() - -; ^^element myElement = $6000 -; myElement.y = $12345678 -; long @shared lv = $10101010 -; cx16.r0 = $ffff -; -; myElement.y += lv+cx16.r0 -; txt.print_ulhex(myElement.y, true) -; txt.spc() -; myElement.y -= lv+cx16.r0 -; txt.print_ulhex(myElement.y, true) + bptr^^=false + ubptr^^=0 } }