mirror of
https://github.com/irmen/prog8.git
synced 2024-09-10 09:54:32 +00:00
IR: implemented inplace prefix op on split array
VM: NEG instructions also set N and Z flags
This commit is contained in:
parent
0800033b47
commit
39d2194d8f
@ -36,8 +36,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
|||||||
else
|
else
|
||||||
fallbackAssign(augAssign)
|
fallbackAssign(augAssign)
|
||||||
} else if(array!=null) {
|
} else if(array!=null) {
|
||||||
// TODO assignArrayAugmented(array, augAssign)
|
assignArrayAugmented(array, augAssign)
|
||||||
fallbackAssign(augAssign)
|
|
||||||
} else {
|
} else {
|
||||||
fallbackAssign(augAssign)
|
fallbackAssign(augAssign)
|
||||||
}
|
}
|
||||||
@ -157,27 +156,84 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun inplacePrefix(operator: String, array: PtArrayIndexer, eltSize: Int): Result<IRCodeChunks, NotImplementedError> {
|
private fun inplacePrefix(operator: String, array: PtArrayIndexer, eltSize: Int): Result<IRCodeChunks, NotImplementedError> {
|
||||||
if(array.splitWords)
|
|
||||||
TODO("inplace prefix for split word array")
|
|
||||||
|
|
||||||
val result = mutableListOf<IRCodeChunkBase>()
|
val result = mutableListOf<IRCodeChunkBase>()
|
||||||
val vmDt = irType(array.type)
|
val vmDt = irType(array.type)
|
||||||
val constIndex = array.index.asConstInteger()
|
val constIndex = array.index.asConstInteger()
|
||||||
|
|
||||||
|
fun loadIndex(): Int {
|
||||||
|
val tr = expressionEval.translateExpression(array.index)
|
||||||
|
addToResult(result, tr, tr.resultReg, -1)
|
||||||
|
if(!array.splitWords && eltSize>1)
|
||||||
|
result += codeGen.multiplyByConst(IRDataType.BYTE, tr.resultReg, eltSize)
|
||||||
|
return tr.resultReg
|
||||||
|
}
|
||||||
|
|
||||||
|
if(array.splitWords) {
|
||||||
|
// handle split LSB/MSB arrays
|
||||||
|
when(operator) {
|
||||||
|
"+" -> { }
|
||||||
|
"-" -> {
|
||||||
|
val skipCarryLabel = codeGen.createLabelName()
|
||||||
|
if(constIndex!=null) {
|
||||||
|
addInstr(result, IRInstruction(Opcode.NEGM, IRDataType.BYTE, labelSymbol = array.variable.name+"_lsb", symbolOffset = constIndex), null)
|
||||||
|
addInstr(result, IRInstruction(Opcode.BSTEQ, labelSymbol = skipCarryLabel), null)
|
||||||
|
addInstr(result, IRInstruction(Opcode.INCM, IRDataType.BYTE, labelSymbol = array.variable.name+"_msb", symbolOffset = constIndex), null)
|
||||||
|
addInstr(result, IRInstruction(Opcode.NEGM, IRDataType.BYTE, labelSymbol = array.variable.name+"_msb", symbolOffset = constIndex), skipCarryLabel)
|
||||||
|
} else {
|
||||||
|
val indexReg = loadIndex()
|
||||||
|
val registerLsb = codeGen.registers.nextFree()
|
||||||
|
val registerMsb = codeGen.registers.nextFree()
|
||||||
|
result += IRCodeChunk(null, null).also {
|
||||||
|
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1 = registerLsb, reg2 = indexReg, labelSymbol = array.variable.name+"_lsb")
|
||||||
|
it += IRInstruction(Opcode.NEG, IRDataType.BYTE, reg1 = registerLsb)
|
||||||
|
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1 = registerLsb, reg2 = indexReg, labelSymbol = array.variable.name+"_lsb")
|
||||||
|
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1 = registerMsb, reg2 = indexReg, labelSymbol = array.variable.name+"_msb")
|
||||||
|
it += IRInstruction(Opcode.NEG, IRDataType.BYTE, reg1 = registerMsb)
|
||||||
|
it += IRInstruction(Opcode.CMPI, IRDataType.BYTE, reg1 = registerLsb, immediate = 0)
|
||||||
|
it += IRInstruction(Opcode.BSTEQ, labelSymbol = skipCarryLabel)
|
||||||
|
it += IRInstruction(Opcode.DEC, IRDataType.BYTE, reg1 = registerMsb)
|
||||||
|
}
|
||||||
|
result += IRCodeChunk(skipCarryLabel, null).also {
|
||||||
|
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1 = registerMsb, reg2 = indexReg, labelSymbol = array.variable.name+"_msb")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"~" -> {
|
||||||
|
if(constIndex!=null) {
|
||||||
|
addInstr(result, IRInstruction(Opcode.INVM, IRDataType.BYTE, labelSymbol = array.variable.name+"_lsb", symbolOffset = constIndex), null)
|
||||||
|
addInstr(result, IRInstruction(Opcode.INVM, IRDataType.BYTE, labelSymbol = array.variable.name+"_msb", symbolOffset = constIndex), null)
|
||||||
|
} else {
|
||||||
|
val indexReg = loadIndex()
|
||||||
|
val register = codeGen.registers.nextFree()
|
||||||
|
result += IRCodeChunk(null, null).also {
|
||||||
|
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1 = register, reg2 = indexReg, labelSymbol = array.variable.name+"_lsb")
|
||||||
|
it += IRInstruction(Opcode.INV, IRDataType.BYTE, reg1 = register)
|
||||||
|
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1 = register, reg2 = indexReg, labelSymbol = array.variable.name+"_lsb")
|
||||||
|
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1 = register, reg2 = indexReg, labelSymbol = array.variable.name+"_msb")
|
||||||
|
it += IRInstruction(Opcode.INV, IRDataType.BYTE, reg1 = register)
|
||||||
|
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1 = register, reg2 = indexReg, labelSymbol = array.variable.name+"_msb")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> throw AssemblyError("weird prefix operator")
|
||||||
|
}
|
||||||
|
return Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// normal array.
|
||||||
|
|
||||||
when(operator) {
|
when(operator) {
|
||||||
"+" -> { }
|
"+" -> { }
|
||||||
"-" -> {
|
"-" -> {
|
||||||
if(constIndex!=null) {
|
if(constIndex!=null) {
|
||||||
addInstr(result, IRInstruction(Opcode.NEGM, vmDt, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize), null)
|
addInstr(result, IRInstruction(Opcode.NEGM, vmDt, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize), null)
|
||||||
} else {
|
} else {
|
||||||
|
val indexReg = loadIndex()
|
||||||
val register = codeGen.registers.nextFree()
|
val register = codeGen.registers.nextFree()
|
||||||
val tr = expressionEval.translateExpression(array.index)
|
|
||||||
addToResult(result, tr, tr.resultReg, -1)
|
|
||||||
if(eltSize>1)
|
|
||||||
result += codeGen.multiplyByConst(IRDataType.BYTE, tr.resultReg, eltSize)
|
|
||||||
result += IRCodeChunk(null, null).also {
|
result += IRCodeChunk(null, null).also {
|
||||||
it += IRInstruction(Opcode.LOADX, vmDt, reg1 = register, reg2 = tr.resultReg, labelSymbol = array.variable.name)
|
it += IRInstruction(Opcode.LOADX, vmDt, reg1 = register, reg2 = indexReg, labelSymbol = array.variable.name)
|
||||||
it += IRInstruction(Opcode.NEG, vmDt, reg1 = register)
|
it += IRInstruction(Opcode.NEG, vmDt, reg1 = register)
|
||||||
it += IRInstruction(Opcode.STOREX, vmDt, reg1 = register, reg2 = tr.resultReg, labelSymbol = array.variable.name)
|
it += IRInstruction(Opcode.STOREX, vmDt, reg1 = register, reg2 = indexReg, labelSymbol = array.variable.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -185,35 +241,29 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
|||||||
if(constIndex!=null) {
|
if(constIndex!=null) {
|
||||||
addInstr(result, IRInstruction(Opcode.INVM, vmDt, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize), null)
|
addInstr(result, IRInstruction(Opcode.INVM, vmDt, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize), null)
|
||||||
} else {
|
} else {
|
||||||
|
val indexReg = loadIndex()
|
||||||
val register = codeGen.registers.nextFree()
|
val register = codeGen.registers.nextFree()
|
||||||
val tr = expressionEval.translateExpression(array.index)
|
|
||||||
addToResult(result, tr, tr.resultReg, -1)
|
|
||||||
if(eltSize>1)
|
|
||||||
result += codeGen.multiplyByConst(IRDataType.BYTE, tr.resultReg, eltSize)
|
|
||||||
result += IRCodeChunk(null, null).also {
|
result += IRCodeChunk(null, null).also {
|
||||||
it += IRInstruction(Opcode.LOADX, vmDt, reg1 = register, reg2 = tr.resultReg, labelSymbol = array.variable.name)
|
it += IRInstruction(Opcode.LOADX, vmDt, reg1 = register, reg2 = indexReg, labelSymbol = array.variable.name)
|
||||||
it += IRInstruction(Opcode.INV, vmDt, reg1 = register)
|
it += IRInstruction(Opcode.INV, vmDt, reg1 = register)
|
||||||
it += IRInstruction(Opcode.STOREX, vmDt, reg1 = register, reg2 = tr.resultReg, labelSymbol = array.variable.name)
|
it += IRInstruction(Opcode.STOREX, vmDt, reg1 = register, reg2 = indexReg, labelSymbol = array.variable.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"not" -> {
|
"not" -> {
|
||||||
|
// TODO: in boolean branch, is 'not' handled ok like this?
|
||||||
val register = codeGen.registers.nextFree()
|
val register = codeGen.registers.nextFree()
|
||||||
if(constIndex!=null) {
|
if(constIndex!=null) {
|
||||||
// TODO: in boolean branch, is 'not' handled ok like this?
|
|
||||||
result += IRCodeChunk(null, null).also {
|
result += IRCodeChunk(null, null).also {
|
||||||
it += IRInstruction(Opcode.LOAD, vmDt, reg1=register, immediate = 1)
|
it += IRInstruction(Opcode.LOAD, vmDt, reg1=register, immediate = 1)
|
||||||
it += IRInstruction(Opcode.XORM, vmDt, reg1=register, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize)
|
it += IRInstruction(Opcode.XORM, vmDt, reg1=register, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val tr = expressionEval.translateExpression(array.index)
|
val indexReg = loadIndex()
|
||||||
addToResult(result, tr, tr.resultReg, -1)
|
|
||||||
if(eltSize>1)
|
|
||||||
result += codeGen.multiplyByConst(IRDataType.BYTE, tr.resultReg, eltSize)
|
|
||||||
result += IRCodeChunk(null, null).also {
|
result += IRCodeChunk(null, null).also {
|
||||||
it += IRInstruction(Opcode.LOADX, vmDt, reg1 = register, reg2 = tr.resultReg, labelSymbol = array.variable.name)
|
it += IRInstruction(Opcode.LOADX, vmDt, reg1 = register, reg2 = indexReg, labelSymbol = array.variable.name)
|
||||||
it += IRInstruction(Opcode.XOR, vmDt, reg1 = register, immediate = 1)
|
it += IRInstruction(Opcode.XOR, vmDt, reg1 = register, immediate = 1)
|
||||||
it += IRInstruction(Opcode.STOREX, vmDt, reg1 = register, reg2 = tr.resultReg, labelSymbol = array.variable.name)
|
it += IRInstruction(Opcode.STOREX, vmDt, reg1 = register, reg2 = indexReg, labelSymbol = array.variable.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,43 +5,27 @@
|
|||||||
|
|
||||||
main {
|
main {
|
||||||
sub start() {
|
sub start() {
|
||||||
ubyte @shared index = 1
|
word[3] @split @shared array = [1111,$10ff,3333]
|
||||||
|
|
||||||
; @(2000) = 99
|
txt.print_w(array[1])
|
||||||
; uword @shared ptr = 2000
|
txt.nl()
|
||||||
; txt.print_ub(@(2000))
|
txt.print_w(-array[1])
|
||||||
; txt.nl()
|
txt.nl()
|
||||||
; @(2000) ++
|
array[1] = -array[1]
|
||||||
; @(2000) ++
|
txt.print_w(array[1])
|
||||||
; @(2000) --
|
|
||||||
; txt.print_ub(@(2000))
|
|
||||||
; txt.nl()
|
|
||||||
|
|
||||||
|
|
||||||
uword[3] @split arr
|
|
||||||
|
|
||||||
arr[1] = 9999
|
|
||||||
txt.print_uw(arr[1])
|
|
||||||
txt.nl()
|
txt.nl()
|
||||||
arr[1] = arr[1]*5
|
|
||||||
cx16.r0=2222
|
|
||||||
arr[1] *= cx16.r0
|
|
||||||
arr[1] -=5
|
|
||||||
arr[1] -=index
|
|
||||||
txt.print_uw(arr[1])
|
|
||||||
txt.nl()
|
txt.nl()
|
||||||
|
|
||||||
; arr[index] = 9999
|
ubyte @shared idx = 1
|
||||||
; txt.print_uw(arr[index])
|
txt.print_w(array[idx])
|
||||||
; txt.nl()
|
txt.nl()
|
||||||
; arr[index] += 5
|
txt.print_w(-array[idx])
|
||||||
; arr[index] += 5
|
txt.nl()
|
||||||
; arr[index] -= 5
|
array[idx] = -array[idx]
|
||||||
; txt.print_uw(arr[index])
|
txt.print_w(array[idx])
|
||||||
; txt.nl()
|
txt.nl()
|
||||||
|
|
||||||
|
|
||||||
;
|
|
||||||
; ubyte @shared xx
|
; ubyte @shared xx
|
||||||
; uword[3] ubarr
|
; uword[3] ubarr
|
||||||
; bool[3] barr
|
; bool[3] barr
|
||||||
@ -52,20 +36,20 @@ main {
|
|||||||
; ubarr[1] = ubarr[1] <= 2
|
; ubarr[1] = ubarr[1] <= 2
|
||||||
; ubarr[1] = ubarr[1] > 3
|
; ubarr[1] = ubarr[1] > 3
|
||||||
; ubarr[1] = ubarr[1] >= 3
|
; ubarr[1] = ubarr[1] >= 3
|
||||||
|
;
|
||||||
; barr[1] = barr[0] and barr[2]
|
; barr[1] = barr[0] and barr[2]
|
||||||
; barr[1] = barr[0] or barr[2]
|
; barr[1] = barr[0] or barr[2]
|
||||||
; barr[1] = barr[0] xor barr[2]
|
; barr[1] = barr[0] xor barr[2]
|
||||||
; barr[1] = not barr[0]
|
; barr[1] = not barr[0]
|
||||||
|
;
|
||||||
; ubarr[1] = 999
|
; ubarr[1] = 999
|
||||||
; ubarr[1] = ubarr[1]==999
|
; ubarr[1] = ubarr[1]==999
|
||||||
; txt.print_uw(ubarr[1])
|
; txt.print_uw(ubarr[1])
|
||||||
|
;
|
||||||
; barr[1] = barr[1] and bb
|
; barr[1] = barr[1] and bb
|
||||||
; barr[1] = barr[1] or bb
|
; barr[1] = barr[1] or bb
|
||||||
; barr[1] = barr[1] xor bb
|
; barr[1] = barr[1] xor bb
|
||||||
|
;
|
||||||
; bb = bb and barr[1]
|
; bb = bb and barr[1]
|
||||||
; bb = bb or barr[1]
|
; bb = bb or barr[1]
|
||||||
; bb = bb xor barr[1]
|
; bb = bb xor barr[1]
|
||||||
|
@ -16,7 +16,7 @@ Program to execute is not stored in the system memory, it's just a separate list
|
|||||||
Value stack, max 128 entries of 1 byte each.
|
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,
|
Status flags: Carry, Zero, Negative. NOTE: status flags are only affected by the CMP instruction or explicit CLC/SEC,
|
||||||
LOAD instructions DO affect the Z and N flags.
|
LOAD instructions DO affect the Z and N flags.
|
||||||
INC/DEC instructions DO affect the Z and N flags,
|
INC/DEC/NEG instructions DO affect the Z and N flags,
|
||||||
other instructions only affect Z an N flags if the value in a result register is written.
|
other instructions only affect Z an N flags if the value in a result register is written.
|
||||||
See OpcodesThatSetStatusbits
|
See OpcodesThatSetStatusbits
|
||||||
|
|
||||||
@ -444,6 +444,8 @@ val OpcodesThatSetStatusbitsButNotCarry = arrayOf(
|
|||||||
Opcode.LOADX,
|
Opcode.LOADX,
|
||||||
Opcode.LOADIX,
|
Opcode.LOADIX,
|
||||||
Opcode.LOADR,
|
Opcode.LOADR,
|
||||||
|
Opcode.NEG,
|
||||||
|
Opcode.NEGM,
|
||||||
Opcode.INC,
|
Opcode.INC,
|
||||||
Opcode.INCM,
|
Opcode.INCM,
|
||||||
Opcode.DEC,
|
Opcode.DEC,
|
||||||
@ -456,7 +458,7 @@ val OpcodesThatSetStatusbitsButNotCarry = arrayOf(
|
|||||||
Opcode.OR,
|
Opcode.OR,
|
||||||
Opcode.XORM,
|
Opcode.XORM,
|
||||||
Opcode.XORR,
|
Opcode.XORR,
|
||||||
Opcode.XOR
|
Opcode.XOR,
|
||||||
)
|
)
|
||||||
|
|
||||||
val OpcodesThatDependOnCarry = arrayOf(
|
val OpcodesThatDependOnCarry = arrayOf(
|
||||||
|
@ -974,8 +974,16 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
|
|
||||||
private fun InsNEG(i: IRInstruction) {
|
private fun InsNEG(i: IRInstruction) {
|
||||||
when(i.type!!) {
|
when(i.type!!) {
|
||||||
IRDataType.BYTE -> registers.setUB(i.reg1!!, (-registers.getUB(i.reg1!!).toInt()).toUByte())
|
IRDataType.BYTE -> {
|
||||||
IRDataType.WORD -> registers.setUW(i.reg1!!, (-registers.getUW(i.reg1!!).toInt()).toUShort())
|
val value = -registers.getUB(i.reg1!!).toInt()
|
||||||
|
registers.setUB(i.reg1!!, value.toUByte())
|
||||||
|
statusbitsNZ(value, IRDataType.BYTE)
|
||||||
|
}
|
||||||
|
IRDataType.WORD -> {
|
||||||
|
val value = -registers.getUW(i.reg1!!).toInt()
|
||||||
|
registers.setUW(i.reg1!!, value.toUShort())
|
||||||
|
statusbitsNZ(value, IRDataType.WORD)
|
||||||
|
}
|
||||||
IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, -registers.getFloat(i.fpReg1!!))
|
IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, -registers.getFloat(i.fpReg1!!))
|
||||||
}
|
}
|
||||||
nextPc()
|
nextPc()
|
||||||
@ -984,8 +992,16 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
private fun InsNEGM(i: IRInstruction) {
|
private fun InsNEGM(i: IRInstruction) {
|
||||||
val address = i.address!!
|
val address = i.address!!
|
||||||
when(i.type!!) {
|
when(i.type!!) {
|
||||||
IRDataType.BYTE -> memory.setUB(address, (-memory.getUB(address).toInt()).toUByte())
|
IRDataType.BYTE -> {
|
||||||
IRDataType.WORD -> memory.setUW(address, (-memory.getUW(address).toInt()).toUShort())
|
val value = -memory.getUB(address).toInt()
|
||||||
|
memory.setUB(address, value.toUByte())
|
||||||
|
statusbitsNZ(value, IRDataType.BYTE)
|
||||||
|
}
|
||||||
|
IRDataType.WORD -> {
|
||||||
|
val value = -memory.getUW(address).toInt()
|
||||||
|
memory.setUW(address, value.toUShort())
|
||||||
|
statusbitsNZ(value, IRDataType.WORD)
|
||||||
|
}
|
||||||
IRDataType.FLOAT -> memory.setFloat(address, -memory.getFloat(address))
|
IRDataType.FLOAT -> memory.setFloat(address, -memory.getFloat(address))
|
||||||
}
|
}
|
||||||
nextPc()
|
nextPc()
|
||||||
|
Loading…
Reference in New Issue
Block a user