diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt index c3aa837a5..02d0d1ce0 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt @@ -241,20 +241,24 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express if(zero) { if(fixedIndex!=null) { val chunk = IRCodeChunk(null, null).also { - it += if(targetArray.splitWords) - IRInstruction(Opcode.STOREZMSPLIT, targetDt, immediate = arrayLength, labelSymbol = "$variable+$fixedIndex") + if(targetArray.splitWords) { + it += IRInstruction(Opcode.STOREZM, IRDataType.BYTE, immediate = arrayLength, labelSymbol = "${variable}_lsb+$fixedIndex") + it += IRInstruction(Opcode.STOREZM, IRDataType.BYTE, immediate = arrayLength, labelSymbol = "${variable}_msb+$fixedIndex") + } else - IRInstruction(Opcode.STOREZM, targetDt, labelSymbol = "$variable+${fixedIndex*itemsize}") + it += IRInstruction(Opcode.STOREZM, targetDt, labelSymbol = "$variable+${fixedIndex*itemsize}") } result += chunk } else { val (code, indexReg) = loadIndexReg(targetArray, itemsize) result += code result += IRCodeChunk(null, null).also { - it += if(targetArray.splitWords) - IRInstruction(Opcode.STOREZXSPLIT, targetDt, reg1 = valueRegister, reg2=indexReg, immediate = arrayLength, labelSymbol = variable) + if(targetArray.splitWords) { + it += IRInstruction(Opcode.STOREZX, IRDataType.BYTE, reg1 = indexReg, immediate = arrayLength, labelSymbol = variable+"_lsb") + it += IRInstruction(Opcode.STOREZX, IRDataType.BYTE, reg1 = indexReg, immediate = arrayLength, labelSymbol = variable+"_msb") + } else - IRInstruction(Opcode.STOREZX, targetDt, reg1=indexReg, labelSymbol = variable) + it += IRInstruction(Opcode.STOREZX, targetDt, reg1=indexReg, labelSymbol = variable) } } } else { @@ -275,20 +279,28 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express } else { if(fixedIndex!=null) { val chunk = IRCodeChunk(null, null).also { - it += if(targetArray.splitWords) - IRInstruction(Opcode.STOREMSPLIT, targetDt, reg1 = valueRegister, immediate = arrayLength, labelSymbol = "$variable+$fixedIndex") + if(targetArray.splitWords) { + val msbReg = codeGen.registers.nextFree() + it += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1 = valueRegister, immediate = arrayLength, labelSymbol = "${variable}_lsb+$fixedIndex") + it += IRInstruction(Opcode.MSIG, IRDataType.BYTE, reg1 = msbReg, reg2 = valueRegister) + it += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1 = msbReg, immediate = arrayLength, labelSymbol = "${variable}_msb+$fixedIndex") + } else - IRInstruction(Opcode.STOREM, targetDt, reg1 = valueRegister, labelSymbol = "$variable+${fixedIndex*itemsize}") + it += IRInstruction(Opcode.STOREM, targetDt, reg1 = valueRegister, labelSymbol = "$variable+${fixedIndex*itemsize}") } result += chunk } else { val (code, indexReg) = loadIndexReg(targetArray, itemsize) result += code result += IRCodeChunk(null, null).also { - it += if(targetArray.splitWords) - IRInstruction(Opcode.STOREXSPLIT, targetDt, reg1 = valueRegister, reg2=indexReg, immediate = arrayLength, labelSymbol = variable) + if(targetArray.splitWords) { + val msbReg = codeGen.registers.nextFree() + it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1 = valueRegister, reg2=indexReg, immediate = arrayLength, labelSymbol = "${variable}_lsb") + it += IRInstruction(Opcode.MSIG, IRDataType.BYTE, reg1 = msbReg, reg2 = valueRegister) + it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1 = msbReg, reg2=indexReg, immediate = arrayLength, labelSymbol = "${variable}_msb") + } else - IRInstruction(Opcode.STOREX, targetDt, reg1 = valueRegister, reg2=indexReg, labelSymbol = variable) + it += IRInstruction(Opcode.STOREX, targetDt, reg1 = valueRegister, reg2=indexReg, labelSymbol = variable) } } } diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt index ef2cda50b..9f7f0f710 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt @@ -168,11 +168,21 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { resultRegister = codeGen.registers.nextFree() if(arrayIx.index is PtNumber) { val memOffset = (arrayIx.index as PtNumber).number.toInt() - addInstr(result, IRInstruction(Opcode.LOADMSPLIT, IRDataType.WORD, reg1=resultRegister, immediate = arrayLength, labelSymbol = "$arrayVarSymbol+$memOffset"), null) + result += IRCodeChunk(null, null).also { + val tmpRegMsb = codeGen.registers.nextFree() + it += IRInstruction(Opcode.LOADM, IRDataType.BYTE, reg1=resultRegister, immediate = arrayLength, labelSymbol= "${arrayVarSymbol}_lsb+$memOffset") + it += IRInstruction(Opcode.LOADM, IRDataType.BYTE, reg1=tmpRegMsb, immediate = arrayLength, labelSymbol= "${arrayVarSymbol}_msb+$memOffset") + it += IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1=resultRegister, reg2=tmpRegMsb) + } } else { val tr = translateExpression(arrayIx.index) addToResult(result, tr, tr.resultReg, -1) - addInstr(result, IRInstruction(Opcode.LOADXSPLIT, IRDataType.WORD, reg1=resultRegister, reg2=tr.resultReg, immediate = arrayLength, labelSymbol = arrayVarSymbol), null) + result += IRCodeChunk(null, null).also { + val tmpRegMsb = codeGen.registers.nextFree() + it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=resultRegister, reg2 = tr.resultReg, immediate = arrayLength, labelSymbol= "${arrayVarSymbol}_lsb") + it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpRegMsb, reg2 = tr.resultReg, immediate = arrayLength, labelSymbol= "${arrayVarSymbol}_msb") + it += IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1=resultRegister, reg2=tmpRegMsb) + } } return ExpressionCodeResult(result, vmDt, resultRegister, -1) } diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt index b279a0cbe..69a4ab4a6 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt @@ -457,23 +457,11 @@ class IRCodeGen( if(iterableVar.dt==DataType.STR) { // iterate over a zero-terminated string addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = indexReg, immediate = 0), null) - val chunk = IRCodeChunk(loopLabel, null) - chunk += IRInstruction( - Opcode.LOADX, - IRDataType.BYTE, - reg1 = tmpReg, - reg2 = indexReg, - labelSymbol = iterable.name - ) - chunk += IRInstruction( - Opcode.BEQ, - IRDataType.BYTE, - reg1 = tmpReg, - immediate = 0, - labelSymbol = endLabel - ) - chunk += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1 = tmpReg, labelSymbol = loopvarSymbol) - result += chunk + result += IRCodeChunk(loopLabel, null).also { + it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1 = tmpReg, reg2 = indexReg, labelSymbol = iterable.name) + it += IRInstruction(Opcode.BEQ, IRDataType.BYTE, reg1 = tmpReg, immediate = 0, labelSymbol = endLabel) + it += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1 = tmpReg, labelSymbol = loopvarSymbol) + } result += translateNode(forLoop.statements) val jumpChunk = IRCodeChunk(null, null) jumpChunk += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1 = indexReg) @@ -488,8 +476,12 @@ class IRCodeGen( val length = iterableVar.length!! addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, immediate = 0), null) result += IRCodeChunk(loopLabel, null).also { - it += IRInstruction(Opcode.LOADXSPLIT, irType(elementDt), reg1=tmpReg, reg2=indexReg, immediate = length, labelSymbol=iterable.name) - it += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=tmpReg, labelSymbol = loopvarSymbol) + val tmpRegLsb = registers.nextFree() + val tmpRegMsb = registers.nextFree() + it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpRegLsb, reg2=indexReg, immediate = length, labelSymbol=iterable.name+"_lsb") + it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpRegMsb, reg2=indexReg, immediate = length, labelSymbol=iterable.name+"_msb") + it += IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1=tmpRegLsb, reg2=tmpRegMsb) + it += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=tmpRegLsb, labelSymbol = loopvarSymbol) } result += translateNode(forLoop.statements) result += IRCodeChunk(null, null).also { @@ -1367,76 +1359,84 @@ class IRCodeGen( } private fun translate(postIncrDecr: PtPostIncrDecr): IRCodeChunks { + val result = mutableListOf() + val array = postIncrDecr.target.array val operationMem: Opcode val operationRegister: Opcode - val array = postIncrDecr.target.array when(postIncrDecr.operator) { "++" -> { - operationMem = if(array?.splitWords==true) Opcode.INCMSPLIT else Opcode.INCM + operationMem = Opcode.INCM operationRegister = Opcode.INC } "--" -> { - operationMem = if(array?.splitWords==true) Opcode.DECMSPLIT else Opcode.DECM + operationMem = Opcode.DECM operationRegister = Opcode.DEC } else -> throw AssemblyError("weird operator") } - val ident = postIncrDecr.target.identifier - val memory = postIncrDecr.target.memory - val irDt = irType(postIncrDecr.target.type) - val result = mutableListOf() - if(ident!=null) { - addInstr(result, IRInstruction(operationMem, irDt, labelSymbol = ident.name), null) - } else if(memory!=null) { - if(memory.address is PtNumber) { - val address = (memory.address as PtNumber).number.toInt() - addInstr(result, IRInstruction(operationMem, irDt, address = address), null) + + if(array?.splitWords==true) { + val variable = array.variable.name + val fixedIndex = constIntValue(array.index) + val iterable = symbolTable.flat.getValue(array.variable.name) as StStaticVariable + val arrayLength = iterable.length!! + if(fixedIndex!=null) { + TODO("split incr decr") + // addInstr(result, IRInstruction(operationMem, irDt, immediate = arrayLength, labelSymbol="$variable+$fixedIndex"), null) } else { - val tr = expressionEval.translateExpression(memory.address) - addToResult(result, tr, tr.resultReg, -1) + val indexTr = expressionEval.translateExpression(array.index) + addToResult(result, indexTr, indexTr.resultReg, -1) val chunk = IRCodeChunk(null, null) val incReg = registers.nextFree() - chunk += IRInstruction(Opcode.LOADI, irDt, reg1 = incReg, reg2 = tr.resultReg) - chunk += IRInstruction(operationRegister, irDt, reg1 = incReg) - chunk += IRInstruction(Opcode.STOREI, irDt, reg1 = incReg, reg2 = tr.resultReg) + TODO("load split") + // chunk += IRInstruction(Opcode.LOADXSPLIT, irDt, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol=variable) + // chunk += IRInstruction(operationRegister, irDt, reg1=incReg) + TODO("store split") + // chunk += IRInstruction(Opcode.STOREXSPLIT, irDt, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol=variable) result += chunk } - } else if (array!=null) { - val variable = array.variable.name - val itemsize = program.memsizer.memorySize(array.type) - val fixedIndex = constIntValue(array.index) - if(array.splitWords) { - val iterable = symbolTable.flat.getValue(array.variable.name) as StStaticVariable - val arrayLength = iterable.length!! - if(fixedIndex!=null) { - addInstr(result, IRInstruction(operationMem, irDt, immediate = arrayLength, labelSymbol="$variable+$fixedIndex"), null) + } else { + val ident = postIncrDecr.target.identifier + val memory = postIncrDecr.target.memory + val irDt = irType(postIncrDecr.target.type) + if(ident!=null) { + addInstr(result, IRInstruction(operationMem, irDt, labelSymbol = ident.name), null) + } else if(memory!=null) { + if(memory.address is PtNumber) { + val address = (memory.address as PtNumber).number.toInt() + addInstr(result, IRInstruction(operationMem, irDt, address = address), null) } else { - val indexTr = expressionEval.translateExpression(array.index) - addToResult(result, indexTr, indexTr.resultReg, -1) - val chunk = IRCodeChunk(null, null) - val incReg = registers.nextFree() - chunk += IRInstruction(Opcode.LOADXSPLIT, irDt, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol=variable) - chunk += IRInstruction(operationRegister, irDt, reg1=incReg) - chunk += IRInstruction(Opcode.STOREXSPLIT, irDt, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol=variable) - result += chunk + val tr = expressionEval.translateExpression(memory.address) + addToResult(result, tr, tr.resultReg, -1) + result += IRCodeChunk(null, null).also { + val incReg = registers.nextFree() + it += IRInstruction(Opcode.LOADI, irDt, reg1 = incReg, reg2 = tr.resultReg) + it += IRInstruction(operationRegister, irDt, reg1 = incReg) + it += IRInstruction(Opcode.STOREI, irDt, reg1 = incReg, reg2 = tr.resultReg) + } } - } else { + } else if (array!=null) { + val variable = array.variable.name + val itemsize = program.memsizer.memorySize(array.type) + val fixedIndex = constIntValue(array.index) if(fixedIndex!=null) { val offset = fixedIndex*itemsize addInstr(result, IRInstruction(operationMem, irDt, labelSymbol="$variable+$offset"), null) } else { val indexTr = expressionEval.translateExpression(array.index) addToResult(result, indexTr, indexTr.resultReg, -1) - val chunk = IRCodeChunk(null, null) - val incReg = registers.nextFree() - chunk += IRInstruction(Opcode.LOADX, irDt, reg1=incReg, reg2=indexTr.resultReg, labelSymbol=variable) - chunk += IRInstruction(operationRegister, irDt, reg1=incReg) - chunk += IRInstruction(Opcode.STOREX, irDt, reg1=incReg, reg2=indexTr.resultReg, labelSymbol=variable) - result += chunk + if(itemsize>1) + result += multiplyByConst(IRDataType.BYTE, indexTr.resultReg, itemsize) + result += IRCodeChunk(null, null).also { + val incReg = registers.nextFree() + it += IRInstruction(Opcode.LOADX, irDt, reg1=incReg, reg2=indexTr.resultReg, labelSymbol=variable) + it += IRInstruction(operationRegister, irDt, reg1=incReg) + it += IRInstruction(Opcode.STOREX, irDt, reg1=incReg, reg2=indexTr.resultReg, labelSymbol=variable) + } } - } - } else - throw AssemblyError("weird assigntarget") + } else + throw AssemblyError("weird assigntarget") + } return result } @@ -1459,10 +1459,10 @@ class IRCodeGen( addToResult(result, countTr, countTr.resultReg, -1) addInstr(result, IRInstruction(Opcode.BEQ, irDt, reg1=countTr.resultReg, immediate = 0, labelSymbol = skipRepeatLabel), null) result += labelFirstChunk(translateNode(repeat.statements), repeatLabel) - val chunk = IRCodeChunk(null, null) - chunk += IRInstruction(Opcode.DEC, irDt, reg1=countTr.resultReg) - chunk += IRInstruction(Opcode.BNE, irDt, reg1=countTr.resultReg, immediate = 0, labelSymbol = repeatLabel) - result += chunk + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.DEC, irDt, reg1 = countTr.resultReg) + it += IRInstruction(Opcode.BNE, irDt, reg1 = countTr.resultReg, immediate = 0, labelSymbol = repeatLabel) + } result += IRCodeChunk(skipRepeatLabel, null) return result } diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index 7f1d02d12..c78703ca4 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -697,6 +697,9 @@ internal class AstChecker(private val program: Program, } } } + + if(decl.splitArray && decl.type==VarDeclType.MEMORY) + err("@split can't be used on memory mapped arrays") } if(decl.datatype==DataType.STR) { diff --git a/docs/source/todo.rst b/docs/source/todo.rst index a842d6814..f68079da8 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,6 +1,8 @@ TODO ==== +- vm: fix the last replacement code for the now removed LOADSPLIT/STORESPLIT opcodes. + ... diff --git a/examples/test.p8 b/examples/test.p8 index 6861351a0..6d97c1eca 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,30 +1,34 @@ %import textio -%option splitarrays +%zeropage basicsafe main { sub start() { str name1 = "name1" str name2 = "name2" - uword[] names = [name1, name2, "name3"] - cx16.r0++ - ubyte xx = 2 - names[xx] = "irmen" - uword ww - for ww in names { - txt.print(ww) - txt.spc() - } - txt.nl() - names = [1111,2222,3333] - for ww in names { - txt.print_uw(ww) - txt.spc() - } - txt.nl() + uword[] names = [name1, name2, "name3"] + + uword ww +; for ww in names { +; txt.print(ww) +; txt.spc() +; } +; txt.nl() + ubyte idx=1 + names[idx] = 2000 + txt.print_uw(names[1]) + names[idx]++ + txt.print_uw(names[1]) + names[idx]-- + txt.print_uw(names[1]) + +; names = [1111,2222,3333] +; for ww in names { +; txt.print_uw(ww) +; txt.spc() +; } +; txt.nl() txt.print("end.") - repeat { - } } } diff --git a/intermediate/src/prog8/intermediate/IRFileWriter.kt b/intermediate/src/prog8/intermediate/IRFileWriter.kt index 1cb02ad92..e58f9f050 100644 --- a/intermediate/src/prog8/intermediate/IRFileWriter.kt +++ b/intermediate/src/prog8/intermediate/IRFileWriter.kt @@ -185,8 +185,14 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) { xml.writeStartElement("VARIABLESNOINIT") xml.writeCharacters("\n") for (variable in variablesNoInit) { - val typeStr = getTypeString(variable) - xml.writeCharacters("$typeStr ${variable.name} zp=${variable.zpwish}\n") + if(variable.dt in SplitWordArrayTypes) { + // split into 2 ubyte arrays lsb+msb + xml.writeCharacters("ubyte[${variable.length}] ${variable.name}_lsb zp=${variable.zpwish}\n") + xml.writeCharacters("ubyte[${variable.length}] ${variable.name}_msb zp=${variable.zpwish}\n") + } else { + val typeStr = getTypeString(variable) + xml.writeCharacters("$typeStr ${variable.name} zp=${variable.zpwish}\n") + } } xml.writeEndElement() @@ -195,36 +201,60 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) { xml.writeCharacters("\n") for (variable in variablesWithInit) { - val typeStr = getTypeString(variable) - val value: String = when(variable.dt) { - DataType.FLOAT -> (variable.onetimeInitializationNumericValue ?: "").toString() - in NumericDatatypes -> (variable.onetimeInitializationNumericValue?.toInt()?.toHex() ?: "").toString() - DataType.STR -> { - val encoded = irProgram.encoding.encodeString(variable.onetimeInitializationStringValue!!.first, variable.onetimeInitializationStringValue!!.second) + listOf(0u) - encoded.joinToString(",") { it.toInt().toString() } - } - DataType.ARRAY_F -> { - if(variable.onetimeInitializationArrayValue!=null) { - variable.onetimeInitializationArrayValue!!.joinToString(",") { it.number!!.toString() } - } else { - "" // array will be zero'd out at program start + if(variable.dt in SplitWordArrayTypes) { + val lsbValue: String + val msbValue: String + if(variable.onetimeInitializationArrayValue==null) { + lsbValue = "" + msbValue = "" + } else { + lsbValue = variable.onetimeInitializationArrayValue!!.joinToString(",") { + if(it.number!=null) + (it.number!!.toInt() and 255).toHex() + else + "@<${it.addressOfSymbol}" + } + msbValue = variable.onetimeInitializationArrayValue!!.joinToString(",") { + if(it.number!=null) + (it.number!!.toInt() shr 8).toHex() + else + "@>${it.addressOfSymbol}" } } - in ArrayDatatypes -> { - if(variable.onetimeInitializationArrayValue!==null) { - variable.onetimeInitializationArrayValue!!.joinToString(",") { - if(it.number!=null) - it.number!!.toInt().toHex() - else - "@${it.addressOfSymbol}" + xml.writeCharacters("ubyte[${variable.length}] ${variable.name}_lsb=$lsbValue zp=${variable.zpwish}\n") + xml.writeCharacters("ubyte[${variable.length}] ${variable.name}_msb=$msbValue zp=${variable.zpwish}\n") + } else { + val typeStr = getTypeString(variable) + val value: String = when(variable.dt) { + DataType.FLOAT -> (variable.onetimeInitializationNumericValue ?: "").toString() + in NumericDatatypes -> (variable.onetimeInitializationNumericValue?.toInt()?.toHex() ?: "").toString() + DataType.STR -> { + val encoded = irProgram.encoding.encodeString(variable.onetimeInitializationStringValue!!.first, variable.onetimeInitializationStringValue!!.second) + listOf(0u) + encoded.joinToString(",") { it.toInt().toString() } + } + DataType.ARRAY_F -> { + if(variable.onetimeInitializationArrayValue!=null) { + variable.onetimeInitializationArrayValue!!.joinToString(",") { it.number!!.toString() } + } else { + "" // array will be zero'd out at program start } - } else { - "" // array will be zero'd out at program start } + in ArrayDatatypes -> { + if(variable.onetimeInitializationArrayValue!==null) { + variable.onetimeInitializationArrayValue!!.joinToString(",") { + if(it.number!=null) + it.number!!.toInt().toHex() + else + "@${it.addressOfSymbol}" + } + } else { + "" // array will be zero'd out at program start + } + } + else -> throw InternalCompilerException("weird dt") } - else -> throw InternalCompilerException("weird dt") + xml.writeCharacters("$typeStr ${variable.name}=$value zp=${variable.zpwish}\n") } - xml.writeCharacters("$typeStr ${variable.name}=$value zp=${variable.zpwish}\n") } xml.writeEndElement() xml.writeCharacters("\n") diff --git a/intermediate/src/prog8/intermediate/IRInstructions.kt b/intermediate/src/prog8/intermediate/IRInstructions.kt index a44122973..cbbd8b451 100644 --- a/intermediate/src/prog8/intermediate/IRInstructions.kt +++ b/intermediate/src/prog8/intermediate/IRInstructions.kt @@ -36,15 +36,11 @@ load reg1, value - load immediate value into register. If y loadm reg1, address - load reg1 with value at memory address loadi reg1, reg2 - load reg1 with value at memory indirect, memory pointed to by reg2 loadx reg1, reg2, address - load reg1 with value at memory address indexed by value in reg2 -loadxsplit reg1, reg2, arraylength, arrayaddress - load reg1 word with value from "split lsb/msb array" indexed by reg2 -loadmsplit reg1, arraylength, indexedarrayaddress - load reg1 word with value from "split lsb/msb array" element at indexedarrayaddress loadix reg1, reg2, pointeraddr - load reg1 with value at memory indirect, pointed to by pointeraddr indexed by value in reg2 loadr reg1, reg2 - load reg1 with value in register reg2 storem reg1, address - store reg1 at memory address storei reg1, reg2 - store reg1 at memory indirect, memory pointed to by reg2 storex reg1, reg2, address - store reg1 at memory address, indexed by value in reg2 -storexsplit reg1, reg2, arraylength, arrayaddress - store reg1 word in "split lsb/msb array", indexed by value in reg2 -storemsplit reg1, arraylength, indexedarrayaddress - store reg1 word in "split lsb/msb array" element at indexedarrayaddress storeix reg1, reg2, pointeraddr - store reg1 at memory indirect, pointed to by pointeraddr indexed by value in reg2 storezm address - store zero at memory address storezi reg1 - store zero at memory pointed to by reg1 @@ -121,10 +117,8 @@ exts reg1 - reg1 = signed extension of reg1 (b ext reg1 - reg1 = unsigned extension of reg1 (which in practice just means clearing the MSB / MSW) (ext.w not yet implemented as we don't have longs yet) inc reg1 - reg1 = reg1+1 incm address - memory at address += 1 -incmsplit arraylen, address - memory at address += 1 (in lsb/msb split word array) dec reg1 - reg1 = reg1-1 decm address - memory at address -= 1 -decmsplit arraylen, address - memory at address -= 1 (in lsb/msb split word array) neg reg1 - reg1 = sign negation of reg1 negm address - sign negate memory at address addr reg1, reg2 - reg1 += reg2 @@ -233,21 +227,15 @@ enum class Opcode { LOADM, LOADI, LOADX, - LOADXSPLIT, - LOADMSPLIT, LOADIX, LOADR, STOREM, STOREI, STOREX, - STOREXSPLIT, - STOREMSPLIT, STOREIX, STOREZM, STOREZI, STOREZX, - STOREZXSPLIT, - STOREZMSPLIT, JUMP, JUMPA, @@ -295,10 +283,8 @@ enum class Opcode { INC, INCM, - INCMSPLIT, DEC, DECM, - DECMSPLIT, NEG, NEGM, ADDR, @@ -516,21 +502,15 @@ val instructionFormats = mutableMapOf( Opcode.LOADM to InstructionFormat.from("BW,>r1,fr1,r1,fr1,r1,fr1,r1,r1,r1,fr1,r1,fr1,a | F,a"), Opcode.STOREI to InstructionFormat.from("BW,a | F,a"), - Opcode.STOREXSPLIT to InstructionFormat.from("W,a"), - Opcode.STOREMSPLIT to InstructionFormat.from("W,a"), Opcode.STOREIX to InstructionFormat.from("BW,a | F,a"), Opcode.STOREZM to InstructionFormat.from("BW,>a | F,>a"), Opcode.STOREZI to InstructionFormat.from("BW,a | F,a"), - Opcode.STOREZMSPLIT to InstructionFormat.from("W,a"), - Opcode.STOREZXSPLIT to InstructionFormat.from("W,a"), Opcode.JUMP to InstructionFormat.from("N,r1,r1 | F,<>fr1"), Opcode.INCM to InstructionFormat.from("BW,<>a | F,<>a"), - Opcode.INCMSPLIT to InstructionFormat.from("W,a"), Opcode.DEC to InstructionFormat.from("BW,<>r1 | F,<>fr1"), Opcode.DECM to InstructionFormat.from("BW,<>a | F,<>a"), - Opcode.DECMSPLIT to InstructionFormat.from("W,a"), Opcode.NEG to InstructionFormat.from("BW,<>r1 | F,<>fr1"), Opcode.NEGM to InstructionFormat.from("BW,<>a | F,<>a"), Opcode.ADDR to InstructionFormat.from("BW,<>r1,fr1, "ubyte[]" DataType.ARRAY_B -> "byte[]" DataType.ARRAY_UW -> "uword[]" - DataType.ARRAY_UW_SPLIT -> "uword_split[]" DataType.ARRAY_W -> "word[]" - DataType.ARRAY_W_SPLIT -> "word_split[]" DataType.ARRAY_F -> "float[]" + in SplitWordArrayTypes -> throw InternalCompilerException("split array should have been converted to 2 ubyte arrays") else -> throw InternalCompilerException("weird dt") } @@ -31,10 +30,9 @@ fun getTypeString(memvar: StMemVar): String = when(memvar.dt) { DataType.ARRAY_UB, DataType.STR -> "ubyte[${memvar.length}]" DataType.ARRAY_B -> "byte[${memvar.length}]" DataType.ARRAY_UW -> "uword[${memvar.length}]" - DataType.ARRAY_UW_SPLIT -> "uword_split[${memvar.length}]" DataType.ARRAY_W -> "word[${memvar.length}]" - DataType.ARRAY_W_SPLIT -> "word_split[${memvar.length}]" DataType.ARRAY_F -> "float[${memvar.length}]" + in SplitWordArrayTypes -> throw InternalCompilerException("@split can't be used on memory mapped arrays") else -> throw InternalCompilerException("weird dt") } @@ -48,10 +46,9 @@ fun getTypeString(variable : StStaticVariable): String = when(variable.dt) { DataType.ARRAY_UB, DataType.STR -> "ubyte[${variable.length}]" DataType.ARRAY_B -> "byte[${variable.length}]" DataType.ARRAY_UW -> "uword[${variable.length}]" - DataType.ARRAY_UW_SPLIT -> "uword_split[${variable.length}]" DataType.ARRAY_W -> "word[${variable.length}]" - DataType.ARRAY_W_SPLIT -> "word_split[${variable.length}]" DataType.ARRAY_F -> "float[${variable.length}]" + in SplitWordArrayTypes -> throw InternalCompilerException("split array should have been converted to 2 ubyte arrays") else -> throw InternalCompilerException("weird dt") } @@ -78,6 +75,8 @@ fun parseIRValue(value: String): Float { throw IRParseException("attempt to parse a label as numeric value") else if(value.startsWith('&')) throw IRParseException("address-of should be done with normal LOAD ") + else if(value.startsWith('@')) + throw IRParseException("address-of @ should have been handled earlier") else return value.toFloat() } diff --git a/virtualmachine/src/prog8/vm/VirtualMachine.kt b/virtualmachine/src/prog8/vm/VirtualMachine.kt index dfc068d34..9918fa3d5 100644 --- a/virtualmachine/src/prog8/vm/VirtualMachine.kt +++ b/virtualmachine/src/prog8/vm/VirtualMachine.kt @@ -164,17 +164,11 @@ class VirtualMachine(irProgram: IRProgram) { Opcode.LOAD -> InsLOAD(ins) Opcode.LOADM -> InsLOADM(ins) Opcode.LOADX -> InsLOADX(ins) - Opcode.LOADXSPLIT -> InsLOADXSPLIT(ins) - Opcode.LOADMSPLIT -> InsLOADMSPLIT(ins) Opcode.LOADI -> InsLOADI(ins) Opcode.LOADIX -> InsLOADIX(ins) Opcode.LOADR -> InsLOADR(ins) Opcode.STOREM -> InsSTOREM(ins) Opcode.STOREX -> InsSTOREX(ins) - Opcode.STOREXSPLIT -> InsSTOREXSPLIT(ins) - Opcode.STOREZXSPLIT -> InsSTOREZXSPLIT(ins) - Opcode.STOREMSPLIT -> InsSTOREMSPLIT(ins) - Opcode.STOREZMSPLIT -> InsSTOREZMSPLIT(ins) Opcode.STOREIX -> InsSTOREIX(ins) Opcode.STOREI -> InsSTOREI(ins) Opcode.STOREZM -> InsSTOREZM(ins) @@ -223,10 +217,8 @@ class VirtualMachine(irProgram: IRProgram) { Opcode.SGES -> InsSGES(ins) Opcode.INC -> InsINC(ins) Opcode.INCM -> InsINCM(ins) - Opcode.INCMSPLIT -> InsINCMSPLIT(ins) Opcode.DEC -> InsDEC(ins) Opcode.DECM -> InsDECM(ins) - Opcode.DECMSPLIT -> InsDECMSPLIT(ins) Opcode.NEG -> InsNEG(ins) Opcode.NEGM -> InsNEGM(ins) Opcode.ADDR -> InsADDR(ins) @@ -421,60 +413,6 @@ class VirtualMachine(irProgram: IRProgram) { nextPc() } - private fun InsLOADXSPLIT(i: IRInstruction) { - require(i.type==IRDataType.WORD) - val address = i.address!! + registers.getUW(i.reg2!!).toInt() - val lsb = memory.getUB(address) - val msb = memory.getUB(address+i.immediate!!) - registers.setUW(i.reg1!!, ((msb.toInt() shl 8) or lsb.toInt()).toUShort()) - nextPc() - } - - private fun InsLOADMSPLIT(i: IRInstruction) { - require(i.type==IRDataType.WORD) - val address = i.address!! - val lsb = memory.getUB(address) - val msb = memory.getUB(address+i.immediate!!) - registers.setUW(i.reg1!!, ((msb.toInt() shl 8) or lsb.toInt()).toUShort()) - nextPc() - } - - private fun InsSTOREXSPLIT(i: IRInstruction) { - require(i.type==IRDataType.WORD) - val address = i.address!! + registers.getUW(i.reg2!!).toInt() - val lsb = registers.getUW(i.reg1!!).toUByte() - val msb = (registers.getUW(i.reg1!!).toInt() shr 8).toUByte() - memory.setUB(address, lsb) - memory.setUB(address+i.immediate!!, msb) - nextPc() - } - - private fun InsSTOREMSPLIT(i: IRInstruction) { - require(i.type==IRDataType.WORD) - val address = i.address!! - val lsb = registers.getUW(i.reg1!!).toUByte() - val msb = (registers.getUW(i.reg1!!).toInt() shr 8).toUByte() - memory.setUB(address, lsb) - memory.setUB(address+i.immediate!!, msb) - nextPc() - } - - private fun InsSTOREZXSPLIT(i: IRInstruction) { - require(i.type==IRDataType.WORD) - val address = i.address!! + registers.getUW(i.reg2!!).toInt() - memory.setUB(address, 0u) - memory.setUB(address+i.immediate!!, 0u) - nextPc() - } - - private fun InsSTOREZMSPLIT(i: IRInstruction) { - require(i.type==IRDataType.WORD) - val address = i.address!! - memory.setUB(address, 0u) - memory.setUB(address+i.immediate!!, 0u) - nextPc() - } - private fun InsLOADIX(i: IRInstruction) { when (i.type!!) { IRDataType.BYTE -> { @@ -921,20 +859,6 @@ class VirtualMachine(irProgram: IRProgram) { nextPc() } - private fun InsINCMSPLIT(i: IRInstruction) { - val address = i.address!! - var lsb = memory.getUB(address).toInt() - var msb = memory.getUB(address+i.immediate!!).toInt() - lsb++ - if(lsb>255) { - lsb = 0 - msb++ - } - memory.setUB(address, lsb.toUByte()) - memory.setUB(address+i.immediate!!, msb.toUByte()) - nextPc() - } - private fun InsDEC(i: IRInstruction) { when(i.type!!) { IRDataType.BYTE -> registers.setUB(i.reg1!!, (registers.getUB(i.reg1!!)-1u).toUByte()) @@ -953,21 +877,6 @@ class VirtualMachine(irProgram: IRProgram) { nextPc() } - private fun InsDECMSPLIT(i: IRInstruction) { - val address = i.address!! - var lsb = memory.getUB(address).toInt() - var msb = memory.getUB(address+i.immediate!!).toInt() - lsb-- - if(lsb<0) { - lsb = 255 - msb-- - } - memory.setUB(address, lsb.toUByte()) - memory.setUB(address+i.immediate!!, msb.toUByte()) - nextPc() - - } - private fun InsNEG(i: IRInstruction) { when(i.type!!) { IRDataType.BYTE -> registers.setUB(i.reg1!!, (-registers.getUB(i.reg1!!).toInt()).toUByte()) diff --git a/virtualmachine/src/prog8/vm/VmProgramLoader.kt b/virtualmachine/src/prog8/vm/VmProgramLoader.kt index 2529be290..8d97f3599 100644 --- a/virtualmachine/src/prog8/vm/VmProgramLoader.kt +++ b/virtualmachine/src/prog8/vm/VmProgramLoader.kt @@ -295,7 +295,20 @@ class VmProgramLoader { when(variable.dt) { DataType.STR, DataType.ARRAY_UB -> { for(elt in it) { - memory.setUB(addr, elt.number!!.toInt().toUByte()) + if(elt.addressOfSymbol!=null) { + val name = elt.addressOfSymbol!! + val symbolAddress = if(name.startsWith('<')) { + symbolAddresses[name.drop(1)]?.and(255) + ?: throw IRParseException("vm cannot yet load a label address as a value: $name") // TODO + } else if(name.startsWith('>')) { + symbolAddresses[name.drop(1)]?.shr(8) + ?: throw IRParseException("vm cannot yet load a label address as a value: $name") // TODO + } else + throw IRParseException("for byte-array address-of, expected < or > (lsb/msb)") + memory.setUB(addr, symbolAddress.toUByte()) + } else { + memory.setUB(addr, elt.number!!.toInt().toUByte()) + } addr++ } }