more split array stuff

This commit is contained in:
Irmen de Jong 2023-05-26 22:56:12 +02:00
parent 91d87c2d9b
commit c94e292176
20 changed files with 278 additions and 91 deletions

View File

@ -1,9 +1,6 @@
package prog8.code.ast package prog8.code.ast
import prog8.code.core.DataType import prog8.code.core.*
import prog8.code.core.Encoding
import prog8.code.core.NumericDatatypes
import prog8.code.core.Position
import java.util.* import java.util.*
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.round import kotlin.math.round
@ -28,7 +25,7 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit
infix fun isSameAs(other: PtExpression): Boolean { infix fun isSameAs(other: PtExpression): Boolean {
return when(this) { return when(this) {
is PtAddressOf -> other is PtAddressOf && other.type==type && other.identifier isSameAs identifier 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 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 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 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 this.name == target.identifier!!.name
} }
target.array != null && this is PtArrayIndexer -> { 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 else -> false
} }
@ -118,6 +115,9 @@ class PtArrayIndexer(elementType: DataType, position: Position): PtExpression(el
val index: PtExpression val index: PtExpression
get() = children[1] as PtExpression get() = children[1] as PtExpression
val splitWords: Boolean
get() = variable.type in SplitWordArrayTypes
init { init {
require(elementType in NumericDatatypes) require(elementType in NumericDatatypes)
} }

View File

@ -17,7 +17,7 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni
is PtConditionalBranch -> "if_${node.condition.name.lowercase()}" is PtConditionalBranch -> "if_${node.condition.name.lowercase()}"
is PtAddressOf -> "&" is PtAddressOf -> "&"
is PtArray -> "array len=${node.children.size} ${type(node.type)}" is PtArray -> "array len=${node.children.size} ${type(node.type)}"
is PtArrayIndexer -> "<arrayindexer> ${type(node.type)}" is PtArrayIndexer -> "<arrayindexer> ${type(node.type)} ${if(node.splitWords) "[splitwords]" else ""}"
is PtBinaryExpression -> "<expr> ${node.operator} ${type(node.type)}" is PtBinaryExpression -> "<expr> ${node.operator} ${type(node.type)}"
is PtBuiltinFunctionCall -> { is PtBuiltinFunctionCall -> {
val str = if(node.void) "void " else "" val str = if(node.void) "void " else ""

View File

@ -123,6 +123,7 @@ val NumericDatatypesNoBool = arrayOf(DataType.UBYTE, DataType.BYTE, DataType.UWO
val SignedDatatypes = arrayOf(DataType.BYTE, DataType.WORD, DataType.FLOAT) 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 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 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( val IterableDatatypes = arrayOf(
DataType.STR, DataType.STR,
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UB, DataType.ARRAY_B,

View File

@ -377,6 +377,10 @@ class AsmGen6502Internal (
?: throw AssemblyError("array indexer should have been replaced with a temp var @ ${expr.index.position}") ?: throw AssemblyError("array indexer should have been replaced with a temp var @ ${expr.index.position}")
val indexName = asmVariableName(indexVar) val indexName = asmVariableName(indexVar)
if(expr.splitWords)
TODO("split word access ${expr.position}")
if (addOneExtra) { if (addOneExtra) {
// add 1 to the result // add 1 to the result
when (elementDt) { when (elementDt) {

View File

@ -432,6 +432,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
DataType.UWORD -> { DataType.UWORD -> {
when (what) { when (what) {
is PtArrayIndexer -> { is PtArrayIndexer -> {
if(what.splitWords)
TODO("splitwords ${what.position}")
translateRolRorArrayArgs(what.variable, what, "ror2", 'w') translateRolRorArrayArgs(what.variable, what, "ror2", 'w')
asmgen.out(" jsr prog8_lib.ror2_array_uw") asmgen.out(" jsr prog8_lib.ror2_array_uw")
} }
@ -491,6 +493,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
DataType.UWORD -> { DataType.UWORD -> {
when (what) { when (what) {
is PtArrayIndexer -> { is PtArrayIndexer -> {
if(what.splitWords)
TODO("splitwords ${what.position}")
translateRolRorArrayArgs(what.variable, what, "ror", 'w') translateRolRorArrayArgs(what.variable, what, "ror", 'w')
asmgen.out(" jsr prog8_lib.ror_array_uw") asmgen.out(" jsr prog8_lib.ror_array_uw")
} }
@ -533,6 +537,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
DataType.UWORD -> { DataType.UWORD -> {
when (what) { when (what) {
is PtArrayIndexer -> { is PtArrayIndexer -> {
if(what.splitWords)
TODO("splitwords ${what.position}")
translateRolRorArrayArgs(what.variable, what, "rol2", 'w') translateRolRorArrayArgs(what.variable, what, "rol2", 'w')
asmgen.out(" jsr prog8_lib.rol2_array_uw") asmgen.out(" jsr prog8_lib.rol2_array_uw")
} }
@ -592,6 +598,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
DataType.UWORD -> { DataType.UWORD -> {
when (what) { when (what) {
is PtArrayIndexer -> { is PtArrayIndexer -> {
if(what.splitWords)
TODO("splitwords ${what.position}")
translateRolRorArrayArgs(what.variable, what, "rol", 'w') translateRolRorArrayArgs(what.variable, what, "rol", 'w')
asmgen.out(" jsr prog8_lib.rol_array_uw") 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) { 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(arrayvar.type==DataType.UWORD) {
if(dt!='b') if(dt!='b')
throw AssemblyError("non-array var indexing requires bytes dt") throw AssemblyError("non-array var indexing requires bytes dt")

View File

@ -237,6 +237,9 @@ internal class ExpressionsAsmGen(private val program: PtProgram,
DataType.FLOAT -> { DataType.FLOAT -> {
asmgen.out(" lda #<$varname | ldy #>$varname| jsr floats.push_float") asmgen.out(" lda #<$varname | ldy #>$varname| jsr floats.push_float")
} }
in SplitWordArrayTypes -> {
TODO("split $varname")
}
in IterableDatatypes -> { in IterableDatatypes -> {
asmgen.out(" lda #<$varname | sta P8ESTACK_LO,x | lda #>$varname | sta P8ESTACK_HI,x | dex") 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 elementDt = arrayExpr.type
val arrayVarName = asmgen.asmVariableName(arrayExpr.variable) val arrayVarName = asmgen.asmVariableName(arrayExpr.variable)
if(arrayExpr.splitWords)
TODO("split word access ${arrayExpr.position}")
if(arrayExpr.variable.type==DataType.UWORD) { if(arrayExpr.variable.type==DataType.UWORD) {
// indexing a pointer var instead of a real array or string // indexing a pointer var instead of a real array or string
if(elementDt !in ByteDatatypes) if(elementDt !in ByteDatatypes)

View File

@ -730,7 +730,7 @@ internal class ProgramAndVarsGen(
val number = it.number!!.toInt() val number = it.number!!.toInt()
"$" + number.toString(16).padStart(4, '0') "$" + 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 number = it.number!!.toInt()
val hexnum = number.absoluteValue.toString(16).padStart(4, '0') val hexnum = number.absoluteValue.toString(16).padStart(4, '0')
if(number>=0) if(number>=0)

View File

@ -115,7 +115,7 @@ internal class AsmAssignTarget(val kind: TargetStorageKind,
left is PtIdentifier && left.name==scopedName left is PtIdentifier && left.name==scopedName
} }
TargetStorageKind.ARRAY -> { TargetStorageKind.ARRAY -> {
left is PtArrayIndexer && left isSameAs array!! left is PtArrayIndexer && left isSameAs array!! && left.splitWords==array.splitWords
} }
TargetStorageKind.MEMORY -> { TargetStorageKind.MEMORY -> {
left isSameAs memory!! left isSameAs memory!!
@ -172,6 +172,8 @@ internal class AsmAssignSource(val kind: SourceStorageKind,
AsmAssignSource(SourceStorageKind.MEMORY, program, asmgen, DataType.UBYTE, memory = value) AsmAssignSource(SourceStorageKind.MEMORY, program, asmgen, DataType.UBYTE, memory = value)
} }
is PtArrayIndexer -> { is PtArrayIndexer -> {
if(value.splitWords)
TODO("splitwords ${value.position}")
AsmAssignSource(SourceStorageKind.ARRAY, program, asmgen, value.type, array = value) AsmAssignSource(SourceStorageKind.ARRAY, program, asmgen, value.type, array = value)
} }
is PtBuiltinFunctionCall -> { is PtBuiltinFunctionCall -> {

View File

@ -1,5 +1,6 @@
package prog8.codegen.intermediate package prog8.codegen.intermediate
import prog8.code.StStaticVariable
import prog8.code.ast.* import prog8.code.ast.*
import prog8.code.core.AssemblyError import prog8.code.core.AssemblyError
import prog8.code.core.DataType 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 fixedIndex = constIntValue(targetArray.index)
val iterable = codeGen.symbolTable.flat.getValue(targetArray.variable.name) as StStaticVariable
val arrayLength = iterable.length!!
if(zero) { if(zero) {
if(fixedIndex!=null) { if(fixedIndex!=null) {
val offset = fixedIndex*itemsize val chunk = IRCodeChunk(null, null).also {
val chunk = IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREZM, targetDt, labelSymbol = "$variable+$offset") } it += if(targetArray.splitWords)
IRInstruction(Opcode.STOREZMSPLIT, targetDt, immediate = arrayLength, labelSymbol = "$variable+$fixedIndex")
else
IRInstruction(Opcode.STOREZM, targetDt, labelSymbol = "$variable+${fixedIndex*itemsize}")
}
result += chunk result += chunk
} else { } else {
val (code, indexReg) = loadIndexReg(targetArray, itemsize) val (code, indexReg) = loadIndexReg(targetArray, itemsize)
result += code 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 { } else {
if(targetDt== IRDataType.FLOAT) { if(targetDt== IRDataType.FLOAT) {
if(fixedIndex!=null) { if(fixedIndex!=null) {
val offset = fixedIndex*itemsize 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 result += chunk
} else { } else {
val (code, indexReg) = loadIndexReg(targetArray, itemsize) val (code, indexReg) = loadIndexReg(targetArray, itemsize)
result += code 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 { } else {
if(fixedIndex!=null) { if(fixedIndex!=null) {
val offset = fixedIndex*itemsize val chunk = IRCodeChunk(null, null).also {
val chunk = IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREM, targetDt, reg1 = valueRegister, labelSymbol = "$variable+$offset") } 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 result += chunk
} else { } else {
val (code, indexReg) = loadIndexReg(targetArray, itemsize) val (code, indexReg) = loadIndexReg(targetArray, itemsize)
result += code 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<IRCodeChunks, Int> { private fun loadIndexReg(array: PtArrayIndexer, itemsize: Int): Pair<IRCodeChunks, Int> {
// 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<IRCodeChunkBase>() val result = mutableListOf<IRCodeChunkBase>()
if(itemsize==1) { if(itemsize==1 || array.splitWords) {
val tr = expressionEval.translateExpression(array.index) val tr = expressionEval.translateExpression(array.index)
addToResult(result, tr, tr.resultReg, -1) addToResult(result, tr, tr.resultReg, -1)
return Pair(result, tr.resultReg) return Pair(result, tr.resultReg)

View File

@ -160,6 +160,23 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
} }
var resultRegister = -1 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 var resultFpRegister = -1
if(arrayIx.index is PtNumber) { if(arrayIx.index is PtNumber) {
val memOffset = ((arrayIx.index as PtNumber).number.toInt() * eltSize).toString() val memOffset = ((arrayIx.index as PtNumber).number.toInt() * eltSize).toString()

View File

@ -456,46 +456,59 @@ class IRCodeGen(
val endLabel = createLabelName() val endLabel = createLabelName()
if(iterableVar.dt==DataType.STR) { if(iterableVar.dt==DataType.STR) {
// iterate over a zero-terminated string // 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) val chunk = IRCodeChunk(loopLabel, null)
chunk += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpReg, reg2=indexReg, labelSymbol = iterable.name) chunk += IRInstruction(
chunk += IRInstruction(Opcode.BEQ, IRDataType.BYTE, reg1=tmpReg, immediate = 0, labelSymbol = endLabel) Opcode.LOADX,
chunk += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1=tmpReg, labelSymbol = loopvarSymbol) 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 += chunk
result += translateNode(forLoop.statements) result += translateNode(forLoop.statements)
val jumpChunk = IRCodeChunk(null, null) 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) jumpChunk += IRInstruction(Opcode.JUMP, labelSymbol = loopLabel)
result += jumpChunk result += jumpChunk
result += IRCodeChunk(endLabel, null) 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 { } else {
// iterate over array // iterate over regular array
val elementDt = ArrayToElementTypes.getValue(iterable.type) val elementDt = ArrayToElementTypes.getValue(iterable.type)
val elementSize = program.memsizer.memorySize(elementDt) val elementSize = program.memsizer.memorySize(elementDt)
val lengthBytes = iterableVar.length!! * elementSize 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) addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, immediate = 0), null)
val chunk = IRCodeChunk(loopLabel, null) result += IRCodeChunk(loopLabel, null).also {
chunk += IRInstruction(Opcode.LOADX, irType(elementDt), reg1=tmpReg, reg2=indexReg, labelSymbol=iterable.name) it += IRInstruction(Opcode.LOADX, irType(elementDt), reg1=tmpReg, reg2=indexReg, labelSymbol=iterable.name)
chunk += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=tmpReg, labelSymbol = loopvarSymbol) it += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=tmpReg, labelSymbol = loopvarSymbol)
result += chunk }
result += translateNode(forLoop.statements) result += translateNode(forLoop.statements)
result += addConstReg(IRDataType.BYTE, indexReg, elementSize) result += addConstReg(IRDataType.BYTE, indexReg, elementSize)
addInstr(result, IRInstruction(Opcode.BNE, IRDataType.BYTE, reg1=indexReg, immediate = 0, labelSymbol = loopLabel), null) addInstr(result, IRInstruction(Opcode.BNE, IRDataType.BYTE, reg1=indexReg, immediate = if(lengthBytes==256) 0 else lengthBytes, labelSymbol = loopLabel), null)
} else {
throw AssemblyError("iterator length should never exceed 256")
}
} }
} }
else -> throw AssemblyError("weird for iterable") else -> throw AssemblyError("weird for iterable")

View File

@ -275,7 +275,7 @@ internal class ConstantIdentifierReplacer(private val program: Program, private
return listOf(IAstModification.ReplaceNode(decl.value!!, newValue, decl)) 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 val rangeExpr = decl.value as? RangeExpression
if(rangeExpr!=null) { if(rangeExpr!=null) {
// convert the initializer range expression to an actual array // convert the initializer range expression to an actual array

View File

@ -628,12 +628,12 @@ internal class AstChecker(private val program: Program,
DataType.ARRAY_B, DataType.ARRAY_UB -> DataType.ARRAY_B, DataType.ARRAY_UB ->
if(arraySize > 256) if(arraySize > 256)
err("byte array length must be 1-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 -> DataType.ARRAY_W, DataType.ARRAY_UW ->
if(arraySize > 128) if(arraySize > 128)
err("word array length must be 1-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 -> DataType.ARRAY_F ->
if(arraySize > 51) if(arraySize > 51)
err("float array length must be 1-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) if (length == 0 || length > 256)
err("string and byte array length must be 1-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 -> { DataType.ARRAY_UW, DataType.ARRAY_W -> {
if (length == 0 || length > 128) if (length == 0 || length > 128)
err("word array length must be 1-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 // check index value 0..255
val dtxNum = arrayIndexedExpression.indexer.indexExpr.inferType(program) 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) errors.err("array indexing is limited to byte size 0..255", arrayIndexedExpression.position)
super.visit(arrayIndexedExpression) 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") 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 // value may be either a single word, or a word arraysize, or a range
if(value.type istype targetDt) { if(value.type istype targetDt) {
if(!checkArrayValues(value, targetDt)) if(!checkArrayValues(value, targetDt))
return false return false
val arraySpecSize = arrayspec.constIndex() val arraySpecSize = arrayspec.constIndex()
val arraySize = value.value.size val arraySize = value.value.size
val maxLength = if(targetDt in SplitWordArrayTypes) 256 else 128
if(arraySpecSize!=null && arraySpecSize>0) { if(arraySpecSize!=null && arraySpecSize>0) {
if(arraySpecSize>128) if(arraySpecSize>maxLength)
return err("word array length must be 1-128") return err("array length must be 1-$maxLength")
val expectedSize = arrayspec.constIndex() ?: return err("array size specifier must be constant integer value") val expectedSize = arrayspec.constIndex() ?: return err("array size specifier must be constant integer value")
if (arraySize != expectedSize) if (arraySize != expectedSize)
return err("initializer array size mismatch (expecting $expectedSize, got $arraySize)") return err("initializer array size mismatch (expecting $expectedSize, got $arraySize)")
return true 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") 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 -> { DataType.ARRAY_F -> {
// value may be either a single float, or a float arraysize // value may be either a single float, or a float arraysize
if(value.type istype targetDt) { if(value.type istype targetDt) {
@ -1555,10 +1556,10 @@ internal class AstChecker(private val program: Program,
DataType.ARRAY_B -> { DataType.ARRAY_B -> {
correct = array.all { it in -128..127 } correct = array.all { it in -128..127 }
} }
DataType.ARRAY_UW -> { DataType.ARRAY_UW, DataType.ARRAY_UW_SPLIT -> {
correct = array.all { (it in 0..65535) } correct = array.all { (it in 0..65535) }
} }
DataType.ARRAY_W -> { DataType.ARRAY_W, DataType.ARRAY_W_SPLIT -> {
correct = array.all { it in -32768..32767 } correct = array.all { it in -32768..32767 }
} }
DataType.ARRAY_F -> correct = true DataType.ARRAY_F -> correct = true

View File

@ -112,7 +112,7 @@ class TestMemory: FunSpec({
} }
fun createTestProgramForMemoryRefViaVar(address: UInt, vartype: VarDeclType): AssignTarget { 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 memexpr = IdentifierReference(listOf("address"), Position.DUMMY)
val target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), 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) 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") { 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 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 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) 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") { test("memory mapped variable not in mapped IO ram on C64") {
val address = 0x1000u 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 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 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) 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") { test("memory mapped variable in mapped IO ram on C64") {
val address = 0xd020u 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 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 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) 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") { 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 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 target = AssignTarget(null, arrayindexed, null, Position.DUMMY)
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, 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") { test("memory mapped array not in mapped IO ram") {
val address = 0x1000u 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 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 target = AssignTarget(null, arrayindexed, null, Position.DUMMY)
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, 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") { test("memory mapped array in mapped IO ram") {
val address = 0xd800u 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 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 target = AssignTarget(null, arrayindexed, null, Position.DUMMY)
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)

View File

@ -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 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, 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 labelInSub = Label("locallabel", Position.DUMMY)
val tgt = AssignTarget(IdentifierReference(listOf("tgt"), Position.DUMMY), null, null, 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 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 subroutine = Subroutine("start", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, false, statements, Position.DUMMY)
val labelInBlock = Label("label_outside", 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 block = Block("main", null, mutableListOf(labelInBlock, varInBlock, subroutine), false, Position.DUMMY)
val module = Module(mutableListOf(block), Position.DUMMY, SourceCode.Generated("test")) val module = Module(mutableListOf(block), Position.DUMMY, SourceCode.Generated("test"))

View File

@ -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 - [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.... 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?) So maybe only allow the bare essentials? (store, get, ++/--/+/-, bitwise operations?)
- TODO: splitarrays unit tests
- [much work:] more support for (64tass) SEGMENTS ? - [much work:] more support for (64tass) SEGMENTS ?
- (What, how, isn't current BSS support enough?) - (What, how, isn't current BSS support enough?)
- Add a mechanism to allocate variables into golden ram (or segments really) (see GoldenRam class) - Add a mechanism to allocate variables into golden ram (or segments really) (see GoldenRam class)

View File

@ -9,11 +9,40 @@ main {
word[] @split split_words = [-12345, -2222, 22222] word[] @split split_words = [-12345, -2222, 22222]
uword[256] @split @shared split2 uword[256] @split @shared split2
word[256] @split @shared split3 word[256] @split @shared split3
ubyte[200] @shared dummy
uword[256] @split split_large = 1000 to 1255
print_arrays() 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() { sub print_arrays() {
ubyte[200] @shared dummy2 = 22
for cx16.r0 in split_uwords { for cx16.r0 in split_uwords {
txt.print_uw(cx16.r0) txt.print_uw(cx16.r0)
txt.spc() txt.spc()
@ -28,7 +57,7 @@ main {
} }
ubyte idx ubyte idx
for idx in 0 to 2 { for idx in 0 to len(split_uwords)-1 {
cx16.r0 = split_uwords[idx] cx16.r0 = split_uwords[idx]
cx16.r1s = split_words[idx] cx16.r1s = split_words[idx]
txt.print_uw(cx16.r0) txt.print_uw(cx16.r0)
@ -36,16 +65,19 @@ main {
txt.print_w(cx16.r1s) txt.print_w(cx16.r1s)
txt.nl() txt.nl()
} }
txt.nl()
split_uwords[1] = 9999 split_uwords[1] = 9999
split_words[1] = -9999 split_words[1] = -9999
print_arrays() print_arrays()
txt.nl()
split_uwords[1]++ split_uwords[1]++
split_words[1]-- split_words[1]--
print_arrays() print_arrays()
txt.nl()
} }
} }

View File

@ -36,11 +36,15 @@ load reg1, value - load immediate value into register. If y
loadm reg1, address - load reg1 with value at memory address 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 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 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 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 loadr reg1, reg2 - load reg1 with value in register reg2
storem reg1, address - store reg1 at memory address storem reg1, address - store reg1 at memory address
storei reg1, reg2 - store reg1 at memory indirect, memory pointed to by reg2 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 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 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 storezm address - store zero at memory address
storezi reg1 - store zero at memory pointed to by reg1 storezi reg1 - store zero at memory pointed to by reg1
@ -227,15 +231,21 @@ enum class Opcode {
LOADM, LOADM,
LOADI, LOADI,
LOADX, LOADX,
LOADXSPLIT,
LOADMSPLIT,
LOADIX, LOADIX,
LOADR, LOADR,
STOREM, STOREM,
STOREI, STOREI,
STOREX, STOREX,
STOREXSPLIT,
STOREMSPLIT,
STOREIX, STOREIX,
STOREZM, STOREZM,
STOREZI, STOREZI,
STOREZX, STOREZX,
STOREZXSPLIT,
STOREZMSPLIT,
JUMP, JUMP,
JUMPA, JUMPA,
@ -502,15 +512,21 @@ val instructionFormats = mutableMapOf(
Opcode.LOADM to InstructionFormat.from("BW,>r1,<a | F,>fr1,<a"), Opcode.LOADM to InstructionFormat.from("BW,>r1,<a | F,>fr1,<a"),
Opcode.LOADI to InstructionFormat.from("BW,>r1,<r2 | F,>fr1,<r1"), Opcode.LOADI to InstructionFormat.from("BW,>r1,<r2 | F,>fr1,<r1"),
Opcode.LOADX to InstructionFormat.from("BW,>r1,<r2,<a | F,>fr1,<r1,<a"), Opcode.LOADX to InstructionFormat.from("BW,>r1,<r2,<a | F,>fr1,<r1,<a"),
Opcode.LOADXSPLIT to InstructionFormat.from("W,>r1,<r2,<i,<a"),
Opcode.LOADMSPLIT to InstructionFormat.from("W,>r1,<i,<a"),
Opcode.LOADIX to InstructionFormat.from("BW,>r1,<r2,<a | F,>fr1,<r1,<a"), Opcode.LOADIX to InstructionFormat.from("BW,>r1,<r2,<a | F,>fr1,<r1,<a"),
Opcode.LOADR to InstructionFormat.from("BW,>r1,<r2 | F,>fr1,<fr2"), Opcode.LOADR to InstructionFormat.from("BW,>r1,<r2 | F,>fr1,<fr2"),
Opcode.STOREM to InstructionFormat.from("BW,<r1,>a | F,<fr1,>a"), Opcode.STOREM to InstructionFormat.from("BW,<r1,>a | F,<fr1,>a"),
Opcode.STOREI to InstructionFormat.from("BW,<r1,<r2 | F,<fr1,<r1"), Opcode.STOREI to InstructionFormat.from("BW,<r1,<r2 | F,<fr1,<r1"),
Opcode.STOREX to InstructionFormat.from("BW,<r1,<r2,>a | F,<fr1,<r1,>a"), Opcode.STOREX to InstructionFormat.from("BW,<r1,<r2,>a | F,<fr1,<r1,>a"),
Opcode.STOREXSPLIT to InstructionFormat.from("W,<r1,<r2,<i,>a"),
Opcode.STOREMSPLIT to InstructionFormat.from("W,<r1,<i,>a"),
Opcode.STOREIX to InstructionFormat.from("BW,<r1,<r2,>a | F,<fr1,<r1,>a"), Opcode.STOREIX to InstructionFormat.from("BW,<r1,<r2,>a | F,<fr1,<r1,>a"),
Opcode.STOREZM to InstructionFormat.from("BW,>a | F,>a"), Opcode.STOREZM to InstructionFormat.from("BW,>a | F,>a"),
Opcode.STOREZI to InstructionFormat.from("BW,<r1 | F,<r1"), Opcode.STOREZI to InstructionFormat.from("BW,<r1 | F,<r1"),
Opcode.STOREZX to InstructionFormat.from("BW,<r1,>a | F,<r1,>a"), Opcode.STOREZX to InstructionFormat.from("BW,<r1,>a | F,<r1,>a"),
Opcode.STOREZMSPLIT to InstructionFormat.from("W,<i,>a"),
Opcode.STOREZXSPLIT to InstructionFormat.from("W,<r1,<i,>a"),
Opcode.JUMP to InstructionFormat.from("N,<a"), Opcode.JUMP to InstructionFormat.from("N,<a"),
Opcode.JUMPA to InstructionFormat.from("N,<a"), Opcode.JUMPA to InstructionFormat.from("N,<a"),
Opcode.CALL to InstructionFormat.from("N,call"), Opcode.CALL to InstructionFormat.from("N,call"),

View File

@ -164,11 +164,17 @@ class VirtualMachine(irProgram: IRProgram) {
Opcode.LOAD -> InsLOAD(ins) Opcode.LOAD -> InsLOAD(ins)
Opcode.LOADM -> InsLOADM(ins) Opcode.LOADM -> InsLOADM(ins)
Opcode.LOADX -> InsLOADX(ins) Opcode.LOADX -> InsLOADX(ins)
Opcode.LOADXSPLIT -> InsLOADXSPLIT(ins)
Opcode.LOADMSPLIT -> InsLOADMSPLIT(ins)
Opcode.LOADI -> InsLOADI(ins) Opcode.LOADI -> InsLOADI(ins)
Opcode.LOADIX -> InsLOADIX(ins) Opcode.LOADIX -> InsLOADIX(ins)
Opcode.LOADR -> InsLOADR(ins) Opcode.LOADR -> InsLOADR(ins)
Opcode.STOREM -> InsSTOREM(ins) Opcode.STOREM -> InsSTOREM(ins)
Opcode.STOREX -> InsSTOREX(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.STOREIX -> InsSTOREIX(ins)
Opcode.STOREI -> InsSTOREI(ins) Opcode.STOREI -> InsSTOREI(ins)
Opcode.STOREZM -> InsSTOREZM(ins) Opcode.STOREZM -> InsSTOREZM(ins)
@ -413,6 +419,60 @@ class VirtualMachine(irProgram: IRProgram) {
nextPc() 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) { private fun InsLOADIX(i: IRInstruction) {
when (i.type!!) { when (i.type!!) {
IRDataType.BYTE -> { IRDataType.BYTE -> {

View File

@ -3,6 +3,7 @@ package prog8.vm
import prog8.code.core.ArrayDatatypes import prog8.code.core.ArrayDatatypes
import prog8.code.core.AssemblyError import prog8.code.core.AssemblyError
import prog8.code.core.DataType import prog8.code.core.DataType
import prog8.code.core.SplitWordArrayTypes
import prog8.intermediate.* import prog8.intermediate.*
class VmProgramLoader { class VmProgramLoader {
@ -190,12 +191,6 @@ class VmProgramLoader {
} }
private val functionCallOpcodes = setOf(Opcode.CALL, Opcode.SYSCALL, Opcode.JUMP, Opcode.JUMPA) 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( private fun varsToMemory(
program: IRProgram, program: IRProgram,
@ -223,7 +218,7 @@ class VmProgramLoader {
memory.setFloat(addr, 0.0f) memory.setFloat(addr, 0.0f)
addr += program.options.compTarget.machine.FLOAT_MEM_SIZE 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 // lo bytes come after the hi bytes
memory.setUB(addr, 0u) memory.setUB(addr, 0u)
memory.setUB(addr+variable.length!!, 0u) memory.setUB(addr+variable.length!!, 0u)
@ -280,11 +275,13 @@ class VmProgramLoader {
addr+=2 addr+=2
} }
} }
DataType.ARRAY_UW_SPLIT -> { in SplitWordArrayTypes -> {
TODO("$it") 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_W_SPLIT -> {
TODO("$it")
} }
DataType.ARRAY_F -> { DataType.ARRAY_F -> {
repeat(variable.length!!) { repeat(variable.length!!) {
@ -327,11 +324,13 @@ class VmProgramLoader {
addr+=2 addr+=2
} }
} }
DataType.ARRAY_UW_SPLIT -> { in SplitWordArrayTypes -> {
TODO("$it") 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_W_SPLIT -> {
TODO("$it")
} }
DataType.ARRAY_F -> { DataType.ARRAY_F -> {
for(elt in it) { for(elt in it) {