From d1ddf05e38742b04d27ed8105666c1e0acd5daed Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Thu, 3 Oct 2024 21:16:11 +0200 Subject: [PATCH] check that block address leaves room for program startup logic --- compiler/res/prog8lib/cx16/syslib.p8 | 3 +- compiler/src/prog8/compiler/Compiler.kt | 6 +- .../compiler/astprocessing/AstChecker.kt | 9 ++- .../test/codegeneration/TestVariousCodeGen.kt | 26 +++++++++ examples/test.p8 | 56 ++++--------------- 5 files changed, 49 insertions(+), 51 deletions(-) diff --git a/compiler/res/prog8lib/cx16/syslib.p8 b/compiler/res/prog8lib/cx16/syslib.p8 index 6f31f0588..560e51683 100644 --- a/compiler/res/prog8lib/cx16/syslib.p8 +++ b/compiler/res/prog8lib/cx16/syslib.p8 @@ -1238,11 +1238,10 @@ sub search_x16edit() -> ubyte { str @shared signature = petscii:"x16edit" for cx16.r1L in 31 downto 0 { cx16.rombank(cx16.r1L) - cx16.r2 = $fff0 %asm {{ ldy #0 - lda signature,y - cmp (cx16.r2),y + cmp $fff0,y bne + iny cpy #7 diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 68c3bfea5..b15a90b11 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -107,14 +107,14 @@ fun compileProgram(args: CompilerArguments): CompilationResult? { ) } + determineProgramLoadAddress(program, compilationOptions, args.errors) + args.errors.report() postprocessAst(program, args.errors, compilationOptions) + args.errors.report() // println("*********** COMPILER AST BEFORE ASSEMBLYGEN *************") // printProgram(program) - determineProgramLoadAddress(program, compilationOptions, args.errors) - args.errors.report() - if (args.writeAssembly) { // re-initialize memory areas with final compilationOptions diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index 384c99fd4..28eac8902 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -280,8 +280,13 @@ internal class AstChecker(private val program: Program, errors.err("identifiers cannot start with an underscore", block.position) val addr = block.address - if(addr!=null && addr>65535u) { - errors.err("block memory address must be valid integer 0..\$ffff", block.position) + if (addr!=null) { + if (addr > 65535u) + errors.err("block address must be valid integer 0..\$ffff", block.position) + if(compilerOptions.loadAddress!=0u) { + if (addr < compilerOptions.loadAddress + 20u) + errors.err("block address must be at least program load address + 20 (to allow for startup logic)", block.position) + } } for (statement in block.statements) { diff --git a/compiler/test/codegeneration/TestVariousCodeGen.kt b/compiler/test/codegeneration/TestVariousCodeGen.kt index eec805e69..22b6c5c44 100644 --- a/compiler/test/codegeneration/TestVariousCodeGen.kt +++ b/compiler/test/codegeneration/TestVariousCodeGen.kt @@ -384,6 +384,32 @@ main { compileText(VMTarget(), false, text, writeAssembly = true) shouldNotBe null } + test("block start address must be greater than program load address") { + val src = """ +%output raw +%launcher none +%address ${'$'}2000 + +main $2000 { + sub start() { + sys.clear_carry() + } +} + +otherblock ${'$'}2013 { + %option force_output +} + +thirdblock ${'$'}2014 { + %option force_output +}""" + val errors = ErrorReporterForTests() + compileText(C64Target(), false, src, writeAssembly = false, errors = errors) shouldBe null + errors.errors.size shouldBe 2 + errors.errors[0] shouldContain "6:1: block address must be at least program load address + 20" + errors.errors[1] shouldContain "12:1: block address must be at least program load address + 20" + } + test("for loops with just 1 iteration") { val src=""" main { diff --git a/examples/test.p8 b/examples/test.p8 index 967d0e4b5..446f56cdf 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,50 +1,18 @@ -%zeropage basicsafe +; EXAMPLE external command source code + +%launcher none %option no_sysinit +%zeropage basicsafe +%encoding iso +%import textio +%address $4000 -main { - sub func() -> ubyte { - cx16.r0++ - return cx16.r0L - } - sub start() { - bool[256] @shared cells - word starw - byte bb - uword uw - ubyte ub +main $4030 { + %option force_output - starw = (240-64 as word) + func() - - for starw in 50 downto 10 { - cx16.r0++ - } - for starw in cx16.r0L downto 10 { - cx16.r0++ - } - - for ub in 0 to len(cells)-1 { - cx16.r0++ - } - for ub in cx16.r0L to len(cells)-1 { - cx16.r0++ - } - for bb in 50 downto 10 { - cx16.r0++ - } - for bb in cx16.r0sL downto 10 { - cx16.r0++ - } - - for starw in 500 downto 10 { - cx16.r0++ - } - for uw in 50 downto 10 { - cx16.r0++ - } - for uw in 500 downto 10 { - cx16.r0++ - } + sub start() { + txt.print("external command\n") + sys.exit(0) } } -