mirror of
https://github.com/irmen/prog8.git
synced 2025-11-03 19:16:13 +00:00
Merge branch 'master' into structs
# Conflicts: # codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt # compiler/test/TestSymbolTable.kt # docs/source/todo.rst # examples/test.p8 # intermediate/src/prog8/intermediate/IRFileReader.kt # intermediate/src/prog8/intermediate/IRFileWriter.kt # intermediate/src/prog8/intermediate/IRSymbolTable.kt # simpleAst/src/prog8/code/SymbolTable.kt # simpleAst/src/prog8/code/SymbolTableMaker.kt # virtualmachine/src/prog8/vm/VmProgramLoader.kt
This commit is contained in:
@@ -186,7 +186,7 @@ private fun PtVariable.prefix(parent: PtNode, st: SymbolTable): PtVariable {
|
||||
else -> throw AssemblyError("weird array value element $elt")
|
||||
}
|
||||
}
|
||||
val result = PtVariable(name, type, zeropage, align, newValue, arraySize, position)
|
||||
val result = PtVariable(name, type, zeropage, align, dirty, newValue, arraySize, position)
|
||||
result.parent = parent
|
||||
result
|
||||
}
|
||||
|
||||
@@ -220,7 +220,8 @@ internal class ProgramAndVarsGen(
|
||||
}
|
||||
|
||||
private fun tempVars() {
|
||||
asmgen.out("; expression temp vars\n .section BSS")
|
||||
// these can be in the no clear section because they'll always get assigned a new value
|
||||
asmgen.out("; expression temp vars\n .section BSS_NOCLEAR")
|
||||
for((dt, count) in asmgen.tempVarsCounters) {
|
||||
if(count>0) {
|
||||
for(num in 1..count) {
|
||||
@@ -238,7 +239,7 @@ internal class ProgramAndVarsGen(
|
||||
}
|
||||
}
|
||||
}
|
||||
asmgen.out(" .send BSS")
|
||||
asmgen.out(" .send BSS_NOCLEAR")
|
||||
}
|
||||
|
||||
private fun footer() {
|
||||
@@ -494,7 +495,7 @@ internal class ProgramAndVarsGen(
|
||||
sub.children.forEach { asmgen.translate(it) }
|
||||
|
||||
asmgen.out("; variables")
|
||||
asmgen.out(" .section BSS")
|
||||
asmgen.out(" .section BSS_NOCLEAR") // these extra vars are initialized before use
|
||||
val asmGenInfo = asmgen.subroutineExtra(sub)
|
||||
for((dt, name, addr) in asmGenInfo.extraVars) {
|
||||
if(addr!=null)
|
||||
@@ -510,7 +511,7 @@ internal class ProgramAndVarsGen(
|
||||
asmgen.out("$subroutineFloatEvalResultVar1 .fill ${options.compTarget.FLOAT_MEM_SIZE}")
|
||||
if(asmGenInfo.usedFloatEvalResultVar2)
|
||||
asmgen.out("$subroutineFloatEvalResultVar2 .fill ${options.compTarget.FLOAT_MEM_SIZE}")
|
||||
asmgen.out(" .send BSS")
|
||||
asmgen.out(" .send BSS_NOCLEAR")
|
||||
|
||||
// normal statically allocated variables
|
||||
val variables = varsInSubroutine
|
||||
@@ -638,15 +639,27 @@ internal class ProgramAndVarsGen(
|
||||
val (varsNoInit, varsWithInit) = variables.partition { it.uninitialized }
|
||||
if(varsNoInit.isNotEmpty()) {
|
||||
asmgen.out("; non-zeropage variables")
|
||||
asmgen.out(" .section BSS")
|
||||
val (notAligned, aligned) = varsNoInit.partition { it.align==0u }
|
||||
notAligned.sortedWith(compareBy<StStaticVariable> { it.name }.thenBy { it.dt.base }).forEach {
|
||||
uninitializedVariable2asm(it)
|
||||
val (dirty, clean) = varsNoInit.partition { it.dirty }
|
||||
|
||||
fun generate(section: String, variables: List<StStaticVariable>) {
|
||||
asmgen.out(" .section $section")
|
||||
val (notAligned, aligned) = variables.partition { it.align == 0u }
|
||||
notAligned.sortedWith(compareBy<StStaticVariable> { it.name }.thenBy { it.dt.base }).forEach {
|
||||
uninitializedVariable2asm(it)
|
||||
}
|
||||
aligned.sortedWith(compareBy<StStaticVariable> { it.align }.thenBy { it.name }.thenBy { it.dt.base })
|
||||
.forEach { uninitializedVariable2asm(it) }
|
||||
asmgen.out(" .send $section")
|
||||
}
|
||||
aligned.sortedWith(compareBy<StStaticVariable> { it.align }.thenBy { it.name }.thenBy { it.dt.base }).forEach {
|
||||
uninitializedVariable2asm(it)
|
||||
|
||||
if(clean.isNotEmpty()) {
|
||||
// clean vars end up in BSS so they're at least cleared to 0 at startup
|
||||
generate("BSS", clean)
|
||||
}
|
||||
if(dirty.isNotEmpty()) {
|
||||
// dirty vars end up in BSS_NOCLEAR so they're left at whatever value is in there on startup
|
||||
generate("BSS_NOCLEAR", dirty)
|
||||
}
|
||||
asmgen.out(" .send BSS")
|
||||
}
|
||||
|
||||
if(varsWithInit.isNotEmpty()) {
|
||||
|
||||
@@ -58,6 +58,7 @@ class TestCodegen: FunSpec({
|
||||
DataType.UBYTE,
|
||||
ZeropageWish.DONTCARE,
|
||||
0u,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
Position.DUMMY
|
||||
@@ -67,6 +68,7 @@ class TestCodegen: FunSpec({
|
||||
DataType.arrayFor(BaseDataType.UBYTE),
|
||||
ZeropageWish.DONTCARE,
|
||||
0u,
|
||||
false,
|
||||
null,
|
||||
3u,
|
||||
Position.DUMMY
|
||||
@@ -76,6 +78,7 @@ class TestCodegen: FunSpec({
|
||||
DataType.arrayFor(BaseDataType.UBYTE),
|
||||
ZeropageWish.DONTCARE,
|
||||
0u,
|
||||
false,
|
||||
null,
|
||||
3u,
|
||||
Position.DUMMY
|
||||
@@ -85,6 +88,7 @@ class TestCodegen: FunSpec({
|
||||
DataType.WORD,
|
||||
ZeropageWish.DONTCARE,
|
||||
0u,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
Position.DUMMY
|
||||
|
||||
@@ -63,7 +63,8 @@ private fun convert(variable: StStaticVariable): IRStStaticVariable {
|
||||
variable.initializationArrayValue?.map { convertArrayElt(it) },
|
||||
variable.length,
|
||||
variable.zpwish,
|
||||
variable.align)
|
||||
variable.align,
|
||||
variable.dirty)
|
||||
} else {
|
||||
fun fixupAddressOfInArray(array: List<StArrayElement>?): List<IRStArrayElement>? {
|
||||
if(array==null)
|
||||
@@ -87,7 +88,8 @@ private fun convert(variable: StStaticVariable): IRStStaticVariable {
|
||||
fixupAddressOfInArray(variable.initializationArrayValue),
|
||||
variable.length,
|
||||
variable.zpwish,
|
||||
variable.align
|
||||
variable.align,
|
||||
variable.dirty
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@ class TestVmCodeGen: FunSpec({
|
||||
DataType.UBYTE,
|
||||
ZeropageWish.DONTCARE,
|
||||
0u,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
Position.DUMMY
|
||||
@@ -61,6 +62,7 @@ class TestVmCodeGen: FunSpec({
|
||||
DataType.arrayFor(BaseDataType.UBYTE),
|
||||
ZeropageWish.DONTCARE,
|
||||
0u,
|
||||
false,
|
||||
null,
|
||||
3u,
|
||||
Position.DUMMY
|
||||
@@ -70,6 +72,7 @@ class TestVmCodeGen: FunSpec({
|
||||
DataType.arrayFor(BaseDataType.UBYTE),
|
||||
ZeropageWish.DONTCARE,
|
||||
0u,
|
||||
false,
|
||||
null,
|
||||
3u,
|
||||
Position.DUMMY
|
||||
@@ -79,6 +82,7 @@ class TestVmCodeGen: FunSpec({
|
||||
DataType.WORD,
|
||||
ZeropageWish.DONTCARE,
|
||||
0u,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
Position.DUMMY
|
||||
@@ -167,6 +171,7 @@ class TestVmCodeGen: FunSpec({
|
||||
DataType.FLOAT,
|
||||
ZeropageWish.DONTCARE,
|
||||
0u,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
Position.DUMMY
|
||||
@@ -238,6 +243,7 @@ class TestVmCodeGen: FunSpec({
|
||||
DataType.FLOAT,
|
||||
ZeropageWish.DONTCARE,
|
||||
0u,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
Position.DUMMY
|
||||
@@ -305,6 +311,7 @@ class TestVmCodeGen: FunSpec({
|
||||
DataType.FLOAT,
|
||||
ZeropageWish.DONTCARE,
|
||||
0u,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
Position.DUMMY
|
||||
@@ -360,6 +367,7 @@ class TestVmCodeGen: FunSpec({
|
||||
DataType.BYTE,
|
||||
ZeropageWish.DONTCARE,
|
||||
0u,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
Position.DUMMY
|
||||
@@ -431,6 +439,7 @@ class TestVmCodeGen: FunSpec({
|
||||
DataType.BYTE,
|
||||
ZeropageWish.DONTCARE,
|
||||
0u,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
Position.DUMMY
|
||||
@@ -498,6 +507,7 @@ class TestVmCodeGen: FunSpec({
|
||||
DataType.BYTE,
|
||||
ZeropageWish.DONTCARE,
|
||||
0u,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
Position.DUMMY
|
||||
|
||||
@@ -646,6 +646,7 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro
|
||||
srcVar.datatype,
|
||||
srcVar.zeropage,
|
||||
srcVar.alignment,
|
||||
srcVar.dirty,
|
||||
value,
|
||||
srcVar.arraysize?.constIndex()?.toUInt(),
|
||||
srcVar.position
|
||||
|
||||
@@ -82,6 +82,7 @@ private fun setDeferMasks(program: PtProgram, errors: IErrorReporter): Map<PtSub
|
||||
DataType.UBYTE,
|
||||
ZeropageWish.NOT_IN_ZEROPAGE,
|
||||
0u,
|
||||
true,
|
||||
null,
|
||||
null,
|
||||
sub.position
|
||||
|
||||
@@ -21,6 +21,8 @@ class TestLaunchEmu: FunSpec({
|
||||
|
||||
<VARIABLESNOINIT>
|
||||
</VARIABLESNOINIT>
|
||||
<VARIABLESNOINITDIRTY>
|
||||
</VARIABLESNOINITDIRTY>
|
||||
<VARIABLESWITHINIT>
|
||||
</VARIABLESWITHINIT>
|
||||
<STRUCTINSTANCESNOINIT>
|
||||
|
||||
@@ -86,14 +86,14 @@ class TestSymbolTable: FunSpec({
|
||||
|
||||
test("static vars") {
|
||||
val node = PtIdentifier("dummy", DataType.UBYTE, Position.DUMMY)
|
||||
val stVar1 = StStaticVariable("initialized", DataType.UBYTE, null, null, null, ZeropageWish.DONTCARE, 0u, node)
|
||||
val stVar1 = StStaticVariable("initialized", DataType.UBYTE, null, null, null, ZeropageWish.DONTCARE, 0u, false,node)
|
||||
stVar1.setOnetimeInitNumeric(99.0)
|
||||
val stVar2 = StStaticVariable("uninitialized", DataType.UBYTE, null, null, null, ZeropageWish.DONTCARE, 0u, node)
|
||||
val stVar2 = StStaticVariable("uninitialized", DataType.UBYTE, null, null, null, ZeropageWish.DONTCARE, 0u, false, node)
|
||||
val arrayInitNonzero = listOf(StArrayElement(1.1, null, null), StArrayElement(2.2, null, null), StArrayElement(3.3, null, null))
|
||||
val arrayInitAllzero = listOf(StArrayElement(0.0, null, null), StArrayElement(0.0, null, null), StArrayElement(0.0, null, null))
|
||||
val stVar3 = StStaticVariable("initialized", DataType.arrayFor(BaseDataType.UWORD), null, arrayInitNonzero, 3u, ZeropageWish.DONTCARE, 0u, node)
|
||||
val stVar4 = StStaticVariable("initialized", DataType.arrayFor(BaseDataType.UWORD), null, arrayInitAllzero, 3u, ZeropageWish.DONTCARE, 0u, node)
|
||||
val stVar5 = StStaticVariable("uninitialized", DataType.arrayFor(BaseDataType.UWORD), null, null, 3u, ZeropageWish.DONTCARE, 0u, node)
|
||||
val stVar3 = StStaticVariable("initialized", DataType.arrayFor(BaseDataType.UWORD), null, arrayInitNonzero, 3u, ZeropageWish.DONTCARE, 0u, false, node)
|
||||
val stVar4 = StStaticVariable("initialized", DataType.arrayFor(BaseDataType.UWORD), null, arrayInitAllzero, 3u, ZeropageWish.DONTCARE, 0u, false, node)
|
||||
val stVar5 = StStaticVariable("uninitialized", DataType.arrayFor(BaseDataType.UWORD), null, null, 3u, ZeropageWish.DONTCARE, 0u, false, node)
|
||||
|
||||
stVar1.uninitialized shouldBe false
|
||||
stVar1.length shouldBe null
|
||||
@@ -125,6 +125,7 @@ private fun makeSt(): SymbolTable {
|
||||
DataType.BYTE,
|
||||
ZeropageWish.DONTCARE,
|
||||
0u,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
Position.DUMMY
|
||||
@@ -134,6 +135,7 @@ private fun makeSt(): SymbolTable {
|
||||
DataType.BYTE,
|
||||
ZeropageWish.DONTCARE,
|
||||
0u,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
Position.DUMMY
|
||||
@@ -143,6 +145,7 @@ private fun makeSt(): SymbolTable {
|
||||
DataType.FLOAT,
|
||||
ZeropageWish.DONTCARE,
|
||||
0u,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
Position.DUMMY
|
||||
@@ -152,6 +155,7 @@ private fun makeSt(): SymbolTable {
|
||||
DataType.UWORD,
|
||||
ZeropageWish.DONTCARE,
|
||||
0u,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
Position.DUMMY
|
||||
@@ -161,6 +165,7 @@ private fun makeSt(): SymbolTable {
|
||||
DataType.BYTE,
|
||||
ZeropageWish.DONTCARE,
|
||||
0u,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
Position.DUMMY
|
||||
@@ -170,6 +175,7 @@ private fun makeSt(): SymbolTable {
|
||||
DataType.BYTE,
|
||||
ZeropageWish.DONTCARE,
|
||||
0u,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
Position.DUMMY
|
||||
@@ -205,12 +211,12 @@ private fun makeSt(): SymbolTable {
|
||||
block1.add(sub12)
|
||||
block1.add(StConstant("c1", BaseDataType.UWORD, 12345.0, astConstant1))
|
||||
block1.add(StConstant("blockc", BaseDataType.UWORD, 999.0, astConstant2))
|
||||
sub11.add(StStaticVariable("v1", DataType.BYTE, null, null, null, ZeropageWish.DONTCARE, 0u, astSub1v1))
|
||||
sub11.add(StStaticVariable("v2", DataType.BYTE, null, null, null, ZeropageWish.DONTCARE, 0u, astSub1v2))
|
||||
sub11.add(StStaticVariable("v1", DataType.BYTE, null, null, null, ZeropageWish.DONTCARE, 0u, false, astSub1v1))
|
||||
sub11.add(StStaticVariable("v2", DataType.BYTE, null, null, null, ZeropageWish.DONTCARE, 0u, false, astSub1v2))
|
||||
sub11.add(StMemVar("v3", DataType.FLOAT, 12345u, null, astSub1v3))
|
||||
sub11.add(StMemorySlab("slab1", 200u, 64u, astSub1v4))
|
||||
sub12.add(StStaticVariable("v1", DataType.BYTE, null, null, null, ZeropageWish.DONTCARE, 0u, astSub2v1))
|
||||
sub12.add(StStaticVariable("v2", DataType.BYTE, null, null, null, ZeropageWish.DONTCARE, 0u, astSub2v2))
|
||||
sub12.add(StStaticVariable("v1", DataType.BYTE, null, null, null, ZeropageWish.DONTCARE, 0u, false, astSub2v1))
|
||||
sub12.add(StStaticVariable("v2", DataType.BYTE, null, null, null, ZeropageWish.DONTCARE, 0u, false, astSub2v2))
|
||||
val block2 = StNode("block2", StNodeType.BLOCK, astBlock2)
|
||||
val sub21 = StNode("sub1", StNodeType.SUBROUTINE, astSub21)
|
||||
val sub22 = StNode("sub2", StNodeType.SUBROUTINE, astSub22)
|
||||
|
||||
@@ -50,6 +50,10 @@ Various things:
|
||||
of routines to perform tile and sprite transformations and rotation, using
|
||||
the VeraFX hardware feature. Includes examples.
|
||||
|
||||
`C64 REU Banking <https://github.com/gillham/prog8reu>`_
|
||||
A Prog8 library module that provides Commander X16 style RAM banking on a C64 with an REU.
|
||||
This module provides cx16.rambank(), x16jsrfar() and extsub @bank functionality on a C64.
|
||||
|
||||
|
||||
.. image:: _static/curious.png
|
||||
:align: center
|
||||
|
||||
@@ -34,8 +34,8 @@ STRUCTS and TYPED POINTERS
|
||||
- DONE: pointer arrays are split-words only, enforce this (variable dt + initializer array dt)
|
||||
- DONE: make an error message for all pointer expressions (prefixed, binary) so we can start implementing the ones we need one by one.
|
||||
- DONE: start by making ptr.value++ work , and ptr.value = ptr.value+20, and ptr.value = cx16.r0L+20+ptr.value Likewise for subtraction. DON'T FORGET C POINTER SEMANTICS. Other operators are nonsensical for ptr arith
|
||||
- DONE: support @dirty on pointer vars -> uninitialized pointer placed in BSS_noclear segment
|
||||
- fix actual _msb/_lsb storage of the split-words pointer-arrays
|
||||
- support @dirty on pointer vars -> uninitialized pointer placed in BSS_noclear segment
|
||||
- pointer types in subroutine signatures (both normal and asm-subs)
|
||||
- support chaining pointer dereference on function calls that return a pointer. (type checking now fails on stuff like func().field and func().next.field)
|
||||
- are the ARRAY_POINTER and ARRAY_STRUCT data type enums realy needed? can't we just use ARRAY?
|
||||
@@ -119,6 +119,7 @@ Optimizations
|
||||
-------------
|
||||
|
||||
- Sorting module gnomesort_uw could be optimized more by fully rewriting it in asm? Shellshort seems consistently faster even if most of the words are already sorted.
|
||||
- can the for loop temp var be replaced by the same logic that createRepeatCounterVar() uses for repeat loops? Take care of nested for/repeat loops to not use the same var
|
||||
- Compare output of some Oscar64 samples to what prog8 does for the equivalent code (see https://github.com/drmortalwombat/OscarTutorials/tree/main and https://github.com/drmortalwombat/oscar64/tree/main/samples)
|
||||
- Optimize the IfExpression code generation to be more like regular if-else code. (both 6502 and IR) search for "TODO don't store condition as expression"
|
||||
- VariableAllocator: can we think of a smarter strategy for allocating variables into zeropage, rather than first-come-first-served?
|
||||
|
||||
382
examples/test.p8
382
examples/test.p8
@@ -4,9 +4,6 @@
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
; uword buf = memory("buffer", 2000, 0)
|
||||
; sys.memset(buf, 2000, 0)
|
||||
|
||||
; put 9 nodes into the buffer sequentially.
|
||||
; each of the first 3 nodes points to the 4th, 5th, 6th.
|
||||
; these in turn point to the 7th, 8th and 9th.
|
||||
@@ -40,196 +37,199 @@ main {
|
||||
|
||||
|
||||
; static initializer syntax:
|
||||
; ^^Node @shared node0 = Node() ; no initialization (will be in BSS and zeroed out at startup)
|
||||
; ^^Node @shared node1 = Node( false, 11, 0 )
|
||||
; ^^Node @shared node2 = Node( false, 22, 0 )
|
||||
; ^^Node @shared node3 = Node( true, 33, 0 )
|
||||
;
|
||||
; ; list of pointers: (W.I.P.):
|
||||
;; ^^Node[5] @shared nodes
|
||||
;; for nptr in nodes {
|
||||
;; txt.print_uw(nptr)
|
||||
;; txt.spc()
|
||||
;; }
|
||||
;; txt.nl()
|
||||
;
|
||||
; ; link up
|
||||
; node0.next = node1
|
||||
; node1.next = node2
|
||||
; node2.next = node3
|
||||
;
|
||||
; ^^Node nptr = node0
|
||||
; while nptr {
|
||||
; txt.print("node at ")
|
||||
^^Node @shared node0 = Node() ; no initialization (will be in BSS and zeroed out at startup)
|
||||
^^Node @shared node1 = Node( false, 11, 0 )
|
||||
^^Node @shared node2 = Node( false, 22, 0 )
|
||||
^^Node @shared node3 = Node( true, 33, 0 )
|
||||
|
||||
; list of pointers: (W.I.P.):
|
||||
; ^^Node[5] @shared nodes
|
||||
; for nptr in nodes {
|
||||
; txt.print_uw(nptr)
|
||||
; txt.print("\n flag=")
|
||||
; txt.print_bool(nptr.flag)
|
||||
; txt.print("\n value=")
|
||||
; txt.print_ub(nptr.value)
|
||||
; txt.nl()
|
||||
; nptr = nptr.next
|
||||
; }
|
||||
;
|
||||
; ^^Node n0,n1,n2,n3,n4,n5,n6,n7,n8
|
||||
;
|
||||
; n0 = buf + 0
|
||||
; n1 = buf + sizeof(Node)
|
||||
; n2 = buf + sizeof(Node)*2
|
||||
; n3 = buf + sizeof(Node)*3
|
||||
; n4 = buf + sizeof(Node)*4
|
||||
; n5 = buf + sizeof(Node)*5
|
||||
; n6 = buf + sizeof(Node)*6
|
||||
; n7 = buf + sizeof(Node)*7
|
||||
; n8 = buf + sizeof(Node)*8
|
||||
;
|
||||
; n0.next = n3
|
||||
; n1.next = n4
|
||||
; n2.next = n5
|
||||
; n3.next = n6
|
||||
; n4.next = n7
|
||||
; n5.next = n8
|
||||
;
|
||||
; n0.value = 'a'
|
||||
; n1.value = 'b'
|
||||
; n2.value = 'c'
|
||||
; n3.value = 'd'
|
||||
; n4.value = 'e'
|
||||
; n5.value = 'f'
|
||||
; n6.value = 'g'
|
||||
; n7.value = 'h'
|
||||
; n8.value = 'i'
|
||||
;
|
||||
; txt.print("struct size: ")
|
||||
; txt.print_uw(sizeof(Node))
|
||||
; txt.nl()
|
||||
;
|
||||
; txt.print("pointer values: ")
|
||||
; txt.print_uw(n0)
|
||||
; txt.spc()
|
||||
; txt.print_uw(n1)
|
||||
; txt.spc()
|
||||
; txt.print_uw(n2)
|
||||
; txt.spc()
|
||||
; txt.print_uw(n3)
|
||||
; txt.spc()
|
||||
; txt.print_uw(n4)
|
||||
; txt.spc()
|
||||
; txt.print_uw(n5)
|
||||
; txt.spc()
|
||||
; txt.print_uw(n6)
|
||||
; txt.spc()
|
||||
; txt.print_uw(n7)
|
||||
; txt.spc()
|
||||
; txt.print_uw(n8)
|
||||
; txt.nl()
|
||||
;
|
||||
; txt.print("field address: ")
|
||||
; txt.print_uw(&n0.value)
|
||||
; txt.spc()
|
||||
; txt.print_uw(&n1.value)
|
||||
; txt.spc()
|
||||
; txt.print_uw(&n2.value)
|
||||
; txt.nl()
|
||||
; txt.print_uw(&n6.value)
|
||||
; txt.spc()
|
||||
; txt.print_uw(&n7.value)
|
||||
; txt.spc()
|
||||
; txt.print_uw(&n8.value)
|
||||
; txt.nl()
|
||||
; txt.print_uw(&n0.next.next.value)
|
||||
; txt.spc()
|
||||
; txt.print_uw(&n1.next.next.value)
|
||||
; txt.spc()
|
||||
; txt.print_uw(&n2.next.next.value)
|
||||
; txt.nl()
|
||||
;
|
||||
; txt.print("node values: ")
|
||||
; txt.chrout(n0.value)
|
||||
; txt.chrout(n1.value)
|
||||
; txt.chrout(n2.value)
|
||||
; txt.chrout(n3.value)
|
||||
; txt.chrout(n4.value)
|
||||
; txt.chrout(n5.value)
|
||||
; txt.chrout(n6.value)
|
||||
; txt.chrout(n7.value)
|
||||
; txt.chrout(n8.value)
|
||||
; txt.nl()
|
||||
;
|
||||
; txt.print("linked values:\n")
|
||||
; txt.print("n0: ")
|
||||
; ^^Node ptr = n0
|
||||
; while ptr {
|
||||
; txt.chrout(ptr.value)
|
||||
; ptr = ptr.next
|
||||
; txt.spc()
|
||||
; }
|
||||
; txt.nl()
|
||||
; txt.print("n1: ")
|
||||
; ptr = n1
|
||||
; while ptr {
|
||||
; txt.chrout(ptr.value)
|
||||
; ptr = ptr.next
|
||||
; }
|
||||
; txt.nl()
|
||||
; txt.print("n2: ")
|
||||
; ptr = n2
|
||||
; while ptr {
|
||||
; txt.chrout(ptr.value)
|
||||
; ptr = ptr.next
|
||||
; }
|
||||
; txt.nl()
|
||||
;
|
||||
; txt.print("array syntax on nodes: ")
|
||||
; txt.chrout(n0[0].value)
|
||||
; txt.chrout(n0[1].value)
|
||||
; txt.chrout(n0[2].value)
|
||||
; txt.chrout(n0[3].value)
|
||||
; txt.chrout(n0[4].value)
|
||||
; txt.chrout(n0[5].value)
|
||||
; txt.chrout(n0[6].value)
|
||||
; txt.chrout(n0[7].value)
|
||||
; txt.chrout(n0[8].value)
|
||||
; txt.nl()
|
||||
;
|
||||
; txt.print("array syntax followed by dereference: ")
|
||||
; txt.chrout(n0[0].next.next.value)
|
||||
; txt.chrout(n0[1].next.next.value)
|
||||
; txt.chrout(n0[2].next.next.value)
|
||||
; txt.nl()
|
||||
;
|
||||
; txt.print("assigning to fields: ")
|
||||
; n0.value = 'q'
|
||||
; n1.value = 'w'
|
||||
; n2.value = 'e'
|
||||
; n0.next.next.value = 'x'
|
||||
; n1.next.next.value = 'y'
|
||||
; n2.next.next.value = 'z'
|
||||
; txt.chrout(n0.value)
|
||||
; txt.chrout(n1.value)
|
||||
; txt.chrout(n2.value)
|
||||
; txt.spc()
|
||||
; txt.chrout(n0.next.next.value)
|
||||
; txt.chrout(n1.next.next.value)
|
||||
; txt.chrout(n2.next.next.value)
|
||||
; txt.spc()
|
||||
; txt.chrout(n6.value)
|
||||
; txt.chrout(n7.value)
|
||||
; txt.chrout(n8.value)
|
||||
; txt.nl()
|
||||
;
|
||||
; txt.print("ptr to simple types: ")
|
||||
; word w_value = -9999
|
||||
; txt.print_w(w_value)
|
||||
; txt.spc()
|
||||
; ^^word w_ptr = &w_value
|
||||
; w_ptr^^ = 5555
|
||||
; txt.print_w(w_value)
|
||||
; txt.nl()
|
||||
;
|
||||
; word[] @nosplit warray = [1111,2222,3333,4444,5555,6666]
|
||||
; w_ptr = &warray
|
||||
; txt.print_w(w_ptr^^)
|
||||
; txt.spc()
|
||||
; txt.print_w(w_ptr[4]^^)
|
||||
; txt.nl()
|
||||
|
||||
; link up
|
||||
node0.next = node1
|
||||
node1.next = node2
|
||||
node2.next = node3
|
||||
|
||||
^^Node nptr = node0
|
||||
while nptr {
|
||||
txt.print("node at ")
|
||||
txt.print_uw(nptr)
|
||||
txt.print("\n flag=")
|
||||
txt.print_bool(nptr.flag)
|
||||
txt.print("\n value=")
|
||||
txt.print_ub(nptr.value)
|
||||
txt.nl()
|
||||
nptr = nptr.next
|
||||
}
|
||||
|
||||
^^Node n0,n1,n2,n3,n4,n5,n6,n7,n8
|
||||
|
||||
uword buf = memory("buffer", 2000, 0)
|
||||
sys.memset(buf, 2000, 0)
|
||||
|
||||
n0 = buf + 0
|
||||
n1 = buf + sizeof(Node)
|
||||
n2 = buf + sizeof(Node)*2
|
||||
n3 = buf + sizeof(Node)*3
|
||||
n4 = buf + sizeof(Node)*4
|
||||
n5 = buf + sizeof(Node)*5
|
||||
n6 = buf + sizeof(Node)*6
|
||||
n7 = buf + sizeof(Node)*7
|
||||
n8 = buf + sizeof(Node)*8
|
||||
|
||||
n0.next = n3
|
||||
n1.next = n4
|
||||
n2.next = n5
|
||||
n3.next = n6
|
||||
n4.next = n7
|
||||
n5.next = n8
|
||||
|
||||
n0.value = 'a'
|
||||
n1.value = 'b'
|
||||
n2.value = 'c'
|
||||
n3.value = 'd'
|
||||
n4.value = 'e'
|
||||
n5.value = 'f'
|
||||
n6.value = 'g'
|
||||
n7.value = 'h'
|
||||
n8.value = 'i'
|
||||
|
||||
txt.print("struct size: ")
|
||||
txt.print_uw(sizeof(Node))
|
||||
txt.nl()
|
||||
|
||||
txt.print("pointer values: ")
|
||||
txt.print_uw(n0)
|
||||
txt.spc()
|
||||
txt.print_uw(n1)
|
||||
txt.spc()
|
||||
txt.print_uw(n2)
|
||||
txt.spc()
|
||||
txt.print_uw(n3)
|
||||
txt.spc()
|
||||
txt.print_uw(n4)
|
||||
txt.spc()
|
||||
txt.print_uw(n5)
|
||||
txt.spc()
|
||||
txt.print_uw(n6)
|
||||
txt.spc()
|
||||
txt.print_uw(n7)
|
||||
txt.spc()
|
||||
txt.print_uw(n8)
|
||||
txt.nl()
|
||||
|
||||
txt.print("field address: ")
|
||||
txt.print_uw(&n0.value)
|
||||
txt.spc()
|
||||
txt.print_uw(&n1.value)
|
||||
txt.spc()
|
||||
txt.print_uw(&n2.value)
|
||||
txt.nl()
|
||||
txt.print_uw(&n6.value)
|
||||
txt.spc()
|
||||
txt.print_uw(&n7.value)
|
||||
txt.spc()
|
||||
txt.print_uw(&n8.value)
|
||||
txt.nl()
|
||||
txt.print_uw(&n0.next.next.value)
|
||||
txt.spc()
|
||||
txt.print_uw(&n1.next.next.value)
|
||||
txt.spc()
|
||||
txt.print_uw(&n2.next.next.value)
|
||||
txt.nl()
|
||||
|
||||
txt.print("node values: ")
|
||||
txt.chrout(n0.value)
|
||||
txt.chrout(n1.value)
|
||||
txt.chrout(n2.value)
|
||||
txt.chrout(n3.value)
|
||||
txt.chrout(n4.value)
|
||||
txt.chrout(n5.value)
|
||||
txt.chrout(n6.value)
|
||||
txt.chrout(n7.value)
|
||||
txt.chrout(n8.value)
|
||||
txt.nl()
|
||||
|
||||
txt.print("linked values:\n")
|
||||
txt.print("n0: ")
|
||||
ptr = n0
|
||||
while ptr {
|
||||
txt.chrout(ptr.value)
|
||||
ptr = ptr.next
|
||||
}
|
||||
txt.nl()
|
||||
txt.print("n1: ")
|
||||
ptr = n1
|
||||
while ptr {
|
||||
txt.chrout(ptr.value)
|
||||
ptr = ptr.next
|
||||
}
|
||||
txt.nl()
|
||||
txt.print("n2: ")
|
||||
ptr = n2
|
||||
while ptr {
|
||||
txt.chrout(ptr.value)
|
||||
ptr = ptr.next
|
||||
}
|
||||
txt.nl()
|
||||
|
||||
txt.print("array syntax on nodes: ")
|
||||
txt.chrout(n0[0].value)
|
||||
txt.chrout(n0[1].value)
|
||||
txt.chrout(n0[2].value)
|
||||
txt.chrout(n0[3].value)
|
||||
txt.chrout(n0[4].value)
|
||||
txt.chrout(n0[5].value)
|
||||
txt.chrout(n0[6].value)
|
||||
txt.chrout(n0[7].value)
|
||||
txt.chrout(n0[8].value)
|
||||
txt.nl()
|
||||
|
||||
txt.print("array syntax followed by dereference: ")
|
||||
txt.chrout(n0[0].next.next.value)
|
||||
txt.chrout(n0[1].next.next.value)
|
||||
txt.chrout(n0[2].next.next.value)
|
||||
txt.nl()
|
||||
|
||||
txt.print("assigning to fields: ")
|
||||
n0.value = 'q'
|
||||
n1.value = 'w'
|
||||
n2.value = 'e'
|
||||
n0.next.next.value = 'x'
|
||||
n1.next.next.value = 'y'
|
||||
n2.next.next.value = 'z'
|
||||
txt.chrout(n0.value)
|
||||
txt.chrout(n1.value)
|
||||
txt.chrout(n2.value)
|
||||
txt.spc()
|
||||
txt.chrout(n0.next.next.value)
|
||||
txt.chrout(n1.next.next.value)
|
||||
txt.chrout(n2.next.next.value)
|
||||
txt.spc()
|
||||
txt.chrout(n6.value)
|
||||
txt.chrout(n7.value)
|
||||
txt.chrout(n8.value)
|
||||
txt.nl()
|
||||
|
||||
txt.print("ptr to simple types: ")
|
||||
word w_value = -9999
|
||||
txt.print_w(w_value)
|
||||
txt.spc()
|
||||
^^word w_ptr = &w_value
|
||||
w_ptr^^ = 5555
|
||||
txt.print_w(w_value)
|
||||
txt.nl()
|
||||
|
||||
word[] @nosplit warray = [1111,2222,3333,4444,5555,6666]
|
||||
w_ptr = &warray
|
||||
txt.print_w(w_ptr^^)
|
||||
txt.spc()
|
||||
txt.print_w(w_ptr[4]^^)
|
||||
txt.nl()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,8 @@ class IRFileReader {
|
||||
val programName = start.attributes.asSequence().single { it.name.localPart == "NAME" }.value
|
||||
val options = parseOptions(reader)
|
||||
val asmsymbols = parseAsmSymbols(reader)
|
||||
val varsWithoutInit = parseVarsWithoutInit(reader)
|
||||
val varsWithoutInitClean = parseVarsWithoutInit("VARIABLESNOINIT", false, reader)
|
||||
val varsWithoutInitDirty = parseVarsWithoutInit("VARIABLESNOINITDIRTY", true, reader)
|
||||
val variables = parseVariables(reader)
|
||||
val structsWithoutInit = parseStructInstancesNoInit(reader)
|
||||
val structs = parseStructInstances(reader)
|
||||
@@ -60,7 +61,8 @@ class IRFileReader {
|
||||
|
||||
val st = IRSymbolTable()
|
||||
asmsymbols.forEach { (name, value) -> st.addAsmSymbol(name, value)}
|
||||
varsWithoutInit.forEach { st.add(it) }
|
||||
varsWithoutInitClean.forEach { st.add(it) }
|
||||
varsWithoutInitDirty.forEach { st.add(it) }
|
||||
variables.forEach { st.add(it) }
|
||||
constants.forEach { st.add(it) }
|
||||
memorymapped.forEach { st.add(it) }
|
||||
@@ -157,10 +159,10 @@ class IRFileReader {
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseVarsWithoutInit(reader: XMLEventReader): List<IRStStaticVariable> {
|
||||
private fun parseVarsWithoutInit(segmentname: String, dirty: Boolean, reader: XMLEventReader): List<IRStStaticVariable> {
|
||||
skipText(reader)
|
||||
val start = reader.nextEvent().asStartElement()
|
||||
require(start.name.localPart=="VARIABLESNOINIT") { "missing VARIABLESNOINIT" }
|
||||
require(start.name.localPart==segmentname) { "missing $segmentname" }
|
||||
val text = readText(reader).trim()
|
||||
require(reader.nextEvent().isEndElement)
|
||||
|
||||
@@ -171,7 +173,7 @@ class IRFileReader {
|
||||
val variables = mutableListOf<IRStStaticVariable>()
|
||||
text.lineSequence().forEach { line ->
|
||||
// example: uword main.start.qq2 zp=DONTCARE
|
||||
val match = varPattern.matchEntire(line) ?: throw IRParseException("invalid VARIABLESNOINIT $line")
|
||||
val match = varPattern.matchEntire(line) ?: throw IRParseException("invalid $segmentname $line")
|
||||
val type = match.groups["type"]!!.value
|
||||
val arrayspec = match.groups["arrayspec"]?.value ?: ""
|
||||
val name = match.groups["name"]!!.value
|
||||
@@ -185,7 +187,7 @@ class IRFileReader {
|
||||
val zp = if(zpwish.isBlank()) ZeropageWish.DONTCARE else ZeropageWish.valueOf(zpwish)
|
||||
// val isSplit = if(split.isBlank()) false else split.toBoolean()
|
||||
val align = if(alignment.isBlank()) 0u else alignment.toUInt()
|
||||
val newVar = IRStStaticVariable(name, dt, null, null, null, arraysize, zp, align)
|
||||
val newVar = IRStStaticVariable(name, dt, null, null, null, arraysize, zp, align, dirty)
|
||||
variables.add(newVar)
|
||||
}
|
||||
return variables
|
||||
@@ -250,6 +252,7 @@ class IRFileReader {
|
||||
val zp = if(zpwish.isBlank()) ZeropageWish.DONTCARE else ZeropageWish.valueOf(zpwish)
|
||||
if(split.isBlank()) false else split.toBoolean()
|
||||
val align = if(alignment.isBlank()) 0u else alignment.toUInt()
|
||||
val dirty = false // these variables have initialization values.
|
||||
var initNumeric: Double? = null
|
||||
var initArray: IRStArray? = null
|
||||
when {
|
||||
@@ -274,7 +277,7 @@ class IRFileReader {
|
||||
if(arraysize!=null && initArray!=null && initArray.all { it.number==0.0 }) {
|
||||
initArray=null // arrays with just zeros can be left uninitialized
|
||||
}
|
||||
val stVar = IRStStaticVariable(name, dt, initNumeric, null, initArray, arraysize, zp, align)
|
||||
val stVar = IRStStaticVariable(name, dt, initNumeric, null, initArray, arraysize, zp, align, dirty)
|
||||
variables.add(stVar)
|
||||
}
|
||||
return variables
|
||||
|
||||
@@ -330,19 +330,25 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
||||
}
|
||||
}
|
||||
|
||||
fun writeNoInitVars(segmentname: String, variables: List<IRStStaticVariable>) {
|
||||
xml.writeStartElement(segmentname)
|
||||
xml.writeCharacters("\n")
|
||||
val (noinitNotAligned, noinitAligned) = variables.partition { it.align==0u || it.align==1u }
|
||||
for (variable in noinitNotAligned) {
|
||||
writeNoInitVar(variable)
|
||||
}
|
||||
for (variable in noinitAligned.sortedBy { it.align }) {
|
||||
writeNoInitVar(variable)
|
||||
}
|
||||
xml.writeEndElement()
|
||||
xml.writeCharacters("\n")
|
||||
}
|
||||
|
||||
val (variablesNoInit, variablesWithInit) = irProgram.st.allVariables().partition { it.uninitialized }
|
||||
|
||||
xml.writeStartElement("VARIABLESNOINIT")
|
||||
xml.writeCharacters("\n")
|
||||
val (noinitNotAligned, noinitAligned) = variablesNoInit.partition { it.align==0u || it.align==1u }
|
||||
for (variable in noinitNotAligned) {
|
||||
writeNoInitVar(variable)
|
||||
}
|
||||
for (variable in noinitAligned.sortedBy { it.align }) {
|
||||
writeNoInitVar(variable)
|
||||
}
|
||||
xml.writeEndElement()
|
||||
xml.writeCharacters("\n")
|
||||
val (dirtyvars, cleanvars) = variablesNoInit.partition { it.dirty }
|
||||
writeNoInitVars("VARIABLESNOINIT", cleanvars)
|
||||
writeNoInitVars("VARIABLESNOINITDIRTY", dirtyvars)
|
||||
|
||||
xml.writeStartElement("VARIABLESWITHINIT")
|
||||
xml.writeCharacters("\n")
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package prog8.intermediate
|
||||
|
||||
import prog8.code.INTERNED_STRINGS_MODULENAME
|
||||
import prog8.code.core.BaseDataType
|
||||
import prog8.code.core.DataType
|
||||
import prog8.code.core.Encoding
|
||||
import prog8.code.core.ZeropageWish
|
||||
import prog8.code.core.BaseDataType
|
||||
|
||||
|
||||
// In the Intermediate Representation, all nesting has been removed.
|
||||
@@ -101,7 +101,8 @@ class IRStStaticVariable(name: String,
|
||||
val onetimeInitializationArrayValue: IRStArray?,
|
||||
val length: UInt?, // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte
|
||||
val zpwish: ZeropageWish, // used in the variable allocator
|
||||
val align: UInt
|
||||
val align: UInt,
|
||||
val dirty: Boolean
|
||||
) : IRStNode(name, IRStNodeType.STATICVAR) {
|
||||
init {
|
||||
if(align > 0u) {
|
||||
|
||||
@@ -55,6 +55,8 @@ loadAddress=$0000
|
||||
<VARIABLESNOINIT>
|
||||
uword sys.bssvar zp=DONTCARE align=0
|
||||
</VARIABLESNOINIT>
|
||||
<VARIABLESNOINITDIRTY>
|
||||
</VARIABLESNOINITDIRTY>
|
||||
<VARIABLESWITHINIT>
|
||||
uword sys.wait.jiffies=10 zp=DONTCARE align=0
|
||||
ubyte[3] sys.emptystring=0,0,0 zp=DONTCARE align=0
|
||||
|
||||
@@ -215,6 +215,7 @@ class StStaticVariable(name: String,
|
||||
val length: UInt?, // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte
|
||||
val zpwish: ZeropageWish, // used in the variable allocator
|
||||
val align: UInt,
|
||||
val dirty: Boolean,
|
||||
astNode: PtNode?) : StNode(name, StNodeType.STATICVAR, astNode) {
|
||||
|
||||
var initializationNumericValue: Double? = null
|
||||
|
||||
@@ -106,7 +106,7 @@ class SymbolTableMaker(private val program: PtProgram, private val options: Comp
|
||||
// if(node.type in SplitWordArrayTypes) {
|
||||
// ... split array also add _lsb and _msb to symboltable?
|
||||
// }
|
||||
val stVar = StStaticVariable(node.name, node.type, initialString, initialArray, numElements, node.zeropage, node.align, node)
|
||||
val stVar = StStaticVariable(node.name, node.type, initialString, initialArray, numElements, node.zeropage, node.align, node.dirty,node)
|
||||
if(initialNumeric!=null)
|
||||
stVar.setOnetimeInitNumeric(initialNumeric)
|
||||
stVar
|
||||
|
||||
@@ -198,6 +198,7 @@ class PtVariable(
|
||||
override val type: DataType,
|
||||
val zeropage: ZeropageWish,
|
||||
val align: UInt,
|
||||
val dirty: Boolean,
|
||||
val value: PtExpression?,
|
||||
val arraySize: UInt?,
|
||||
position: Position
|
||||
@@ -215,6 +216,8 @@ class PtVariable(
|
||||
// The IR codegen however is different it has a special section <VARIABLESWITHINIT> for all variables
|
||||
// that have a non-zero initialization value, regardless of the datatype. It removes the initialization
|
||||
// assignment and puts the value back into the variable (but only in the symboltable).
|
||||
|
||||
require(!dirty) { "dirty var cannot have init value" }
|
||||
}
|
||||
|
||||
value?.let {it.parent=this}
|
||||
|
||||
@@ -196,10 +196,10 @@ class VmProgramLoader {
|
||||
program.st.allVariables().forEach { variable ->
|
||||
var addr = allocations.allocations.getValue(variable.name)
|
||||
|
||||
// zero out uninitialized ('bss') variables.
|
||||
if(variable.uninitialized) {
|
||||
// zero out uninitialized non-dirty ('bss') variables.
|
||||
if(variable.uninitialized && !variable.dirty) {
|
||||
val dt = variable.dt
|
||||
if(dt.isArray) {
|
||||
if(variable.dt.isArray) {
|
||||
repeat(variable.length!!.toInt()) {
|
||||
when {
|
||||
dt.isPointerArray -> {
|
||||
|
||||
@@ -103,6 +103,8 @@ class TestVm: FunSpec( {
|
||||
|
||||
<VARIABLESNOINIT>
|
||||
</VARIABLESNOINIT>
|
||||
<VARIABLESNOINITDIRTY>
|
||||
</VARIABLESNOINITDIRTY>
|
||||
<VARIABLESWITHINIT>
|
||||
</VARIABLESWITHINIT>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user