IR: handle split arrays without new custom opcodes

This commit is contained in:
Irmen de Jong 2023-06-02 23:39:57 +02:00
parent 0b580ad05d
commit bfaad1388c
11 changed files with 207 additions and 247 deletions

View File

@ -241,20 +241,24 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
if(zero) {
if(fixedIndex!=null) {
val chunk = IRCodeChunk(null, null).also {
it += if(targetArray.splitWords)
IRInstruction(Opcode.STOREZMSPLIT, targetDt, immediate = arrayLength, labelSymbol = "$variable+$fixedIndex")
if(targetArray.splitWords) {
it += IRInstruction(Opcode.STOREZM, IRDataType.BYTE, immediate = arrayLength, labelSymbol = "${variable}_lsb+$fixedIndex")
it += IRInstruction(Opcode.STOREZM, IRDataType.BYTE, immediate = arrayLength, labelSymbol = "${variable}_msb+$fixedIndex")
}
else
IRInstruction(Opcode.STOREZM, targetDt, labelSymbol = "$variable+${fixedIndex*itemsize}")
it += IRInstruction(Opcode.STOREZM, targetDt, labelSymbol = "$variable+${fixedIndex*itemsize}")
}
result += chunk
} else {
val (code, indexReg) = loadIndexReg(targetArray, itemsize)
result += code
result += IRCodeChunk(null, null).also {
it += if(targetArray.splitWords)
IRInstruction(Opcode.STOREZXSPLIT, targetDt, reg1 = valueRegister, reg2=indexReg, immediate = arrayLength, labelSymbol = variable)
if(targetArray.splitWords) {
it += IRInstruction(Opcode.STOREZX, IRDataType.BYTE, reg1 = indexReg, immediate = arrayLength, labelSymbol = variable+"_lsb")
it += IRInstruction(Opcode.STOREZX, IRDataType.BYTE, reg1 = indexReg, immediate = arrayLength, labelSymbol = variable+"_msb")
}
else
IRInstruction(Opcode.STOREZX, targetDt, reg1=indexReg, labelSymbol = variable)
it += IRInstruction(Opcode.STOREZX, targetDt, reg1=indexReg, labelSymbol = variable)
}
}
} else {
@ -275,20 +279,28 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
} else {
if(fixedIndex!=null) {
val chunk = IRCodeChunk(null, null).also {
it += if(targetArray.splitWords)
IRInstruction(Opcode.STOREMSPLIT, targetDt, reg1 = valueRegister, immediate = arrayLength, labelSymbol = "$variable+$fixedIndex")
if(targetArray.splitWords) {
val msbReg = codeGen.registers.nextFree()
it += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1 = valueRegister, immediate = arrayLength, labelSymbol = "${variable}_lsb+$fixedIndex")
it += IRInstruction(Opcode.MSIG, IRDataType.BYTE, reg1 = msbReg, reg2 = valueRegister)
it += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1 = msbReg, immediate = arrayLength, labelSymbol = "${variable}_msb+$fixedIndex")
}
else
IRInstruction(Opcode.STOREM, targetDt, reg1 = valueRegister, labelSymbol = "$variable+${fixedIndex*itemsize}")
it += IRInstruction(Opcode.STOREM, targetDt, reg1 = valueRegister, labelSymbol = "$variable+${fixedIndex*itemsize}")
}
result += chunk
} else {
val (code, indexReg) = loadIndexReg(targetArray, itemsize)
result += code
result += IRCodeChunk(null, null).also {
it += if(targetArray.splitWords)
IRInstruction(Opcode.STOREXSPLIT, targetDt, reg1 = valueRegister, reg2=indexReg, immediate = arrayLength, labelSymbol = variable)
if(targetArray.splitWords) {
val msbReg = codeGen.registers.nextFree()
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1 = valueRegister, reg2=indexReg, immediate = arrayLength, labelSymbol = "${variable}_lsb")
it += IRInstruction(Opcode.MSIG, IRDataType.BYTE, reg1 = msbReg, reg2 = valueRegister)
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1 = msbReg, reg2=indexReg, immediate = arrayLength, labelSymbol = "${variable}_msb")
}
else
IRInstruction(Opcode.STOREX, targetDt, reg1 = valueRegister, reg2=indexReg, labelSymbol = variable)
it += IRInstruction(Opcode.STOREX, targetDt, reg1 = valueRegister, reg2=indexReg, labelSymbol = variable)
}
}
}

View File

@ -168,11 +168,21 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
resultRegister = codeGen.registers.nextFree()
if(arrayIx.index is PtNumber) {
val memOffset = (arrayIx.index as PtNumber).number.toInt()
addInstr(result, IRInstruction(Opcode.LOADMSPLIT, IRDataType.WORD, reg1=resultRegister, immediate = arrayLength, labelSymbol = "$arrayVarSymbol+$memOffset"), null)
result += IRCodeChunk(null, null).also {
val tmpRegMsb = codeGen.registers.nextFree()
it += IRInstruction(Opcode.LOADM, IRDataType.BYTE, reg1=resultRegister, immediate = arrayLength, labelSymbol= "${arrayVarSymbol}_lsb+$memOffset")
it += IRInstruction(Opcode.LOADM, IRDataType.BYTE, reg1=tmpRegMsb, immediate = arrayLength, labelSymbol= "${arrayVarSymbol}_msb+$memOffset")
it += IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1=resultRegister, reg2=tmpRegMsb)
}
} else {
val tr = translateExpression(arrayIx.index)
addToResult(result, tr, tr.resultReg, -1)
addInstr(result, IRInstruction(Opcode.LOADXSPLIT, IRDataType.WORD, reg1=resultRegister, reg2=tr.resultReg, immediate = arrayLength, labelSymbol = arrayVarSymbol), null)
result += IRCodeChunk(null, null).also {
val tmpRegMsb = codeGen.registers.nextFree()
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=resultRegister, reg2 = tr.resultReg, immediate = arrayLength, labelSymbol= "${arrayVarSymbol}_lsb")
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpRegMsb, reg2 = tr.resultReg, immediate = arrayLength, labelSymbol= "${arrayVarSymbol}_msb")
it += IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1=resultRegister, reg2=tmpRegMsb)
}
}
return ExpressionCodeResult(result, vmDt, resultRegister, -1)
}

View File

@ -457,23 +457,11 @@ class IRCodeGen(
if(iterableVar.dt==DataType.STR) {
// iterate over a zero-terminated string
addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = indexReg, immediate = 0), null)
val chunk = IRCodeChunk(loopLabel, null)
chunk += IRInstruction(
Opcode.LOADX,
IRDataType.BYTE,
reg1 = tmpReg,
reg2 = indexReg,
labelSymbol = iterable.name
)
chunk += IRInstruction(
Opcode.BEQ,
IRDataType.BYTE,
reg1 = tmpReg,
immediate = 0,
labelSymbol = endLabel
)
chunk += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1 = tmpReg, labelSymbol = loopvarSymbol)
result += chunk
result += IRCodeChunk(loopLabel, null).also {
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1 = tmpReg, reg2 = indexReg, labelSymbol = iterable.name)
it += IRInstruction(Opcode.BEQ, IRDataType.BYTE, reg1 = tmpReg, immediate = 0, labelSymbol = endLabel)
it += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1 = tmpReg, labelSymbol = loopvarSymbol)
}
result += translateNode(forLoop.statements)
val jumpChunk = IRCodeChunk(null, null)
jumpChunk += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1 = indexReg)
@ -488,8 +476,12 @@ class IRCodeGen(
val length = iterableVar.length!!
addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, immediate = 0), null)
result += IRCodeChunk(loopLabel, null).also {
it += IRInstruction(Opcode.LOADXSPLIT, irType(elementDt), reg1=tmpReg, reg2=indexReg, immediate = length, labelSymbol=iterable.name)
it += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=tmpReg, labelSymbol = loopvarSymbol)
val tmpRegLsb = registers.nextFree()
val tmpRegMsb = registers.nextFree()
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpRegLsb, reg2=indexReg, immediate = length, labelSymbol=iterable.name+"_lsb")
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpRegMsb, reg2=indexReg, immediate = length, labelSymbol=iterable.name+"_msb")
it += IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1=tmpRegLsb, reg2=tmpRegMsb)
it += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=tmpRegLsb, labelSymbol = loopvarSymbol)
}
result += translateNode(forLoop.statements)
result += IRCodeChunk(null, null).also {
@ -1367,76 +1359,84 @@ class IRCodeGen(
}
private fun translate(postIncrDecr: PtPostIncrDecr): IRCodeChunks {
val result = mutableListOf<IRCodeChunkBase>()
val array = postIncrDecr.target.array
val operationMem: Opcode
val operationRegister: Opcode
val array = postIncrDecr.target.array
when(postIncrDecr.operator) {
"++" -> {
operationMem = if(array?.splitWords==true) Opcode.INCMSPLIT else Opcode.INCM
operationMem = Opcode.INCM
operationRegister = Opcode.INC
}
"--" -> {
operationMem = if(array?.splitWords==true) Opcode.DECMSPLIT else Opcode.DECM
operationMem = Opcode.DECM
operationRegister = Opcode.DEC
}
else -> throw AssemblyError("weird operator")
}
val ident = postIncrDecr.target.identifier
val memory = postIncrDecr.target.memory
val irDt = irType(postIncrDecr.target.type)
val result = mutableListOf<IRCodeChunkBase>()
if(ident!=null) {
addInstr(result, IRInstruction(operationMem, irDt, labelSymbol = ident.name), null)
} else if(memory!=null) {
if(memory.address is PtNumber) {
val address = (memory.address as PtNumber).number.toInt()
addInstr(result, IRInstruction(operationMem, irDt, address = address), null)
if(array?.splitWords==true) {
val variable = array.variable.name
val fixedIndex = constIntValue(array.index)
val iterable = symbolTable.flat.getValue(array.variable.name) as StStaticVariable
val arrayLength = iterable.length!!
if(fixedIndex!=null) {
TODO("split incr decr")
// addInstr(result, IRInstruction(operationMem, irDt, immediate = arrayLength, labelSymbol="$variable+$fixedIndex"), null)
} else {
val tr = expressionEval.translateExpression(memory.address)
addToResult(result, tr, tr.resultReg, -1)
val indexTr = expressionEval.translateExpression(array.index)
addToResult(result, indexTr, indexTr.resultReg, -1)
val chunk = IRCodeChunk(null, null)
val incReg = registers.nextFree()
chunk += IRInstruction(Opcode.LOADI, irDt, reg1 = incReg, reg2 = tr.resultReg)
chunk += IRInstruction(operationRegister, irDt, reg1 = incReg)
chunk += IRInstruction(Opcode.STOREI, irDt, reg1 = incReg, reg2 = tr.resultReg)
TODO("load split")
// chunk += IRInstruction(Opcode.LOADXSPLIT, irDt, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol=variable)
// chunk += IRInstruction(operationRegister, irDt, reg1=incReg)
TODO("store split")
// chunk += IRInstruction(Opcode.STOREXSPLIT, irDt, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol=variable)
result += chunk
}
} else if (array!=null) {
val variable = array.variable.name
val itemsize = program.memsizer.memorySize(array.type)
val fixedIndex = constIntValue(array.index)
if(array.splitWords) {
val iterable = symbolTable.flat.getValue(array.variable.name) as StStaticVariable
val arrayLength = iterable.length!!
if(fixedIndex!=null) {
addInstr(result, IRInstruction(operationMem, irDt, immediate = arrayLength, labelSymbol="$variable+$fixedIndex"), null)
} else {
val ident = postIncrDecr.target.identifier
val memory = postIncrDecr.target.memory
val irDt = irType(postIncrDecr.target.type)
if(ident!=null) {
addInstr(result, IRInstruction(operationMem, irDt, labelSymbol = ident.name), null)
} else if(memory!=null) {
if(memory.address is PtNumber) {
val address = (memory.address as PtNumber).number.toInt()
addInstr(result, IRInstruction(operationMem, irDt, address = address), null)
} else {
val indexTr = expressionEval.translateExpression(array.index)
addToResult(result, indexTr, indexTr.resultReg, -1)
val chunk = IRCodeChunk(null, null)
val incReg = registers.nextFree()
chunk += IRInstruction(Opcode.LOADXSPLIT, irDt, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol=variable)
chunk += IRInstruction(operationRegister, irDt, reg1=incReg)
chunk += IRInstruction(Opcode.STOREXSPLIT, irDt, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol=variable)
result += chunk
val tr = expressionEval.translateExpression(memory.address)
addToResult(result, tr, tr.resultReg, -1)
result += IRCodeChunk(null, null).also {
val incReg = registers.nextFree()
it += IRInstruction(Opcode.LOADI, irDt, reg1 = incReg, reg2 = tr.resultReg)
it += IRInstruction(operationRegister, irDt, reg1 = incReg)
it += IRInstruction(Opcode.STOREI, irDt, reg1 = incReg, reg2 = tr.resultReg)
}
}
} else {
} else if (array!=null) {
val variable = array.variable.name
val itemsize = program.memsizer.memorySize(array.type)
val fixedIndex = constIntValue(array.index)
if(fixedIndex!=null) {
val offset = fixedIndex*itemsize
addInstr(result, IRInstruction(operationMem, irDt, labelSymbol="$variable+$offset"), null)
} else {
val indexTr = expressionEval.translateExpression(array.index)
addToResult(result, indexTr, indexTr.resultReg, -1)
val chunk = IRCodeChunk(null, null)
val incReg = registers.nextFree()
chunk += IRInstruction(Opcode.LOADX, irDt, reg1=incReg, reg2=indexTr.resultReg, labelSymbol=variable)
chunk += IRInstruction(operationRegister, irDt, reg1=incReg)
chunk += IRInstruction(Opcode.STOREX, irDt, reg1=incReg, reg2=indexTr.resultReg, labelSymbol=variable)
result += chunk
if(itemsize>1)
result += multiplyByConst(IRDataType.BYTE, indexTr.resultReg, itemsize)
result += IRCodeChunk(null, null).also {
val incReg = registers.nextFree()
it += IRInstruction(Opcode.LOADX, irDt, reg1=incReg, reg2=indexTr.resultReg, labelSymbol=variable)
it += IRInstruction(operationRegister, irDt, reg1=incReg)
it += IRInstruction(Opcode.STOREX, irDt, reg1=incReg, reg2=indexTr.resultReg, labelSymbol=variable)
}
}
}
} else
throw AssemblyError("weird assigntarget")
} else
throw AssemblyError("weird assigntarget")
}
return result
}
@ -1459,10 +1459,10 @@ class IRCodeGen(
addToResult(result, countTr, countTr.resultReg, -1)
addInstr(result, IRInstruction(Opcode.BEQ, irDt, reg1=countTr.resultReg, immediate = 0, labelSymbol = skipRepeatLabel), null)
result += labelFirstChunk(translateNode(repeat.statements), repeatLabel)
val chunk = IRCodeChunk(null, null)
chunk += IRInstruction(Opcode.DEC, irDt, reg1=countTr.resultReg)
chunk += IRInstruction(Opcode.BNE, irDt, reg1=countTr.resultReg, immediate = 0, labelSymbol = repeatLabel)
result += chunk
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.DEC, irDt, reg1 = countTr.resultReg)
it += IRInstruction(Opcode.BNE, irDt, reg1 = countTr.resultReg, immediate = 0, labelSymbol = repeatLabel)
}
result += IRCodeChunk(skipRepeatLabel, null)
return result
}

View File

@ -697,6 +697,9 @@ internal class AstChecker(private val program: Program,
}
}
}
if(decl.splitArray && decl.type==VarDeclType.MEMORY)
err("@split can't be used on memory mapped arrays")
}
if(decl.datatype==DataType.STR) {

View File

@ -1,6 +1,8 @@
TODO
====
- vm: fix the last replacement code for the now removed LOADSPLIT/STORESPLIT opcodes.
...

View File

@ -1,30 +1,34 @@
%import textio
%option splitarrays
%zeropage basicsafe
main {
sub start() {
str name1 = "name1"
str name2 = "name2"
uword[] names = [name1, name2, "name3"]
cx16.r0++
ubyte xx = 2
names[xx] = "irmen"
uword ww
for ww in names {
txt.print(ww)
txt.spc()
}
txt.nl()
names = [1111,2222,3333]
for ww in names {
txt.print_uw(ww)
txt.spc()
}
txt.nl()
uword[] names = [name1, name2, "name3"]
uword ww
; for ww in names {
; txt.print(ww)
; txt.spc()
; }
; txt.nl()
ubyte idx=1
names[idx] = 2000
txt.print_uw(names[1])
names[idx]++
txt.print_uw(names[1])
names[idx]--
txt.print_uw(names[1])
; names = [1111,2222,3333]
; for ww in names {
; txt.print_uw(ww)
; txt.spc()
; }
; txt.nl()
txt.print("end.")
repeat {
}
}
}

View File

@ -185,8 +185,14 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
xml.writeStartElement("VARIABLESNOINIT")
xml.writeCharacters("\n")
for (variable in variablesNoInit) {
val typeStr = getTypeString(variable)
xml.writeCharacters("$typeStr ${variable.name} zp=${variable.zpwish}\n")
if(variable.dt in SplitWordArrayTypes) {
// split into 2 ubyte arrays lsb+msb
xml.writeCharacters("ubyte[${variable.length}] ${variable.name}_lsb zp=${variable.zpwish}\n")
xml.writeCharacters("ubyte[${variable.length}] ${variable.name}_msb zp=${variable.zpwish}\n")
} else {
val typeStr = getTypeString(variable)
xml.writeCharacters("$typeStr ${variable.name} zp=${variable.zpwish}\n")
}
}
xml.writeEndElement()
@ -195,36 +201,60 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
xml.writeCharacters("\n")
for (variable in variablesWithInit) {
val typeStr = getTypeString(variable)
val value: String = when(variable.dt) {
DataType.FLOAT -> (variable.onetimeInitializationNumericValue ?: "").toString()
in NumericDatatypes -> (variable.onetimeInitializationNumericValue?.toInt()?.toHex() ?: "").toString()
DataType.STR -> {
val encoded = irProgram.encoding.encodeString(variable.onetimeInitializationStringValue!!.first, variable.onetimeInitializationStringValue!!.second) + listOf(0u)
encoded.joinToString(",") { it.toInt().toString() }
}
DataType.ARRAY_F -> {
if(variable.onetimeInitializationArrayValue!=null) {
variable.onetimeInitializationArrayValue!!.joinToString(",") { it.number!!.toString() }
} else {
"" // array will be zero'd out at program start
if(variable.dt in SplitWordArrayTypes) {
val lsbValue: String
val msbValue: String
if(variable.onetimeInitializationArrayValue==null) {
lsbValue = ""
msbValue = ""
} else {
lsbValue = variable.onetimeInitializationArrayValue!!.joinToString(",") {
if(it.number!=null)
(it.number!!.toInt() and 255).toHex()
else
"@<${it.addressOfSymbol}"
}
msbValue = variable.onetimeInitializationArrayValue!!.joinToString(",") {
if(it.number!=null)
(it.number!!.toInt() shr 8).toHex()
else
"@>${it.addressOfSymbol}"
}
}
in ArrayDatatypes -> {
if(variable.onetimeInitializationArrayValue!==null) {
variable.onetimeInitializationArrayValue!!.joinToString(",") {
if(it.number!=null)
it.number!!.toInt().toHex()
else
"@${it.addressOfSymbol}"
xml.writeCharacters("ubyte[${variable.length}] ${variable.name}_lsb=$lsbValue zp=${variable.zpwish}\n")
xml.writeCharacters("ubyte[${variable.length}] ${variable.name}_msb=$msbValue zp=${variable.zpwish}\n")
} else {
val typeStr = getTypeString(variable)
val value: String = when(variable.dt) {
DataType.FLOAT -> (variable.onetimeInitializationNumericValue ?: "").toString()
in NumericDatatypes -> (variable.onetimeInitializationNumericValue?.toInt()?.toHex() ?: "").toString()
DataType.STR -> {
val encoded = irProgram.encoding.encodeString(variable.onetimeInitializationStringValue!!.first, variable.onetimeInitializationStringValue!!.second) + listOf(0u)
encoded.joinToString(",") { it.toInt().toString() }
}
DataType.ARRAY_F -> {
if(variable.onetimeInitializationArrayValue!=null) {
variable.onetimeInitializationArrayValue!!.joinToString(",") { it.number!!.toString() }
} else {
"" // array will be zero'd out at program start
}
} else {
"" // array will be zero'd out at program start
}
in ArrayDatatypes -> {
if(variable.onetimeInitializationArrayValue!==null) {
variable.onetimeInitializationArrayValue!!.joinToString(",") {
if(it.number!=null)
it.number!!.toInt().toHex()
else
"@${it.addressOfSymbol}"
}
} else {
"" // array will be zero'd out at program start
}
}
else -> throw InternalCompilerException("weird dt")
}
else -> throw InternalCompilerException("weird dt")
xml.writeCharacters("$typeStr ${variable.name}=$value zp=${variable.zpwish}\n")
}
xml.writeCharacters("$typeStr ${variable.name}=$value zp=${variable.zpwish}\n")
}
xml.writeEndElement()
xml.writeCharacters("\n")

View File

@ -36,15 +36,11 @@ load reg1, value - load immediate value into register. If y
loadm reg1, address - load reg1 with value at memory address
loadi reg1, reg2 - load reg1 with value at memory indirect, memory pointed to by reg2
loadx reg1, reg2, address - load reg1 with value at memory address indexed by value in reg2
loadxsplit reg1, reg2, arraylength, arrayaddress - load reg1 word with value from "split lsb/msb array" indexed by reg2
loadmsplit reg1, arraylength, indexedarrayaddress - load reg1 word with value from "split lsb/msb array" element at indexedarrayaddress
loadix reg1, reg2, pointeraddr - load reg1 with value at memory indirect, pointed to by pointeraddr indexed by value in reg2
loadr reg1, reg2 - load reg1 with value in register reg2
storem reg1, address - store reg1 at memory address
storei reg1, reg2 - store reg1 at memory indirect, memory pointed to by reg2
storex reg1, reg2, address - store reg1 at memory address, indexed by value in reg2
storexsplit reg1, reg2, arraylength, arrayaddress - store reg1 word in "split lsb/msb array", indexed by value in reg2
storemsplit reg1, arraylength, indexedarrayaddress - store reg1 word in "split lsb/msb array" element at indexedarrayaddress
storeix reg1, reg2, pointeraddr - store reg1 at memory indirect, pointed to by pointeraddr indexed by value in reg2
storezm address - store zero at memory address
storezi reg1 - store zero at memory pointed to by reg1
@ -121,10 +117,8 @@ exts reg1 - reg1 = signed extension of reg1 (b
ext reg1 - reg1 = unsigned extension of reg1 (which in practice just means clearing the MSB / MSW) (ext.w not yet implemented as we don't have longs yet)
inc reg1 - reg1 = reg1+1
incm address - memory at address += 1
incmsplit arraylen, address - memory at address += 1 (in lsb/msb split word array)
dec reg1 - reg1 = reg1-1
decm address - memory at address -= 1
decmsplit arraylen, address - memory at address -= 1 (in lsb/msb split word array)
neg reg1 - reg1 = sign negation of reg1
negm address - sign negate memory at address
addr reg1, reg2 - reg1 += reg2
@ -233,21 +227,15 @@ enum class Opcode {
LOADM,
LOADI,
LOADX,
LOADXSPLIT,
LOADMSPLIT,
LOADIX,
LOADR,
STOREM,
STOREI,
STOREX,
STOREXSPLIT,
STOREMSPLIT,
STOREIX,
STOREZM,
STOREZI,
STOREZX,
STOREZXSPLIT,
STOREZMSPLIT,
JUMP,
JUMPA,
@ -295,10 +283,8 @@ enum class Opcode {
INC,
INCM,
INCMSPLIT,
DEC,
DECM,
DECMSPLIT,
NEG,
NEGM,
ADDR,
@ -516,21 +502,15 @@ val instructionFormats = mutableMapOf(
Opcode.LOADM to InstructionFormat.from("BW,>r1,<a | F,>fr1,<a"),
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.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.LOADR to InstructionFormat.from("BW,>r1,<r2 | F,>fr1,<fr2"),
Opcode.STOREM to InstructionFormat.from("BW,<r1,>a | F,<fr1,>a"),
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.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.STOREZM to InstructionFormat.from("BW,>a | F,>a"),
Opcode.STOREZI to InstructionFormat.from("BW,<r1 | F,<r1"),
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.JUMPA to InstructionFormat.from("N,<a"),
Opcode.CALL to InstructionFormat.from("N,call"),
@ -575,10 +555,8 @@ val instructionFormats = mutableMapOf(
Opcode.SGES to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.INC to InstructionFormat.from("BW,<>r1 | F,<>fr1"),
Opcode.INCM to InstructionFormat.from("BW,<>a | F,<>a"),
Opcode.INCMSPLIT to InstructionFormat.from("W,<i,<>a"),
Opcode.DEC to InstructionFormat.from("BW,<>r1 | F,<>fr1"),
Opcode.DECM to InstructionFormat.from("BW,<>a | F,<>a"),
Opcode.DECMSPLIT to InstructionFormat.from("W,<i,<>a"),
Opcode.NEG to InstructionFormat.from("BW,<>r1 | F,<>fr1"),
Opcode.NEGM to InstructionFormat.from("BW,<>a | F,<>a"),
Opcode.ADDR to InstructionFormat.from("BW,<>r1,<r2 | F,<>fr1,<fr2"),

View File

@ -14,10 +14,9 @@ fun getTypeString(dt : DataType): String = when(dt) {
DataType.ARRAY_UB, DataType.STR -> "ubyte[]"
DataType.ARRAY_B -> "byte[]"
DataType.ARRAY_UW -> "uword[]"
DataType.ARRAY_UW_SPLIT -> "uword_split[]"
DataType.ARRAY_W -> "word[]"
DataType.ARRAY_W_SPLIT -> "word_split[]"
DataType.ARRAY_F -> "float[]"
in SplitWordArrayTypes -> throw InternalCompilerException("split array should have been converted to 2 ubyte arrays")
else -> throw InternalCompilerException("weird dt")
}
@ -31,10 +30,9 @@ fun getTypeString(memvar: StMemVar): String = when(memvar.dt) {
DataType.ARRAY_UB, DataType.STR -> "ubyte[${memvar.length}]"
DataType.ARRAY_B -> "byte[${memvar.length}]"
DataType.ARRAY_UW -> "uword[${memvar.length}]"
DataType.ARRAY_UW_SPLIT -> "uword_split[${memvar.length}]"
DataType.ARRAY_W -> "word[${memvar.length}]"
DataType.ARRAY_W_SPLIT -> "word_split[${memvar.length}]"
DataType.ARRAY_F -> "float[${memvar.length}]"
in SplitWordArrayTypes -> throw InternalCompilerException("@split can't be used on memory mapped arrays")
else -> throw InternalCompilerException("weird dt")
}
@ -48,10 +46,9 @@ fun getTypeString(variable : StStaticVariable): String = when(variable.dt) {
DataType.ARRAY_UB, DataType.STR -> "ubyte[${variable.length}]"
DataType.ARRAY_B -> "byte[${variable.length}]"
DataType.ARRAY_UW -> "uword[${variable.length}]"
DataType.ARRAY_UW_SPLIT -> "uword_split[${variable.length}]"
DataType.ARRAY_W -> "word[${variable.length}]"
DataType.ARRAY_W_SPLIT -> "word_split[${variable.length}]"
DataType.ARRAY_F -> "float[${variable.length}]"
in SplitWordArrayTypes -> throw InternalCompilerException("split array should have been converted to 2 ubyte arrays")
else -> throw InternalCompilerException("weird dt")
}
@ -78,6 +75,8 @@ fun parseIRValue(value: String): Float {
throw IRParseException("attempt to parse a label as numeric value")
else if(value.startsWith('&'))
throw IRParseException("address-of should be done with normal LOAD <symbol>")
else if(value.startsWith('@'))
throw IRParseException("address-of @ should have been handled earlier")
else
return value.toFloat()
}

View File

@ -164,17 +164,11 @@ class VirtualMachine(irProgram: IRProgram) {
Opcode.LOAD -> InsLOAD(ins)
Opcode.LOADM -> InsLOADM(ins)
Opcode.LOADX -> InsLOADX(ins)
Opcode.LOADXSPLIT -> InsLOADXSPLIT(ins)
Opcode.LOADMSPLIT -> InsLOADMSPLIT(ins)
Opcode.LOADI -> InsLOADI(ins)
Opcode.LOADIX -> InsLOADIX(ins)
Opcode.LOADR -> InsLOADR(ins)
Opcode.STOREM -> InsSTOREM(ins)
Opcode.STOREX -> InsSTOREX(ins)
Opcode.STOREXSPLIT -> InsSTOREXSPLIT(ins)
Opcode.STOREZXSPLIT -> InsSTOREZXSPLIT(ins)
Opcode.STOREMSPLIT -> InsSTOREMSPLIT(ins)
Opcode.STOREZMSPLIT -> InsSTOREZMSPLIT(ins)
Opcode.STOREIX -> InsSTOREIX(ins)
Opcode.STOREI -> InsSTOREI(ins)
Opcode.STOREZM -> InsSTOREZM(ins)
@ -223,10 +217,8 @@ class VirtualMachine(irProgram: IRProgram) {
Opcode.SGES -> InsSGES(ins)
Opcode.INC -> InsINC(ins)
Opcode.INCM -> InsINCM(ins)
Opcode.INCMSPLIT -> InsINCMSPLIT(ins)
Opcode.DEC -> InsDEC(ins)
Opcode.DECM -> InsDECM(ins)
Opcode.DECMSPLIT -> InsDECMSPLIT(ins)
Opcode.NEG -> InsNEG(ins)
Opcode.NEGM -> InsNEGM(ins)
Opcode.ADDR -> InsADDR(ins)
@ -421,60 +413,6 @@ class VirtualMachine(irProgram: IRProgram) {
nextPc()
}
private fun InsLOADXSPLIT(i: IRInstruction) {
require(i.type==IRDataType.WORD)
val address = i.address!! + registers.getUW(i.reg2!!).toInt()
val lsb = memory.getUB(address)
val msb = memory.getUB(address+i.immediate!!)
registers.setUW(i.reg1!!, ((msb.toInt() shl 8) or lsb.toInt()).toUShort())
nextPc()
}
private fun InsLOADMSPLIT(i: IRInstruction) {
require(i.type==IRDataType.WORD)
val address = i.address!!
val lsb = memory.getUB(address)
val msb = memory.getUB(address+i.immediate!!)
registers.setUW(i.reg1!!, ((msb.toInt() shl 8) or lsb.toInt()).toUShort())
nextPc()
}
private fun InsSTOREXSPLIT(i: IRInstruction) {
require(i.type==IRDataType.WORD)
val address = i.address!! + registers.getUW(i.reg2!!).toInt()
val lsb = registers.getUW(i.reg1!!).toUByte()
val msb = (registers.getUW(i.reg1!!).toInt() shr 8).toUByte()
memory.setUB(address, lsb)
memory.setUB(address+i.immediate!!, msb)
nextPc()
}
private fun InsSTOREMSPLIT(i: IRInstruction) {
require(i.type==IRDataType.WORD)
val address = i.address!!
val lsb = registers.getUW(i.reg1!!).toUByte()
val msb = (registers.getUW(i.reg1!!).toInt() shr 8).toUByte()
memory.setUB(address, lsb)
memory.setUB(address+i.immediate!!, msb)
nextPc()
}
private fun InsSTOREZXSPLIT(i: IRInstruction) {
require(i.type==IRDataType.WORD)
val address = i.address!! + registers.getUW(i.reg2!!).toInt()
memory.setUB(address, 0u)
memory.setUB(address+i.immediate!!, 0u)
nextPc()
}
private fun InsSTOREZMSPLIT(i: IRInstruction) {
require(i.type==IRDataType.WORD)
val address = i.address!!
memory.setUB(address, 0u)
memory.setUB(address+i.immediate!!, 0u)
nextPc()
}
private fun InsLOADIX(i: IRInstruction) {
when (i.type!!) {
IRDataType.BYTE -> {
@ -921,20 +859,6 @@ class VirtualMachine(irProgram: IRProgram) {
nextPc()
}
private fun InsINCMSPLIT(i: IRInstruction) {
val address = i.address!!
var lsb = memory.getUB(address).toInt()
var msb = memory.getUB(address+i.immediate!!).toInt()
lsb++
if(lsb>255) {
lsb = 0
msb++
}
memory.setUB(address, lsb.toUByte())
memory.setUB(address+i.immediate!!, msb.toUByte())
nextPc()
}
private fun InsDEC(i: IRInstruction) {
when(i.type!!) {
IRDataType.BYTE -> registers.setUB(i.reg1!!, (registers.getUB(i.reg1!!)-1u).toUByte())
@ -953,21 +877,6 @@ class VirtualMachine(irProgram: IRProgram) {
nextPc()
}
private fun InsDECMSPLIT(i: IRInstruction) {
val address = i.address!!
var lsb = memory.getUB(address).toInt()
var msb = memory.getUB(address+i.immediate!!).toInt()
lsb--
if(lsb<0) {
lsb = 255
msb--
}
memory.setUB(address, lsb.toUByte())
memory.setUB(address+i.immediate!!, msb.toUByte())
nextPc()
}
private fun InsNEG(i: IRInstruction) {
when(i.type!!) {
IRDataType.BYTE -> registers.setUB(i.reg1!!, (-registers.getUB(i.reg1!!).toInt()).toUByte())

View File

@ -295,7 +295,20 @@ class VmProgramLoader {
when(variable.dt) {
DataType.STR, DataType.ARRAY_UB -> {
for(elt in it) {
memory.setUB(addr, elt.number!!.toInt().toUByte())
if(elt.addressOfSymbol!=null) {
val name = elt.addressOfSymbol!!
val symbolAddress = if(name.startsWith('<')) {
symbolAddresses[name.drop(1)]?.and(255)
?: throw IRParseException("vm cannot yet load a label address as a value: $name") // TODO
} else if(name.startsWith('>')) {
symbolAddresses[name.drop(1)]?.shr(8)
?: throw IRParseException("vm cannot yet load a label address as a value: $name") // TODO
} else
throw IRParseException("for byte-array address-of, expected < or > (lsb/msb)")
memory.setUB(addr, symbolAddress.toUByte())
} else {
memory.setUB(addr, elt.number!!.toInt().toUByte())
}
addr++
}
}