diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index fec378eda..13a4b0d62 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -314,18 +314,100 @@ internal class AssignmentAsmGen(private val program: PtProgram, } private fun assignByteFromAddressExpression(address: PtExpression, target: AsmAssignTarget) { - // TODO optimize this into more efficient code, using indexed register ,Y instead of explicitly calculating the full pointer value, or use self=modifying code and just use absolute addressing. - // see: https://discord.com/channels/547559626024157184/629863245934755860/1262873088782110750 + if(address is PtBinaryExpression) { + if(address.operator=="+" && address.right.type==DataType.UWORD) { + if (address.left is PtIdentifier) { + // use (zp),Y instead of explicitly calculating the full zp pointer value + val pointer = (address.left as PtIdentifier).name + when(val index=address.right) { + is PtIdentifier -> { + val indexName = index.name + asmgen.out(""" + lda $pointer + sta P8ZP_SCRATCH_W2 + lda $pointer+1 + clc + adc $indexName+1 + sta P8ZP_SCRATCH_W2+1 + ldy $indexName + lda (P8ZP_SCRATCH_W2),y""") + assignRegisterByte(target, CpuRegister.A, false, true) + return + } + is PtNumber -> { + val indexValue = index.number.toString() + asmgen.out(""" + lda $pointer + sta P8ZP_SCRATCH_W2 + lda $pointer+1 + clc + adc #>$indexValue + sta P8ZP_SCRATCH_W2+1 + ldy #<$indexValue + lda (P8ZP_SCRATCH_W2),y""") + assignRegisterByte(target, CpuRegister.A, false, true) + return + } + else -> {} + } + } + } +// else if(address.operator=="-") { +// // does this ever occur? we could optimize it too, but it seems like a pathological case +// } + } assignExpressionToVariable(address, "P8ZP_SCRATCH_W2", DataType.UWORD) asmgen.loadAFromZpPointerVar("P8ZP_SCRATCH_W2", false) assignRegisterByte(target, CpuRegister.A, false, true) } - private fun storeByteInAToAddressExpression(addressExpr: PtExpression, saveA: Boolean) { - // TODO optimize this into more efficient code, using indexed register ,Y instead of explicitly calculating the full pointer value, or use self=modifying code and just use absolute addressing. - // see: https://discord.com/channels/547559626024157184/629863245934755860/1262873088782110750 + private fun storeByteInAToAddressExpression(address: PtExpression, saveA: Boolean) { + if(address is PtBinaryExpression) { + if(address.operator=="+") { + if (address.left is PtIdentifier && address.right.type==DataType.UWORD) { + // use (zp),Y instead of explicitly calculating the full zp pointer value + val pointer = (address.left as PtIdentifier).name + when(val index=address.right) { + is PtIdentifier -> { + val indexName = index.name + asmgen.out(""" + tax + lda $pointer + sta P8ZP_SCRATCH_W2 + lda $pointer+1 + clc + adc $indexName+1 + sta P8ZP_SCRATCH_W2+1 + ldy $indexName + txa + sta (P8ZP_SCRATCH_W2),y""") + return + } + is PtNumber -> { + val indexValue = index.number.toString() + asmgen.out(""" + tax + lda $pointer + sta P8ZP_SCRATCH_W2 + lda $pointer+1 + clc + adc #>$indexValue + sta P8ZP_SCRATCH_W2+1 + ldy #<$indexValue + txa + sta (P8ZP_SCRATCH_W2),y""") + return + } + else -> {} + } + } + } +// else if(address.operator=="-") { +// // does this ever occur? we could optimize it too, but it seems like a pathological case +// } + } if(saveA) asmgen.out(" pha") - assignExpressionToVariable(addressExpr, "P8ZP_SCRATCH_W2", DataType.UWORD) + assignExpressionToVariable(address, "P8ZP_SCRATCH_W2", DataType.UWORD) if(saveA) asmgen.out(" pla") asmgen.storeAIntoZpPointerVar("P8ZP_SCRATCH_W2", false) } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index f0aee5278..08e34b40b 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,7 +3,10 @@ TODO See open issues on github. -Optimize code in assignByteFromAddressExpression() and storeByteInAToAddressExpression() +Generate proper index out of bounds error for array[-11] if the array is only size 10. (only array[-1]..array[-10] are valid) + +Putting a signed variable as an array index should be a compiler error. (using it for a pointer indexing is fine - but weird). +Add some more explanation about this to the "array indexing" paragraph in the docs. Re-generate the skeletons doc files. diff --git a/examples/test.p8 b/examples/test.p8 index de01e86c9..1b284c4f1 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -8,10 +8,47 @@ main { uword @shared ptr = $2000 uword @shared index = 1000 + @($2000+1000) = 123 + @($2000+1001) = 124 + cx16.r0L = @(ptr+index) - cx16.r1L = ptr[index] + cx16.r1L = @(ptr+1001) + + txt.print_ub(cx16.r0L) + txt.spc() + txt.print_ub(cx16.r1L) + txt.spc() + + cx16.r2L = ptr[index] + cx16.r3L = ptr[1001] + + txt.print_ub(cx16.r2L) + txt.spc() + txt.print_ub(cx16.r3L) + txt.spc() + + cx16.r0L = 200 + cx16.r1L = 201 + @(ptr+index) = cx16.r0L - ptr[index] = cx16.r1L + @(ptr+1001) = cx16.r1L + + txt.print_ub(@($2000+1000)) + txt.spc() + txt.print_ub(@($2000+1001)) + txt.spc() + + cx16.r0L = 203 + cx16.r1L = 204 + + ptr[index] = cx16.r0L + ptr[1001] = cx16.r1L + + txt.print_ub(@($2000+1000)) + txt.spc() + txt.print_ub(@($2000+1001)) + txt.spc() + ; txt.print_ub(ptr[index]) ; txt.nl() ; ptr[index] = 123