mirror of
https://github.com/irmen/prog8.git
synced 2024-11-29 17:50:35 +00:00
more split array stuff
This commit is contained in:
parent
91d87c2d9b
commit
c94e292176
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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 ""
|
||||||
|
@ -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,
|
||||||
|
@ -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) {
|
||||||
|
@ -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")
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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 -> {
|
||||||
|
@ -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)
|
||||||
|
@ -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()
|
||||||
|
@ -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")
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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"))
|
||||||
|
@ -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)
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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"),
|
||||||
|
@ -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 -> {
|
||||||
|
@ -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) {
|
||||||
|
Loading…
Reference in New Issue
Block a user