added %option romable to enable romable mode, but only generate a bunch of warnings for problematic codegeneration atm

This commit is contained in:
Irmen de Jong
2025-02-20 23:39:29 +01:00
parent fb1e89d9ef
commit e55ce5504e
21 changed files with 94 additions and 115 deletions
@@ -11,6 +11,7 @@ class CompilationOptions(val output: OutputType,
val zpAllowed: List<UIntRange>,
val floats: Boolean,
val noSysInit: Boolean,
val romable: Boolean,
val compTarget: ICompilationTarget,
// these are set later, based on command line arguments or options in the source code:
var loadAddress: UInt,
@@ -1711,6 +1711,14 @@ $repeatLabel""")
}
return null
}
fun romableWarning(problem: String, pos: Position) {
if(options.romable) {
// until the code generation can provide an alternative, we have to report about code generated that is incompatible with ROMable code mode...
errors.warn("problem for ROMable code: $problem", pos)
out(" .warn \"ROMable code selected but incompatible code was generated: $problem\"")
}
}
}
/**
@@ -236,6 +236,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
jsr $jsrfar
+ .word 0
+ .byte 0""")
asmgen.romableWarning("self-modifying code for jsrfar", fcall.position) // TODO
}
// note that by convention the values in A+Y registers are now the return value of the call.
@@ -292,6 +293,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
jsr $jsrfar
+ .word 0
+ .byte 0""")
asmgen.romableWarning("self-modifying code for jsrfar", fcall.position) // TODO
}
// note that by convention the values in A+Y registers are now the return value of the call.
@@ -411,12 +413,12 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
is PtArrayIndexer -> {
asmgen.loadScaledArrayIndexIntoRegister(what, CpuRegister.X)
val varname = asmgen.asmVariableName(what.variable)
asmgen.out(" lda ${varname},x | lsr a | bcc + | ora #\$80 |+ | sta ${varname},x")
asmgen.out(" lda ${varname},x | lsr a | bcc + | ora #$80 |+ | sta ${varname},x")
}
is PtMemoryByte -> {
if (what.address is PtNumber) {
val number = (what.address as PtNumber).number
asmgen.out(" lda ${number.toHex()} | lsr a | bcc + | ora #\$80 |+ | sta ${number.toHex()}")
asmgen.out(" lda ${number.toHex()} | lsr a | bcc + | ora #$80 |+ | sta ${number.toHex()}")
} else {
asmgen.assignExpressionToRegister(what.address, RegisterOrPair.AY)
asmgen.out(" jsr prog8_lib.ror2_mem_ub")
@@ -424,7 +426,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
}
is PtIdentifier -> {
val variable = asmgen.asmVariableName(what)
asmgen.out(" lda $variable | lsr a | bcc + | ora #\$80 |+ | sta $variable")
asmgen.out(" lda $variable | lsr a | bcc + | ora #$80 |+ | sta $variable")
}
else -> throw AssemblyError("weird type")
}
@@ -435,13 +437,13 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
asmgen.loadScaledArrayIndexIntoRegister(what, CpuRegister.X)
val varname = asmgen.asmVariableName(what.variable)
if(what.splitWords)
asmgen.out(" lsr ${varname}_msb,x | ror ${varname}_lsb,x | bcc + | lda ${varname}_msb,x | ora #\$80 | sta ${varname}_msb,x |+ ")
asmgen.out(" lsr ${varname}_msb,x | ror ${varname}_lsb,x | bcc + | lda ${varname}_msb,x | ora #$80 | sta ${varname}_msb,x |+ ")
else
asmgen.out(" lsr ${varname}+1,x | ror ${varname},x | bcc + | lda ${varname}+1,x | ora #\$80 | sta ${varname}+1,x |+ ")
asmgen.out(" lsr ${varname}+1,x | ror ${varname},x | bcc + | lda ${varname}+1,x | ora #$80 | sta ${varname}+1,x |+ ")
}
is PtIdentifier -> {
val variable = asmgen.asmVariableName(what)
asmgen.out(" lsr $variable+1 | ror $variable | bcc + | lda $variable+1 | ora #\$80 | sta $variable+1 |+ ")
asmgen.out(" lsr $variable+1 | ror $variable | bcc + | lda $variable+1 | ora #$80 | sta $variable+1 |+ ")
}
else -> throw AssemblyError("weird type")
}
@@ -478,6 +480,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
asmgen.out("""
plp
+ ror ${'$'}ffff,x ; modified""")
asmgen.romableWarning("self-modifying code (ror)", fcall.position) // TODO
} else {
if(!what.address.isSimple()) asmgen.out(" php") // save Carry
asmgen.assignExpressionToRegister(what.address, RegisterOrPair.AY)
@@ -486,6 +489,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
sta (+) + 1
sty (+) + 2
+ ror ${'$'}ffff ; modified""")
asmgen.romableWarning("self-modifying code (ror)", fcall.position) // TODO
}
}
}
@@ -527,12 +531,12 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
is PtArrayIndexer -> {
asmgen.loadScaledArrayIndexIntoRegister(what, CpuRegister.X)
val varname = asmgen.asmVariableName(what.variable)
asmgen.out(" lda ${varname},x | cmp #\$80 | rol a | sta ${varname},x")
asmgen.out(" lda ${varname},x | cmp #$80 | rol a | sta ${varname},x")
}
is PtMemoryByte -> {
if (what.address is PtNumber) {
val number = (what.address as PtNumber).number
asmgen.out(" lda ${number.toHex()} | cmp #\$80 | rol a | sta ${number.toHex()}")
asmgen.out(" lda ${number.toHex()} | cmp #$80 | rol a | sta ${number.toHex()}")
} else {
asmgen.assignExpressionToRegister(what.address, RegisterOrPair.AY)
asmgen.out(" jsr prog8_lib.rol2_mem_ub")
@@ -540,7 +544,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
}
is PtIdentifier -> {
val variable = asmgen.asmVariableName(what)
asmgen.out(" lda $variable | cmp #\$80 | rol a | sta $variable")
asmgen.out(" lda $variable | cmp #$80 | rol a | sta $variable")
}
else -> throw AssemblyError("weird type")
}
@@ -594,6 +598,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
asmgen.out("""
plp
+ rol ${'$'}ffff,x ; modified""")
asmgen.romableWarning("self-modifying code (rol)", fcall.position) // TODO
} else {
if(!what.address.isSimple()) asmgen.out(" php") // save Carry
asmgen.assignExpressionToRegister(what.address, RegisterOrPair.AY)
@@ -602,6 +607,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
sta (+) + 1
sty (+) + 2
+ rol ${'$'}ffff ; modified""")
asmgen.romableWarning("self-modifying code (rol)", fcall.position) // TODO
}
}
}
@@ -111,6 +111,7 @@ internal class ForLoopsAsmGen(
$modifiedLabel cmp #0 ; modified
beq $endLabel
$incdec $varname""")
asmgen.romableWarning("self-modifying code (forloop over range)", stmt.position) // TODO
asmgen.jmp(loopLabel)
asmgen.out(endLabel)
@@ -159,6 +160,7 @@ $modifiedLabel cmp #0 ; modified
$modifiedLabel cmp #0 ; modified
bmi $loopLabel
beq $loopLabel""")
asmgen.romableWarning("self-modifying code (forloop over range)", stmt.position) // TODO
} else {
asmgen.out("""
lda $varname
@@ -167,6 +169,7 @@ $modifiedLabel cmp #0 ; modified
sta $varname
$modifiedLabel cmp #0 ; modified
bpl $loopLabel""")
asmgen.romableWarning("self-modifying code (forloop over range)", stmt.position) // TODO
}
asmgen.out(endLabel)
}
@@ -223,6 +226,7 @@ $modifiedLabel cmp #0 ; modified
lda $varname
$modifiedLabel2 cmp #0 ; modified
beq $endLabel""")
asmgen.romableWarning("self-modifying code (forloop over range)", stmt.position) // TODO
if(stepsize==1) {
asmgen.out("""
+ inc $varname
@@ -266,6 +270,7 @@ $modifiedLabel2 lda #0 ; modified
bcc $endLabel
bcs $loopLabel
$endLabel""")
asmgen.romableWarning("self-modifying code (forloop over range)", stmt.position) // TODO
} else {
asmgen.out("""
lda $varname
@@ -283,6 +288,7 @@ $modifiedLabel lda #0 ; modified
eor #$80
+ bpl $loopLabel
$endLabel""")
asmgen.romableWarning("self-modifying code (forloop over range)", stmt.position) // TODO
}
}
else {
@@ -313,6 +319,7 @@ $modifiedLabel sbc #0 ; modified
eor #$80
+ bpl $loopLabel
$endLabel""")
asmgen.romableWarning("self-modifying code (forloop over range)", stmt.position) // TODO
}
}
else -> throw AssemblyError("range expression can only be byte or word")
@@ -391,6 +398,7 @@ $endLabel""")
$loopLabel lda ${65535.toHex()} ; modified
beq $endLabel
sta ${asmgen.asmVariableName(stmt.variable)}""")
asmgen.romableWarning("self-modifying code (forloop over iterable)", stmt.position) // TODO
asmgen.translate(stmt.statements)
asmgen.out("""
inc $loopLabel+1
@@ -65,6 +65,7 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as
.word $subAsmName ; ${sub.address!!.address.toHex()}
+ .byte 0 ; modified"""
)
asmgen.romableWarning("self-modifying code for cx16 banked jsr", call.position) // TODO
}
"c64" -> {
asmgen.out("""
@@ -78,6 +79,7 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as
.word $subAsmName ; ${sub.address!!.address.toHex()}
+ .byte 0 ; modified"""
)
asmgen.romableWarning("self-modifying code for c64 banked jsr", call.position) // TODO
}
"c128" -> {
asmgen.out("""
@@ -91,6 +93,7 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as
.word $subAsmName ; ${sub.address!!.address.toHex()}
+ .byte 0 ; modified"""
)
asmgen.romableWarning("self-modifying code for c128 banked jsr", call.position) // TODO
}
else -> throw AssemblyError("callfar is not supported on the selected compilation target")
}
@@ -965,6 +965,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
asmgen.assignExpressionToRegister(pointervar, RegisterOrPair.AY)
asmgen.out(" sta (+) + 1 | sty (+) + 2")
asmgen.out("+\tinc ${'$'}ffff\t; modified")
asmgen.romableWarning("self-modifying code (access pointer)", pointervar.position) // TODO
} else {
val sourceName = asmgen.loadByteFromPointerIntoA(pointervar)
asmgen.out(" clc | adc #$value")
@@ -976,6 +977,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
asmgen.assignExpressionToRegister(pointervar, RegisterOrPair.AY)
asmgen.out(" sta (+) + 1 | sty (+) + 2")
asmgen.out("+\tdec ${'$'}ffff\t; modified")
asmgen.romableWarning("self-modifying code (access pointer)", pointervar.position) // TODO
} else {
val sourceName = asmgen.loadByteFromPointerIntoA(pointervar)
asmgen.out(" sec | sbc #$value")
+1
View File
@@ -26,6 +26,7 @@ class TestCodegen: FunSpec({
zpAllowed = CompilationOptions.AllZeropageAllowed,
floats = true,
noSysInit = false,
romable = false,
compTarget = target,
loadAddress = target.PROGRAM_LOAD_ADDRESS,
memtopAddress = 0xffffu
@@ -21,6 +21,7 @@ class TestIRPeepholeOpt: FunSpec({
CompilationOptions.AllZeropageAllowed,
floats = false,
noSysInit = true,
romable = false,
compTarget = target,
loadAddress = target.PROGRAM_LOAD_ADDRESS,
memtopAddress = 0xffffu
@@ -23,6 +23,7 @@ class TestVmCodeGen: FunSpec({
zpAllowed = CompilationOptions.AllZeropageAllowed,
floats = true,
noSysInit = false,
romable = false,
compTarget = target,
loadAddress = target.PROGRAM_LOAD_ADDRESS,
memtopAddress = 0xffffu
+2 -1
View File
@@ -352,6 +352,7 @@ internal fun determineCompilationOptions(program: Program, compTarget: ICompilat
val allOptions = program.modules.flatMap { it.options() }.toSet()
val floatsEnabled = "enable_floats" in allOptions
var noSysInit = "no_sysinit" in allOptions
var rombale = "romable" in allOptions
var zpType: ZeropageType =
if (zpoption == null)
if (floatsEnabled) ZeropageType.FLOATSAFE else ZeropageType.KERNALSAFE
@@ -408,7 +409,7 @@ internal fun determineCompilationOptions(program: Program, compTarget: ICompilat
return CompilationOptions(
outputType, launcherType,
zpType, zpReserved, zpAllowed, floatsEnabled, noSysInit,
zpType, zpReserved, zpAllowed, floatsEnabled, noSysInit, rombale,
compTarget, 0u, 0xffffu
)
}
@@ -1033,14 +1033,14 @@ internal class AstChecker(private val program: Program,
err("this directive may only occur in a block or at module level")
if(directive.args.isEmpty())
err("missing option directive argument(s)")
else if(directive.args.map{it.string in arrayOf("enable_floats", "force_output", "no_sysinit", "merge", "verafxmuls", "no_symbol_prefixing", "ignore_unused")}.any { !it })
else if(directive.args.map{it.string in arrayOf("enable_floats", "force_output", "no_sysinit", "merge", "verafxmuls", "no_symbol_prefixing", "ignore_unused", "romable")}.any { !it })
err("invalid option directive argument(s)")
if(directive.parent is Block) {
if(directive.args.any {it.string !in arrayOf("force_output", "merge", "verafxmuls", "no_symbol_prefixing", "ignore_unused")})
err("using an option that is not valid for blocks")
}
if(directive.parent is Module) {
if(directive.args.any {it.string !in arrayOf("enable_floats", "no_sysinit", "no_symbol_prefixing", "ignore_unused")})
if(directive.args.any {it.string !in arrayOf("enable_floats", "no_sysinit", "no_symbol_prefixing", "ignore_unused", "romable")})
err("using an option that is not valid for modules")
}
if(directive.args.any { it.string=="verafxmuls" } && compilerOptions.compTarget.name != Cx16Target.NAME)
+1
View File
@@ -19,6 +19,7 @@ class TestGoldenRam: FunSpec({
CompilationOptions.AllZeropageAllowed,
floats = true,
noSysInit = false,
romable = false,
compTarget = VMTarget(),
loadAddress = 999u,
memtopAddress = 0xffffu
+31 -29
View File
@@ -47,6 +47,7 @@ class TestAbstractZeropage: FunSpec({
CompilationOptions.AllZeropageAllowed,
floats = false,
noSysInit = false,
romable = false,
compTarget = C64Target(),
loadAddress = 999u,
memtopAddress = 0xffffu
@@ -67,6 +68,7 @@ class TestC64Zeropage: FunSpec({
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed,
floats = false,
noSysInit = false,
romable = false,
compTarget = c64target, loadAddress = 999u, memtopAddress = 0xffffu
))
@@ -82,33 +84,33 @@ class TestC64Zeropage: FunSpec({
}
test("testZpFloatEnable") {
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, c64target, 999u, 0xffffu))
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, c64target, 999u, 0xffffu))
var result = zp.allocate("", DataType.forDt(BaseDataType.FLOAT), null, null, errors)
result.expectError { "should be allocation error due to disabled floats" }
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.DONTUSE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, c64target, 999u, 0xffffu))
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.DONTUSE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, false, c64target, 999u, 0xffffu))
result = zp2.allocate("", DataType.forDt(BaseDataType.FLOAT), null, null, errors)
result.expectError { "should be allocation error due to disabled ZP use" }
val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, c64target, 999u, 0xffffu))
val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, false, c64target, 999u, 0xffffu))
zp3.allocate("", DataType.forDt(BaseDataType.FLOAT), null, null, errors)
}
test("testZpModesWithFloats") {
C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, c64target, 999u, 0xffffu))
C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, c64target, 999u, 0xffffu))
C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, c64target, 999u, 0xffffu))
C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, c64target, 999u, 0xffffu))
C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, c64target, 999u, 0xffffu))
C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, c64target, 999u, 0xffffu))
C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, c64target, 999u, 0xffffu))
C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, c64target, 999u, 0xffffu))
C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, c64target, 999u, 0xffffu))
C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, c64target, 999u, 0xffffu))
C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, false, c64target, 999u, 0xffffu))
C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, false, c64target, 999u, 0xffffu))
shouldThrow<InternalCompilerException> {
C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, c64target, 999u, 0xffffu))
C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, false, c64target, 999u, 0xffffu))
}
shouldThrow<InternalCompilerException> {
C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, c64target, 999u, 0xffffu))
C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, false, c64target, 999u, 0xffffu))
}
}
test("testZpDontuse") {
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.DONTUSE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, c64target, 999u, 0xffffu))
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.DONTUSE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, c64target, 999u, 0xffffu))
println(zp.free)
zp.availableBytes() shouldBe 0
val result = zp.allocate("", DataType.forDt(BaseDataType.BYTE), null, null, errors)
@@ -116,13 +118,13 @@ class TestC64Zeropage: FunSpec({
}
test("testFreeSpacesBytes") {
val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, c64target, 999u, 0xffffu))
val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, false, c64target, 999u, 0xffffu))
zp1.availableBytes() shouldBe 17
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, c64target, 999u, 0xffffu))
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, c64target, 999u, 0xffffu))
zp2.availableBytes() shouldBe 87
val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, c64target, 999u, 0xffffu))
val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, c64target, 999u, 0xffffu))
zp3.availableBytes() shouldBe 96
val zp4 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, c64target, 999u, 0xffffu))
val zp4 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, c64target, 999u, 0xffffu))
zp4.availableBytes() shouldBe 207
zp4.allocate("test", DataType.forDt(BaseDataType.UBYTE), null, null, errors)
zp4.availableBytes() shouldBe 206
@@ -131,7 +133,7 @@ class TestC64Zeropage: FunSpec({
}
test("testReservedSpace") {
val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, c64target, 999u, 0xffffu))
val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, c64target, 999u, 0xffffu))
zp1.availableBytes() shouldBe 207
4u shouldNotBeIn zp1.free
35u shouldNotBeIn zp1.free
@@ -142,7 +144,7 @@ class TestC64Zeropage: FunSpec({
200u shouldBeIn zp1.free
255u shouldBeIn zp1.free
199u shouldBeIn zp1.free
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, listOf(50u .. 100u, 200u..255u), CompilationOptions.AllZeropageAllowed, false, false, c64target, 999u, 0xffffu))
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, listOf(50u .. 100u, 200u..255u), CompilationOptions.AllZeropageAllowed, false, false, false, c64target, 999u, 0xffffu))
zp2.availableBytes() shouldBe 107
4u shouldNotBeIn zp2.free
35u shouldNotBeIn zp2.free
@@ -153,14 +155,14 @@ class TestC64Zeropage: FunSpec({
200u shouldNotBeIn zp2.free
255u shouldNotBeIn zp2.free
199u shouldBeIn zp2.free
val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FLOATSAFE, listOf(50u .. 100u, 200u..255u), CompilationOptions.AllZeropageAllowed, false, false, c64target, 999u, 0xffffu))
val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FLOATSAFE, listOf(50u .. 100u, 200u..255u), CompilationOptions.AllZeropageAllowed, false, false, false, c64target, 999u, 0xffffu))
zp2.availableBytes() shouldBe 107
4u shouldBeIn zp3.free
35u shouldNotBeIn zp3.free
}
test("testBasicsafeAllocation") {
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, c64target, 999u, 0xffffu))
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, false, c64target, 999u, 0xffffu))
zp.availableBytes() shouldBe 17
zp.hasByteAvailable() shouldBe true
zp.hasWordAvailable() shouldBe true
@@ -182,7 +184,7 @@ class TestC64Zeropage: FunSpec({
}
test("testFullAllocation") {
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, c64target, 999u, 0xffffu))
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, c64target, 999u, 0xffffu))
zp.availableBytes() shouldBe 207
zp.hasByteAvailable() shouldBe true
zp.hasWordAvailable() shouldBe true
@@ -213,7 +215,7 @@ class TestC64Zeropage: FunSpec({
}
test("testEfficientAllocation") {
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, c64target, 999u, 0xffffu))
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, false, c64target, 999u, 0xffffu))
zp.availableBytes() shouldBe 17
zp.allocate("", DataType.forDt(BaseDataType.WORD), null, null, errors).getOrElse{throw it}.address shouldBe 0x04u
zp.allocate("", DataType.forDt(BaseDataType.UBYTE), null, null, errors).getOrElse{throw it}.address shouldBe 0x06u
@@ -231,7 +233,7 @@ class TestC64Zeropage: FunSpec({
}
test("testReservedLocations") {
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, c64target, 999u, 0xffffu))
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, c64target, 999u, 0xffffu))
withClue("zp _B1 and _REG must be next to each other to create a word") {
zp.SCRATCH_B1 + 1u shouldBe zp.SCRATCH_REG
}
@@ -244,18 +246,18 @@ class TestCx16Zeropage: FunSpec({
val cx16target = Cx16Target()
test("testReservedLocations") {
val zp = CX16Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, cx16target, 999u, 0xffffu))
val zp = CX16Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, cx16target, 999u, 0xffffu))
withClue("zp _B1 and _REG must be next to each other to create a word") {
zp.SCRATCH_B1 + 1u shouldBe zp.SCRATCH_REG
}
}
test("testFreeSpacesBytes") {
val zp1 = CX16Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, cx16target, 999u, 0xffffu))
val zp1 = CX16Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, false, cx16target, 999u, 0xffffu))
zp1.availableBytes() shouldBe 88
val zp2 = CX16Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, cx16target, 999u, 0xffffu))
val zp2 = CX16Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, cx16target, 999u, 0xffffu))
zp2.availableBytes() shouldBe 175
val zp3 = CX16Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, cx16target, 999u, 0xffffu))
val zp3 = CX16Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, cx16target, 999u, 0xffffu))
zp3.availableBytes() shouldBe 216
zp3.allocate("test", DataType.forDt(BaseDataType.UBYTE), null, null, errors)
zp3.availableBytes() shouldBe 215
@@ -264,7 +266,7 @@ class TestCx16Zeropage: FunSpec({
}
test("testReservedSpace") {
val zp1 = CX16Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, cx16target, 999u, 0xffffu))
val zp1 = CX16Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, cx16target, 999u, 0xffffu))
zp1.availableBytes() shouldBe 216
0x22u shouldBeIn zp1.free
0x80u shouldBeIn zp1.free
@@ -274,7 +276,7 @@ class TestCx16Zeropage: FunSpec({
}
test("preallocated zp vars") {
val zp1 = CX16Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, cx16target, 999u, 0xffffu))
val zp1 = CX16Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, cx16target, 999u, 0xffffu))
zp1.allocatedVariables["test"] shouldBe null
zp1.allocatedVariables["cx16.r0"] shouldNotBe null
zp1.allocatedVariables["cx16.r15"] shouldNotBe null
@@ -78,7 +78,7 @@ class TestAsmGenSymbols: StringSpec({
fun createTestAsmGen6502(program: Program): AsmGen6502Internal {
val errors = ErrorReporterForTests()
val options = CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, true, C64Target(), 999u, 0xffffu)
val options = CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, true, false, C64Target(), 999u, 0xffffu)
val astchecker = AstChecker(program, errors, options)
astchecker.visit(program)
errors.report()
+1
View File
@@ -429,6 +429,7 @@ Directives
- ``ignore_unused`` (block or module) suppress warnings about unused variables and subroutines. Instead, these will be silently stripped.
This option is useful in library modules that contain many more routines beside the ones that you actually use.
- ``verafxmuls`` (block, cx16 target only) uses Vera FX hardware word multiplication on the CommanderX16 for all word multiplications in this block. Warning: this may interfere with IRQs and other Vera operations, so use this only when you know what you're doing. It's safer to explicitly use ``verafx.muls()``.
- ``romable`` (module) *WORK-IN-PROGRESS/EXPERIMENTAL* make sure that the generated code is suitable for running in ROM (so no self-modifying code and such)
.. data:: %output <type>
+1
View File
@@ -8,6 +8,7 @@ Future Things and Ideas
^^^^^^^^^^^^^^^^^^^^^^^
- Look at github PR for improved romability (see github issue 149)
- const values should always either be of type long or float, this is how they were usually treated in const expression evaluation already anyway
- Kotlin: can we use inline value classes in certain spots?
- add float support to the configurable compiler targets
- Improve the SublimeText syntax file for prog8, you can also install this for 'bat': https://github.com/sharkdp/bat?tab=readme-ov-file#adding-new-syntaxes--language-definitions
+7 -71
View File
@@ -1,78 +1,14 @@
%import textio
%zeropage basicsafe
%option no_sysinit
%option no_sysinit, romable
main {
sub start() {
cx16.r5 = one()
txt.print_uw(cx16.r5)
txt.nl()
uword @shared pointer = $4000
ubyte @shared size = 42
cx16.r5, cx16.r6 = two()
txt.print_uw(cx16.r5)
txt.spc()
txt.print_uw(cx16.r6)
txt.nl()
cx16.r5, cx16.r6, cx16.r7 = three()
txt.print_uw(cx16.r5)
txt.spc()
txt.print_uw(cx16.r6)
txt.spc()
txt.print_uw(cx16.r7)
txt.nl()
; bytes
cx16.r5L = oneb()
txt.print_ub(cx16.r5L)
txt.nl()
cx16.r5L, cx16.r6L = twob()
txt.print_ub(cx16.r5L)
txt.spc()
txt.print_ub(cx16.r6L)
txt.nl()
cx16.r5L, cx16.r6L, cx16.r7L = threeb()
txt.print_ub(cx16.r5L)
txt.spc()
txt.print_ub(cx16.r6L)
txt.spc()
txt.print_ub(cx16.r7L)
txt.nl()
}
uword @shared w1=1111
uword @shared w2=2222
uword @shared w3=3333
ubyte @shared b1=11
ubyte @shared b2=22
ubyte @shared b3=33
sub one() -> uword {
cx16.r0L++
return w1
}
sub two() -> uword, uword { ; TODO no P8SRC generated in IR?
return w1, w2
}
sub three() -> uword, uword, uword { ; TODO no P8SRC generated in IR?
return w1, w2, w3
}
sub oneb() -> ubyte {
cx16.r0L++
return b1
}
sub twob() -> ubyte,ubyte { ; TODO no P8SRC generated in IR?
return b1, b2
}
sub threeb() -> ubyte, ubyte, ubyte { ; TODO no P8SRC generated in IR?
return b1, b2, b3
for cx16.r0L in 5 to size {
@(pointer)++
@(pointer)--
}
}
}
@@ -92,6 +92,7 @@ class IRFileReader {
var loadAddress = target.PROGRAM_LOAD_ADDRESS
var memtop = target.PROGRAM_MEMTOP_ADDRESS
var optimize = true
var romable = false
var outputDir = Path("")
if(text.isNotBlank()) {
@@ -114,6 +115,7 @@ class IRFileReader {
}
"outputDir" -> outputDir = Path(value)
"optimize" -> optimize = value.toBoolean()
"romable" -> romable = value.toBoolean()
else -> throw IRParseException("illegal OPTION $name")
}
}
@@ -125,8 +127,9 @@ class IRFileReader {
zeropage,
zpReserved,
zpAllowed,
false,
false,
false, // TODO always false?
false, // TODO always false?
romable,
target,
loadAddress,
memtop,
@@ -224,6 +224,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
xml.writeCharacters("loadAddress=${irProgram.options.loadAddress.toHex()}\n")
xml.writeCharacters("memtop=${irProgram.options.memtopAddress.toHex()}\n")
xml.writeCharacters("optimize=${irProgram.options.optimize}\n")
xml.writeCharacters("romable=${irProgram.options.romable}\n")
xml.writeCharacters("outputDir=${irProgram.options.outputDir.absolute()}\n")
// other options not yet useful here?
xml.writeEndElement()
+1
View File
@@ -21,6 +21,7 @@ class TestIRFileInOut: FunSpec({
CompilationOptions.AllZeropageAllowed,
floats = false,
noSysInit = true,
romable = false,
compTarget = target,
loadAddress = target.PROGRAM_LOAD_ADDRESS,
memtopAddress = 0xffffu,
+1
View File
@@ -22,6 +22,7 @@ class TestVm: FunSpec( {
zpAllowed = CompilationOptions.AllZeropageAllowed,
floats = true,
noSysInit = false,
romable = false,
compTarget = target,
loadAddress = target.PROGRAM_LOAD_ADDRESS,
memtopAddress = 0xffffu