Merge branch 'master' into next_compositetypes

This commit is contained in:
Irmen de Jong 2024-10-27 13:52:17 +01:00
commit c8b090a98b
32 changed files with 167 additions and 67 deletions

View File

@ -27,6 +27,7 @@ class CompilationOptions(val output: OutputType,
var slabsHighBank: Int? = null, var slabsHighBank: Int? = null,
var slabsGolden: Boolean = false, var slabsGolden: Boolean = false,
var splitWordArrays: Boolean = false, var splitWordArrays: Boolean = false,
var addMissingRts: Boolean = false, // deprecated, will likely go way in future version
var breakpointCpuInstruction: String? = null, var breakpointCpuInstruction: String? = null,
var outputDir: Path = Path(""), var outputDir: Path = Path(""),
var symbolDefs: Map<String, String> = emptyMap() var symbolDefs: Map<String, String> = emptyMap()

View File

@ -1040,7 +1040,7 @@ $repeatLabel""")
} }
} }
private fun translate(ret: PtReturn, withRts: Boolean=true) { private fun translate(ret: PtReturn) {
ret.value?.let { returnvalue -> ret.value?.let { returnvalue ->
val sub = ret.definingSub()!! val sub = ret.definingSub()!!
val returnReg = sub.returnRegister()!! val returnReg = sub.returnRegister()!!
@ -1055,8 +1055,6 @@ $repeatLabel""")
assignmentAsmGen.assignExpressionToRegister(addrofValue, returnReg.registerOrPair!!, false) assignmentAsmGen.assignExpressionToRegister(addrofValue, returnReg.registerOrPair!!, false)
} }
} }
if(withRts)
out(" rts") out(" rts")
} }

View File

@ -248,6 +248,7 @@ save_SCRATCH_ZPB1 .byte 0
save_SCRATCH_ZPREG .byte 0 save_SCRATCH_ZPREG .byte 0
save_SCRATCH_ZPWORD1 .word 0 save_SCRATCH_ZPWORD1 .word 0
save_SCRATCH_ZPWORD2 .word 0 save_SCRATCH_ZPWORD2 .word 0
; !notreached!
}} }}
} }
@ -461,6 +462,7 @@ cx16 {
_cx16_vreg_storage _cx16_vreg_storage
.word 0,0,0,0,0,0,0,0 .word 0,0,0,0,0,0,0,0
.word 0,0,0,0,0,0,0,0 .word 0,0,0,0,0,0,0,0
; !notreached!
}} }}
} }

View File

@ -453,6 +453,7 @@ save_SCRATCH_ZPB1 .byte 0
save_SCRATCH_ZPREG .byte 0 save_SCRATCH_ZPREG .byte 0
save_SCRATCH_ZPWORD1 .word 0 save_SCRATCH_ZPWORD1 .word 0
save_SCRATCH_ZPWORD2 .word 0 save_SCRATCH_ZPWORD2 .word 0
; !notreached!
}} }}
} }
@ -504,8 +505,6 @@ _modified
tax tax
pla pla
rti rti
_use_kernal .byte 0
}} }}
} }
@ -978,6 +977,7 @@ cx16 {
_cx16_vreg_storage _cx16_vreg_storage
.word 0,0,0,0,0,0,0,0 .word 0,0,0,0,0,0,0,0
.word 0,0,0,0,0,0,0,0 .word 0,0,0,0,0,0,0,0
; !notreached!
}} }}
} }

View File

@ -314,6 +314,7 @@ _mod sta $ffff ; modified
rts rts
_screenrows .word cbm.Screen + range(0, 1000, 40) _screenrows .word cbm.Screen + range(0, 1000, 40)
; !notreached!
}} }}
} }
@ -357,6 +358,7 @@ _mod sta $ffff ; modified
rts rts
_colorrows .word $d800 + range(0, 1000, 40) _colorrows .word $d800 + range(0, 1000, 40)
; !notreached!
}} }}
} }

View File

@ -386,6 +386,7 @@ _plot_y_values := p8c_BITMAP_ADDRESS + 320*(range(200)>>3) + (range(200) & 7)
_y_lookup_lo .byte <_plot_y_values _y_lookup_lo .byte <_plot_y_values
_y_lookup_hi .byte >_plot_y_values _y_lookup_hi .byte >_plot_y_values
; !notreached!
}} }}
} }

View File

@ -451,6 +451,7 @@ save_SCRATCH_ZPB1 .byte 0
save_SCRATCH_ZPREG .byte 0 save_SCRATCH_ZPREG .byte 0
save_SCRATCH_ZPWORD1 .word 0 save_SCRATCH_ZPWORD1 .word 0
save_SCRATCH_ZPWORD2 .word 0 save_SCRATCH_ZPWORD2 .word 0
; !notreached!
}} }}
} }
@ -975,6 +976,7 @@ cx16 {
_cx16_vreg_storage _cx16_vreg_storage
.word 0,0,0,0,0,0,0,0 .word 0,0,0,0,0,0,0,0
.word 0,0,0,0,0,0,0,0 .word 0,0,0,0,0,0,0,0
; !notreached!
}} }}
} }

View File

@ -317,6 +317,7 @@ _mod sta $ffff ; modified
rts rts
_screenrows .word cbm.Screen + range(0, 1000, 40) _screenrows .word cbm.Screen + range(0, 1000, 40)
; !notreached!
}} }}
} }
@ -360,6 +361,7 @@ _mod sta $ffff ; modified
rts rts
_colorrows .word $d800 + range(0, 1000, 40) _colorrows .word $d800 + range(0, 1000, 40)
; !notreached!
}} }}
} }

View File

@ -200,6 +200,7 @@ _allzero lda #'0'
sta string_out,x sta string_out,x
inx inx
bne _end bne _end
; !notreached!
}} }}
} }
@ -402,6 +403,7 @@ _digit
bne _parse bne _parse
; never reached ; never reached
_negative .byte 0 _negative .byte 0
; !notreached!
}} }}
} }
@ -472,6 +474,7 @@ _try_iso
bcs _stop bcs _stop
and #63 and #63
bne _add_letter bne _add_letter
; !notreached!
}} }}
} }
@ -702,7 +705,7 @@ decHundreds .byte 0
decTens .byte 0 decTens .byte 0
decOnes .byte 0 decOnes .byte 0
.byte 0 ; zero-terminate the decimal output string .byte 0 ; zero-terminate the decimal output string
; !notreached!
}} }}
} }
@ -736,6 +739,7 @@ asmsub internal_ubyte2hex (ubyte value @A) clobbers(X) -> ubyte @A, ubyte @Y
rts rts
_hex_digits .text "0123456789abcdef" ; can probably be reused for other stuff as well _hex_digits .text "0123456789abcdef" ; can probably be reused for other stuff as well
; !notreached!
}} }}
} }
@ -753,6 +757,7 @@ asmsub internal_uword2hex (uword value @AY) clobbers(A,Y) {
sty output+3 sty output+3
rts rts
output .text "0000", $00 ; 0-terminated output buffer (to make printing easier) output .text "0000", $00 ; 0-terminated output buffer (to make printing easier)
; !notreached!
}} }}
} }

View File

@ -186,6 +186,7 @@ _borked
+ jmp sys.exit + jmp sys.exit
_msg .text 13,"?rom 47+ required for val1",13,0 _msg .text 13,"?rom 47+ required for val1",13,0
; !notreached!
}} }}
} }

View File

@ -838,6 +838,7 @@ _large ora cx16.r2L
+ lda #0 + lda #0
rts rts
_strides_lsb .byte 0,1,2,4,8,16,32,64,128,255,255,40,80,160,255,255 _strides_lsb .byte 0,1,2,4,8,16,32,64,128,255,255,40,80,160,255,255
; !notreached!
}} }}
} }
@ -955,6 +956,7 @@ asmsub save_virtual_registers() clobbers(A,Y) {
_cx16_vreg_storage _cx16_vreg_storage
.word 0,0,0,0,0,0,0,0 .word 0,0,0,0,0,0,0,0
.word 0,0,0,0,0,0,0,0 .word 0,0,0,0,0,0,0,0
; !notreached!
}} }}
} }
@ -993,6 +995,7 @@ asmsub save_vera_context() clobbers(A) {
sta _vera_storage+6 sta _vera_storage+6
rts rts
_vera_storage: .byte 0,0,0,0,0,0,0,0 _vera_storage: .byte 0,0,0,0,0,0,0,0
; !notreached!
}} }}
} }
@ -1315,6 +1318,7 @@ _continue iny
bne _continue bne _continue
+ pla + pla
sta $00 sta $00
rts
}} }}
} }
@ -1499,6 +1503,7 @@ asmsub restore_irq() clobbers(A) {
cli cli
rts rts
_orig_irqvec .word 0 _orig_irqvec .word 0
; !notreached!
}} }}
} }
@ -1775,6 +1780,7 @@ save_SCRATCH_ZPB1 .byte 0
save_SCRATCH_ZPREG .byte 0 save_SCRATCH_ZPREG .byte 0
save_SCRATCH_ZPWORD1 .word 0 save_SCRATCH_ZPWORD1 .word 0
save_SCRATCH_ZPWORD2 .word 0 save_SCRATCH_ZPWORD2 .word 0
; !notreached!
}} }}
} }

View File

@ -13,6 +13,7 @@ math {
lda _sinecos8u,y lda _sinecos8u,y
rts rts
_sinecos8u .byte trunc(128.0 + 127.5 * sin(range(256+64) * rad(360.0/256.0))) _sinecos8u .byte trunc(128.0 + 127.5 * sin(range(256+64) * rad(360.0/256.0)))
; !notreached!
}} }}
} }
@ -30,6 +31,7 @@ _sinecos8u .byte trunc(128.0 + 127.5 * sin(range(256+64) * rad(360.0/256.0)))
lda _sinecos8,y lda _sinecos8,y
rts rts
_sinecos8 .char trunc(127.0 * sin(range(256+64) * rad(360.0/256.0))) _sinecos8 .char trunc(127.0 * sin(range(256+64) * rad(360.0/256.0)))
; !notreached!
}} }}
} }
@ -47,6 +49,7 @@ _sinecos8 .char trunc(127.0 * sin(range(256+64) * rad(360.0/256.0)))
lda _sinecosR8u,y lda _sinecosR8u,y
rts rts
_sinecosR8u .byte trunc(128.0 + 127.5 * sin(range(180+45) * rad(360.0/180.0))) _sinecosR8u .byte trunc(128.0 + 127.5 * sin(range(180+45) * rad(360.0/180.0)))
; !notreached!
}} }}
} }
@ -64,6 +67,7 @@ _sinecosR8u .byte trunc(128.0 + 127.5 * sin(range(180+45) * rad(360.0/180.0)))
lda _sinecosR8,y lda _sinecosR8,y
rts rts
_sinecosR8 .char trunc(127.0 * sin(range(180+45) * rad(360.0/180.0))) _sinecosR8 .char trunc(127.0 * sin(range(180+45) * rad(360.0/180.0)))
; !notreached!
}} }}
} }
@ -131,6 +135,7 @@ _sinecosR8 .char trunc(127.0 * sin(range(180+45) * rad(360.0/180.0)))
rts rts
+ lsr a + lsr a
bne - bne -
; !notreached!
}} }}
} }
@ -331,7 +336,7 @@ _quadrant_region_to_direction:
.byte 8, 4,16,20 .byte 8, 4,16,20
.byte 7, 5,17,19 .byte 7, 5,17,19
.byte 6, 6,18,18 .byte 6, 6,18,18
; !notreached!
}} }}
} }
@ -464,7 +469,7 @@ log2_tab
.byte $fb,$fb,$fb,$fc,$fc,$fc,$fc,$fc .byte $fb,$fb,$fb,$fc,$fc,$fc,$fc,$fc
.byte $fd,$fd,$fd,$fd,$fd,$fd,$fe,$fe .byte $fd,$fd,$fd,$fd,$fd,$fd,$fe,$fe
.byte $fe,$fe,$fe,$ff,$ff,$ff,$ff,$ff .byte $fe,$fe,$fe,$ff,$ff,$ff,$ff,$ff
; !notreached!
}} }}
} }

View File

@ -350,6 +350,7 @@ save_SCRATCH_ZPB1 .byte 0
save_SCRATCH_ZPREG .byte 0 save_SCRATCH_ZPREG .byte 0
save_SCRATCH_ZPWORD1 .word 0 save_SCRATCH_ZPWORD1 .word 0
save_SCRATCH_ZPWORD2 .word 0 save_SCRATCH_ZPWORD2 .word 0
; !notreached!
}} }}
} }
@ -564,6 +565,7 @@ cx16 {
_cx16_vreg_storage _cx16_vreg_storage
.word 0,0,0,0,0,0,0,0 .word 0,0,0,0,0,0,0,0
.word 0,0,0,0,0,0,0,0 .word 0,0,0,0,0,0,0,0
; !notreached!
}} }}
} }

View File

@ -171,6 +171,7 @@ _mod sta $ffff ; modified
rts rts
_screenrows .word cbm.Screen + range(0, 1000, 40) _screenrows .word cbm.Screen + range(0, 1000, 40)
; !notreached!
}} }}
} }

View File

@ -171,6 +171,7 @@ _allzero lda #'0'
eor P8ZP_SCRATCH_REG eor P8ZP_SCRATCH_REG
rts rts
_offsets .byte 128, 0, 64, 32, 64, 192, 128, 128 _offsets .byte 128, 0, 64, 32, 64, 192, 128, 128
; !notreached!
}} }}
} }

View File

@ -178,7 +178,7 @@ _found tya
rts rts
_str .word 0 _str .word 0
; !notreached!
}} }}
} }

View File

@ -56,6 +56,7 @@ private fun compileMain(args: Array<String>): Boolean {
val outputDir by cli.option(ArgType.String, fullName = "out", description = "directory for output files instead of current directory").default(".") val outputDir by cli.option(ArgType.String, fullName = "out", description = "directory for output files instead of current directory").default(".")
val quietAssembler by cli.option(ArgType.Boolean, fullName = "quietasm", description = "don't print assembler output results") val quietAssembler by cli.option(ArgType.Boolean, fullName = "quietasm", description = "don't print assembler output results")
val warnSymbolShadowing by cli.option(ArgType.Boolean, fullName = "warnshadow", description="show assembler warnings about symbol shadowing") val warnSymbolShadowing by cli.option(ArgType.Boolean, fullName = "warnshadow", description="show assembler warnings about symbol shadowing")
val addMissingRts by cli.option(ArgType.Boolean, fullName = "addmissingrts", description="enable old behavior that silently adds RTS to asmsubs that don't have one (deprecated, may go away in future version)")
val sourceDirs by cli.option(ArgType.String, fullName="srcdirs", description = "list of extra paths, separated with ${File.pathSeparator}, to search in for imported modules").multiple().delimiter(File.pathSeparator) val sourceDirs by cli.option(ArgType.String, fullName="srcdirs", description = "list of extra paths, separated with ${File.pathSeparator}, to search in for imported modules").multiple().delimiter(File.pathSeparator)
val includeSourcelines by cli.option(ArgType.Boolean, fullName = "sourcelines", description = "include original Prog8 source lines in generated asm code") val includeSourcelines by cli.option(ArgType.Boolean, fullName = "sourcelines", description = "include original Prog8 source lines in generated asm code")
val splitWordArrays by cli.option(ArgType.Boolean, fullName = "splitarrays", description = "treat all word arrays as tagged with @split to make them lsb/msb split in memory") val splitWordArrays by cli.option(ArgType.Boolean, fullName = "splitarrays", description = "treat all word arrays as tagged with @split to make them lsb/msb split in memory")
@ -181,6 +182,7 @@ private fun compileMain(args: Array<String>): Boolean {
slabsGolden == true, slabsGolden == true,
compilationTarget!!, compilationTarget!!,
splitWordArrays == true, splitWordArrays == true,
addMissingRts == true,
breakpointCpuInstruction, breakpointCpuInstruction,
printAst1 == true, printAst1 == true,
printAst2 == true, printAst2 == true,
@ -261,6 +263,7 @@ private fun compileMain(args: Array<String>): Boolean {
slabsGolden == true, slabsGolden == true,
compilationTarget!!, compilationTarget!!,
splitWordArrays == true, splitWordArrays == true,
addMissingRts == true,
breakpointCpuInstruction, breakpointCpuInstruction,
printAst1 == true, printAst1 == true,
printAst2 == true, printAst2 == true,

View File

@ -52,6 +52,7 @@ class CompilerArguments(val filepath: Path,
val slabsGolden: Boolean, val slabsGolden: Boolean,
val compilationTarget: String, val compilationTarget: String,
val splitWordArrays: Boolean, val splitWordArrays: Boolean,
val addMissingRts: Boolean,
val breakpointCpuInstruction: String?, val breakpointCpuInstruction: String?,
val printAst1: Boolean, val printAst1: Boolean,
val printAst2: Boolean, val printAst2: Boolean,
@ -89,6 +90,7 @@ fun compileProgram(args: CompilerArguments): CompilationResult? {
slabsHighBank = args.slabsHighBank slabsHighBank = args.slabsHighBank
slabsGolden = args.slabsGolden slabsGolden = args.slabsGolden
splitWordArrays = args.splitWordArrays splitWordArrays = args.splitWordArrays
addMissingRts = args.addMissingRts
outputDir = args.outputDir.normalize() outputDir = args.outputDir.normalize()
symbolDefs = args.symbolDefs symbolDefs = args.symbolDefs
} }

View File

@ -22,7 +22,7 @@ internal fun Program.checkValid(errors: IErrorReporter, compilerOptions: Compila
} }
internal fun Program.processAstBeforeAsmGeneration(compilerOptions: CompilationOptions, errors: IErrorReporter) { internal fun Program.processAstBeforeAsmGeneration(compilerOptions: CompilationOptions, errors: IErrorReporter) {
val fixer = BeforeAsmAstChanger(this, compilerOptions) val fixer = BeforeAsmAstChanger(this, compilerOptions, errors)
fixer.visit(this) fixer.visit(this)
while (errors.noErrors() && fixer.applyModifications() > 0) { while (errors.noErrors() && fixer.applyModifications() > 0) {
fixer.visit(this) fixer.visit(this)
@ -155,11 +155,29 @@ internal fun IdentifierReference.isSubroutineParameter(program: Program): Boolea
return false return false
} }
internal fun Subroutine.hasRtsInAsm(): Boolean { internal fun Subroutine.hasRtsInAsm(checkOnlyLastInstruction: Boolean): Boolean {
return statements val asms = statements
.asSequence() .asSequence()
.filterIsInstance<InlineAssembly>() .filterIsInstance<InlineAssembly>()
.any { it.hasReturnOrRts() } if(checkOnlyLastInstruction) {
val lastAsm = asms.lastOrNull() ?: return false
val lastLine = lastAsm.assembly.lineSequence().map { it.trim() }.last {
it.isNotBlank() && (!it.startsWith(';') || it.contains("!notreached!"))
}
if(lastLine.contains("!notreached!"))
return true
val inlineAsm = InlineAssembly(" $lastLine", lastAsm.isIR, lastAsm.position)
return inlineAsm.hasReturnOrRts()
} else {
val allAsms = asms.toList()
val lastAsm = allAsms.lastOrNull() ?: return false
val lastLine = lastAsm.assembly.lineSequence().map { it.trim() }.last {
it.isNotBlank() && (!it.startsWith(';') || it.contains("!notreached!"))
}
if(lastLine.contains("!notreached!"))
return true
return allAsms.any { it.hasReturnOrRts() }
}
} }
internal fun IdentifierReference.checkFunctionOrLabelExists(program: Program, statement: Statement, errors: IErrorReporter): Statement? { internal fun IdentifierReference.checkFunctionOrLabelExists(program: Program, statement: Statement, errors: IErrorReporter): Statement? {

View File

@ -11,7 +11,7 @@ import prog8.ast.walk.IAstModification
import prog8.code.core.* import prog8.code.core.*
import prog8.code.target.VMTarget import prog8.code.target.VMTarget
internal class BeforeAsmAstChanger(val program: Program, private val options: CompilationOptions) : AstWalker() { internal class BeforeAsmAstChanger(val program: Program, private val options: CompilationOptions, private val errors: IErrorReporter) : AstWalker() {
override fun before(breakStmt: Break, parent: Node): Iterable<IAstModification> { override fun before(breakStmt: Break, parent: Node): Iterable<IAstModification> {
throw InternalCompilerException("break should have been replaced by goto $breakStmt") throw InternalCompilerException("break should have been replaced by goto $breakStmt")
@ -81,13 +81,22 @@ internal class BeforeAsmAstChanger(val program: Program, private val options: Co
} }
if (!subroutine.inline) { if (!subroutine.inline) {
if (subroutine.isAsmSubroutine && subroutine.asmAddress==null && !subroutine.hasRtsInAsm()) { if (subroutine.isAsmSubroutine && subroutine.asmAddress==null) {
if(!options.addMissingRts && !subroutine.hasRtsInAsm(true)) {
errors.err("asmsub seems to never return as it doesn't end with RTS/JMP/branch. If this is intended, add a '; !notreached!' comment at the end, or use -addmissingrts", subroutine.position)
}
else if (!subroutine.hasRtsInAsm(false)) {
// make sure the NOT INLINED asm subroutine actually has a rts at the end // make sure the NOT INLINED asm subroutine actually has a rts at the end
// (non-asm routines get a Return statement as needed, above) // (non-asm routines get a Return statement as needed, above)
if(options.addMissingRts) {
errors.info("added missing RTS to asmsub", subroutine.position)
mods += if(options.compTarget.name==VMTarget.NAME) mods += if(options.compTarget.name==VMTarget.NAME)
IAstModification.InsertLast(InlineAssembly(" return\n", true, Position.DUMMY), subroutine) IAstModification.InsertLast(InlineAssembly(" return\n", true, Position.DUMMY), subroutine)
else else
IAstModification.InsertLast(InlineAssembly(" rts\n", false, Position.DUMMY), subroutine) IAstModification.InsertLast(InlineAssembly(" rts\n", false, Position.DUMMY), subroutine)
} else
errors.err("asmsub seems to never return as it doesn't end with RTS/JMP/branch. If this is intended, add a '; !notreached!' comment at the end, or use -addmissingrts", subroutine.position)
}
} }
} }

View File

@ -40,6 +40,7 @@ private fun compileTheThing(filepath: Path, optimize: Boolean, target: ICompilat
slabsGolden = false, slabsGolden = false,
compilationTarget = target.name, compilationTarget = target.name,
splitWordArrays = false, splitWordArrays = false,
addMissingRts = false,
breakpointCpuInstruction = null, breakpointCpuInstruction = null,
printAst1 = false, printAst1 = false,
printAst2 = false, printAst2 = false,

View File

@ -38,6 +38,7 @@ class TestCompilerOptionSourcedirs: FunSpec({
slabsGolden = false, slabsGolden = false,
compilationTarget = Cx16Target.NAME, compilationTarget = Cx16Target.NAME,
splitWordArrays = false, splitWordArrays = false,
addMissingRts = false,
breakpointCpuInstruction = null, breakpointCpuInstruction = null,
printAst1 = false, printAst1 = false,
printAst2 = false, printAst2 = false,

View File

@ -57,6 +57,7 @@ main {
asmsub baz() { asmsub baz() {
%asm{{ %asm{{
jsr p8s_foo jsr p8s_foo
jmp blah
}} }}
} }
asmsub bar() { asmsub bar() {

View File

@ -105,6 +105,9 @@ class TestSubroutines: FunSpec({
} }
asmsub asmfunc(str thing @AY) { asmsub asmfunc(str thing @AY) {
%asm {{
rts
}}
} }
sub func(str thing) { sub func(str thing) {
@ -125,7 +128,7 @@ class TestSubroutines: FunSpec({
asmfunc.isAsmSubroutine shouldBe true asmfunc.isAsmSubroutine shouldBe true
asmfunc.statements.single() shouldBe instanceOf<InlineAssembly>() asmfunc.statements.single() shouldBe instanceOf<InlineAssembly>()
(asmfunc.statements.single() as InlineAssembly).assembly.trim() shouldBe "rts" (asmfunc.statements.single() as InlineAssembly).assembly.trim() shouldBe "rts"
asmfunc.hasRtsInAsm() shouldBe true asmfunc.hasRtsInAsm(false) shouldBe true
func.isAsmSubroutine shouldBe false func.isAsmSubroutine shouldBe false
withClue("str param should have been changed to uword") { withClue("str param should have been changed to uword") {
asmfunc.parameters.single().type shouldBe DataType.forDt(BaseDataType.UWORD) asmfunc.parameters.single().type shouldBe DataType.forDt(BaseDataType.UWORD)

View File

@ -1,6 +1,7 @@
package prog8tests.codegeneration package prog8tests.codegeneration
import io.kotest.core.spec.style.FunSpec import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.collections.shouldContain
import io.kotest.matchers.ints.shouldBeGreaterThan import io.kotest.matchers.ints.shouldBeGreaterThan
import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe import io.kotest.matchers.shouldNotBe
@ -467,4 +468,52 @@ main {
}""" }"""
compileText(Cx16Target(), false, src, writeAssembly = true) shouldNotBe null compileText(Cx16Target(), false, src, writeAssembly = true) shouldNotBe null
} }
test("missing rts in asmsub") {
val src="""
main {
sub start() {
test()
test2()
}
asmsub test() {
%asm {{
nop
nop
}}
}
inline asmsub test2() {
%asm {{
nop
nop
}}
}
}"""
val errors = ErrorReporterForTests()
compileText(C64Target(), false, src, writeAssembly = true, errors = errors) shouldBe null
errors.errors.size shouldBe 1
errors.errors[0] shouldContain "asmsub seems to never return"
}
test("missing rts in asmsub suppressed") {
val src="""
main {
sub start() {
test()
}
asmsub test() {
%asm {{
nop
nop
; !notreached!
}}
}
}"""
compileText(C64Target(), false, src, writeAssembly = true) shouldNotBe null
}
}) })

View File

@ -40,6 +40,7 @@ internal fun compileFile(
outputDir = outputDir, outputDir = outputDir,
errors = errors ?: ErrorReporterForTests(), errors = errors ?: ErrorReporterForTests(),
splitWordArrays = false, splitWordArrays = false,
addMissingRts = false,
breakpointCpuInstruction = null, breakpointCpuInstruction = null,
printAst1 = false, printAst1 = false,
printAst2 = false, printAst2 = false,

View File

@ -182,6 +182,12 @@ One or more .p8 module files
interpret certain instructions differently and produce unexpected opcodes (like LDA X getting interpret certain instructions differently and produce unexpected opcodes (like LDA X getting
turned into TXA, or not, depending on the symbol 'x' being defined in your own assembly code or not) turned into TXA, or not, depending on the symbol 'x' being defined in your own assembly code or not)
``-addmissingrts``
Enables old compiler behavior that silently adds RTS to asmsubs that don't have one.
This was done to fix asmsubs so they return properly to the caller instead of crashing the program.
However the new compiler behavior is to not silently modify the code anymore and instead give an error message
that tells you how to fix the problem. This option may go away in future version.
``-quietasm`` ``-quietasm``
Don't print assembler output results. Don't print assembler output results.

View File

@ -1,6 +1,8 @@
TODO TODO
==== ====
- check benchmark score vs previous version
Improve register load order in subroutine call args assignments: Improve register load order in subroutine call args assignments:
in certain situations, the "wrong" order of evaluation of function call arguments is done which results in certain situations, the "wrong" order of evaluation of function call arguments is done which results
in overwriting registers that already got their value, which requires a lot of stack juggling (especially on plain 6502 cpu!) in overwriting registers that already got their value, which requires a lot of stack juggling (especially on plain 6502 cpu!)
@ -11,7 +13,6 @@ Future Things and Ideas
^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^
- 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 - 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
- Can we support signed % (remainder) somehow? - Can we support signed % (remainder) somehow?
- Don't add "random" rts to %asm blocks but instead give a warning about it? (but this breaks existing behavior that others already depend on... command line switch? block directive?)
- IR: implement missing operators in AssignmentGen (array shifts etc) - IR: implement missing operators in AssignmentGen (array shifts etc)
- instead of copy-pasting inline asmsubs, make them into a 64tass macro and use that instead. - instead of copy-pasting inline asmsubs, make them into a 64tass macro and use that instead.
that will allow them to be reused from custom user written assembly code as well. that will allow them to be reused from custom user written assembly code as well.

View File

@ -71,7 +71,7 @@ interrupts {
; no other irqs in this example. ; no other irqs in this example.
} }
asmsub wait() { inline asmsub wait() {
%asm {{ %asm {{
wai wai
}} }}

View File

@ -161,7 +161,7 @@ interrupts {
bool aflow bool aflow
asmsub wait() { inline asmsub wait() {
%asm {{ %asm {{
wai wai
}} }}
@ -285,6 +285,7 @@ _lp2 lda $ffff,y
inc _lp2+2 inc _lp2+2
dex dex
bne _loop bne _loop
; !notreached!
}} }}
; original prog8 code: ; original prog8 code:
; uword @requirezp ptr = main.start.buffer ; uword @requirezp ptr = main.start.buffer

View File

@ -327,7 +327,7 @@ interrupts {
bool aflow bool aflow
bool vsync bool vsync
asmsub wait() { inline asmsub wait() {
%asm {{ %asm {{
wai wai
}} }}

View File

@ -4,46 +4,21 @@
main { main {
sub start() { sub start() {
str @alignword @shared name1 = "abc123456789" derp()
str @alignpage @shared name2 = "def123456789" derp2()
str @alignword @shared @nozp name3 = "ghi123456789" }
str @alignword @shared @nozp name4 = "jkl123456789"
ubyte[9] @alignword @shared array1
ubyte[9] @alignword @shared array2
ubyte[9] @alignpage @shared array3
ubyte[9] @alignword @shared array4
ubyte[9] @alignword @shared array5
ubyte[9] @alignword @shared array6
ubyte[9] @alignword @shared array7
ubyte[9] @alignword @shared array8
ubyte[] @alignword @shared array9 = [1,2,3]
ubyte[] @alignword @shared array10 = [1,2,3]
ubyte[] @alignpage @shared array11 = [1,2,3]
ubyte[] @alignpage @shared array12 = [1,2,3]
ubyte[] @alignword @shared array13 = [1,2,3]
ubyte[] @alignword @shared array14 = [1,2,3]
ubyte[] @alignpage @shared array15 = [1,2,3]
ubyte[] @alignpage @shared array16 = [1,2,3]
uword[3] @alignword @split @shared array17
uword[] @alignword @split @shared array18 = [1111,2222,3333]
array9[2]++ asmsub derp() {
array10[2]++ %asm {{
array11[2]++ nop
array12[2]++ nop
array13[2]++ }}
array14[2]++ }
array15[2]++
array16[2]++
array17[2]++
array18[2]++
name1[2]++
name2[2]++
name3[2]++
name4[2]++
%align 2 inline asmsub derp2() {
%align 3 %asm {{
%align 1000 nop
nop
}}
} }
} }