diff --git a/benchmark-c/result-sieve.png b/benchmark-c/result-sieve.png index 97aa8a093..80dce3f43 100644 Binary files a/benchmark-c/result-sieve.png and b/benchmark-c/result-sieve.png differ diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt index 0a7cac613..98d7c3e15 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt @@ -1067,6 +1067,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, val varname = asmgen.asmVariableName(pointer) asmgen.assignExpressionToRegister(result.second, RegisterOrPair.Y) asmgen.out(" lda ($varname),y") + } else if(addrExpr.operator in arrayOf("+", "-") && addrExpr.left is PtIdentifier) { + readValueFromPointerPlusOrMinOffset(addrExpr.left as PtIdentifier, addrExpr.operator, addrExpr.right, BaseDataType.BOOL) } else fallback() } else -> fallback() @@ -1112,6 +1114,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, lda ($varname),y tay txa""") + } else if(addrExpr.operator in arrayOf("+", "-") && addrExpr.left is PtIdentifier) { + readValueFromPointerPlusOrMinOffset(addrExpr.left as PtIdentifier, addrExpr.operator, addrExpr.right, BaseDataType.UWORD) } else fallback() } else -> fallback() @@ -1129,6 +1133,37 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, } } + private fun readValueFromPointerPlusOrMinOffset(ptr: PtIdentifier, operator: String, offset: PtExpression, dt: BaseDataType) { + val varname = asmgen.asmVariableName(ptr) + asmgen.assignExpressionToRegister(offset, RegisterOrPair.AY) + if(operator=="+") + asmgen.out(""" + clc + adc $varname + sta P8ZP_SCRATCH_W1 + tya + adc $varname+1 + sta P8ZP_SCRATCH_W1+1""") + else + asmgen.out(""" + sec + sbc $varname + sta P8ZP_SCRATCH_W1 + tya + sbc $varname+1 + sta P8ZP_SCRATCH_W1+1""") + + if (dt.isByteOrBool) { + if(asmgen.isTargetCpu(CpuType.CPU65C02)) { + asmgen.out(" lda (P8ZP_SCRATCH_W1)") + } else { + asmgen.out(" ldy #0 | lda (P8ZP_SCRATCH_W1),y") + } + } else if(dt.isWord) { + asmgen.out(" jsr prog8_lib.func_peekw.from_scratchW1") + } else throw AssemblyError("unsupported type for peek $dt") + } + private fun funcPeekL(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) { // TODO optimize for the simple cases asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.AY) diff --git a/compiler/res/prog8lib/prog8_funcs.asm b/compiler/res/prog8lib/prog8_funcs.asm index 909a1e875..6cc4e60e6 100644 --- a/compiler/res/prog8lib/prog8_funcs.asm +++ b/compiler/res/prog8lib/prog8_funcs.asm @@ -435,6 +435,7 @@ func_peek .proc ; -- read the byte value on the address in AY, into A sta P8ZP_SCRATCH_W1 sty P8ZP_SCRATCH_W1+1 +from_scratchW1 ldy #0 lda (P8ZP_SCRATCH_W1),y rts @@ -444,6 +445,7 @@ func_peekw .proc ; -- read the word value on the address in AY, into AY sta P8ZP_SCRATCH_W1 sty P8ZP_SCRATCH_W1+1 +from_scratchW1 ldy #0 lda (P8ZP_SCRATCH_W1),y pha @@ -458,6 +460,7 @@ func_peekl .proc ; -- read the ;pmg value on the address in AY, into R0:R1 sta P8ZP_SCRATCH_W1 sty P8ZP_SCRATCH_W1+1 +from_scratchW1 ldy #0 lda (P8ZP_SCRATCH_W1),y sta cx16.r0 diff --git a/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt b/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt index a26bc8fa8..5a480366c 100644 --- a/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt +++ b/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt @@ -297,6 +297,17 @@ _after: val peek = FunctionCallExpression(IdentifierReference(listOf("peekbool"), arrayIndexedExpression.position), mutableListOf(address), arrayIndexedExpression.position) return listOf(IAstModification.ReplaceNode(arrayIndexedExpression, peek, parent)) } + } else if(arrayVar.datatype.sub==BaseDataType.LONG) { + // use peekl/pokel + if(parent is AssignTarget) { + val assignment = parent.parent as Assignment + val args = mutableListOf(address, assignment.value) + val poke = FunctionCallStatement(IdentifierReference(listOf("pokel"), arrayIndexedExpression.position), args, false, arrayIndexedExpression.position) + return listOf(IAstModification.ReplaceNode(assignment, poke, assignment.parent)) + } else { + val peek = FunctionCallExpression(IdentifierReference(listOf("peekl"), arrayIndexedExpression.position), mutableListOf(address), arrayIndexedExpression.position) + return listOf(IAstModification.ReplaceNode(arrayIndexedExpression, peek, parent)) + } } else if(arrayVar.datatype.sub==BaseDataType.FLOAT) { // use peekf/pokef if(parent is AssignTarget) { diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 359f89172..ea3e1de2e 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,12 +1,15 @@ TODO ==== +- optimized translation for pokeX and peekX if address = pointer + uwordoffset. + + STRUCTS and TYPED POINTERS -------------------------- - implement the remaining TODO's in PointerAssignmentsGen. - optimize deref in PointerAssignmentsGen: optimize 'forceTemporary' to only use a temporary when the offset is >0 -- optimize the float copying in assignIndexedPointer() (also word?) +- optimize the float copying in assignIndexedPointer() (also word and long?) - optimize augmented assignments to indexed pointer targets like sprptr[2]^^.y++ (these are now not performend in-place but as a regular assignment) - implement even more struct instance assignments (via memcopy) in CodeDesugarer (see the TODO) (add to documentation as well, paragraph 'Structs') - support @nosplit pointer arrays? @@ -24,6 +27,8 @@ Future Things and Ideas This will break some existing programs that depend on value wrap arounds, but gives more intuitive constant number handling. Can give descriptive error message for old syntax that still includes the type name? - improve ANTLR grammar with better error handling (as suggested by Qwen AI) +- add documentation for more library modules instead of just linking to the source code +- add an Index to the documentation - allow memory() to occur in array initializer - when a complete block is removed because unused, suppress all info messages about everything in the block being removed - fix the line, cols in Position, sometimes they count from 0 sometimes from 1 diff --git a/examples/c64/simplemultiplexer.p8 b/examples/c64/simplemultiplexer.p8 index 61a905b1e..968b059e2 100644 --- a/examples/c64/simplemultiplexer.p8 +++ b/examples/c64/simplemultiplexer.p8 @@ -36,7 +36,7 @@ irq { ; Here is the actual multiplexing routine. ; it's a raster irq just after the start of the sprite, ; that updates the Y position of all the sprits, - ; and registers a new rater irq for that next row of sprites. + ; and registers a new raster irq for that next row of sprites. ; If the bottom of the screen is reached, it resets the X position of the sprites as well, ; and moves the sprites back to the top of the screen. sub multiplexer() -> bool { @@ -48,15 +48,18 @@ irq { sprites_Y = sprites.sprites_Y_start first_sprite_X++ if first_sprite_X >= 340 - first_sprite_X =0 + first_sprite_X = 0 sprites.set_sprites_Y(sprites_Y) while c64.RASTER != cx16.r2 { - ; wait until raster line after sprite has been fully drawn (at least 24 lines down) + ; wait until raster line after sprites have been fully drawn (at least 24 lines down) } sprites.set_sprites_X(first_sprite_X) ; we can now update the X positions without risk of sprite tearing system_irq = true } else { + ; only set the new Y positions. But it's possible to change other attributes as well ofcourse (colors, x-position, data) + ; but raster timing is critical for that if you want to avoid tearing and glitches. Can probably not be done here at this raster position... sprites.set_sprites_Y(sprites_Y) + c64.SPXY[0]++ } sys.set_rasterline(sprites_Y+1) diff --git a/examples/test.p8 b/examples/test.p8 index 2d10ff380..4fc4c20e1 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -3,45 +3,17 @@ main { sub start() { - long @shared lv1 = -9999 -; txt.print_uw(lsw(lv1)) -; txt.spc() -; txt.print_w(lv1 as word) -; txt.spc() -; txt.print_uw(lv1 as uword) -; txt.spc() -; txt.print_b(lv1 as byte) -; txt.spc() -; txt.print_ub(lv1 as ubyte) -; txt.spc() -; txt.print_w(msw(lv1 << 8) as word) -; txt.spc() -; txt.print_w(lsw(lv1 >> 8) as word) + ^^bool flags + ^^word words + ^^long longs - txt.nl() - txt.nl() - lv1 = -9876543 - conv.str_ub0(123) - txt.print(conv.str_l(lv1)) - txt.spc() - txt.print(conv.string_out) - txt.nl() - lv1 = 123456 - txt.print(conv.str_l(lv1)) - txt.spc() - txt.print(conv.string_out) - txt.nl() - lv1 = -2147483647 - txt.print(conv.str_l(lv1)) - txt.spc() - txt.print(conv.string_out) - txt.nl() - lv1 = 2147483647 - txt.print(conv.str_l(lv1)) - txt.spc() - txt.print(conv.string_out) - txt.nl() - + ; TODO optimized translation of the peekX and pokeX calls: + if flags[cx16.r0] + flags[cx16.r0] = true + if words[cx16.r0]!=0 + words[cx16.r0] = 9990 + if longs[cx16.r0]!=0 + longs[cx16.r0] = 999999 } }