vm: actually use the store-zero instructions in codegen

This commit is contained in:
Irmen de Jong 2022-05-11 15:13:44 +02:00
parent 627aa61184
commit d43ad849d1
7 changed files with 202 additions and 140 deletions

View File

@ -2,7 +2,6 @@ package prog8.codegen.virtual
import prog8.code.StStaticVariable import prog8.code.StStaticVariable
import prog8.code.ast.* import prog8.code.ast.*
import prog8.code.core.ArrayToElementTypes
import prog8.code.core.AssemblyError import prog8.code.core.AssemblyError
import prog8.code.core.DataType import prog8.code.core.DataType
import prog8.vm.Opcode import prog8.vm.Opcode
@ -241,32 +240,54 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
private fun funcPokeW(call: PtBuiltinFunctionCall): VmCodeChunk { private fun funcPokeW(call: PtBuiltinFunctionCall): VmCodeChunk {
val code = VmCodeChunk() val code = VmCodeChunk()
val valueReg = codeGen.vmRegisters.nextFree() if(codeGen.isZero(call.args[1])) {
if(call.args[0] is PtNumber) { if (call.args[0] is PtNumber) {
val address = (call.args[0] as PtNumber).number.toInt() val address = (call.args[0] as PtNumber).number.toInt()
code += exprGen.translateExpression(call.args[1], valueReg, -1) code += VmCodeInstruction(Opcode.STOREZM, VmDataType.WORD, value = address)
code += VmCodeInstruction(Opcode.STOREM, VmDataType.WORD, reg1 = valueReg, value=address) } else {
val addressReg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args[0], addressReg, -1)
code += VmCodeInstruction(Opcode.STOREZI, VmDataType.WORD, reg2 = addressReg)
}
} else { } else {
val addressReg = codeGen.vmRegisters.nextFree() val valueReg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args[0], addressReg, -1) if (call.args[0] is PtNumber) {
code += exprGen.translateExpression(call.args[1], valueReg, -1) val address = (call.args[0] as PtNumber).number.toInt()
code += VmCodeInstruction(Opcode.STOREI, VmDataType.WORD, reg1 = valueReg, reg2 = addressReg) code += exprGen.translateExpression(call.args[1], valueReg, -1)
code += VmCodeInstruction(Opcode.STOREM, VmDataType.WORD, reg1 = valueReg, value = address)
} else {
val addressReg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args[0], addressReg, -1)
code += exprGen.translateExpression(call.args[1], valueReg, -1)
code += VmCodeInstruction(Opcode.STOREI, VmDataType.WORD, reg1 = valueReg, reg2 = addressReg)
}
} }
return code return code
} }
private fun funcPoke(call: PtBuiltinFunctionCall): VmCodeChunk { private fun funcPoke(call: PtBuiltinFunctionCall): VmCodeChunk {
val code = VmCodeChunk() val code = VmCodeChunk()
val valueReg = codeGen.vmRegisters.nextFree() if(codeGen.isZero(call.args[1])) {
if(call.args[0] is PtNumber) { if (call.args[0] is PtNumber) {
val address = (call.args[0] as PtNumber).number.toInt() val address = (call.args[0] as PtNumber).number.toInt()
code += exprGen.translateExpression(call.args[1], valueReg, -1) code += VmCodeInstruction(Opcode.STOREZM, VmDataType.BYTE, value = address)
code += VmCodeInstruction(Opcode.STOREM, VmDataType.BYTE, reg1 = valueReg, value=address) } else {
val addressReg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args[0], addressReg, -1)
code += VmCodeInstruction(Opcode.STOREZI, VmDataType.BYTE, reg2 = addressReg)
}
} else { } else {
val addressReg = codeGen.vmRegisters.nextFree() val valueReg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args[0], addressReg, -1) if (call.args[0] is PtNumber) {
code += exprGen.translateExpression(call.args[1], valueReg, -1) val address = (call.args[0] as PtNumber).number.toInt()
code += VmCodeInstruction(Opcode.STOREI, VmDataType.BYTE, reg1 = valueReg, reg2 = addressReg) code += exprGen.translateExpression(call.args[1], valueReg, -1)
code += VmCodeInstruction(Opcode.STOREM, VmDataType.BYTE, reg1 = valueReg, value = address)
} else {
val addressReg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args[0], addressReg, -1)
code += exprGen.translateExpression(call.args[1], valueReg, -1)
code += VmCodeInstruction(Opcode.STOREI, VmDataType.BYTE, reg1 = valueReg, reg2 = addressReg)
}
} }
return code return code
} }
@ -361,5 +382,4 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
code += codeGen.translateNode(assignment) code += codeGen.translateNode(assignment)
return code return code
} }
} }

View File

@ -6,7 +6,6 @@ import prog8.code.ast.*
import prog8.code.core.* import prog8.code.core.*
import prog8.vm.Opcode import prog8.vm.Opcode
import prog8.vm.VmDataType import prog8.vm.VmDataType
import java.nio.file.Path
import kotlin.math.pow import kotlin.math.pow
@ -410,7 +409,7 @@ class CodeGen(internal val program: PtProgram,
// just shift multiple bits // just shift multiple bits
val pow2reg = vmRegisters.nextFree() val pow2reg = vmRegisters.nextFree()
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2) code += VmCodeInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2)
code += VmCodeInstruction(Opcode.LSLX, dt, reg1=reg, reg2=reg, reg3=pow2reg) code += VmCodeInstruction(Opcode.LSLN, dt, reg1=reg, reg2=reg, reg3=pow2reg)
} else { } else {
if (factor == 0) { if (factor == 0) {
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=reg, value=0) code += VmCodeInstruction(Opcode.LOAD, dt, reg1=reg, value=0)
@ -451,7 +450,7 @@ class CodeGen(internal val program: PtProgram,
// just shift multiple bits // just shift multiple bits
val pow2reg = vmRegisters.nextFree() val pow2reg = vmRegisters.nextFree()
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2) code += VmCodeInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2)
code += VmCodeInstruction(Opcode.LSRX, dt, reg1=reg, reg2=reg, reg3=pow2reg) code += VmCodeInstruction(Opcode.LSRN, dt, reg1=reg, reg2=reg, reg3=pow2reg)
} else { } else {
if (factor == 0) { if (factor == 0) {
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=reg, value=0xffff) code += VmCodeInstruction(Opcode.LOAD, dt, reg1=reg, value=0xffff)
@ -615,24 +614,32 @@ class CodeGen(internal val program: PtProgram,
val vmDt = vmType(assignment.value.type) val vmDt = vmType(assignment.value.type)
var resultRegister = -1 var resultRegister = -1
var resultFpRegister = -1 var resultFpRegister = -1
if(vmDt==VmDataType.FLOAT) { val zero = isZero(assignment.value)
resultFpRegister = vmRegisters.nextFreeFloat() if(!zero) {
code += expressionEval.translateExpression(assignment.value, -1, resultFpRegister) // calculate the assignment value
} else { if (vmDt == VmDataType.FLOAT) {
resultRegister = if (assignment.value is PtMachineRegister) { resultFpRegister = vmRegisters.nextFreeFloat()
(assignment.value as PtMachineRegister).register code += expressionEval.translateExpression(assignment.value, -1, resultFpRegister)
} else { } else {
val reg = vmRegisters.nextFree() resultRegister = if (assignment.value is PtMachineRegister) {
code += expressionEval.translateExpression(assignment.value, reg, -1) (assignment.value as PtMachineRegister).register
reg } else {
val reg = vmRegisters.nextFree()
code += expressionEval.translateExpression(assignment.value, reg, -1)
reg
}
} }
} }
if(ident!=null) { if(ident!=null) {
val address = allocations.get(ident.targetName) val address = allocations.get(ident.targetName)
code += if(vmDt==VmDataType.FLOAT) code += if(zero) {
VmCodeInstruction(Opcode.STOREM, vmDt, fpReg1=resultFpRegister, value=address) VmCodeInstruction(Opcode.STOREZM, vmDt, value = address)
else } else {
VmCodeInstruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=address) if (vmDt == VmDataType.FLOAT)
VmCodeInstruction(Opcode.STOREM, vmDt, fpReg1 = resultFpRegister, value = address)
else
VmCodeInstruction(Opcode.STOREM, vmDt, reg1 = resultRegister, value = address)
}
} }
else if(array!=null) { else if(array!=null) {
val variable = array.variable.targetName val variable = array.variable.targetName
@ -640,23 +647,45 @@ class CodeGen(internal val program: PtProgram,
val itemsize = program.memsizer.memorySize(array.type) val itemsize = program.memsizer.memorySize(array.type)
val fixedIndex = constIntValue(array.index) val fixedIndex = constIntValue(array.index)
val vmDtArrayIdx = vmType(array.type) val vmDtArrayIdx = vmType(array.type)
if(fixedIndex!=null) { // TODO floating point array incorrect?
variableAddr += fixedIndex*itemsize if(zero) {
code += VmCodeInstruction(Opcode.STOREM, vmDtArrayIdx, reg1 = resultRegister, value=variableAddr) if(fixedIndex!=null) {
variableAddr += fixedIndex*itemsize
code += VmCodeInstruction(Opcode.STOREZM, vmDtArrayIdx, value=variableAddr)
} else {
val indexReg = vmRegisters.nextFree()
code += expressionEval.translateExpression(array.index, indexReg, -1)
code += VmCodeInstruction(Opcode.STOREZX, vmDtArrayIdx, reg1=indexReg, value=variableAddr)
}
} else { } else {
val indexReg = vmRegisters.nextFree() if(fixedIndex!=null) {
code += expressionEval.translateExpression(array.index, indexReg, -1) variableAddr += fixedIndex*itemsize
code += VmCodeInstruction(Opcode.STOREX, vmDtArrayIdx, reg1 = resultRegister, reg2=indexReg, value=variableAddr) code += VmCodeInstruction(Opcode.STOREM, vmDtArrayIdx, reg1 = resultRegister, value=variableAddr)
} else {
val indexReg = vmRegisters.nextFree()
code += expressionEval.translateExpression(array.index, indexReg, -1)
code += VmCodeInstruction(Opcode.STOREX, vmDtArrayIdx, reg1 = resultRegister, reg2=indexReg, value=variableAddr)
}
} }
} }
else if(memory!=null) { else if(memory!=null) {
require(vmDt==VmDataType.BYTE) require(vmDt==VmDataType.BYTE)
if(memory.address is PtNumber) { if(zero) {
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=(memory.address as PtNumber).number.toInt()) if(memory.address is PtNumber) {
code += VmCodeInstruction(Opcode.STOREZM, vmDt, value=(memory.address as PtNumber).number.toInt())
} else {
val addressReg = vmRegisters.nextFree()
code += expressionEval.translateExpression(memory.address, addressReg, -1)
code += VmCodeInstruction(Opcode.STOREZI, vmDt, reg1=addressReg)
}
} else { } else {
val addressReg = vmRegisters.nextFree() if(memory.address is PtNumber) {
code += expressionEval.translateExpression(memory.address, addressReg, -1) code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=(memory.address as PtNumber).number.toInt())
code += VmCodeInstruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressReg) } else {
val addressReg = vmRegisters.nextFree()
code += expressionEval.translateExpression(memory.address, addressReg, -1)
code += VmCodeInstruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressReg)
}
} }
} }
else else
@ -722,4 +751,6 @@ class CodeGen(internal val program: PtProgram,
internal fun translateBuiltinFunc(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk = internal fun translateBuiltinFunc(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk =
builtinFuncGen.translate(call, resultRegister) builtinFuncGen.translate(call, resultRegister)
internal fun isZero(expression: PtExpression): Boolean = expression is PtNumber && expression.number==0.0
} }

View File

@ -9,7 +9,6 @@ import prog8.code.core.PassByValueDatatypes
import prog8.code.core.SignedDatatypes import prog8.code.core.SignedDatatypes
import prog8.vm.Opcode import prog8.vm.Opcode
import prog8.vm.VmDataType import prog8.vm.VmDataType
import java.nio.channels.FileLock
internal class ExpressionGen(private val codeGen: CodeGen) { internal class ExpressionGen(private val codeGen: CodeGen) {
@ -174,6 +173,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
private fun translate(expr: PtPrefix, resultRegister: Int): VmCodeChunk { private fun translate(expr: PtPrefix, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk() val code = VmCodeChunk()
// TODO if the value is a variable or memory read, use memory-versions of the opcodes instead of using intermediary register
code += translateExpression(expr.value, resultRegister, -1) code += translateExpression(expr.value, resultRegister, -1)
val vmDt = codeGen.vmType(expr.type) val vmDt = codeGen.vmType(expr.type)
when(expr.operator) { when(expr.operator) {
@ -363,22 +363,24 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
private fun operatorShiftRight(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, signed: Boolean): VmCodeChunk { private fun operatorShiftRight(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, signed: Boolean): VmCodeChunk {
val code = VmCodeChunk() val code = VmCodeChunk()
// TODO if shift is 1, use ASR/LSR instruction instead of multishift
val leftResultReg = codeGen.vmRegisters.nextFree() val leftResultReg = codeGen.vmRegisters.nextFree()
val rightResultReg = codeGen.vmRegisters.nextFree() val rightResultReg = codeGen.vmRegisters.nextFree()
code += translateExpression(binExpr.left, leftResultReg, -1) code += translateExpression(binExpr.left, leftResultReg, -1)
code += translateExpression(binExpr.right, rightResultReg, -1) code += translateExpression(binExpr.right, rightResultReg, -1)
val opc = if(signed) Opcode.ASRX else Opcode.LSRX val opc = if(signed) Opcode.ASRN else Opcode.LSRN
code += VmCodeInstruction(opc, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg) code += VmCodeInstruction(opc, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
return code return code
} }
private fun operatorShiftLeft(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk { private fun operatorShiftLeft(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk() val code = VmCodeChunk()
// TODO if shift is 1, use LSL instruction instead of multishift
val leftResultReg = codeGen.vmRegisters.nextFree() val leftResultReg = codeGen.vmRegisters.nextFree()
val rightResultReg = codeGen.vmRegisters.nextFree() val rightResultReg = codeGen.vmRegisters.nextFree()
code += translateExpression(binExpr.left, leftResultReg, -1) code += translateExpression(binExpr.left, leftResultReg, -1)
code += translateExpression(binExpr.right, rightResultReg, -1) code += translateExpression(binExpr.right, rightResultReg, -1)
code += VmCodeInstruction(Opcode.LSLX, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg) code += VmCodeInstruction(Opcode.LSLN, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
return code return code
} }
@ -568,16 +570,26 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
val code = VmCodeChunk() val code = VmCodeChunk()
for ((arg, parameter) in fcall.args.zip(subroutine.parameters)) { for ((arg, parameter) in fcall.args.zip(subroutine.parameters)) {
val paramDt = codeGen.vmType(parameter.type) val paramDt = codeGen.vmType(parameter.type)
if(paramDt==VmDataType.FLOAT) { if(codeGen.isZero(arg)) {
val argFpReg = codeGen.vmRegisters.nextFreeFloat() if (paramDt == VmDataType.FLOAT) {
code += translateExpression(arg, -1, argFpReg) val mem = codeGen.allocations.get(fcall.functionName + parameter.name)
val mem = codeGen.allocations.get(fcall.functionName + parameter.name) code += VmCodeInstruction(Opcode.STOREZM, paramDt, value = mem)
code += VmCodeInstruction(Opcode.STOREM, paramDt, fpReg1 = argFpReg, value = mem) } else {
val mem = codeGen.allocations.get(fcall.functionName + parameter.name)
code += VmCodeInstruction(Opcode.STOREZM, paramDt, value = mem)
}
} else { } else {
val argReg = codeGen.vmRegisters.nextFree() if (paramDt == VmDataType.FLOAT) {
code += translateExpression(arg, argReg, -1) val argFpReg = codeGen.vmRegisters.nextFreeFloat()
val mem = codeGen.allocations.get(fcall.functionName + parameter.name) code += translateExpression(arg, -1, argFpReg)
code += VmCodeInstruction(Opcode.STOREM, paramDt, reg1 = argReg, value = mem) val mem = codeGen.allocations.get(fcall.functionName + parameter.name)
code += VmCodeInstruction(Opcode.STOREM, paramDt, fpReg1 = argFpReg, value = mem)
} else {
val argReg = codeGen.vmRegisters.nextFree()
code += translateExpression(arg, argReg, -1)
val mem = codeGen.allocations.get(fcall.functionName + parameter.name)
code += VmCodeInstruction(Opcode.STOREM, paramDt, reg1 = argReg, value = mem)
}
} }
} }
code += VmCodeInstruction(Opcode.CALL, symbol=fcall.functionName) code += VmCodeInstruction(Opcode.CALL, symbol=fcall.functionName)

View File

@ -3,7 +3,11 @@ TODO
For next release For next release
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
- vm: add way more instructions operating directly on memory instead of only registers - vm: assignment to float array is not correct? also zero?
- vm: use more instructions in codegen: shift one
- vm: use more instructions in codegen: branching
- vm: add more instructions operating directly on memory instead of only registers?
- in-place modifiying functions (rol, ror, ..) don't accept a memory address but require a memory-read expression. that is weird.
- complete the Inliner - complete the Inliner
- add McCarthy evaluation to shortcircuit and/or expressions. First do ifs by splitting them up? Then do expressions that compute a value? - add McCarthy evaluation to shortcircuit and/or expressions. First do ifs by splitting them up? Then do expressions that compute a value?

View File

@ -6,21 +6,57 @@
; NOTE: meant to test to virtual machine output target (use -target vitual) ; NOTE: meant to test to virtual machine output target (use -target vitual)
main { main {
ubyte value = 42 ; ubyte value = 42
;
; sub inline_candidate() -> ubyte {
; return math.sin8u(value)
; }
;
; sub add(ubyte first, ubyte second) -> ubyte {
; return first + second
; }
;
; sub mul(ubyte first, ubyte second) -> ubyte {
; return first * second
; }
sub derp() -> ubyte { sub ding(uword arg) {
return math.sin8u(value) arg++
txt.print_uw(arg)
} }
sub start() { sub start() {
ubyte value = derp() ding(0)
txt.print_ub(value)
txt.nl() txt.nl()
txt.print_ub(derp()) ding(2)
txt.nl() txt.nl()
; TODO: test with builtin function using multiple args (such as mkword) ; ubyte value = inline_candidate()
; ubyte value = add(3,4) |> add(10) |> mul(2) |> math.sin8u() ; TODO should not work yet on vm codegen, but it compiles.... :/ ; byte svalue = 99
; svalue = -svalue
; @($5000) = not @($5000)
; rol(value)
; rol(@($5000))
; ror(value)
; ror(@($5000))
; rol2(value)
; rol2(@($5000))
; ror2(value)
; ror2(@($5000))
; @($5000) <<= 1
; @($5000) >>= 1
; value <<= 1
; value >>= 1
; @($5000) <<= 3
; @($5000) >>= 3
; value <<= 3
; value >>= 3
; txt.print_ub(value)
; txt.nl()
; txt.print_ub(inline_candidate())
; txt.nl()
; ubyte value = add(3,4) |> add(10) |> mul(2) |> math.sin8u()
; txt.print_ub(value) ; txt.print_ub(value)
; txt.nl() ; txt.nl()
; uword wvalue = add(3,4) |> add($30) |> mkword($ea) ; uword wvalue = add(3,4) |> add($30) |> mkword($ea)

View File

@ -31,7 +31,7 @@ loadr reg1, reg2 - load reg1 with value at 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
storez 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
storezx reg1, address - store zero at memory address, indexed by value in reg storezx reg1, address - store zero at memory address, indexed by value in reg
@ -89,8 +89,8 @@ ARITHMETIC
---------- ----------
All have type b or w or f. Note: result types are the same as operand types! E.g. byte*byte->byte. All have type b or w or f. Note: result types are the same as operand types! E.g. byte*byte->byte.
ext reg1 - reg1 = unsigned extension of reg1 (which in practice just means clearing the MSB / MSW) (latter not yet implemented as we don't have longs yet) 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)
exts reg1 - reg1 = signed extension of reg1 (byte to word, or word to long) (note: latter ext.w, not yet implemented as we don't have longs yet) exts reg1 - reg1 = signed extension of reg1 (byte to word, or word to long) (note: ext.w is not yet implemented as we don't have longs yet)
inc reg1 - reg1 = reg1+1 inc reg1 - reg1 = reg1+1
incm address - memory at address += 1 incm address - memory at address += 1
dec reg1 - reg1 = reg1-1 dec reg1 - reg1 = reg1-1
@ -116,9 +116,9 @@ All have type b or w.
and reg1, reg2, reg3 - reg1 = reg2 bitwise and reg3 and reg1, reg2, reg3 - reg1 = reg2 bitwise and reg3
or reg1, reg2, reg3 - reg1 = reg2 bitwise or reg3 or reg1, reg2, reg3 - reg1 = reg2 bitwise or reg3
xor reg1, reg2, reg3 - reg1 = reg2 bitwise xor reg3 xor reg1, reg2, reg3 - reg1 = reg2 bitwise xor reg3
lsrx reg1, reg2, reg3 - reg1 = multi-shift reg2 right by reg3 bits + set Carry to shifted bit lsrn reg1, reg2, reg3 - reg1 = multi-shift reg2 right by reg3 bits + set Carry to shifted bit
asrx reg1, reg2, reg3 - reg1 = multi-shift reg2 right by reg3 bits (signed) + set Carry to shifted bit asrn reg1, reg2, reg3 - reg1 = multi-shift reg2 right by reg3 bits (signed) + set Carry to shifted bit
lslx reg1, reg2, reg3 - reg1 = multi-shift reg2 left by reg3 bits + set Carry to shifted bit lsln reg1, reg2, reg3 - reg1 = multi-shift reg2 left by reg3 bits + set Carry to shifted bit
lsr reg1 - shift reg1 right by 1 bits + set Carry to shifted bit lsr reg1 - shift reg1 right by 1 bits + set Carry to shifted bit
asr reg1 - shift reg1 right by 1 bits (signed) + set Carry to shifted bit asr reg1 - shift reg1 right by 1 bits (signed) + set Carry to shifted bit
lsl reg1 - shift reg1 left by 1 bits + set Carry to shifted bit lsl reg1 - shift reg1 left by 1 bits + set Carry to shifted bit
@ -149,10 +149,7 @@ clc - clear Carry status bit
sec - set Carry status bit sec - set Carry status bit
nop - do nothing nop - do nothing
breakpoint - trigger a breakpoint breakpoint - trigger a breakpoint
copy reg1, reg2, length - copy memory from ptrs in reg1 to reg3, length bytes
copyz reg1, reg2 - copy memory from ptrs in reg1 to reg3, stop after first 0-byte
msig [b, w] reg1, reg2 - reg1 becomes the most significant byte (or word) of the word (or int) in reg2 (.w not yet implemented; requires 32 bits regs) msig [b, w] reg1, reg2 - reg1 becomes the most significant byte (or word) of the word (or int) in reg2 (.w not yet implemented; requires 32 bits regs)
swapreg reg1, reg2 - swap values in reg1 and reg2
concat [b, w] reg1, reg2, reg3 - reg1 = concatenated lsb/lsw of reg2 and lsb/lsw of reg3 into new word or int (int not yet implemented; requires 32bits regs) concat [b, w] reg1, reg2, reg3 - reg1 = concatenated lsb/lsw of reg2 and lsb/lsw of reg3 into new word or int (int not yet implemented; requires 32bits regs)
push [b, w] reg1 - push value in reg1 on the stack push [b, w] reg1 - push value in reg1 on the stack
pop [b, w] reg1 - pop value from stack into reg1 pop [b, w] reg1 - pop value from stack into reg1
@ -169,14 +166,12 @@ enum class Opcode {
STOREM, STOREM,
STOREI, STOREI,
STOREX, STOREX,
STOREZ, STOREZM,
STOREZI, STOREZI,
STOREZX, STOREZX,
JUMP, JUMP,
JUMPI,
CALL, CALL,
CALLI,
SYSCALL, SYSCALL,
RETURN, RETURN,
@ -190,14 +185,14 @@ enum class Opcode {
BNZ, BNZ,
BEQ, BEQ,
BNE, BNE,
BLT, BLT, // TODO not used in codegen??? <
BLTS, BLTS, // TODO not used in codegen??? <
BGT, BGT, // TODO not used in codegen??? >
BGTS, BGTS, // TODO not used in codegen??? >
BLE, BLE, // TODO should be used in codegen conditional branch too
BLES, BLES, // TODO should be used in codegen conditional branch too
BGE, BGE, // TODO not used in codegen??? >=
BGES, BGES, // TODO not used in codegen??? >=
SEQ, SEQ,
SNE, SNE,
SLT, SLT,
@ -229,12 +224,12 @@ enum class Opcode {
AND, AND,
OR, OR,
XOR, XOR,
ASRX, ASRN,
LSRX, LSRN,
LSLX, LSLN,
ASR, ASR, // TODO not used in codegen of shift 1
LSR, LSR, // TODO not used in codegen of shift 1
LSL, LSL, // TODO not used in codegen of shift 1
ROR, ROR,
ROXR, ROXR,
ROL, ROL,
@ -266,7 +261,6 @@ enum class Opcode {
PUSH, PUSH,
POP, POP,
MSIG, MSIG,
SWAPREG,
CONCAT, CONCAT,
BREAKPOINT BREAKPOINT
} }
@ -276,7 +270,7 @@ val OpcodesWithAddress = setOf(
Opcode.LOADX, Opcode.LOADX,
Opcode.STOREM, Opcode.STOREM,
Opcode.STOREX, Opcode.STOREX,
Opcode.STOREZ, Opcode.STOREZM,
Opcode.STOREZX Opcode.STOREZX
) )
@ -443,17 +437,14 @@ val instructionFormats = mutableMapOf(
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,v | F,fr1,r1,v"), Opcode.LOADX to InstructionFormat.from("BW,r1,r2,v | F,fr1,r1,v"),
Opcode.LOADR to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"), Opcode.LOADR to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
Opcode.SWAPREG to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
Opcode.STOREM to InstructionFormat.from("BW,r1,v | F,fr1,v"), Opcode.STOREM to InstructionFormat.from("BW,r1,v | F,fr1,v"),
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,v | F,fr1,r1,v"), Opcode.STOREX to InstructionFormat.from("BW,r1,r2,v | F,fr1,r1,v"),
Opcode.STOREZ to InstructionFormat.from("BW,v | F,v"), Opcode.STOREZM to InstructionFormat.from("BW,v | F,v"),
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,v | F,r1,v"), Opcode.STOREZX to InstructionFormat.from("BW,r1,v | F,r1,v"),
Opcode.JUMP to InstructionFormat.from("N,v"), Opcode.JUMP to InstructionFormat.from("N,v"),
Opcode.JUMPI to InstructionFormat.from("N,r1"),
Opcode.CALL to InstructionFormat.from("N,v"), Opcode.CALL to InstructionFormat.from("N,v"),
Opcode.CALLI to InstructionFormat.from("N,r1"),
Opcode.SYSCALL to InstructionFormat.from("N,v"), Opcode.SYSCALL to InstructionFormat.from("N,v"),
Opcode.RETURN to InstructionFormat.from("N"), Opcode.RETURN to InstructionFormat.from("N"),
Opcode.BSTCC to InstructionFormat.from("N,v"), Opcode.BSTCC to InstructionFormat.from("N,v"),
@ -503,9 +494,9 @@ val instructionFormats = mutableMapOf(
Opcode.AND to InstructionFormat.from("BW,r1,r2,r3"), Opcode.AND to InstructionFormat.from("BW,r1,r2,r3"),
Opcode.OR to InstructionFormat.from("BW,r1,r2,r3"), Opcode.OR to InstructionFormat.from("BW,r1,r2,r3"),
Opcode.XOR to InstructionFormat.from("BW,r1,r2,r3"), Opcode.XOR to InstructionFormat.from("BW,r1,r2,r3"),
Opcode.ASRX to InstructionFormat.from("BW,r1,r2,r3"), Opcode.ASRN to InstructionFormat.from("BW,r1,r2,r3"),
Opcode.LSRX to InstructionFormat.from("BW,r1,r2,r3"), Opcode.LSRN to InstructionFormat.from("BW,r1,r2,r3"),
Opcode.LSLX to InstructionFormat.from("BW,r1,r2,r3"), Opcode.LSLN to InstructionFormat.from("BW,r1,r2,r3"),
Opcode.ASR to InstructionFormat.from("BW,r1"), Opcode.ASR to InstructionFormat.from("BW,r1"),
Opcode.LSR to InstructionFormat.from("BW,r1"), Opcode.LSR to InstructionFormat.from("BW,r1"),
Opcode.LSL to InstructionFormat.from("BW,r1"), Opcode.LSL to InstructionFormat.from("BW,r1"),

View File

@ -92,17 +92,14 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
Opcode.LOADX -> InsLOADX(ins) Opcode.LOADX -> InsLOADX(ins)
Opcode.LOADI -> InsLOADI(ins) Opcode.LOADI -> InsLOADI(ins)
Opcode.LOADR -> InsLOADR(ins) Opcode.LOADR -> InsLOADR(ins)
Opcode.SWAPREG -> InsSWAPREG(ins)
Opcode.STOREM -> InsSTOREM(ins) Opcode.STOREM -> InsSTOREM(ins)
Opcode.STOREX -> InsSTOREX(ins) Opcode.STOREX -> InsSTOREX(ins)
Opcode.STOREI -> InsSTOREI(ins) Opcode.STOREI -> InsSTOREI(ins)
Opcode.STOREZ -> InsSTOREZ(ins) Opcode.STOREZM -> InsSTOREZ(ins)
Opcode.STOREZX -> InsSTOREZX(ins) Opcode.STOREZX -> InsSTOREZX(ins)
Opcode.STOREZI -> InsSTOREZI(ins) Opcode.STOREZI -> InsSTOREZI(ins)
Opcode.JUMP -> InsJUMP(ins) Opcode.JUMP -> InsJUMP(ins)
Opcode.JUMPI -> InsJUMPI(ins)
Opcode.CALL -> InsCALL(ins) Opcode.CALL -> InsCALL(ins)
Opcode.CALLI -> InsCALLI(ins)
Opcode.SYSCALL -> InsSYSCALL(ins) Opcode.SYSCALL -> InsSYSCALL(ins)
Opcode.RETURN -> InsRETURN() Opcode.RETURN -> InsRETURN()
Opcode.BSTCC -> InsBSTCC(ins) Opcode.BSTCC -> InsBSTCC(ins)
@ -153,9 +150,9 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
Opcode.AND -> InsAND(ins) Opcode.AND -> InsAND(ins)
Opcode.OR -> InsOR(ins) Opcode.OR -> InsOR(ins)
Opcode.XOR -> InsXOR(ins) Opcode.XOR -> InsXOR(ins)
Opcode.ASRX -> InsASRM(ins) Opcode.ASRN -> InsASRM(ins)
Opcode.LSRX -> InsLSRM(ins) Opcode.LSRN -> InsLSRM(ins)
Opcode.LSLX -> InsLSLM(ins) Opcode.LSLN -> InsLSLM(ins)
Opcode.ASR -> InsASR(ins) Opcode.ASR -> InsASR(ins)
Opcode.LSR -> InsLSR(ins) Opcode.LSR -> InsLSR(ins)
Opcode.LSL -> InsLSL(ins) Opcode.LSL -> InsLSL(ins)
@ -297,27 +294,6 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
pc++ pc++
} }
private fun InsSWAPREG(i: Instruction) {
when(i.type!!) {
VmDataType.BYTE -> {
val oldR2 = registers.getUB(i.reg2!!)
registers.setUB(i.reg2, registers.getUB(i.reg1!!))
registers.setUB(i.reg1, oldR2)
}
VmDataType.WORD -> {
val oldR2 = registers.getUW(i.reg2!!)
registers.setUW(i.reg2, registers.getUW(i.reg1!!))
registers.setUW(i.reg1, oldR2)
}
VmDataType.FLOAT -> {
val oldR2 = registers.getFloat(i.fpReg2!!)
registers.setFloat(i.fpReg2, registers.getFloat(i.fpReg1!!))
registers.setFloat(i.fpReg1, oldR2)
}
}
pc++
}
private fun InsSTOREM(i: Instruction) { private fun InsSTOREM(i: Instruction) {
when(i.type!!) { when(i.type!!) {
VmDataType.BYTE -> memory.setUB(i.value!!, registers.getUB(i.reg1!!)) VmDataType.BYTE -> memory.setUB(i.value!!, registers.getUB(i.reg1!!))
@ -351,6 +327,7 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
VmDataType.WORD -> memory.setUW(i.value!!, 0u) VmDataType.WORD -> memory.setUW(i.value!!, 0u)
VmDataType.FLOAT -> memory.setFloat(i.value!!, 0f) VmDataType.FLOAT -> memory.setFloat(i.value!!, 0f)
} }
pc++
} }
private fun InsSTOREZI(i: Instruction) { private fun InsSTOREZI(i: Instruction) {
@ -375,20 +352,11 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
pc = i.value!! pc = i.value!!
} }
private fun InsJUMPI(i: Instruction) {
pc = registers.getUW(i.reg1!!).toInt()
}
private fun InsCALL(i: Instruction) { private fun InsCALL(i: Instruction) {
callStack.push(pc+1) callStack.push(pc+1)
pc = i.value!! pc = i.value!!
} }
private fun InsCALLI(i: Instruction) {
callStack.push(pc+1)
pc = registers.getUW(i.reg1!!).toInt()
}
private fun InsRETURN() { private fun InsRETURN() {
if(callStack.isEmpty()) if(callStack.isEmpty())
exit() exit()