fix various IR file and symboltable issues

This commit is contained in:
Irmen de Jong 2023-03-06 21:42:08 +01:00
parent 8acd94fc89
commit fd07ae5225
15 changed files with 595 additions and 160 deletions

View File

@ -133,7 +133,7 @@ open class StNode(val name: String,
}
private val scopedNameList: List<String> by lazy {
if(type== StNodeType.GLOBAL)
if(type==StNodeType.GLOBAL)
emptyList()
else
parent.scopedNameList + name
@ -142,7 +142,7 @@ open class StNode(val name: String,
private fun lookup(scopedName: List<String>): StNode? {
// a scoped name refers to a name in another namespace, and always stars from the root.
var node = this
while(node.type!= StNodeType.GLOBAL)
while(node.type!=StNodeType.GLOBAL)
node = node.parent
for(name in scopedName) {
@ -201,6 +201,11 @@ class StMemVar(name: String,
val length: Int?, // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte
astNode: PtNode) :
StNode(name, StNodeType.MEMVAR, astNode) {
init{
if(dt in ArrayDatatypes || dt == DataType.STR)
require(length!=null) { "memory mapped array or string must have known length" }
}
}
class StMemorySlab(

View File

@ -26,11 +26,11 @@ class SymbolTableMaker(private val program: PtProgram, private val options: Comp
PtMemMapped("P8ZP_SCRATCH_REG", DataType.UBYTE, options.compTarget.machine.zeropage.SCRATCH_REG, null, Position.DUMMY),
PtMemMapped("P8ZP_SCRATCH_W1", DataType.UWORD, options.compTarget.machine.zeropage.SCRATCH_W1, null, Position.DUMMY),
PtMemMapped("P8ZP_SCRATCH_W2", DataType.UWORD, options.compTarget.machine.zeropage.SCRATCH_W2, null, Position.DUMMY),
PtMemMapped("P8ESTACK_LO", DataType.ARRAY_UB, options.compTarget.machine.ESTACK_LO, 256u, Position.DUMMY),
PtMemMapped("P8ESTACK_HI", DataType.ARRAY_UB, options.compTarget.machine.ESTACK_HI, 256u, Position.DUMMY)
PtMemMapped("P8ESTACK_LO", DataType.ARRAY_UB, options.compTarget.machine.ESTACK_LO, 128u, Position.DUMMY),
PtMemMapped("P8ESTACK_HI", DataType.ARRAY_UB, options.compTarget.machine.ESTACK_HI, 128u, Position.DUMMY)
).forEach {
it.parent = program
st.add(StMemVar(it.name, it.type, it.address, null, it))
st.add(StMemVar(it.name, it.type, it.address, it.arraySize?.toInt(), it))
}
}

View File

@ -265,7 +265,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
val addressReg = codeGen.registers.nextFree()
result += exprGen.translateExpression(call.args[0], addressReg, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.STOREZI, IRDataType.WORD, reg2 = addressReg)
it += IRInstruction(Opcode.STOREZI, IRDataType.WORD, reg1 = addressReg)
}
}
} else {
@ -300,7 +300,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
val addressReg = codeGen.registers.nextFree()
result += exprGen.translateExpression(call.args[0], addressReg, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.STOREZI, IRDataType.BYTE, reg2 = addressReg)
it += IRInstruction(Opcode.STOREZI, IRDataType.BYTE, reg1 = addressReg)
}
}
} else {

View File

@ -16,6 +16,9 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
require(codeGen.registers.peekNext() > resultRegister || resultRegister >= SyscallRegisterBase) {
"no more registers for expression ${expr.position}"
}
require((expr.type!=DataType.FLOAT && resultRegister>=0) || (expr.type==DataType.FLOAT && resultFpRegister>=0)) {
"mismatched result register for expression datatype ${expr.type} ${expr.position}"
}
return when (expr) {
is PtMachineRegister -> {

View File

@ -358,6 +358,12 @@ class IRCodeGen(
}
private fun labelFirstChunk(chunks: IRCodeChunks, label: String): IRCodeChunks {
if(chunks.isEmpty()) {
return listOf(
IRCodeChunk(label, null)
)
}
require(chunks.isNotEmpty() && label.isNotBlank())
val first = chunks[0]
if(first.label!=null) {
@ -883,16 +889,25 @@ class IRCodeGen(
}
private fun translate(ifElse: PtIfElse): IRCodeChunks {
if(ifElse.condition.operator !in ComparisonOperators)
val condition = ifElse.condition
if(condition.operator !in ComparisonOperators)
throw AssemblyError("if condition should only be a binary comparison expression")
val signed = ifElse.condition.left.type in SignedDatatypes
val irDt = irType(ifElse.condition.left.type)
val signed = condition.left.type in SignedDatatypes
val irDtLeft = irType(condition.left.type)
val goto = ifElse.ifScope.children.firstOrNull() as? PtJump
if(goto!=null && ifElse.elseScope.children.isEmpty()) {
// special case the form: if <condition> goto <place>
val result = mutableListOf<IRCodeChunkBase>()
return when {
goto!=null && ifElse.elseScope.children.isEmpty() -> translateIfFollowedByJustGoto(ifElse, goto, irDtLeft, signed)
constValue(condition.right) == 0.0 -> translateIfElseZeroComparison(ifElse, irDtLeft, signed)
else -> translateIfElseNonZeroComparison(ifElse, irDtLeft, signed)
}
}
private fun translateIfFollowedByJustGoto(ifElse: PtIfElse, goto: PtJump, irDtLeft: IRDataType, signed: Boolean): MutableList<IRCodeChunkBase> {
val result = mutableListOf<IRCodeChunkBase>()
if(irDtLeft==IRDataType.FLOAT) {
TODO("float comparison followed by goto")
} else {
val leftRegNum = registers.nextFree()
val rightRegNum = registers.nextFree()
result += expressionEval.translateExpression(ifElse.condition.left, leftRegNum, -1)
@ -900,7 +915,7 @@ class IRCodeGen(
val opcode: Opcode
val firstReg: Int
val secondReg: Int
when(ifElse.condition.operator) {
when (ifElse.condition.operator) {
"==" -> {
opcode = Opcode.BEQ
firstReg = leftRegNum
@ -913,48 +928,93 @@ class IRCodeGen(
}
"<" -> {
// swapped '>'
opcode = if(signed) Opcode.BGTS else Opcode.BGT
opcode = if (signed) Opcode.BGTS else Opcode.BGT
firstReg = rightRegNum
secondReg = leftRegNum
}
">" -> {
opcode = if(signed) Opcode.BGTS else Opcode.BGT
opcode = if (signed) Opcode.BGTS else Opcode.BGT
firstReg = leftRegNum
secondReg = rightRegNum
}
"<=" -> {
// swapped '>='
opcode = if(signed) Opcode.BGES else Opcode.BGE
opcode = if (signed) Opcode.BGES else Opcode.BGE
firstReg = rightRegNum
secondReg = leftRegNum
}
">=" -> {
opcode = if(signed) Opcode.BGES else Opcode.BGE
opcode = if (signed) Opcode.BGES else Opcode.BGE
firstReg = leftRegNum
secondReg = rightRegNum
}
else -> throw AssemblyError("invalid comparison operator")
}
if(goto.address!=null)
addInstr(result, IRInstruction(opcode, irDt, reg1=firstReg, reg2=secondReg, value = goto.address?.toInt()), null)
else if(goto.generatedLabel!=null)
addInstr(result, IRInstruction(opcode, irDt, reg1=firstReg, reg2=secondReg, labelSymbol = goto.generatedLabel), null)
if (goto.address != null)
addInstr(result, IRInstruction(opcode, irDtLeft, reg1 = firstReg, reg2 = secondReg, value = goto.address?.toInt()), null)
else if (goto.generatedLabel != null)
addInstr(result, IRInstruction(opcode, irDtLeft, reg1 = firstReg, reg2 = secondReg, labelSymbol = goto.generatedLabel), null)
else
addInstr(result, IRInstruction(opcode, irDt, reg1=firstReg, reg2=secondReg, labelSymbol = goto.identifier!!.name), null)
return result
addInstr(result, IRInstruction(opcode, irDtLeft, reg1 = firstReg, reg2 = secondReg, labelSymbol = goto.identifier!!.name), null)
}
return result
}
fun translateNonZeroComparison(): IRCodeChunks {
val result = mutableListOf<IRCodeChunkBase>()
private fun translateIfElseZeroComparison(ifElse: PtIfElse, irDtLeft: IRDataType, signed: Boolean): IRCodeChunks {
if(irDtLeft==IRDataType.FLOAT) {
TODO("float zero compare via fcomp instruction")
} else {
// integer comparisons
fun equalOrNotEqualZero(elseBranch: Opcode): IRCodeChunks {
val result = mutableListOf<IRCodeChunkBase>()
val leftReg = registers.nextFree()
result += expressionEval.translateExpression(ifElse.condition.left, leftReg, -1)
if(ifElse.elseScope.children.isNotEmpty()) {
// if and else parts
val elseLabel = createLabelName()
val afterIfLabel = createLabelName()
addInstr(result, IRInstruction(elseBranch, irDtLeft, reg1=leftReg, labelSymbol = elseLabel), null)
result += translateNode(ifElse.ifScope)
addInstr(result, IRInstruction(Opcode.JUMP, labelSymbol = afterIfLabel), null)
result += labelFirstChunk(translateNode(ifElse.elseScope), elseLabel)
result += IRCodeChunk(afterIfLabel, null)
} else {
// only if part
val afterIfLabel = createLabelName()
addInstr(result, IRInstruction(elseBranch, irDtLeft, reg1=leftReg, labelSymbol = afterIfLabel), null)
result += translateNode(ifElse.ifScope)
result += IRCodeChunk(afterIfLabel, null)
}
return result
}
return when (ifElse.condition.operator) {
"==" -> equalOrNotEqualZero(Opcode.BNZ)
"!=" -> equalOrNotEqualZero(Opcode.BZ)
"<" -> if (signed) equalOrNotEqualZero(Opcode.BGEZS) else throw AssemblyError("unsigned < 0 shouldn't occur in codegen")
">" -> if (signed) equalOrNotEqualZero(Opcode.BLEZS) else throw AssemblyError("unsigned > 0 shouldn't occur in codegen")
"<=" -> if (signed) equalOrNotEqualZero(Opcode.BGZS) else throw AssemblyError("unsigned <= 0 shouldn't occur in codegen")
">=" -> if (signed) equalOrNotEqualZero(Opcode.BLZS) else throw AssemblyError("unsigned >= 0 shouldn't occur in codegen")
else -> throw AssemblyError("weird operator")
}
}
}
private fun translateIfElseNonZeroComparison(ifElse: PtIfElse, irDtLeft: IRDataType, signed: Boolean): IRCodeChunks {
val result = mutableListOf<IRCodeChunkBase>()
val elseBranchOpcode: Opcode
val elseBranchFirstReg: Int
val elseBranchSecondReg: Int
if(irDtLeft==IRDataType.FLOAT) {
TODO("float non-zero compare via fcomp instruction")
} else {
// integer comparisons
val leftRegNum = registers.nextFree()
val rightRegNum = registers.nextFree()
result += expressionEval.translateExpression(ifElse.condition.left, leftRegNum, -1)
result += expressionEval.translateExpression(ifElse.condition.right, rightRegNum, -1)
val elseBranchOpcode: Opcode
val elseBranchFirstReg: Int
val elseBranchSecondReg: Int
when(ifElse.condition.operator) {
when (ifElse.condition.operator) {
"==" -> {
elseBranchOpcode = Opcode.BNE
elseBranchFirstReg = leftRegNum
@ -967,36 +1027,37 @@ class IRCodeGen(
}
"<" -> {
// else part when left >= right
elseBranchOpcode = if(signed) Opcode.BGES else Opcode.BGE
elseBranchOpcode = if (signed) Opcode.BGES else Opcode.BGE
elseBranchFirstReg = leftRegNum
elseBranchSecondReg = rightRegNum
}
">" -> {
// else part when left <= right --> right >= left
elseBranchOpcode = if(signed) Opcode.BGES else Opcode.BGE
elseBranchOpcode = if (signed) Opcode.BGES else Opcode.BGE
elseBranchFirstReg = rightRegNum
elseBranchSecondReg = leftRegNum
}
"<=" -> {
// else part when left > right
elseBranchOpcode = if(signed) Opcode.BGTS else Opcode.BGT
elseBranchOpcode = if (signed) Opcode.BGTS else Opcode.BGT
elseBranchFirstReg = leftRegNum
elseBranchSecondReg = rightRegNum
}
">=" -> {
// else part when left < right --> right > left
elseBranchOpcode = if(signed) Opcode.BGTS else Opcode.BGT
elseBranchOpcode = if (signed) Opcode.BGTS else Opcode.BGT
elseBranchFirstReg = rightRegNum
elseBranchSecondReg = leftRegNum
}
else -> throw AssemblyError("invalid comparison operator")
}
if(ifElse.elseScope.children.isNotEmpty()) {
// if and else parts
val elseLabel = createLabelName()
val afterIfLabel = createLabelName()
addInstr(result, IRInstruction(elseBranchOpcode, irDt, reg1=elseBranchFirstReg, reg2=elseBranchSecondReg, labelSymbol = elseLabel), null)
addInstr(result, IRInstruction(elseBranchOpcode, irDtLeft,
reg1=elseBranchFirstReg, reg2=elseBranchSecondReg,
labelSymbol = elseLabel), null)
result += translateNode(ifElse.ifScope)
addInstr(result, IRInstruction(Opcode.JUMP, labelSymbol = afterIfLabel), null)
result += labelFirstChunk(translateNode(ifElse.elseScope), elseLabel)
@ -1004,52 +1065,15 @@ class IRCodeGen(
} else {
// only if part
val afterIfLabel = createLabelName()
addInstr(result, IRInstruction(elseBranchOpcode, irDt, reg1=elseBranchFirstReg, reg2=elseBranchSecondReg, labelSymbol = afterIfLabel), null)
addInstr(result, IRInstruction(elseBranchOpcode, irDtLeft,
reg1=elseBranchFirstReg, reg2=elseBranchSecondReg,
labelSymbol = afterIfLabel), null)
result += translateNode(ifElse.ifScope)
result += IRCodeChunk(afterIfLabel, null)
}
return result
}
fun translateZeroComparison(): IRCodeChunks {
fun equalOrNotEqualZero(elseBranch: Opcode): IRCodeChunks {
val result = mutableListOf<IRCodeChunkBase>()
val leftReg = registers.nextFree()
result += expressionEval.translateExpression(ifElse.condition.left, leftReg, -1)
if(ifElse.elseScope.children.isNotEmpty()) {
// if and else parts
val elseLabel = createLabelName()
val afterIfLabel = createLabelName()
addInstr(result, IRInstruction(elseBranch, irDt, reg1=leftReg, labelSymbol = elseLabel), null)
result += translateNode(ifElse.ifScope)
addInstr(result, IRInstruction(Opcode.JUMP, labelSymbol = afterIfLabel), null)
result += labelFirstChunk(translateNode(ifElse.elseScope), elseLabel)
result += IRCodeChunk(afterIfLabel, null)
} else {
// only if part
val afterIfLabel = createLabelName()
addInstr(result, IRInstruction(elseBranch, irDt, reg1=leftReg, labelSymbol = afterIfLabel), null)
result += translateNode(ifElse.ifScope)
result += IRCodeChunk(afterIfLabel, null)
}
return result
}
return when (ifElse.condition.operator) {
"==" -> equalOrNotEqualZero(Opcode.BNZ)
"!=" -> equalOrNotEqualZero(Opcode.BZ)
"<" -> if(signed) equalOrNotEqualZero(Opcode.BGEZS) else throw AssemblyError("unsigned < 0 shouldn't occur in codegen")
">" -> if(signed) equalOrNotEqualZero(Opcode.BLEZS) else throw AssemblyError("unsigned > 0 shouldn't occur in codegen")
"<=" -> if(signed) equalOrNotEqualZero(Opcode.BGZS) else throw AssemblyError("unsigned <= 0 shouldn't occur in codegen")
">=" -> if(signed) equalOrNotEqualZero(Opcode.BLZS) else throw AssemblyError("unsigned >= 0 shouldn't occur in codegen")
else -> throw AssemblyError("weird operator")
}
}
return if(constValue(ifElse.condition.right)==0.0)
translateZeroComparison()
else
translateNonZeroComparison()
return result
}
private fun translate(postIncrDecr: PtPostIncrDecr): IRCodeChunks {

View File

@ -100,4 +100,343 @@ class TestVmCodeGen: FunSpec({
val irChunks = (result.irProgram.blocks.first().children.single() as IRSubroutine).chunks
irChunks.size shouldBeGreaterThan 4
}
test("float comparison expressions against zero") {
//main {
// sub start() {
// float @shared f1
//
// if f1==0
// nop
// if f1!=0
// nop
// if f1>0
// nop
// if f1<0
// nop
// }
//}
val codegen = VmCodeGen()
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val block = PtBlock("main", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
sub.add(PtVariable("f1", DataType.FLOAT, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
val if1 = PtIfElse(Position.DUMMY)
val cmp1 = PtBinaryExpression("==", DataType.UBYTE, Position.DUMMY)
cmp1.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY))
cmp1.add(PtNumber(DataType.FLOAT, 0.0, Position.DUMMY))
if1.add(cmp1)
if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
sub.add(if1)
val if2 = PtIfElse(Position.DUMMY)
val cmp2 = PtBinaryExpression("!=", DataType.UBYTE, Position.DUMMY)
cmp2.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY))
cmp2.add(PtNumber(DataType.FLOAT, 0.0, Position.DUMMY))
if2.add(cmp2)
if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
sub.add(if2)
val if3 = PtIfElse(Position.DUMMY)
val cmp3 = PtBinaryExpression("<", DataType.UBYTE, Position.DUMMY)
cmp3.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY))
cmp3.add(PtNumber(DataType.FLOAT, 0.0, Position.DUMMY))
if3.add(cmp3)
if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
sub.add(if3)
val if4 = PtIfElse(Position.DUMMY)
val cmp4 = PtBinaryExpression(">", DataType.UBYTE, Position.DUMMY)
cmp4.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY))
cmp4.add(PtNumber(DataType.FLOAT, 0.0, Position.DUMMY))
if4.add(cmp4)
if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
sub.add(if4)
block.add(sub)
program.add(block)
val options = getTestOptions()
val st = SymbolTableMaker(program, options).make()
val errors = ErrorReporterForTests()
val result = codegen.generate(program, st, options, errors) as VmAssemblyProgram
val irChunks = (result.irProgram.blocks.first().children.single() as IRSubroutine).chunks
irChunks.size shouldBeGreaterThan 4
}
test("float comparison expressions against nonzero") {
//main {
// sub start() {
// float @shared f1
//
// if f1==42
// nop
// if f1!=42
// nop
// if f1>42
// nop
// if f1<42
// nop
// }
//}
val codegen = VmCodeGen()
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val block = PtBlock("main", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
sub.add(PtVariable("f1", DataType.FLOAT, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
val if1 = PtIfElse(Position.DUMMY)
val cmp1 = PtBinaryExpression("==", DataType.UBYTE, Position.DUMMY)
cmp1.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY))
cmp1.add(PtNumber(DataType.FLOAT, 42.0, Position.DUMMY))
if1.add(cmp1)
if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
sub.add(if1)
val if2 = PtIfElse(Position.DUMMY)
val cmp2 = PtBinaryExpression("!=", DataType.UBYTE, Position.DUMMY)
cmp2.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY))
cmp2.add(PtNumber(DataType.FLOAT, 42.0, Position.DUMMY))
if2.add(cmp2)
if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
sub.add(if2)
val if3 = PtIfElse(Position.DUMMY)
val cmp3 = PtBinaryExpression("<", DataType.UBYTE, Position.DUMMY)
cmp3.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY))
cmp3.add(PtNumber(DataType.FLOAT, 42.0, Position.DUMMY))
if3.add(cmp3)
if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
sub.add(if3)
val if4 = PtIfElse(Position.DUMMY)
val cmp4 = PtBinaryExpression(">", DataType.UBYTE, Position.DUMMY)
cmp4.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY))
cmp4.add(PtNumber(DataType.FLOAT, 42.0, Position.DUMMY))
if4.add(cmp4)
if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
sub.add(if4)
block.add(sub)
program.add(block)
val options = getTestOptions()
val st = SymbolTableMaker(program, options).make()
val errors = ErrorReporterForTests()
val result = codegen.generate(program, st, options, errors) as VmAssemblyProgram
val irChunks = (result.irProgram.blocks.first().children.single() as IRSubroutine).chunks
irChunks.size shouldBeGreaterThan 4
}
test("float conditional jump") {
//main {
// sub start() {
// float @shared f1
//
// if f1==42
// goto $c000
// if f1>42
// goto $c000
// }
//}
val codegen = VmCodeGen()
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val block = PtBlock("main", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
sub.add(PtVariable("f1", DataType.FLOAT, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
val if1 = PtIfElse(Position.DUMMY)
val cmp1 = PtBinaryExpression("==", DataType.UBYTE, Position.DUMMY)
cmp1.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY))
cmp1.add(PtNumber(DataType.FLOAT, 42.0, Position.DUMMY))
if1.add(cmp1)
if1.add(PtNodeGroup().also { it.add(PtJump(null, 0xc000u, null, Position.DUMMY)) })
if1.add(PtNodeGroup())
sub.add(if1)
val if2 = PtIfElse(Position.DUMMY)
val cmp2 = PtBinaryExpression(">", DataType.UBYTE, Position.DUMMY)
cmp2.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY))
cmp2.add(PtNumber(DataType.FLOAT, 42.0, Position.DUMMY))
if2.add(cmp2)
if2.add(PtNodeGroup().also { it.add(PtJump(null, 0xc000u, null, Position.DUMMY)) })
if2.add(PtNodeGroup())
sub.add(if2)
block.add(sub)
program.add(block)
val options = getTestOptions()
val st = SymbolTableMaker(program, options).make()
val errors = ErrorReporterForTests()
val result = codegen.generate(program, st, options, errors) as VmAssemblyProgram
val irChunks = (result.irProgram.blocks.first().children.single() as IRSubroutine).chunks
irChunks.size shouldBeGreaterThan 4
}
test("integer comparison expressions against zero") {
//main {
// sub start() {
// byte @shared sb1
//
// if sb1==0
// nop
// if sb1!=0
// nop
// if sb1>0
// nop
// if sb1<0
// nop
// }
//}
val codegen = VmCodeGen()
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val block = PtBlock("main", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
sub.add(PtVariable("sb1", DataType.BYTE, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
val if1 = PtIfElse(Position.DUMMY)
val cmp1 = PtBinaryExpression("==", DataType.BYTE, Position.DUMMY)
cmp1.add(PtIdentifier("main.start.sb1", DataType.BYTE, Position.DUMMY))
cmp1.add(PtNumber(DataType.BYTE, 0.0, Position.DUMMY))
if1.add(cmp1)
if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
sub.add(if1)
val if2 = PtIfElse(Position.DUMMY)
val cmp2 = PtBinaryExpression("!=", DataType.BYTE, Position.DUMMY)
cmp2.add(PtIdentifier("main.start.sb1", DataType.BYTE, Position.DUMMY))
cmp2.add(PtNumber(DataType.BYTE, 0.0, Position.DUMMY))
if2.add(cmp2)
if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
sub.add(if2)
val if3 = PtIfElse(Position.DUMMY)
val cmp3 = PtBinaryExpression("<", DataType.BYTE, Position.DUMMY)
cmp3.add(PtIdentifier("main.start.sb1", DataType.BYTE, Position.DUMMY))
cmp3.add(PtNumber(DataType.BYTE, 0.0, Position.DUMMY))
if3.add(cmp3)
if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
sub.add(if3)
val if4 = PtIfElse(Position.DUMMY)
val cmp4 = PtBinaryExpression(">", DataType.BYTE, Position.DUMMY)
cmp4.add(PtIdentifier("main.start.sb1", DataType.BYTE, Position.DUMMY))
cmp4.add(PtNumber(DataType.BYTE, 0.0, Position.DUMMY))
if4.add(cmp4)
if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
sub.add(if4)
block.add(sub)
program.add(block)
val options = getTestOptions()
val st = SymbolTableMaker(program, options).make()
val errors = ErrorReporterForTests()
val result = codegen.generate(program, st, options, errors) as VmAssemblyProgram
val irChunks = (result.irProgram.blocks.first().children.single() as IRSubroutine).chunks
irChunks.size shouldBeGreaterThan 4
}
test("integer comparison expressions against nonzero") {
//main {
// sub start() {
// byte @shared sb1
//
// if sb1==42
// nop
// if sb1!=42
// nop
// if sb1>42
// nop
// if sb1<42
// nop
// }
//}
val codegen = VmCodeGen()
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val block = PtBlock("main", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
sub.add(PtVariable("sb1", DataType.BYTE, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
val if1 = PtIfElse(Position.DUMMY)
val cmp1 = PtBinaryExpression("==", DataType.BYTE, Position.DUMMY)
cmp1.add(PtIdentifier("main.start.sb1", DataType.BYTE, Position.DUMMY))
cmp1.add(PtNumber(DataType.BYTE, 42.0, Position.DUMMY))
if1.add(cmp1)
if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
sub.add(if1)
val if2 = PtIfElse(Position.DUMMY)
val cmp2 = PtBinaryExpression("!=", DataType.BYTE, Position.DUMMY)
cmp2.add(PtIdentifier("main.start.sb1", DataType.BYTE, Position.DUMMY))
cmp2.add(PtNumber(DataType.BYTE, 42.0, Position.DUMMY))
if2.add(cmp2)
if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
sub.add(if2)
val if3 = PtIfElse(Position.DUMMY)
val cmp3 = PtBinaryExpression("<", DataType.BYTE, Position.DUMMY)
cmp3.add(PtIdentifier("main.start.sb1", DataType.BYTE, Position.DUMMY))
cmp3.add(PtNumber(DataType.BYTE, 42.0, Position.DUMMY))
if3.add(cmp3)
if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
sub.add(if3)
val if4 = PtIfElse(Position.DUMMY)
val cmp4 = PtBinaryExpression(">", DataType.BYTE, Position.DUMMY)
cmp4.add(PtIdentifier("main.start.sb1", DataType.BYTE, Position.DUMMY))
cmp4.add(PtNumber(DataType.BYTE, 42.0, Position.DUMMY))
if4.add(cmp4)
if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
sub.add(if4)
block.add(sub)
program.add(block)
val options = getTestOptions()
val st = SymbolTableMaker(program, options).make()
val errors = ErrorReporterForTests()
val result = codegen.generate(program, st, options, errors) as VmAssemblyProgram
val irChunks = (result.irProgram.blocks.first().children.single() as IRSubroutine).chunks
irChunks.size shouldBeGreaterThan 4
}
test("integer conditional jump") {
//main {
// sub start() {
// ubyte @shared ub1
//
// if ub1==42
// goto $c000
// if ub1>42
// goto $c000
// }
//}
val codegen = VmCodeGen()
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val block = PtBlock("main", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
sub.add(PtVariable("ub1", DataType.UBYTE, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
val if1 = PtIfElse(Position.DUMMY)
val cmp1 = PtBinaryExpression("==", DataType.UBYTE, Position.DUMMY)
cmp1.add(PtIdentifier("main.start.ub1", DataType.UBYTE, Position.DUMMY))
cmp1.add(PtNumber(DataType.UBYTE, 42.0, Position.DUMMY))
if1.add(cmp1)
if1.add(PtNodeGroup().also { it.add(PtJump(null, 0xc000u, null, Position.DUMMY)) })
if1.add(PtNodeGroup())
sub.add(if1)
val if2 = PtIfElse(Position.DUMMY)
val cmp2 = PtBinaryExpression(">", DataType.UBYTE, Position.DUMMY)
cmp2.add(PtIdentifier("main.start.ub1", DataType.UBYTE, Position.DUMMY))
cmp2.add(PtNumber(DataType.UBYTE, 42.0, Position.DUMMY))
if2.add(cmp2)
if2.add(PtNodeGroup().also { it.add(PtJump(null, 0xc000u, null, Position.DUMMY)) })
if2.add(PtNodeGroup())
sub.add(if2)
block.add(sub)
program.add(block)
val options = getTestOptions()
val st = SymbolTableMaker(program, options).make()
val errors = ErrorReporterForTests()
val result = codegen.generate(program, st, options, errors) as VmAssemblyProgram
val irChunks = (result.irProgram.blocks.first().children.single() as IRSubroutine).chunks
irChunks.size shouldBeGreaterThan 4
}
})

View File

@ -1 +1 @@
8.10
8.11-dev

View File

@ -33,7 +33,7 @@ class TestLaunchEmu: FunSpec({
<INITGLOBALS>
</INITGLOBALS>
<BLOCK NAME="main" ADDRESS="null" ALIGN="NONE" POS="[unittest: line 42 col 1-9]">
<BLOCK NAME="main" ADDRESS="" ALIGN="NONE" POS="[unittest: line 42 col 1-9]">
</BLOCK>
</PROGRAM>
""")

View File

@ -3,6 +3,14 @@ TODO
For next minor release
^^^^^^^^^^^^^^^^^^^^^^
- fix expericodegen compiler crashes:
float comparison <= , >= , == , != all crash with mismatched result register for FLOAT (cube3d-float uses this)
maze: thinks draw is unused
tehtriz: thinks sound.init routine is unused
textelite: thinks trader.do_local routine is unused , and debug_seed
- fix IR/VM: animals.p8 example somehow doesn't print the animal name in the first question, and exits after 1 animal instead of looping
- fix Github issue with X register https://github.com/irmen/prog8/issues/94
...

View File

@ -103,8 +103,8 @@ class IRFileReader {
"output" -> outputType = OutputType.valueOf(value)
"launcher" -> launcher = CbmPrgLauncherType.valueOf(value)
"zeropage" -> zeropage = ZeropageType.valueOf(value)
"loadAddress" -> loadAddress = value.toUInt()
"evalStackBaseAddress" -> evalStackBaseAddress = if(value=="null") null else parseIRValue(value).toUInt()
"loadAddress" -> loadAddress = parseIRValue(value).toUInt()
"evalStackBaseAddress" -> evalStackBaseAddress = if(value=="") null else parseIRValue(value).toUInt()
"zpReserved" -> {
val (zpstart, zpend) = value.split(',')
zpReserved.add(UIntRange(zpstart.toUInt(), zpend.toUInt()))
@ -262,10 +262,10 @@ class IRFileReader {
emptyList()
else {
val slabs = mutableListOf<StMemorySlab>()
val slabPattern = Regex("SLAB (.+) (.+) (.+)")
val slabPattern = Regex("(.+) (.+) (.+)")
text.lineSequence().forEach { line ->
// example: "SLAB slabname 4096 0"
val match = slabPattern.matchEntire(line) ?: throw IRParseException("invalid SLAB $line")
// example: "slabname 4096 0"
val match = slabPattern.matchEntire(line) ?: throw IRParseException("invalid slab $line")
val (name, size, align) = match.destructured
val dummyNode = PtVariable(name, DataType.ARRAY_UB, ZeropageWish.NOT_IN_ZEROPAGE, null, null, Position.DUMMY)
slabs.add(StMemorySlab(name, size.toUInt(), align.toUInt(), dummyNode))
@ -331,7 +331,7 @@ class IRFileReader {
val attrs = start.attributes.asSequence().associate { it.name.localPart to it.value }
val block = IRBlock(
attrs.getValue("NAME"),
if(attrs.getValue("ADDRESS")=="null") null else parseIRValue(attrs.getValue("ADDRESS")).toUInt(),
if(attrs.getValue("ADDRESS")=="") null else parseIRValue(attrs.getValue("ADDRESS")).toUInt(),
IRBlock.BlockAlignment.valueOf(attrs.getValue("ALIGN")),
parsePosition(attrs.getValue("POS")))
skipText(reader)
@ -364,7 +364,7 @@ class IRFileReader {
skipText(reader)
val sub = IRSubroutine(attrs.getValue("NAME"),
parseParameters(reader),
if(returntype=="null") null else parseDatatype(returntype, false),
if(returntype=="") null else parseDatatype(returntype, false),
parsePosition(attrs.getValue("POS")))
skipText(reader)
@ -433,7 +433,7 @@ class IRFileReader {
}
return IRAsmSubroutine(
attrs.getValue("NAME"),
if(attrs.getValue("ADDRESS")=="null") null else parseIRValue(attrs.getValue("ADDRESS")).toUInt(),
if(attrs.getValue("ADDRESS")=="") null else parseIRValue(attrs.getValue("ADDRESS")).toUInt(),
clobberRegs.toSet(),
params,
returns,

View File

@ -2,6 +2,7 @@ package prog8.intermediate
import prog8.code.core.*
import java.nio.file.Path
import javax.xml.stream.XMLOutputFactory
import kotlin.io.path.bufferedWriter
import kotlin.io.path.div
@ -9,23 +10,32 @@ import kotlin.io.path.div
class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
private val outfile = outfileOverride ?: (irProgram.options.outputDir / ("${irProgram.name}.p8ir"))
private val out = outfile.bufferedWriter(charset=Charsets.UTF_8)
private val xml = XMLOutputFactory.newInstance().createXMLStreamWriter(out)
private var numChunks = 0
private var numInstr = 0
fun write(): Path {
println("Writing intermediate representation to $outfile")
out.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")
out.write("<PROGRAM NAME=\"${irProgram.name}\">\n")
xml.writeStartDocument("utf-8", "1.0")
xml.writeEndDocument()
xml.writeCharacters("\n")
xml.writeStartElement("PROGRAM")
xml.writeAttribute("NAME", irProgram.name)
xml.writeCharacters("\n")
writeOptions()
writeAsmSymbols()
writeVariables()
out.write("\n<INITGLOBALS>\n")
xml.writeStartElement("INITGLOBALS")
xml.writeCharacters("\n")
writeCodeChunk(irProgram.globalInits)
out.write("</INITGLOBALS>\n")
xml.writeEndElement()
xml.writeCharacters("\n\n")
writeBlocks()
out.write("</PROGRAM>\n")
xml.writeEndElement()
xml.writeCharacters("\n")
xml.close()
out.close()
val used = irProgram.registersUsed()
@ -35,14 +45,21 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
}
private fun writeAsmSymbols() {
out.write("<ASMSYMBOLS>\n")
irProgram.asmSymbols.forEach { (name, value) -> out.write("$name=$value\n" )}
out.write("</ASMSYMBOLS>\n")
xml.writeStartElement("ASMSYMBOLS")
xml.writeCharacters("\n")
irProgram.asmSymbols.forEach { (name, value) -> xml.writeCharacters("$name=$value\n" )}
xml.writeEndElement()
xml.writeCharacters("\n")
}
private fun writeBlocks() {
irProgram.blocks.forEach { block ->
out.write("\n<BLOCK NAME=\"${block.name}\" ADDRESS=\"${block.address?.toHex()}\" ALIGN=\"${block.alignment}\" POS=\"${block.position}\">\n")
xml.writeStartElement("BLOCK")
xml.writeAttribute("NAME", block.name)
xml.writeAttribute("ADDRESS", block.address?.toHex() ?: "")
xml.writeAttribute("ALIGN", block.alignment.toString())
xml.writeAttribute("POS", block.position.toString())
xml.writeCharacters("\n")
block.children.forEach { child ->
when(child) {
is IRAsmSubroutine -> {
@ -51,25 +68,40 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
if(ret.reg.registerOrPair!=null) "${ret.reg.registerOrPair}:${ret.dt.toString().lowercase()}"
else "${ret.reg.statusflag}:${ret.dt.toString().lowercase()}"
}.joinToString(",")
out.write("<ASMSUB NAME=\"${child.label}\" ADDRESS=\"${child.address?.toHex()}\" CLOBBERS=\"$clobbers\" RETURNS=\"$returns\" POS=\"${child.position}\">\n")
out.write("<ASMPARAMS>\n")
xml.writeStartElement("ASMSUB")
xml.writeAttribute("NAME", child.label)
xml.writeAttribute("ADDRESS", child.address?.toHex() ?: "")
xml.writeAttribute("CLOBBERS", clobbers)
xml.writeAttribute("RETURNS", returns)
xml.writeAttribute("POS", child.position.toString())
xml.writeCharacters("\n")
xml.writeStartElement("ASMPARAMS")
xml.writeCharacters("\n")
child.parameters.forEach { ret ->
val reg = if(ret.reg.registerOrPair!=null) ret.reg.registerOrPair.toString()
else ret.reg.statusflag.toString()
out.write("${ret.dt.toString().lowercase()} $reg\n")
xml.writeCharacters("${ret.dt.toString().lowercase()} $reg\n")
}
out.write("</ASMPARAMS>\n")
xml.writeEndElement()
xml.writeCharacters("\n")
writeInlineAsm(child.asmChunk)
out.write("</ASMSUB>\n")
xml.writeEndElement()
xml.writeCharacters("\n\n")
}
is IRCodeChunk -> writeCodeChunk(child)
is IRInlineAsmChunk -> writeInlineAsm(child)
is IRInlineBinaryChunk -> writeInlineBytes(child)
is IRSubroutine -> {
out.write("<SUB NAME=\"${child.label}\" RETURNTYPE=\"${child.returnType.toString().lowercase()}\" POS=\"${child.position}\">\n")
out.write("<PARAMS>\n")
child.parameters.forEach { param -> out.write("${getTypeString(param.dt)} ${param.name}\n") }
out.write("</PARAMS>\n")
xml.writeStartElement("SUB")
xml.writeAttribute("NAME", child.label)
xml.writeAttribute("RETURNTYPE", child.returnType?.toString()?.lowercase() ?: "")
xml.writeAttribute("POS", child.position.toString())
xml.writeCharacters("\n")
xml.writeStartElement("PARAMS")
xml.writeCharacters("\n")
child.parameters.forEach { param -> xml.writeCharacters("${getTypeString(param.dt)} ${param.name}\n") }
xml.writeEndElement()
xml.writeCharacters("\n")
child.chunks.forEach { chunk ->
numChunks++
when (chunk) {
@ -79,71 +111,87 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
else -> throw InternalCompilerException("invalid chunk")
}
}
out.write("</SUB>\n")
xml.writeEndElement()
xml.writeCharacters("\n\n")
}
}
}
out.write("</BLOCK>\n")
xml.writeEndElement()
xml.writeCharacters("\n\n")
}
}
private fun writeCodeChunk(chunk: IRCodeChunk) {
if(chunk.label!=null)
out.write("<CODE LABEL=\"${chunk.label}\">\n")
else
out.write("<CODE>\n")
xml.writeStartElement("CODE")
chunk.label?.let { xml.writeAttribute("LABEL", chunk.label) }
xml.writeCharacters("\n")
chunk.instructions.forEach { instr ->
numInstr++
out.write(instr.toString())
out.write("\n")
xml.writeCharacters(instr.toString())
xml.writeCharacters("\n")
}
out.write("</CODE>\n")
xml.writeEndElement()
xml.writeCharacters("\n")
}
private fun writeInlineBytes(chunk: IRInlineBinaryChunk) {
out.write("<BYTES LABEL=\"${chunk.label ?: ""}\">\n")
xml.writeStartElement("BYTES")
chunk.label?.let { xml.writeAttribute("LABEL", chunk.label) }
xml.writeCharacters("\n")
chunk.data.withIndex().forEach {(index, byte) ->
out.write(byte.toString(16).padStart(2,'0'))
xml.writeCharacters(byte.toString(16).padStart(2,'0'))
if(index and 63 == 63 && index < chunk.data.size-1)
out.write("\n")
xml.writeCharacters("\n")
}
out.write("\n</BYTES>\n")
xml.writeEndElement()
xml.writeCharacters("\n")
}
private fun writeInlineAsm(chunk: IRInlineAsmChunk) {
out.write("<INLINEASM LABEL=\"${chunk.label ?: ""}\" IR=\"${chunk.isIR}\">\n")
out.write(chunk.assembly)
out.write("\n</INLINEASM>\n")
xml.writeStartElement("INLINEASM")
xml.writeAttribute("LABEL", chunk.label ?: "")
xml.writeAttribute("IR", chunk.isIR.toString())
xml.writeCharacters("\n")
xml.writeCharacters(chunk.assembly)
xml.writeEndElement()
xml.writeCharacters("\n")
}
private fun writeOptions() {
out.write("<OPTIONS>\n")
out.write("compTarget=${irProgram.options.compTarget.name}\n")
out.write("output=${irProgram.options.output}\n")
out.write("launcher=${irProgram.options.launcher}\n")
out.write("zeropage=${irProgram.options.zeropage}\n")
xml.writeStartElement("OPTIONS")
xml.writeCharacters("\n")
xml.writeCharacters("compTarget=${irProgram.options.compTarget.name}\n")
xml.writeCharacters("output=${irProgram.options.output}\n")
xml.writeCharacters("launcher=${irProgram.options.launcher}\n")
xml.writeCharacters("zeropage=${irProgram.options.zeropage}\n")
for(range in irProgram.options.zpReserved) {
out.write("zpReserved=${range.first},${range.last}\n")
xml.writeCharacters("zpReserved=${range.first},${range.last}\n")
}
out.write("loadAddress=${irProgram.options.loadAddress.toHex()}\n")
out.write("optimize=${irProgram.options.optimize}\n")
out.write("evalStackBaseAddress=${irProgram.options.evalStackBaseAddress?.toHex()}\n")
out.write("outputDir=${irProgram.options.outputDir.toAbsolutePath()}\n")
xml.writeCharacters("loadAddress=${irProgram.options.loadAddress.toHex()}\n")
xml.writeCharacters("optimize=${irProgram.options.optimize}\n")
xml.writeCharacters("evalStackBaseAddress=${irProgram.options.evalStackBaseAddress?.toHex() ?: ""}\n")
xml.writeCharacters("outputDir=${irProgram.options.outputDir.toAbsolutePath()}\n")
// other options not yet useful here?
out.write("</OPTIONS>\n")
xml.writeEndElement()
xml.writeCharacters("\n\n")
}
private fun writeVariables() {
val (variablesNoInit, variablesWithInit) = irProgram.st.allVariables().partition { it.uninitialized }
out.write("\n<VARIABLESNOINIT>\n")
xml.writeStartElement("VARIABLESNOINIT")
xml.writeCharacters("\n")
for (variable in variablesNoInit) {
val typeStr = getTypeString(variable)
out.write("$typeStr ${variable.name} zp=${variable.zpwish}\n")
xml.writeCharacters("$typeStr ${variable.name} zp=${variable.zpwish}\n")
}
out.write("</VARIABLESNOINIT>\n<VARIABLESWITHINIT>\n")
xml.writeEndElement()
xml.writeCharacters("\n")
xml.writeStartElement("VARIABLESWITHINIT")
xml.writeCharacters("\n")
for (variable in variablesWithInit) {
val typeStr = getTypeString(variable)
val value: String = when(variable.dt) {
@ -174,19 +222,24 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
}
else -> throw InternalCompilerException("weird dt")
}
out.write("$typeStr ${variable.name}=$value zp=${variable.zpwish}\n")
xml.writeCharacters("$typeStr ${variable.name}=$value zp=${variable.zpwish}\n")
}
out.write("</VARIABLESWITHINIT>\n")
xml.writeEndElement()
xml.writeCharacters("\n")
out.write("\n<MEMORYMAPPEDVARIABLES>\n")
xml.writeStartElement("MEMORYMAPPEDVARIABLES")
xml.writeCharacters("\n")
for (variable in irProgram.st.allMemMappedVariables()) {
val typeStr = getTypeString(variable)
out.write("@$typeStr ${variable.name}=${variable.address.toHex()}\n")
xml.writeCharacters("@$typeStr ${variable.name}=${variable.address.toHex()}\n")
}
out.write("</MEMORYMAPPEDVARIABLES>\n")
xml.writeEndElement()
xml.writeCharacters("\n")
out.write("\n<MEMORYSLABS>\n")
irProgram.st.allMemorySlabs().forEach{ slab -> out.write("SLAB ${slab.name} ${slab.size} ${slab.align}\n") }
out.write("</MEMORYSLABS>\n")
xml.writeStartElement("MEMORYSLABS")
xml.writeCharacters("\n")
irProgram.st.allMemorySlabs().forEach{ slab -> xml.writeCharacters("${slab.name} ${slab.size} ${slab.align}\n") }
xml.writeEndElement()
xml.writeCharacters("\n")
}
}

View File

@ -585,10 +585,10 @@ val instructionFormats = mutableMapOf(
Opcode.SLES to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.SGE to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.SGES to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.INC to InstructionFormat.from("BW,<>r1"),
Opcode.INCM to InstructionFormat.from("BW,<v"),
Opcode.DEC to InstructionFormat.from("BW,<>r1"),
Opcode.DECM to InstructionFormat.from("BW,<v"),
Opcode.INC to InstructionFormat.from("BW,<>r1 | F,<>fr1"),
Opcode.INCM to InstructionFormat.from("BW,<v | F,<v"),
Opcode.DEC to InstructionFormat.from("BW,<>r1 | F,<>fr1"),
Opcode.DECM to InstructionFormat.from("BW,<v | F,<v"),
Opcode.NEG to InstructionFormat.from("BW,<>r1 | F,<>fr1"),
Opcode.NEGM to InstructionFormat.from("BW,<v | F,<v"),
Opcode.ADDR to InstructionFormat.from("BW,<>r1,<r2 | F,<>fr1,<fr2"),

View File

@ -95,9 +95,12 @@ class IRSymbolTable(sourceSt: SymbolTable?) {
scopedName = variable.name
varToadd = variable
} else {
scopedName = variable.scopedName
val dummyNode = PtVariable(scopedName, variable.dt, ZeropageWish.NOT_IN_ZEROPAGE, null, null, variable.astNode.position)
varToadd = StMemVar(scopedName, variable.dt, variable.address, variable.length, dummyNode)
scopedName = try {
variable.scopedName
} catch (ux: UninitializedPropertyAccessException) {
variable.name
}
varToadd = StMemVar(scopedName, variable.dt, variable.address, variable.length, variable.astNode)
}
table[scopedName] = varToadd
}

View File

@ -47,8 +47,8 @@ compTarget=virtual
output=PRG
launcher=BASIC
zeropage=KERNALSAFE
loadAddress=0
evalStackBaseAddress=null
loadAddress=$0000
evalStackBaseAddress=
</OPTIONS>
<ASMSYMBOLS>
@ -75,8 +75,8 @@ load.b r1,42
</CODE>
</INITGLOBALS>
<BLOCK NAME="main" ADDRESS="null" ALIGN="NONE" POS="[examples/test.p8: line 2 col 2-5]">
<SUB NAME="main.start" RETURNTYPE="null" POS="[examples/test.p8: line 4 col 6-8]">
<BLOCK NAME="main" ADDRESS="" ALIGN="NONE" POS="[examples/test.p8: line 2 col 2-5]">
<SUB NAME="main.start" RETURNTYPE="" POS="[examples/test.p8: line 4 col 6-8]">
<PARAMS>
</PARAMS>
<CODE LABEL="main.start">
@ -85,8 +85,8 @@ return
</SUB>
</BLOCK>
<BLOCK NAME="sys" ADDRESS="null" ALIGN="NONE" POS="[library:/prog8lib/virtual/syslib.p8: line 3 col 2-4]">
<SUB NAME="sys.wait" RETURNTYPE="null" POS="[library:/prog8lib/virtual/syslib.p8: line 15 col 6-8]">
<BLOCK NAME="sys" ADDRESS="" ALIGN="NONE" POS="[library:/prog8lib/virtual/syslib.p8: line 3 col 2-4]">
<SUB NAME="sys.wait" RETURNTYPE="" POS="[library:/prog8lib/virtual/syslib.p8: line 15 col 6-8]">
<PARAMS>
uword sys.wait.jiffies
</PARAMS>

View File

@ -129,7 +129,7 @@ class TestVm: FunSpec( {
<INITGLOBALS>
</INITGLOBALS>
<BLOCK NAME="main" ADDRESS="null" ALIGN="NONE" POS="[unittest: line 42 col 1-9]">
<BLOCK NAME="main" ADDRESS="" ALIGN="NONE" POS="[unittest: line 42 col 1-9]">
</BLOCK>
</PROGRAM>
"""