From c94e292176e271e6e58156a277564e1ad826a572 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Fri, 26 May 2023 22:56:12 +0200 Subject: [PATCH] more split array stuff --- codeCore/src/prog8/code/ast/AstExpressions.kt | 12 ++-- codeCore/src/prog8/code/ast/AstPrinter.kt | 2 +- codeCore/src/prog8/code/core/Enumerations.kt | 1 + .../src/prog8/codegen/cpu6502/AsmGen.kt | 4 ++ .../codegen/cpu6502/BuiltinFunctionsAsmGen.kt | 10 +++ .../codegen/cpu6502/ExpressionsAsmGen.kt | 6 ++ .../codegen/cpu6502/ProgramAndVarsGen.kt | 2 +- .../cpu6502/assignment/AsmAssignment.kt | 4 +- .../codegen/intermediate/AssignmentGen.kt | 45 +++++++++--- .../codegen/intermediate/ExpressionGen.kt | 17 +++++ .../prog8/codegen/intermediate/IRCodeGen.kt | 69 +++++++++++-------- .../optimizer/ConstantIdentifierReplacer.kt | 2 +- .../compiler/astprocessing/AstChecker.kt | 29 ++++---- compiler/test/TestMemory.kt | 14 ++-- .../test/codegeneration/TestAsmGenSymbols.kt | 6 +- docs/source/todo.rst | 1 + examples/test.p8 | 36 +++++++++- .../src/prog8/intermediate/IRInstructions.kt | 16 +++++ virtualmachine/src/prog8/vm/VirtualMachine.kt | 60 ++++++++++++++++ .../src/prog8/vm/VmProgramLoader.kt | 33 +++++---- 20 files changed, 278 insertions(+), 91 deletions(-) diff --git a/codeCore/src/prog8/code/ast/AstExpressions.kt b/codeCore/src/prog8/code/ast/AstExpressions.kt index 44c038ebe..472c0d2a8 100644 --- a/codeCore/src/prog8/code/ast/AstExpressions.kt +++ b/codeCore/src/prog8/code/ast/AstExpressions.kt @@ -1,9 +1,6 @@ package prog8.code.ast -import prog8.code.core.DataType -import prog8.code.core.Encoding -import prog8.code.core.NumericDatatypes -import prog8.code.core.Position +import prog8.code.core.* import java.util.* import kotlin.math.abs import kotlin.math.round @@ -28,7 +25,7 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit infix fun isSameAs(other: PtExpression): Boolean { return when(this) { is PtAddressOf -> other is PtAddressOf && other.type==type && other.identifier isSameAs identifier - is PtArrayIndexer -> other is PtArrayIndexer && other.type==type && other.variable isSameAs variable && other.index isSameAs index + is PtArrayIndexer -> other is PtArrayIndexer && other.type==type && other.variable isSameAs variable && other.index isSameAs index && other.splitWords==splitWords is PtBinaryExpression -> other is PtBinaryExpression && other.left isSameAs left && other.right isSameAs right is PtContainmentCheck -> other is PtContainmentCheck && other.type==type && other.element isSameAs element && other.iterable isSameAs iterable is PtIdentifier -> other is PtIdentifier && other.type==type && other.name==name @@ -51,7 +48,7 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit this.name == target.identifier!!.name } target.array != null && this is PtArrayIndexer -> { - this.variable.name == target.array!!.variable.name && this.index isSameAs target.array!!.index + this.variable.name == target.array!!.variable.name && this.index isSameAs target.array!!.index && this.splitWords==target.array!!.splitWords } else -> false } @@ -118,6 +115,9 @@ class PtArrayIndexer(elementType: DataType, position: Position): PtExpression(el val index: PtExpression get() = children[1] as PtExpression + val splitWords: Boolean + get() = variable.type in SplitWordArrayTypes + init { require(elementType in NumericDatatypes) } diff --git a/codeCore/src/prog8/code/ast/AstPrinter.kt b/codeCore/src/prog8/code/ast/AstPrinter.kt index f120a70b6..0c64bf454 100644 --- a/codeCore/src/prog8/code/ast/AstPrinter.kt +++ b/codeCore/src/prog8/code/ast/AstPrinter.kt @@ -17,7 +17,7 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni is PtConditionalBranch -> "if_${node.condition.name.lowercase()}" is PtAddressOf -> "&" is PtArray -> "array len=${node.children.size} ${type(node.type)}" - is PtArrayIndexer -> " ${type(node.type)}" + is PtArrayIndexer -> " ${type(node.type)} ${if(node.splitWords) "[splitwords]" else ""}" is PtBinaryExpression -> " ${node.operator} ${type(node.type)}" is PtBuiltinFunctionCall -> { val str = if(node.void) "void " else "" diff --git a/codeCore/src/prog8/code/core/Enumerations.kt b/codeCore/src/prog8/code/core/Enumerations.kt index 58b5740cb..b5f33d19a 100644 --- a/codeCore/src/prog8/code/core/Enumerations.kt +++ b/codeCore/src/prog8/code/core/Enumerations.kt @@ -123,6 +123,7 @@ val NumericDatatypesNoBool = arrayOf(DataType.UBYTE, DataType.BYTE, DataType.UWO val SignedDatatypes = arrayOf(DataType.BYTE, DataType.WORD, DataType.FLOAT) val ArrayDatatypes = arrayOf(DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_UW_SPLIT, DataType.ARRAY_W, DataType.ARRAY_W_SPLIT, DataType.ARRAY_F, DataType.ARRAY_BOOL) val StringlyDatatypes = arrayOf(DataType.STR, DataType.ARRAY_UB, DataType.ARRAY_B, DataType.UWORD) +val SplitWordArrayTypes = arrayOf(DataType.ARRAY_UW_SPLIT, DataType.ARRAY_W_SPLIT) val IterableDatatypes = arrayOf( DataType.STR, DataType.ARRAY_UB, DataType.ARRAY_B, diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt index 23f9a7de5..2fb90a192 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt @@ -377,6 +377,10 @@ class AsmGen6502Internal ( ?: throw AssemblyError("array indexer should have been replaced with a temp var @ ${expr.index.position}") val indexName = asmVariableName(indexVar) + + if(expr.splitWords) + TODO("split word access ${expr.position}") + if (addOneExtra) { // add 1 to the result when (elementDt) { diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt index edfafc528..fcec7b005 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt @@ -432,6 +432,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, DataType.UWORD -> { when (what) { is PtArrayIndexer -> { + if(what.splitWords) + TODO("splitwords ${what.position}") translateRolRorArrayArgs(what.variable, what, "ror2", 'w') asmgen.out(" jsr prog8_lib.ror2_array_uw") } @@ -491,6 +493,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, DataType.UWORD -> { when (what) { is PtArrayIndexer -> { + if(what.splitWords) + TODO("splitwords ${what.position}") translateRolRorArrayArgs(what.variable, what, "ror", 'w') asmgen.out(" jsr prog8_lib.ror_array_uw") } @@ -533,6 +537,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, DataType.UWORD -> { when (what) { is PtArrayIndexer -> { + if(what.splitWords) + TODO("splitwords ${what.position}") translateRolRorArrayArgs(what.variable, what, "rol2", 'w') asmgen.out(" jsr prog8_lib.rol2_array_uw") } @@ -592,6 +598,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, DataType.UWORD -> { when (what) { is PtArrayIndexer -> { + if(what.splitWords) + TODO("splitwords ${what.position}") translateRolRorArrayArgs(what.variable, what, "rol", 'w') asmgen.out(" jsr prog8_lib.rol_array_uw") } @@ -607,6 +615,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, } private fun translateRolRorArrayArgs(arrayvar: PtIdentifier, indexer: PtArrayIndexer, operation: String, dt: Char) { + if(indexer.splitWords) + TODO("split word access ${indexer.position}") if(arrayvar.type==DataType.UWORD) { if(dt!='b') throw AssemblyError("non-array var indexing requires bytes dt") diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ExpressionsAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ExpressionsAsmGen.kt index 1b74cb6aa..c0f11a4c1 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ExpressionsAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ExpressionsAsmGen.kt @@ -237,6 +237,9 @@ internal class ExpressionsAsmGen(private val program: PtProgram, DataType.FLOAT -> { asmgen.out(" lda #<$varname | ldy #>$varname| jsr floats.push_float") } + in SplitWordArrayTypes -> { + TODO("split $varname") + } in IterableDatatypes -> { asmgen.out(" lda #<$varname | sta P8ESTACK_LO,x | lda #>$varname | sta P8ESTACK_HI,x | dex") } @@ -744,6 +747,9 @@ internal class ExpressionsAsmGen(private val program: PtProgram, val elementDt = arrayExpr.type val arrayVarName = asmgen.asmVariableName(arrayExpr.variable) + if(arrayExpr.splitWords) + TODO("split word access ${arrayExpr.position}") + if(arrayExpr.variable.type==DataType.UWORD) { // indexing a pointer var instead of a real array or string if(elementDt !in ByteDatatypes) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt index 04502e95f..e0e40c3ed 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt @@ -730,7 +730,7 @@ internal class ProgramAndVarsGen( val number = it.number!!.toInt() "$" + number.toString(16).padStart(4, '0') } - DataType.ARRAY_W, DataType.ARRAY_W_SPLIT -> array.map { + in SplitWordArrayTypes -> array.map { val number = it.number!!.toInt() val hexnum = number.absoluteValue.toString(16).padStart(4, '0') if(number>=0) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt index 9f7b9cc9b..ac9685237 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt @@ -115,7 +115,7 @@ internal class AsmAssignTarget(val kind: TargetStorageKind, left is PtIdentifier && left.name==scopedName } TargetStorageKind.ARRAY -> { - left is PtArrayIndexer && left isSameAs array!! + left is PtArrayIndexer && left isSameAs array!! && left.splitWords==array.splitWords } TargetStorageKind.MEMORY -> { left isSameAs memory!! @@ -172,6 +172,8 @@ internal class AsmAssignSource(val kind: SourceStorageKind, AsmAssignSource(SourceStorageKind.MEMORY, program, asmgen, DataType.UBYTE, memory = value) } is PtArrayIndexer -> { + if(value.splitWords) + TODO("splitwords ${value.position}") AsmAssignSource(SourceStorageKind.ARRAY, program, asmgen, value.type, array = value) } is PtBuiltinFunctionCall -> { diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt index 29ad7f341..c3aa837a5 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt @@ -1,5 +1,6 @@ package prog8.codegen.intermediate +import prog8.code.StStaticVariable import prog8.code.ast.* import prog8.code.core.AssemblyError import prog8.code.core.DataType @@ -235,36 +236,60 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express } val fixedIndex = constIntValue(targetArray.index) + val iterable = codeGen.symbolTable.flat.getValue(targetArray.variable.name) as StStaticVariable + val arrayLength = iterable.length!! if(zero) { if(fixedIndex!=null) { - val offset = fixedIndex*itemsize - val chunk = IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREZM, targetDt, labelSymbol = "$variable+$offset") } + val chunk = IRCodeChunk(null, null).also { + it += if(targetArray.splitWords) + IRInstruction(Opcode.STOREZMSPLIT, targetDt, immediate = arrayLength, labelSymbol = "$variable+$fixedIndex") + else + 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 += IRInstruction(Opcode.STOREZX, targetDt, reg1=indexReg, labelSymbol = variable) } + result += IRCodeChunk(null, null).also { + it += if(targetArray.splitWords) + IRInstruction(Opcode.STOREZXSPLIT, targetDt, reg1 = valueRegister, reg2=indexReg, immediate = arrayLength, labelSymbol = variable) + else + IRInstruction(Opcode.STOREZX, targetDt, reg1=indexReg, labelSymbol = variable) + } } } else { if(targetDt== IRDataType.FLOAT) { if(fixedIndex!=null) { val offset = fixedIndex*itemsize - val chunk = IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREM, targetDt, fpReg1 = valueFpRegister, labelSymbol = "$variable+$offset") } + val chunk = IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.STOREM, targetDt, fpReg1 = valueFpRegister, labelSymbol = "$variable+$offset") + } result += chunk } else { val (code, indexReg) = loadIndexReg(targetArray, itemsize) result += code - result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREX, targetDt, reg1 = indexReg, fpReg1 = valueFpRegister, labelSymbol = variable) } + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.STOREX, targetDt, reg1 = indexReg, fpReg1 = valueFpRegister, labelSymbol = variable) + } } } else { if(fixedIndex!=null) { - val offset = fixedIndex*itemsize - val chunk = IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREM, targetDt, reg1 = valueRegister, labelSymbol = "$variable+$offset") } + val chunk = IRCodeChunk(null, null).also { + it += if(targetArray.splitWords) + IRInstruction(Opcode.STOREMSPLIT, targetDt, reg1 = valueRegister, immediate = arrayLength, labelSymbol = "$variable+$fixedIndex") + else + 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 += IRInstruction(Opcode.STOREX, targetDt, reg1 = valueRegister, reg2=indexReg, labelSymbol = variable) } + result += IRCodeChunk(null, null).also { + it += if(targetArray.splitWords) + IRInstruction(Opcode.STOREXSPLIT, targetDt, reg1 = valueRegister, reg2=indexReg, immediate = arrayLength, labelSymbol = variable) + else + IRInstruction(Opcode.STOREX, targetDt, reg1 = valueRegister, reg2=indexReg, labelSymbol = variable) + } } } } @@ -301,10 +326,10 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express } private fun loadIndexReg(array: PtArrayIndexer, itemsize: Int): Pair { - // returns the code to load the Index into the register, which is also return\ed. + // returns the code to load the Index into the register, which is also returned. val result = mutableListOf() - if(itemsize==1) { + if(itemsize==1 || array.splitWords) { val tr = expressionEval.translateExpression(array.index) addToResult(result, tr, tr.resultReg, -1) return Pair(result, tr.resultReg) diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt index d270f1786..ef2cda50b 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt @@ -160,6 +160,23 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { } var resultRegister = -1 + + if(arrayIx.splitWords) { + require(vmDt==IRDataType.WORD) + val iterable = codeGen.symbolTable.flat.getValue(arrayIx.variable.name) as StStaticVariable + val arrayLength = iterable.length!! + 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) + } 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) + } + return ExpressionCodeResult(result, vmDt, resultRegister, -1) + } + var resultFpRegister = -1 if(arrayIx.index is PtNumber) { val memOffset = ((arrayIx.index as PtNumber).number.toInt() * eltSize).toString() diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt index 4660ed21e..76852e67e 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt @@ -456,46 +456,59 @@ class IRCodeGen( val endLabel = createLabelName() if(iterableVar.dt==DataType.STR) { // iterate over a zero-terminated string - addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, immediate = 0), null) + 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) + 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 += translateNode(forLoop.statements) val jumpChunk = IRCodeChunk(null, null) - jumpChunk += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=indexReg) + jumpChunk += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1 = indexReg) jumpChunk += IRInstruction(Opcode.JUMP, labelSymbol = loopLabel) result += jumpChunk result += IRCodeChunk(endLabel, null) + } else if(iterable.type in SplitWordArrayTypes) { + // iterate over lsb/msb split word array + val elementDt = ArrayToElementTypes.getValue(iterable.type) + if(elementDt !in WordDatatypes) + throw AssemblyError("weird dt") + 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) + } + result += translateNode(forLoop.statements) + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=indexReg) + it += IRInstruction(Opcode.BNE, IRDataType.BYTE, reg1=indexReg, immediate = if(length==256) 0 else length, labelSymbol = loopLabel) + } } else { - // iterate over array + // iterate over regular array val elementDt = ArrayToElementTypes.getValue(iterable.type) val elementSize = program.memsizer.memorySize(elementDt) val lengthBytes = iterableVar.length!! * elementSize - if(lengthBytes<256) { - val chunk = IRCodeChunk(null, null) - chunk += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, immediate = 0) - result += chunk - val chunk2 = IRCodeChunk(loopLabel, null) - chunk2 += IRInstruction(Opcode.LOADX, irType(elementDt), reg1=tmpReg, reg2=indexReg, labelSymbol=iterable.name) - chunk2 += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=tmpReg, labelSymbol = loopvarSymbol) - result += chunk2 - result += translateNode(forLoop.statements) - result += addConstReg(IRDataType.BYTE, indexReg, elementSize) - addInstr(result, IRInstruction(Opcode.BNE, IRDataType.BYTE, reg1=indexReg, immediate = lengthBytes, labelSymbol = loopLabel), null) - } else if(lengthBytes==256) { - addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, immediate = 0), null) - val chunk = IRCodeChunk(loopLabel, null) - chunk += IRInstruction(Opcode.LOADX, irType(elementDt), reg1=tmpReg, reg2=indexReg, labelSymbol=iterable.name) - chunk += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=tmpReg, labelSymbol = loopvarSymbol) - result += chunk - result += translateNode(forLoop.statements) - result += addConstReg(IRDataType.BYTE, indexReg, elementSize) - addInstr(result, IRInstruction(Opcode.BNE, IRDataType.BYTE, reg1=indexReg, immediate = 0, labelSymbol = loopLabel), null) - } else { - throw AssemblyError("iterator length should never exceed 256") + addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, immediate = 0), null) + result += IRCodeChunk(loopLabel, null).also { + it += IRInstruction(Opcode.LOADX, irType(elementDt), reg1=tmpReg, reg2=indexReg, labelSymbol=iterable.name) + it += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=tmpReg, labelSymbol = loopvarSymbol) } + result += translateNode(forLoop.statements) + result += addConstReg(IRDataType.BYTE, indexReg, elementSize) + addInstr(result, IRInstruction(Opcode.BNE, IRDataType.BYTE, reg1=indexReg, immediate = if(lengthBytes==256) 0 else lengthBytes, labelSymbol = loopLabel), null) } } else -> throw AssemblyError("weird for iterable") diff --git a/codeOptimizers/src/prog8/optimizer/ConstantIdentifierReplacer.kt b/codeOptimizers/src/prog8/optimizer/ConstantIdentifierReplacer.kt index 5bb2bceb7..ed24d22d8 100644 --- a/codeOptimizers/src/prog8/optimizer/ConstantIdentifierReplacer.kt +++ b/codeOptimizers/src/prog8/optimizer/ConstantIdentifierReplacer.kt @@ -275,7 +275,7 @@ internal class ConstantIdentifierReplacer(private val program: Program, private return listOf(IAstModification.ReplaceNode(decl.value!!, newValue, decl)) } } - DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W -> { + DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W, DataType.ARRAY_W_SPLIT, DataType.ARRAY_UW_SPLIT -> { val rangeExpr = decl.value as? RangeExpression if(rangeExpr!=null) { // convert the initializer range expression to an actual array diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index f64a39112..b30cc5845 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -628,12 +628,12 @@ internal class AstChecker(private val program: Program, DataType.ARRAY_B, DataType.ARRAY_UB -> if(arraySize > 256) err("byte array length must be 1-256") + in SplitWordArrayTypes -> + if(arraySize > 256) + err("split word array length must be 1-256") DataType.ARRAY_W, DataType.ARRAY_UW -> if(arraySize > 128) err("word array length must be 1-128") - DataType.ARRAY_W_SPLIT, DataType.ARRAY_UW_SPLIT -> - if(arraySize > 256) - err("split word array length must be 1-256") DataType.ARRAY_F -> if(arraySize > 51) err("float array length must be 1-51") @@ -679,6 +679,10 @@ internal class AstChecker(private val program: Program, if (length == 0 || length > 256) err("string and byte array length must be 1-256") } + in SplitWordArrayTypes -> { + if (length == 0 || length > 256) + err("split word array length must be 1-256") + } DataType.ARRAY_UW, DataType.ARRAY_W -> { if (length == 0 || length > 128) err("word array length must be 1-128") @@ -1279,7 +1283,7 @@ internal class AstChecker(private val program: Program, // check index value 0..255 val dtxNum = arrayIndexedExpression.indexer.indexExpr.inferType(program) - if(dtxNum isnot DataType.UBYTE && dtxNum isnot DataType.BYTE) + if(dtxNum.isKnown && dtxNum isnot DataType.UBYTE && dtxNum isnot DataType.BYTE) errors.err("array indexing is limited to byte size 0..255", arrayIndexedExpression.position) super.visit(arrayIndexedExpression) @@ -1429,29 +1433,26 @@ internal class AstChecker(private val program: Program, } return err("invalid byte array initialization value ${value.type}, expected $targetDt") } - DataType.ARRAY_UW, DataType.ARRAY_W -> { + DataType.ARRAY_UW, DataType.ARRAY_W, DataType.ARRAY_W_SPLIT, DataType.ARRAY_UW_SPLIT-> { // value may be either a single word, or a word arraysize, or a range if(value.type istype targetDt) { if(!checkArrayValues(value, targetDt)) return false val arraySpecSize = arrayspec.constIndex() val arraySize = value.value.size + val maxLength = if(targetDt in SplitWordArrayTypes) 256 else 128 if(arraySpecSize!=null && arraySpecSize>0) { - if(arraySpecSize>128) - return err("word array length must be 1-128") + if(arraySpecSize>maxLength) + return err("array length must be 1-$maxLength") val expectedSize = arrayspec.constIndex() ?: return err("array size specifier must be constant integer value") if (arraySize != expectedSize) return err("initializer array size mismatch (expecting $expectedSize, got $arraySize)") return true } - return err("invalid word array size, must be 1-128") + return err("invalid array size, must be 1-$maxLength") } return err("invalid word array initialization value ${value.type}, expected $targetDt") } - DataType.ARRAY_UW_SPLIT, DataType.ARRAY_W_SPLIT -> { - return true - TODO("check split array type") - } DataType.ARRAY_F -> { // value may be either a single float, or a float arraysize if(value.type istype targetDt) { @@ -1555,10 +1556,10 @@ internal class AstChecker(private val program: Program, DataType.ARRAY_B -> { correct = array.all { it in -128..127 } } - DataType.ARRAY_UW -> { + DataType.ARRAY_UW, DataType.ARRAY_UW_SPLIT -> { correct = array.all { (it in 0..65535) } } - DataType.ARRAY_W -> { + DataType.ARRAY_W, DataType.ARRAY_W_SPLIT -> { correct = array.all { it in -32768..32767 } } DataType.ARRAY_F -> correct = true diff --git a/compiler/test/TestMemory.kt b/compiler/test/TestMemory.kt index 55df8a6c1..834f3e46e 100644 --- a/compiler/test/TestMemory.kt +++ b/compiler/test/TestMemory.kt @@ -112,7 +112,7 @@ class TestMemory: FunSpec({ } fun createTestProgramForMemoryRefViaVar(address: UInt, vartype: VarDeclType): AssignTarget { - val decl = VarDecl(vartype, VarDeclOrigin.USERCODE, DataType.BYTE, ZeropageWish.DONTCARE, null, "address", NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, Position.DUMMY) + val decl = VarDecl(vartype, VarDeclOrigin.USERCODE, DataType.BYTE, ZeropageWish.DONTCARE, null, "address", NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, false, Position.DUMMY) val memexpr = IdentifierReference(listOf("address"), Position.DUMMY) val target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY) val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) @@ -150,7 +150,7 @@ class TestMemory: FunSpec({ } test("regular variable not in mapped IO ram on C64") { - val decl = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.BYTE, ZeropageWish.DONTCARE, null, "address", null, false, false, Position.DUMMY) + val decl = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.BYTE, ZeropageWish.DONTCARE, null, "address", null, false, false, false, Position.DUMMY) val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY) val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) val subroutine = Subroutine("test", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, false, mutableListOf(decl, assignment), Position.DUMMY) @@ -162,7 +162,7 @@ class TestMemory: FunSpec({ test("memory mapped variable not in mapped IO ram on C64") { val address = 0x1000u - val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.UBYTE, ZeropageWish.DONTCARE, null, "address", NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, Position.DUMMY) + val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.UBYTE, ZeropageWish.DONTCARE, null, "address", NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, false, Position.DUMMY) val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY) val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) val subroutine = Subroutine("test", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, false, mutableListOf(decl, assignment), Position.DUMMY) @@ -174,7 +174,7 @@ class TestMemory: FunSpec({ test("memory mapped variable in mapped IO ram on C64") { val address = 0xd020u - val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.UBYTE, ZeropageWish.DONTCARE, null, "address", NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, Position.DUMMY) + val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.UBYTE, ZeropageWish.DONTCARE, null, "address", NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, false, Position.DUMMY) val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY) val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) val subroutine = Subroutine("test", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, false, mutableListOf(decl, assignment), Position.DUMMY) @@ -185,7 +185,7 @@ class TestMemory: FunSpec({ } test("array not in mapped IO ram") { - val decl = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", null, false, false, Position.DUMMY) + val decl = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", null, false, false, false, Position.DUMMY) val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteral.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY) val target = AssignTarget(null, arrayindexed, null, Position.DUMMY) val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) @@ -198,7 +198,7 @@ class TestMemory: FunSpec({ test("memory mapped array not in mapped IO ram") { val address = 0x1000u - val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, Position.DUMMY) + val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, false, Position.DUMMY) val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteral.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY) val target = AssignTarget(null, arrayindexed, null, Position.DUMMY) val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) @@ -211,7 +211,7 @@ class TestMemory: FunSpec({ test("memory mapped array in mapped IO ram") { val address = 0xd800u - val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, Position.DUMMY) + val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, false, Position.DUMMY) val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteral.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY) val target = AssignTarget(null, arrayindexed, null, Position.DUMMY) val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) diff --git a/compiler/test/codegeneration/TestAsmGenSymbols.kt b/compiler/test/codegeneration/TestAsmGenSymbols.kt index c24cfb505..6a92ca16d 100644 --- a/compiler/test/codegeneration/TestAsmGenSymbols.kt +++ b/compiler/test/codegeneration/TestAsmGenSymbols.kt @@ -46,8 +46,8 @@ class TestAsmGenSymbols: StringSpec({ } */ - val varInSub = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.UWORD, ZeropageWish.DONTCARE, null, "localvar", NumericLiteral.optimalInteger(1234, Position.DUMMY), false, false, Position.DUMMY) - val var2InSub = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.UWORD, ZeropageWish.DONTCARE, null, "tgt", null, false, false, Position.DUMMY) + val varInSub = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.UWORD, ZeropageWish.DONTCARE, null, "localvar", NumericLiteral.optimalInteger(1234, Position.DUMMY), false, false, false, Position.DUMMY) + val var2InSub = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.UWORD, ZeropageWish.DONTCARE, null, "tgt", null, false, false, false, Position.DUMMY) val labelInSub = Label("locallabel", Position.DUMMY) val tgt = AssignTarget(IdentifierReference(listOf("tgt"), Position.DUMMY), null, null, Position.DUMMY) @@ -63,7 +63,7 @@ class TestAsmGenSymbols: StringSpec({ val statements = mutableListOf(varInSub, var2InSub, labelInSub, assign1, assign2, assign3, assign4, assign5, assign6, assign7, assign8) val subroutine = Subroutine("start", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, false, statements, Position.DUMMY) val labelInBlock = Label("label_outside", Position.DUMMY) - val varInBlock = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.UWORD, ZeropageWish.DONTCARE, null, "var_outside", null, false, false, Position.DUMMY) + val varInBlock = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.UWORD, ZeropageWish.DONTCARE, null, "var_outside", null, false, false, false, Position.DUMMY) val block = Block("main", null, mutableListOf(labelInBlock, varInBlock, subroutine), false, Position.DUMMY) val module = Module(mutableListOf(block), Position.DUMMY, SourceCode.Generated("test")) diff --git a/docs/source/todo.rst b/docs/source/todo.rst index bf51aae79..203408fb9 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -20,6 +20,7 @@ For 9.0 major changes - [much work:] add special (u)word array type (or modifier such as @fast or @split? ) that puts the array into memory as 2 separate byte-arrays 1 for LSB 1 for MSB -> allows for word arrays of length 256 and faster indexing this is an enormous amout of work, if this type is to be treated equally as existing (u)word , because all expression / lookup / assignment routines need to know about the distinction.... So maybe only allow the bare essentials? (store, get, ++/--/+/-, bitwise operations?) +- TODO: splitarrays unit tests - [much work:] more support for (64tass) SEGMENTS ? - (What, how, isn't current BSS support enough?) - Add a mechanism to allocate variables into golden ram (or segments really) (see GoldenRam class) diff --git a/examples/test.p8 b/examples/test.p8 index 42993fafb..dcefefabb 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -9,11 +9,40 @@ main { word[] @split split_words = [-12345, -2222, 22222] uword[256] @split @shared split2 word[256] @split @shared split3 - + ubyte[200] @shared dummy + uword[256] @split split_large = 1000 to 1255 print_arrays() + txt.nl() + uword ww + for ww in split_large { + txt.print_uw(ww) + txt.spc() + } + txt.nl() + txt.nl() + + + ubyte xx=1 + split_uwords[1] = 0 + txt.print_uw(split_uwords[1]) + txt.spc() + txt.print_w(split_words[1]) + txt.spc() + split_words[1] = -9999 + txt.print_w(split_words[1]) + txt.spc() + txt.print_uw(split_uwords[xx]) + txt.spc() + txt.print_w(split_words[xx]) + txt.spc() + split_words[1]=-1111 + txt.print_w(split_words[xx]) + txt.nl() + txt.nl() sub print_arrays() { + ubyte[200] @shared dummy2 = 22 for cx16.r0 in split_uwords { txt.print_uw(cx16.r0) txt.spc() @@ -28,7 +57,7 @@ main { } ubyte idx - for idx in 0 to 2 { + for idx in 0 to len(split_uwords)-1 { cx16.r0 = split_uwords[idx] cx16.r1s = split_words[idx] txt.print_uw(cx16.r0) @@ -36,16 +65,19 @@ main { txt.print_w(cx16.r1s) txt.nl() } + txt.nl() split_uwords[1] = 9999 split_words[1] = -9999 print_arrays() + txt.nl() split_uwords[1]++ split_words[1]-- print_arrays() + txt.nl() } } diff --git a/intermediate/src/prog8/intermediate/IRInstructions.kt b/intermediate/src/prog8/intermediate/IRInstructions.kt index cbbd8b451..5b3b84461 100644 --- a/intermediate/src/prog8/intermediate/IRInstructions.kt +++ b/intermediate/src/prog8/intermediate/IRInstructions.kt @@ -36,11 +36,15 @@ 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 @@ -227,15 +231,21 @@ enum class Opcode { LOADM, LOADI, LOADX, + LOADXSPLIT, + LOADMSPLIT, LOADIX, LOADR, STOREM, STOREI, STOREX, + STOREXSPLIT, + STOREMSPLIT, STOREIX, STOREZM, STOREZI, STOREZX, + STOREZXSPLIT, + STOREZMSPLIT, JUMP, JUMPA, @@ -502,15 +512,21 @@ 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, 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) @@ -413,6 +419,60 @@ 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 -> { diff --git a/virtualmachine/src/prog8/vm/VmProgramLoader.kt b/virtualmachine/src/prog8/vm/VmProgramLoader.kt index 23736334c..3c98caf37 100644 --- a/virtualmachine/src/prog8/vm/VmProgramLoader.kt +++ b/virtualmachine/src/prog8/vm/VmProgramLoader.kt @@ -3,6 +3,7 @@ package prog8.vm import prog8.code.core.ArrayDatatypes import prog8.code.core.AssemblyError import prog8.code.core.DataType +import prog8.code.core.SplitWordArrayTypes import prog8.intermediate.* class VmProgramLoader { @@ -190,12 +191,6 @@ class VmProgramLoader { } private val functionCallOpcodes = setOf(Opcode.CALL, Opcode.SYSCALL, Opcode.JUMP, Opcode.JUMPA) - private fun findCall(it: IRCodeChunk, startIndex: Int): IRInstruction { - var idx = startIndex - while(it.instructions[idx].opcode !in functionCallOpcodes) - idx++ - return it.instructions[idx] - } private fun varsToMemory( program: IRProgram, @@ -223,7 +218,7 @@ class VmProgramLoader { memory.setFloat(addr, 0.0f) addr += program.options.compTarget.machine.FLOAT_MEM_SIZE } - DataType.ARRAY_UW_SPLIT, DataType.ARRAY_W_SPLIT -> { + in SplitWordArrayTypes -> { // lo bytes come after the hi bytes memory.setUB(addr, 0u) memory.setUB(addr+variable.length!!, 0u) @@ -280,11 +275,13 @@ class VmProgramLoader { addr+=2 } } - DataType.ARRAY_UW_SPLIT -> { - TODO("$it") - } - DataType.ARRAY_W_SPLIT -> { - TODO("$it") + in SplitWordArrayTypes -> { + val number = value.toUInt() + for(elt in it) { + memory.setUB(addr, (number and 255u).toUByte()) + memory.setUB(addr+variable.length!!, (number shr 8).toUByte()) + addr++ + } } DataType.ARRAY_F -> { repeat(variable.length!!) { @@ -327,11 +324,13 @@ class VmProgramLoader { addr+=2 } } - DataType.ARRAY_UW_SPLIT -> { - TODO("$it") - } - DataType.ARRAY_W_SPLIT -> { - TODO("$it") + in SplitWordArrayTypes -> { + for(elt in it) { + val number = elt.number!!.toInt().toUInt() + memory.setUB(addr, (number and 255u).toUByte()) + memory.setUB(addr+variable.length!!, (number shr 8).toUByte()) + addr++ + } } DataType.ARRAY_F -> { for(elt in it) {