This commit is contained in:
Irmen de Jong 2023-02-19 03:07:55 +01:00
parent f7dd388954
commit 9ca6860ffa
11 changed files with 145 additions and 45 deletions

View File

@ -65,7 +65,7 @@ internal class ProgramAndVarsGen(
asmgen.out("; assembler syntax is for the 64tasm cross-assembler") asmgen.out("; assembler syntax is for the 64tasm cross-assembler")
asmgen.out("; output options: output=${options.output} launcher=${options.launcher} zp=${options.zeropage}") asmgen.out("; output options: output=${options.output} launcher=${options.launcher} zp=${options.zeropage}")
asmgen.out("") asmgen.out("")
asmgen.out(".cpu '$cpu'\n.enc 'none'\n") asmgen.out(".cpu '$cpu'\n.enc 'none'")
// the global prog8 variables needed // the global prog8 variables needed
val zp = zeropage val zp = zeropage
@ -88,7 +88,7 @@ internal class ProgramAndVarsGen(
when(options.output) { when(options.output) {
OutputType.RAW -> { OutputType.RAW -> {
asmgen.out("; ---- raw assembler program ----") asmgen.out("; ---- raw assembler program ----")
asmgen.out("* = ${options.loadAddress.toHex()}\n") asmgen.out("* = ${options.loadAddress.toHex()}")
} }
OutputType.PRG -> { OutputType.PRG -> {
when(options.launcher) { when(options.launcher) {
@ -102,14 +102,14 @@ internal class ProgramAndVarsGen(
asmgen.out(" .word (+), $year") asmgen.out(" .word (+), $year")
asmgen.out(" .null $9e, format(' %d ', prog8_entrypoint), $3a, $8f, ' prog8'") asmgen.out(" .null $9e, format(' %d ', prog8_entrypoint), $3a, $8f, ' prog8'")
asmgen.out("+\t.word 0") asmgen.out("+\t.word 0")
asmgen.out("prog8_entrypoint\t; assembly code starts here\n") asmgen.out("prog8_entrypoint\t; assembly code starts here")
if(!options.noSysInit) if(!options.noSysInit)
asmgen.out(" jsr ${compTarget.name}.init_system") asmgen.out(" jsr ${compTarget.name}.init_system")
asmgen.out(" jsr ${compTarget.name}.init_system_phase2") asmgen.out(" jsr ${compTarget.name}.init_system_phase2")
} }
CbmPrgLauncherType.NONE -> { CbmPrgLauncherType.NONE -> {
asmgen.out("; ---- program without basic sys call ----") asmgen.out("; ---- program without basic sys call ----")
asmgen.out("* = ${options.loadAddress.toHex()}\n") asmgen.out("* = ${options.loadAddress.toHex()}")
if(!options.noSysInit) if(!options.noSysInit)
asmgen.out(" jsr ${compTarget.name}.init_system") asmgen.out(" jsr ${compTarget.name}.init_system")
asmgen.out(" jsr ${compTarget.name}.init_system_phase2") asmgen.out(" jsr ${compTarget.name}.init_system_phase2")
@ -118,7 +118,7 @@ internal class ProgramAndVarsGen(
} }
OutputType.XEX -> { OutputType.XEX -> {
asmgen.out("; ---- atari xex program ----") asmgen.out("; ---- atari xex program ----")
asmgen.out("* = ${options.loadAddress.toHex()}\n") asmgen.out("* = ${options.loadAddress.toHex()}")
if(!options.noSysInit) if(!options.noSysInit)
asmgen.out(" jsr ${compTarget.name}.init_system") asmgen.out(" jsr ${compTarget.name}.init_system")
asmgen.out(" jsr ${compTarget.name}.init_system_phase2") asmgen.out(" jsr ${compTarget.name}.init_system_phase2")
@ -189,7 +189,7 @@ internal class ProgramAndVarsGen(
asmgen.out("\t.align $100") asmgen.out("\t.align $100")
} }
asmgen.out("${block.name}\t" + (if(block.forceOutput) ".block\n" else ".proc\n")) asmgen.out("${block.name}\t" + (if(block.forceOutput) ".block" else ".proc"))
asmgen.outputSourceLine(block) asmgen.outputSourceLine(block)
createBlockVariables(block) createBlockVariables(block)
@ -204,13 +204,13 @@ internal class ProgramAndVarsGen(
if(!options.dontReinitGlobals) { if(!options.dontReinitGlobals) {
// generate subroutine to initialize block-level (global) variables // generate subroutine to initialize block-level (global) variables
if (initializers.isNotEmpty()) { if (initializers.isNotEmpty()) {
asmgen.out("prog8_init_vars\t.block\n") asmgen.out("prog8_init_vars\t.block")
initializers.forEach { assign -> asmgen.translate(assign) } initializers.forEach { assign -> asmgen.translate(assign) }
asmgen.out(" rts\n .bend") asmgen.out(" rts\n .bend")
} }
} }
asmgen.out(if(block.forceOutput) "\n\t.bend\n" else "\n\t.pend\n") asmgen.out(if(block.forceOutput) "\n\t.bend" else "\n\t.pend")
} }
private fun getVars(scope: StNode): Map<String, StNode> = private fun getVars(scope: StNode): Map<String, StNode> =
@ -266,7 +266,7 @@ internal class ProgramAndVarsGen(
// asmsub with most likely just an inline asm in it // asmsub with most likely just an inline asm in it
asmgen.out("${sub.name}\t$asmStartScope") asmgen.out("${sub.name}\t$asmStartScope")
sub.children.forEach { asmgen.translate(it) } sub.children.forEach { asmgen.translate(it) }
asmgen.out(" $asmEndScope\n") asmgen.out(" $asmEndScope")
} }
@ -358,7 +358,7 @@ internal class ProgramAndVarsGen(
.map { it.value as StStaticVariable } .map { it.value as StStaticVariable }
nonZpVariables2asm(variables) nonZpVariables2asm(variables)
asmgen.out(" $asmEndScope\n") asmgen.out(" $asmEndScope")
} }
private fun entrypointInitialization() { private fun entrypointInitialization() {

View File

@ -19,10 +19,10 @@ class TestLaunchEmu: FunSpec({
<ASMSYMBOLS> <ASMSYMBOLS>
</ASMSYMBOLS> </ASMSYMBOLS>
<BSS> <VARIABLESNOINIT>
</BSS> </VARIABLESNOINIT>
<VARIABLES> <VARIABLESWITHINIT>
</VARIABLES> </VARIABLESWITHINIT>
<MEMORYMAPPEDVARIABLES> <MEMORYMAPPEDVARIABLES>
</MEMORYMAPPEDVARIABLES> </MEMORYMAPPEDVARIABLES>

View File

@ -14,7 +14,7 @@ import prog8.code.core.Position
import prog8.code.target.C64Target import prog8.code.target.C64Target
import prog8tests.helpers.compileText import prog8tests.helpers.compileText
class TestVarious: FunSpec({ class TestVariousCompilerAst: FunSpec({
test("symbol names in inline assembly blocks") { test("symbol names in inline assembly blocks") {
val names1 = InlineAssembly(""" val names1 = InlineAssembly("""

View File

@ -13,7 +13,7 @@ import prog8.code.core.DataType
import prog8.code.target.C64Target import prog8.code.target.C64Target
import prog8tests.helpers.compileText import prog8tests.helpers.compileText
class TestVarious: FunSpec({ class TestVariousCodeGen: FunSpec({
test("bool to byte cast in expression is correct") { test("bool to byte cast in expression is correct") {
val text=""" val text="""
main { main {

View File

@ -3,10 +3,17 @@ TODO
For next minor release For next minor release
^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^
- fix hasInitValue() and isBssVar()
- BSS.
64tass can put variables into a section with .section BSS <variable> .send BSS
and then putting .dsection BSS where it should output the BSS
Define vars in BSS with .fill rather than .byte otherwise they STILL take up space!
- BSS in 6502 codegen: create BSS section in output assembly code and put StStaticVariables in there with bss=true. - BSS in 6502 codegen: create BSS section in output assembly code and put StStaticVariables in there with bss=true.
Don't forget to add init code to zero out everything that was put in bss. If array in bss->only zero ONCE if possible. Don't forget to add init code to zero out everything that was put in bss. If array in bss->only zero ONCE if possible.
Note that bss can still contain variables that have @zp tag and those are already dealt with differently Note that 'bss' can still be true for variables that were moved into zeropage, so have to check that!
- BSS: subroutine parameters don't have to be set to 0. - BSS subroutine parameters don't have to be set to 0.
- when putting BSS in specific memory block ($a000-$bfff, $c000-$cfff) add a .cerror check for overflow!
... ...

View File

@ -1,13 +1,107 @@
%import floats
%import textio
%option no_sysinit
%zeropage basicsafe %zeropage basicsafe
main { main {
&ubyte[40] topline = $0400 uword b_wordvar
ubyte b_bb =123
float b_fl
ubyte[10] b_emptyarray
ubyte[10] b_filledarray = [1,2,3,4,5,6,7,8,9,10]
float[3] b_floatarray
uword[3] b_wordarray
sub start() { sub start() {
topline[0] = 'a' uword wordvar
topline[1] = 'b' float fl
topline[2] = 'd' ubyte bb =123
topline[39] = '@' ubyte[10] emptyarray
ubyte[10] filledarray = [1,2,3,4,5,6,7,8,9,10]
float[3] floatarray
uword[3] wordarray
txt.print("**subroutine scope**\n")
txt.print("uninit wordvar=")
txt.print_uw(wordvar)
txt.print("\nuninit float=")
floats.print_f(fl)
txt.print("\ninit bb=")
txt.print_ub(bb)
txt.print("\nuninit emptyarray[2]=")
txt.print_ub(emptyarray[2])
txt.print("\nuninit wordarray[2]=")
txt.print_uw(wordarray[2])
txt.print("\nuninit floatarray[2]=")
floats.print_f(floatarray[2])
txt.print("\ninit filledarray[2]=")
txt.print_ub(filledarray[2])
txt.print("\n**block scope**\n")
txt.print("uninit b_wordvar=")
txt.print_uw(b_wordvar)
txt.print("\nuninit b_float=")
floats.print_f(b_fl)
txt.print("\ninit b_bb=")
txt.print_ub(b_bb)
txt.print("\nuninit b_emptyarray[2]=")
txt.print_ub(b_emptyarray[2])
txt.print("\nuninit b_wordarray[2]=")
txt.print_uw(b_wordarray[2])
txt.print("\nuninit b_floatarray[2]=")
floats.print_f(b_floatarray[2])
txt.print("\ninit b_filledarray[2]=")
txt.print_ub(b_filledarray[2])
txt.print("\n\nadding 42 to all values.\n")
wordvar += 42
bb += 42
fl += 42.42
floatarray[2] += 42.42
wordarray[2] += 42
emptyarray[2] += 42
filledarray[2] += 42
b_wordvar += 42
b_bb += 42
b_fl += 42.42
b_floatarray[2] += 42.42
b_wordarray[2] += 42
b_emptyarray[2] += 42
b_filledarray[2] += 42
txt.print("\n**subroutine scope**\n")
txt.print("uninit wordvar=")
txt.print_uw(wordvar)
txt.print("\nuninit float=")
floats.print_f(fl)
txt.print("\ninit bb=")
txt.print_ub(bb)
txt.print("\nuninit emptyarray[2]=")
txt.print_ub(emptyarray[2])
txt.print("\nuninit wordarray[2]=")
txt.print_uw(wordarray[2])
txt.print("\nuninit floatarray[2]=")
floats.print_f(floatarray[2])
txt.print("\ninit filledarray[2]=")
txt.print_ub(filledarray[2])
txt.print("\n**block scope**\n")
txt.print("uninit b_wordvar=")
txt.print_uw(b_wordvar)
txt.print("\nuninit b_float=")
floats.print_f(b_fl)
txt.print("\ninit b_bb=")
txt.print_ub(b_bb)
txt.print("\nuninit b_emptyarray[2]=")
txt.print_ub(b_emptyarray[2])
txt.print("\nuninit b_wordarray[2]=")
txt.print_uw(b_wordarray[2])
txt.print("\nuninit b_floatarray[2]=")
floats.print_f(b_floatarray[2])
txt.print("\ninit b_filledarray[2]=")
txt.print_ub(b_filledarray[2])
txt.print("\n\nrun again to see effect of re-init.\n")
} }
} }

View File

@ -45,7 +45,7 @@ class IRFileReader {
val programName = start.attributes.asSequence().single { it.name.localPart == "NAME" }.value val programName = start.attributes.asSequence().single { it.name.localPart == "NAME" }.value
val options = parseOptions(reader) val options = parseOptions(reader)
val asmsymbols = parseAsmSymbols(reader) val asmsymbols = parseAsmSymbols(reader)
val bss = parseBss(reader) val varsWithoutInit = parseVarsWithoutInit(reader)
val variables = parseVariables(reader, options.dontReinitGlobals) val variables = parseVariables(reader, options.dontReinitGlobals)
val memorymapped = parseMemMapped(reader) val memorymapped = parseMemMapped(reader)
val slabs = parseSlabs(reader) val slabs = parseSlabs(reader)
@ -54,7 +54,7 @@ class IRFileReader {
val st = IRSymbolTable(null) val st = IRSymbolTable(null)
asmsymbols.forEach { (name, value) -> st.addAsmSymbol(name, value)} asmsymbols.forEach { (name, value) -> st.addAsmSymbol(name, value)}
bss.forEach { st.add(it) } varsWithoutInit.forEach { st.add(it) }
variables.forEach { st.add(it) } variables.forEach { st.add(it) }
memorymapped.forEach { st.add(it) } memorymapped.forEach { st.add(it) }
slabs.forEach { st.add(it) } slabs.forEach { st.add(it) }
@ -150,10 +150,10 @@ class IRFileReader {
} }
} }
private fun parseBss(reader: XMLEventReader): List<StStaticVariable> { private fun parseVarsWithoutInit(reader: XMLEventReader): List<StStaticVariable> {
skipText(reader) skipText(reader)
val start = reader.nextEvent().asStartElement() val start = reader.nextEvent().asStartElement()
require(start.name.localPart=="BSS") { "missing BSS" } require(start.name.localPart=="VARIABLESNOINIT") { "missing VARIABLESNOINIT" }
val text = readText(reader).trim() val text = readText(reader).trim()
require(reader.nextEvent().isEndElement) require(reader.nextEvent().isEndElement)
@ -161,10 +161,10 @@ class IRFileReader {
emptyList() emptyList()
else { else {
val varPattern = Regex("(.+?)(\\[.+?\\])? (.+) (zp=(.+))?") val varPattern = Regex("(.+?)(\\[.+?\\])? (.+) (zp=(.+))?")
val bssVariables = mutableListOf<StStaticVariable>() val variables = mutableListOf<StStaticVariable>()
text.lineSequence().forEach { line -> text.lineSequence().forEach { line ->
// example: uword main.start.qq2 zp=DONTCARE // example: uword main.start.qq2 zp=DONTCARE
val match = varPattern.matchEntire(line) ?: throw IRParseException("invalid BSS $line") val match = varPattern.matchEntire(line) ?: throw IRParseException("invalid VARIABLESNOINIT $line")
val (type, arrayspec, name, _, zpwish) = match.destructured val (type, arrayspec, name, _, zpwish) = match.destructured
if('.' !in name) if('.' !in name)
throw IRParseException("unscoped varname: $name") throw IRParseException("unscoped varname: $name")
@ -173,16 +173,16 @@ class IRFileReader {
val zp = if(zpwish.isBlank()) ZeropageWish.DONTCARE else ZeropageWish.valueOf(zpwish) val zp = if(zpwish.isBlank()) ZeropageWish.DONTCARE else ZeropageWish.valueOf(zpwish)
val dummyNode = PtVariable(name, dt, zp, null, null, Position.DUMMY) val dummyNode = PtVariable(name, dt, zp, null, null, Position.DUMMY)
val newVar = StStaticVariable(name, dt, true, null, null, null, arraysize, zp, dummyNode) val newVar = StStaticVariable(name, dt, true, null, null, null, arraysize, zp, dummyNode)
bssVariables.add(newVar) variables.add(newVar)
} }
return bssVariables return variables
} }
} }
private fun parseVariables(reader: XMLEventReader, dontReinitGlobals: Boolean): List<StStaticVariable> { private fun parseVariables(reader: XMLEventReader, dontReinitGlobals: Boolean): List<StStaticVariable> {
skipText(reader) skipText(reader)
val start = reader.nextEvent().asStartElement() val start = reader.nextEvent().asStartElement()
require(start.name.localPart=="VARIABLES") { "missing VARIABLES" } require(start.name.localPart=="VARIABLESWITHINIT") { "missing VARIABLESWITHINIT" }
val text = readText(reader).trim() val text = readText(reader).trim()
require(reader.nextEvent().isEndElement) require(reader.nextEvent().isEndElement)

View File

@ -139,14 +139,13 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
private fun writeVariables() { private fun writeVariables() {
out.write("\n<BSS>\n") out.write("\n<VARIABLESNOINIT>\n")
for (variable in irProgram.st.allVariables().filter { it.bss }) { for (variable in irProgram.st.allVariables().filter { it.bss }) {
val typeStr = getTypeString(variable) val typeStr = getTypeString(variable)
// bss variables have no initialization value
out.write("$typeStr ${variable.name} zp=${variable.zpwish}\n") out.write("$typeStr ${variable.name} zp=${variable.zpwish}\n")
} }
out.write("</BSS>\n<VARIABLES>\n") out.write("</VARIABLESNOINIT>\n<VARIABLESWITHINIT>\n")
for (variable in irProgram.st.allVariables().filter { !it.bss }) { for (variable in irProgram.st.allVariables().filter { !it.bss }) {
val typeStr = getTypeString(variable) val typeStr = getTypeString(variable)
val value: String = when(variable.dt) { val value: String = when(variable.dt) {
@ -179,7 +178,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
} }
out.write("$typeStr ${variable.name}=$value zp=${variable.zpwish}\n") out.write("$typeStr ${variable.name}=$value zp=${variable.zpwish}\n")
} }
out.write("</VARIABLES>\n") out.write("</VARIABLESWITHINIT>\n")
out.write("\n<MEMORYMAPPEDVARIABLES>\n") out.write("\n<MEMORYMAPPEDVARIABLES>\n")
for (variable in irProgram.st.allMemMappedVariables()) { for (variable in irProgram.st.allMemMappedVariables()) {

View File

@ -55,12 +55,12 @@ evalStackBaseAddress=null
<ASMSYMBOLS> <ASMSYMBOLS>
</ASMSYMBOLS> </ASMSYMBOLS>
<BSS> <VARIABLESNOINIT>
uword sys.bssvar zp=DONTCARE uword sys.bssvar zp=DONTCARE
</BSS> </VARIABLESNOINIT>
<VARIABLES> <VARIABLESWITHINIT>
uword sys.wait.jiffies=10 zp=DONTCARE uword sys.wait.jiffies=10 zp=DONTCARE
</VARIABLES> </VARIABLESWITHINIT>
<MEMORYMAPPEDVARIABLES> <MEMORYMAPPEDVARIABLES>
@uword cx16.r0=65282 @uword cx16.r0=65282

View File

@ -176,7 +176,7 @@ class VmProgramLoader {
program.st.allVariables().forEach { variable -> program.st.allVariables().forEach { variable ->
var addr = allocations.allocations.getValue(variable.name) var addr = allocations.allocations.getValue(variable.name)
// zero out BSS variables. // zero out uninitialized variables.
if(variable.bss) { if(variable.bss) {
if(variable.dt in ArrayDatatypes) { if(variable.dt in ArrayDatatypes) {
repeat(variable.length!!) { repeat(variable.length!!) {

View File

@ -115,10 +115,10 @@ class TestVm: FunSpec( {
<ASMSYMBOLS> <ASMSYMBOLS>
</ASMSYMBOLS> </ASMSYMBOLS>
<BSS> <VARIABLESNOINIT>
</BSS> </VARIABLESNOINIT>
<VARIABLES> <VARIABLESWITHINIT>
</VARIABLES> </VARIABLESWITHINIT>
<MEMORYMAPPEDVARIABLES> <MEMORYMAPPEDVARIABLES>
</MEMORYMAPPEDVARIABLES> </MEMORYMAPPEDVARIABLES>