vm: implement split incr/decr

This commit is contained in:
Irmen de Jong 2023-06-03 22:22:13 +02:00
parent 1bdae53f4e
commit 380f557c45
6 changed files with 186 additions and 53 deletions

View File

@ -1361,44 +1361,87 @@ class IRCodeGen(
private fun translate(postIncrDecr: PtPostIncrDecr): IRCodeChunks {
val result = mutableListOf<IRCodeChunkBase>()
val array = postIncrDecr.target.array
val operationMem: Opcode
val operationRegister: Opcode
when(postIncrDecr.operator) {
"++" -> {
operationMem = Opcode.INCM
operationRegister = Opcode.INC
}
"--" -> {
operationMem = Opcode.DECM
operationRegister = Opcode.DEC
}
else -> throw AssemblyError("weird operator")
}
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)
val skipLabel = createLabelName()
when(postIncrDecr.operator) {
"++" -> {
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.INCM, IRDataType.BYTE, labelSymbol = "${variable}_lsb+$fixedIndex")
it += IRInstruction(Opcode.BSTNE, labelSymbol = skipLabel)
it += IRInstruction(Opcode.INCM, IRDataType.BYTE, labelSymbol = "${variable}_msb+$fixedIndex")
}
result += IRCodeChunk(skipLabel, null)
}
"--" -> {
val valueReg=registers.nextFree()
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOADM, IRDataType.BYTE, reg1=valueReg, labelSymbol = "${variable}_lsb+$fixedIndex")
it += IRInstruction(Opcode.BSTNE, labelSymbol = skipLabel)
it += IRInstruction(Opcode.DECM, IRDataType.BYTE, labelSymbol = "${variable}_msb+$fixedIndex")
}
result += IRCodeChunk(skipLabel, null).also {
it += IRInstruction(Opcode.DECM, IRDataType.BYTE, labelSymbol = "${variable}_lsb+$fixedIndex")
}
}
else -> throw AssemblyError("weird operator")
}
} else {
val arrayLength = iterable.length!!
val indexTr = expressionEval.translateExpression(array.index)
addToResult(result, indexTr, indexTr.resultReg, -1)
val chunk = IRCodeChunk(null, null)
val incReg = registers.nextFree()
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
val skipLabel = createLabelName()
when(postIncrDecr.operator) {
"++" -> {
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol = "${variable}_lsb")
it += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=incReg)
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol = "${variable}_lsb")
it += IRInstruction(Opcode.BSTNE, labelSymbol = skipLabel)
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol = "${variable}_msb")
it += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=incReg)
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol = "${variable}_msb")
}
result += IRCodeChunk(skipLabel, null)
}
"--" -> {
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol = "${variable}_lsb")
it += IRInstruction(Opcode.BSTNE, labelSymbol = skipLabel)
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol = "${variable}_msb")
it += IRInstruction(Opcode.DEC, IRDataType.BYTE, reg1=incReg)
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol = "${variable}_msb")
}
result += IRCodeChunk(skipLabel, null).also {
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol = "${variable}_lsb")
it += IRInstruction(Opcode.DEC, IRDataType.BYTE, reg1=incReg)
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol = "${variable}_lsb")
}
}
else -> throw AssemblyError("weird operator")
}
}
} else {
val ident = postIncrDecr.target.identifier
val memory = postIncrDecr.target.memory
val irDt = irType(postIncrDecr.target.type)
val operationMem: Opcode
val operationRegister: Opcode
when(postIncrDecr.operator) {
"++" -> {
operationMem = Opcode.INCM
operationRegister = Opcode.INC
}
"--" -> {
operationMem = Opcode.DECM
operationRegister = Opcode.DEC
}
else -> throw AssemblyError("weird operator")
}
if(ident!=null) {
addInstr(result, IRInstruction(operationMem, irDt, labelSymbol = ident.name), null)
} else if(memory!=null) {

View File

@ -14,7 +14,7 @@ Then you can choose a few ways to get a compiler:
**Download a precompiled version from github:**
#. download a recent "fat-jar" (called something like "prog8compiler-all.jar") from `the releases on Github <https://github.com/irmen/prog8/releases>`_
#. run the compiler with "java -jar prog8compiler-all.jar" to see how you can use it.
#. run the compiler with "java -jar prog8compiler.jar" to see how you can use it (use the correct name and version of the jar file you've downloaded).
**Using the Gradle build system to build it yourself:**
@ -86,11 +86,12 @@ The compiler will link everything together into one output program at the end.
If you start the compiler without arguments, it will print a short usage text.
For normal use the compiler can be invoked with the command:
``$ java -jar prog8compiler-8.14-all.jar sourcefile.p8``
``$ java -jar prog8compiler.jar -target cx16 sourcefile.p8``
(Use the appropriate name and version of the jar file downloaded from one of the Git releases.
Other ways to invoke the compiler are also available: see the introduction page about how
to build and run the compiler yourself)
to build and run the compiler yourself. The -target option is required, in this case we
tell it to compile a program for the Commander X16)
By default, assembly code is generated and written to ``sourcefile.asm``.

View File

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

View File

@ -15,12 +15,12 @@ main {
; }
; txt.nl()
ubyte idx=1
names[idx] = 2000
txt.print_uw(names[1])
names[idx] = $20ff
txt.print_uwhex(names[1], true)
names[idx]++
txt.print_uw(names[1])
txt.print_uwhex(names[1], true)
names[idx]--
txt.print_uw(names[1])
txt.print_uwhex(names[1], true)
names = [1111,2222,3333]
for ww in names {

View File

@ -15,7 +15,9 @@ Program to execute is not stored in the system memory, it's just a separate list
65536 bytes of memory. Thus memory pointers (addresses) are limited to 16 bits.
Value stack, max 128 entries of 1 byte each.
Status flags: Carry, Zero, Negative. NOTE: status flags are only affected by the CMP instruction or explicit CLC/SEC!!!
logical or arithmetic operations DO NOT AFFECT THE STATUS FLAGS UNLESS EXPLICITLY NOTED!
LOAD instructions DO affect the Z and N flags
INC/DEC instructions DO affect the Z and N flags
other instructions such as logical or arithmetic operations DO NOT AFFECT THE STATUS FLAGS UNLESS EXPLICITLY NOTED!
Instruction set is mostly a load/store architecture, there are few instructions operating on memory directly.

View File

@ -375,8 +375,11 @@ class VirtualMachine(irProgram: IRProgram) {
if(i.type==IRDataType.FLOAT)
registers.setFloat(i.fpReg1!!, i.immediateFp!!)
else {
if(i.immediate!=null)
if(i.immediate!=null) {
setResultReg(i.reg1!!, i.immediate!!, i.type!!)
statusZero = i.immediate==0
statusNegative = i.immediate!! <0
}
else {
if(i.labelSymbol==null)
throw IllegalArgumentException("expected LOAD of address of labelsymbol")
@ -388,8 +391,18 @@ class VirtualMachine(irProgram: IRProgram) {
private fun InsLOADM(i: IRInstruction) {
when(i.type!!) {
IRDataType.BYTE -> registers.setUB(i.reg1!!, memory.getUB(i.address!!))
IRDataType.WORD -> registers.setUW(i.reg1!!, memory.getUW(i.address!!))
IRDataType.BYTE -> {
val value = memory.getUB(i.address!!)
registers.setUB(i.reg1!!, value)
statusZero = value==0.toUByte()
statusNegative = value>=0x80u
}
IRDataType.WORD -> {
val value = memory.getUW(i.address!!)
registers.setUW(i.reg1!!, value)
statusZero = value== 0.toUShort()
statusNegative = value>=0x8000u
}
IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, memory.getFloat(i.address!!))
}
nextPc()
@ -397,8 +410,18 @@ class VirtualMachine(irProgram: IRProgram) {
private fun InsLOADI(i: IRInstruction) {
when(i.type!!) {
IRDataType.BYTE -> registers.setUB(i.reg1!!, memory.getUB(registers.getUW(i.reg2!!).toInt()))
IRDataType.WORD -> registers.setUW(i.reg1!!, memory.getUW(registers.getUW(i.reg2!!).toInt()))
IRDataType.BYTE -> {
val value = memory.getUB(registers.getUW(i.reg2!!).toInt())
registers.setUB(i.reg1!!, value)
statusZero = value==0.toUByte()
statusNegative = value>=0x80u
}
IRDataType.WORD -> {
val value = memory.getUW(registers.getUW(i.reg2!!).toInt())
registers.setUW(i.reg1!!, value)
statusZero = value== 0.toUShort()
statusNegative = value>=0x8000u
}
IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, memory.getFloat(registers.getUW(i.reg1!!).toInt()))
}
nextPc()
@ -406,8 +429,18 @@ class VirtualMachine(irProgram: IRProgram) {
private fun InsLOADX(i: IRInstruction) {
when (i.type!!) {
IRDataType.BYTE -> registers.setUB(i.reg1!!, memory.getUB(i.address!! + registers.getUW(i.reg2!!).toInt()))
IRDataType.WORD -> registers.setUW(i.reg1!!, memory.getUW(i.address!! + registers.getUW(i.reg2!!).toInt()))
IRDataType.BYTE -> {
val value = memory.getUB(i.address!! + registers.getUW(i.reg2!!).toInt())
registers.setUB(i.reg1!!, value)
statusZero = value==0.toUByte()
statusNegative = value>=0x80u
}
IRDataType.WORD -> {
val value = memory.getUW(i.address!! + registers.getUW(i.reg2!!).toInt())
registers.setUW(i.reg1!!, value)
statusZero = value== 0.toUShort()
statusNegative = value>=0x8000u
}
IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, memory.getFloat(i.address!! + registers.getUW(i.reg1!!).toInt()))
}
nextPc()
@ -417,11 +450,17 @@ class VirtualMachine(irProgram: IRProgram) {
when (i.type!!) {
IRDataType.BYTE -> {
val pointer = memory.getUW(i.address!!) + registers.getUB(i.reg2!!)
registers.setUB(i.reg1!!, memory.getUB(pointer.toInt()))
val value = memory.getUB(pointer.toInt())
registers.setUB(i.reg1!!, value)
statusZero = value==0.toUByte()
statusNegative = value>=0x80u
}
IRDataType.WORD -> {
val pointer = memory.getUW(i.address!!) + registers.getUB(i.reg2!!)
registers.setUW(i.reg1!!, memory.getUW(pointer.toInt()))
val value = memory.getUW(pointer.toInt())
registers.setUW(i.reg1!!, value)
statusZero = value== 0.toUShort()
statusNegative = value>=0x8000u
}
IRDataType.FLOAT -> {
val pointer = memory.getUW(i.address!!) + registers.getUB(i.reg1!!)
@ -433,8 +472,18 @@ class VirtualMachine(irProgram: IRProgram) {
private fun InsLOADR(i: IRInstruction) {
when(i.type!!) {
IRDataType.BYTE -> registers.setUB(i.reg1!!, registers.getUB(i.reg2!!))
IRDataType.WORD -> registers.setUW(i.reg1!!, registers.getUW(i.reg2!!))
IRDataType.BYTE -> {
val value = registers.getUB(i.reg2!!)
registers.setUB(i.reg1!!, value)
statusZero = value==0.toUByte()
statusNegative = value>=0x80u
}
IRDataType.WORD -> {
val value = registers.getUW(i.reg2!!)
registers.setUW(i.reg1!!, value)
statusZero = value== 0.toUShort()
statusNegative = value>=0x8000u
}
IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, registers.getFloat(i.fpReg2!!))
}
nextPc()
@ -842,8 +891,18 @@ class VirtualMachine(irProgram: IRProgram) {
private fun InsINC(i: IRInstruction) {
when(i.type!!) {
IRDataType.BYTE -> registers.setUB(i.reg1!!, (registers.getUB(i.reg1!!)+1u).toUByte())
IRDataType.WORD -> registers.setUW(i.reg1!!, (registers.getUW(i.reg1!!)+1u).toUShort())
IRDataType.BYTE -> {
val value = (registers.getUB(i.reg1!!)+1u).toUByte()
registers.setUB(i.reg1!!, value)
statusZero = value==0.toUByte()
statusNegative = value>=0x80u
}
IRDataType.WORD -> {
val value = (registers.getUW(i.reg1!!)+1u).toUShort()
registers.setUW(i.reg1!!, value)
statusZero = value==0.toUShort()
statusNegative = value>=0x8000u
}
IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, registers.getFloat(i.fpReg1!!)+1f)
}
nextPc()
@ -852,8 +911,18 @@ class VirtualMachine(irProgram: IRProgram) {
private fun InsINCM(i: IRInstruction) {
val address = i.address!!
when(i.type!!) {
IRDataType.BYTE -> memory.setUB(address, (memory.getUB(address)+1u).toUByte())
IRDataType.WORD -> memory.setUW(address, (memory.getUW(address)+1u).toUShort())
IRDataType.BYTE -> {
val value = (memory.getUB(address)+1u).toUByte()
memory.setUB(address, value)
statusZero = value==0.toUByte()
statusNegative = value>=0x80u
}
IRDataType.WORD -> {
val value = (memory.getUW(address)+1u).toUShort()
memory.setUW(address, value)
statusZero = value== 0.toUShort()
statusNegative = value>=0x8000u
}
IRDataType.FLOAT -> memory.setFloat(address, memory.getFloat(address)+1f)
}
nextPc()
@ -861,8 +930,18 @@ class VirtualMachine(irProgram: IRProgram) {
private fun InsDEC(i: IRInstruction) {
when(i.type!!) {
IRDataType.BYTE -> registers.setUB(i.reg1!!, (registers.getUB(i.reg1!!)-1u).toUByte())
IRDataType.WORD -> registers.setUW(i.reg1!!, (registers.getUW(i.reg1!!)-1u).toUShort())
IRDataType.BYTE -> {
val value = (registers.getUB(i.reg1!!)-1u).toUByte()
registers.setUB(i.reg1!!, value)
statusZero = value== 0.toUByte()
statusNegative = value>=0x80u
}
IRDataType.WORD -> {
val value = (registers.getUW(i.reg1!!)-1u).toUShort()
registers.setUW(i.reg1!!, value)
statusZero = value== 0.toUShort()
statusNegative = value>=0x8000u
}
IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, registers.getFloat(i.fpReg1!!)-1f)
}
nextPc()
@ -870,8 +949,18 @@ class VirtualMachine(irProgram: IRProgram) {
private fun InsDECM(i: IRInstruction) {
when(i.type!!) {
IRDataType.BYTE -> memory.setUB(i.address!!, (memory.getUB(i.address!!)-1u).toUByte())
IRDataType.WORD -> memory.setUW(i.address!!, (memory.getUW(i.address!!)-1u).toUShort())
IRDataType.BYTE -> {
val value = (memory.getUB(i.address!!)-1u).toUByte()
memory.setUB(i.address!!, value)
statusZero = value== 0.toUByte()
statusNegative = value>=0x80u
}
IRDataType.WORD -> {
val value = (memory.getUW(i.address!!)-1u).toUShort()
memory.setUW(i.address!!, value)
statusZero = value== 0.toUShort()
statusNegative = value>=0x8000u
}
IRDataType.FLOAT -> memory.setFloat(i.address!!, memory.getFloat(i.address!!)-1f)
}
nextPc()