mirror of
https://github.com/irmen/prog8.git
synced 2024-12-24 16:29:21 +00:00
vm: actually use the store-zero instructions in codegen
This commit is contained in:
parent
627aa61184
commit
d43ad849d1
@ -2,7 +2,6 @@ package prog8.codegen.virtual
|
||||
|
||||
import prog8.code.StStaticVariable
|
||||
import prog8.code.ast.*
|
||||
import prog8.code.core.ArrayToElementTypes
|
||||
import prog8.code.core.AssemblyError
|
||||
import prog8.code.core.DataType
|
||||
import prog8.vm.Opcode
|
||||
@ -241,32 +240,54 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
|
||||
private fun funcPokeW(call: PtBuiltinFunctionCall): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
val valueReg = codeGen.vmRegisters.nextFree()
|
||||
if(call.args[0] is PtNumber) {
|
||||
val address = (call.args[0] as PtNumber).number.toInt()
|
||||
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
||||
code += VmCodeInstruction(Opcode.STOREM, VmDataType.WORD, reg1 = valueReg, value=address)
|
||||
if(codeGen.isZero(call.args[1])) {
|
||||
if (call.args[0] is PtNumber) {
|
||||
val address = (call.args[0] as PtNumber).number.toInt()
|
||||
code += VmCodeInstruction(Opcode.STOREZM, VmDataType.WORD, 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 {
|
||||
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)
|
||||
val valueReg = codeGen.vmRegisters.nextFree()
|
||||
if (call.args[0] is PtNumber) {
|
||||
val address = (call.args[0] as PtNumber).number.toInt()
|
||||
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
|
||||
}
|
||||
|
||||
private fun funcPoke(call: PtBuiltinFunctionCall): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
val valueReg = codeGen.vmRegisters.nextFree()
|
||||
if(call.args[0] is PtNumber) {
|
||||
val address = (call.args[0] as PtNumber).number.toInt()
|
||||
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
||||
code += VmCodeInstruction(Opcode.STOREM, VmDataType.BYTE, reg1 = valueReg, value=address)
|
||||
if(codeGen.isZero(call.args[1])) {
|
||||
if (call.args[0] is PtNumber) {
|
||||
val address = (call.args[0] as PtNumber).number.toInt()
|
||||
code += VmCodeInstruction(Opcode.STOREZM, VmDataType.BYTE, 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 {
|
||||
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)
|
||||
val valueReg = codeGen.vmRegisters.nextFree()
|
||||
if (call.args[0] is PtNumber) {
|
||||
val address = (call.args[0] as PtNumber).number.toInt()
|
||||
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
|
||||
}
|
||||
@ -361,5 +382,4 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
code += codeGen.translateNode(assignment)
|
||||
return code
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import prog8.code.ast.*
|
||||
import prog8.code.core.*
|
||||
import prog8.vm.Opcode
|
||||
import prog8.vm.VmDataType
|
||||
import java.nio.file.Path
|
||||
import kotlin.math.pow
|
||||
|
||||
|
||||
@ -410,7 +409,7 @@ class CodeGen(internal val program: PtProgram,
|
||||
// just shift multiple bits
|
||||
val pow2reg = vmRegisters.nextFree()
|
||||
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 {
|
||||
if (factor == 0) {
|
||||
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=reg, value=0)
|
||||
@ -451,7 +450,7 @@ class CodeGen(internal val program: PtProgram,
|
||||
// just shift multiple bits
|
||||
val pow2reg = vmRegisters.nextFree()
|
||||
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 {
|
||||
if (factor == 0) {
|
||||
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)
|
||||
var resultRegister = -1
|
||||
var resultFpRegister = -1
|
||||
if(vmDt==VmDataType.FLOAT) {
|
||||
resultFpRegister = vmRegisters.nextFreeFloat()
|
||||
code += expressionEval.translateExpression(assignment.value, -1, resultFpRegister)
|
||||
} else {
|
||||
resultRegister = if (assignment.value is PtMachineRegister) {
|
||||
(assignment.value as PtMachineRegister).register
|
||||
val zero = isZero(assignment.value)
|
||||
if(!zero) {
|
||||
// calculate the assignment value
|
||||
if (vmDt == VmDataType.FLOAT) {
|
||||
resultFpRegister = vmRegisters.nextFreeFloat()
|
||||
code += expressionEval.translateExpression(assignment.value, -1, resultFpRegister)
|
||||
} else {
|
||||
val reg = vmRegisters.nextFree()
|
||||
code += expressionEval.translateExpression(assignment.value, reg, -1)
|
||||
reg
|
||||
resultRegister = if (assignment.value is PtMachineRegister) {
|
||||
(assignment.value as PtMachineRegister).register
|
||||
} else {
|
||||
val reg = vmRegisters.nextFree()
|
||||
code += expressionEval.translateExpression(assignment.value, reg, -1)
|
||||
reg
|
||||
}
|
||||
}
|
||||
}
|
||||
if(ident!=null) {
|
||||
val address = allocations.get(ident.targetName)
|
||||
code += if(vmDt==VmDataType.FLOAT)
|
||||
VmCodeInstruction(Opcode.STOREM, vmDt, fpReg1=resultFpRegister, value=address)
|
||||
else
|
||||
VmCodeInstruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=address)
|
||||
code += if(zero) {
|
||||
VmCodeInstruction(Opcode.STOREZM, vmDt, value = address)
|
||||
} else {
|
||||
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) {
|
||||
val variable = array.variable.targetName
|
||||
@ -640,23 +647,45 @@ class CodeGen(internal val program: PtProgram,
|
||||
val itemsize = program.memsizer.memorySize(array.type)
|
||||
val fixedIndex = constIntValue(array.index)
|
||||
val vmDtArrayIdx = vmType(array.type)
|
||||
if(fixedIndex!=null) {
|
||||
variableAddr += fixedIndex*itemsize
|
||||
code += VmCodeInstruction(Opcode.STOREM, vmDtArrayIdx, reg1 = resultRegister, value=variableAddr)
|
||||
// TODO floating point array incorrect?
|
||||
if(zero) {
|
||||
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 {
|
||||
val indexReg = vmRegisters.nextFree()
|
||||
code += expressionEval.translateExpression(array.index, indexReg, -1)
|
||||
code += VmCodeInstruction(Opcode.STOREX, vmDtArrayIdx, reg1 = resultRegister, reg2=indexReg, value=variableAddr)
|
||||
if(fixedIndex!=null) {
|
||||
variableAddr += fixedIndex*itemsize
|
||||
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) {
|
||||
require(vmDt==VmDataType.BYTE)
|
||||
if(memory.address is PtNumber) {
|
||||
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=(memory.address as PtNumber).number.toInt())
|
||||
if(zero) {
|
||||
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 {
|
||||
val addressReg = vmRegisters.nextFree()
|
||||
code += expressionEval.translateExpression(memory.address, addressReg, -1)
|
||||
code += VmCodeInstruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressReg)
|
||||
if(memory.address is PtNumber) {
|
||||
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=(memory.address as PtNumber).number.toInt())
|
||||
} else {
|
||||
val addressReg = vmRegisters.nextFree()
|
||||
code += expressionEval.translateExpression(memory.address, addressReg, -1)
|
||||
code += VmCodeInstruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressReg)
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -722,4 +751,6 @@ class CodeGen(internal val program: PtProgram,
|
||||
|
||||
internal fun translateBuiltinFunc(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk =
|
||||
builtinFuncGen.translate(call, resultRegister)
|
||||
|
||||
internal fun isZero(expression: PtExpression): Boolean = expression is PtNumber && expression.number==0.0
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import prog8.code.core.PassByValueDatatypes
|
||||
import prog8.code.core.SignedDatatypes
|
||||
import prog8.vm.Opcode
|
||||
import prog8.vm.VmDataType
|
||||
import java.nio.channels.FileLock
|
||||
|
||||
|
||||
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 {
|
||||
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)
|
||||
val vmDt = codeGen.vmType(expr.type)
|
||||
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 {
|
||||
val code = VmCodeChunk()
|
||||
// TODO if shift is 1, use ASR/LSR instruction instead of multishift
|
||||
val leftResultReg = codeGen.vmRegisters.nextFree()
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(binExpr.left, leftResultReg, -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)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun operatorShiftLeft(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
// TODO if shift is 1, use LSL instruction instead of multishift
|
||||
val leftResultReg = codeGen.vmRegisters.nextFree()
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(binExpr.left, leftResultReg, -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
|
||||
}
|
||||
|
||||
@ -568,16 +570,26 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
val code = VmCodeChunk()
|
||||
for ((arg, parameter) in fcall.args.zip(subroutine.parameters)) {
|
||||
val paramDt = codeGen.vmType(parameter.type)
|
||||
if(paramDt==VmDataType.FLOAT) {
|
||||
val argFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
code += translateExpression(arg, -1, argFpReg)
|
||||
val mem = codeGen.allocations.get(fcall.functionName + parameter.name)
|
||||
code += VmCodeInstruction(Opcode.STOREM, paramDt, fpReg1 = argFpReg, value = mem)
|
||||
if(codeGen.isZero(arg)) {
|
||||
if (paramDt == VmDataType.FLOAT) {
|
||||
val mem = codeGen.allocations.get(fcall.functionName + parameter.name)
|
||||
code += VmCodeInstruction(Opcode.STOREZM, paramDt, value = mem)
|
||||
} else {
|
||||
val mem = codeGen.allocations.get(fcall.functionName + parameter.name)
|
||||
code += VmCodeInstruction(Opcode.STOREZM, paramDt, 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)
|
||||
if (paramDt == VmDataType.FLOAT) {
|
||||
val argFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
code += translateExpression(arg, -1, argFpReg)
|
||||
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)
|
||||
|
@ -3,7 +3,11 @@ TODO
|
||||
|
||||
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
|
||||
- add McCarthy evaluation to shortcircuit and/or expressions. First do ifs by splitting them up? Then do expressions that compute a value?
|
||||
|
||||
|
@ -6,21 +6,57 @@
|
||||
; NOTE: meant to test to virtual machine output target (use -target vitual)
|
||||
|
||||
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 {
|
||||
return math.sin8u(value)
|
||||
sub ding(uword arg) {
|
||||
arg++
|
||||
txt.print_uw(arg)
|
||||
}
|
||||
|
||||
sub start() {
|
||||
ubyte value = derp()
|
||||
txt.print_ub(value)
|
||||
ding(0)
|
||||
txt.nl()
|
||||
txt.print_ub(derp())
|
||||
ding(2)
|
||||
txt.nl()
|
||||
|
||||
; TODO: test with builtin function using multiple args (such as mkword)
|
||||
; ubyte value = add(3,4) |> add(10) |> mul(2) |> math.sin8u() ; TODO should not work yet on vm codegen, but it compiles.... :/
|
||||
; ubyte value = inline_candidate()
|
||||
; 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.nl()
|
||||
; uword wvalue = add(3,4) |> add($30) |> mkword($ea)
|
||||
|
@ -31,7 +31,7 @@ loadr reg1, reg2 - load reg1 with value at 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
|
||||
storez address - store zero at memory address
|
||||
storezm address - store zero at memory address
|
||||
storezi reg1 - store zero at memory pointed to by reg1
|
||||
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.
|
||||
|
||||
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)
|
||||
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)
|
||||
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: ext.w is not yet implemented as we don't have longs yet)
|
||||
inc reg1 - reg1 = reg1+1
|
||||
incm address - memory at address += 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
|
||||
or reg1, reg2, reg3 - reg1 = reg2 bitwise or 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
|
||||
asrx 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
|
||||
lsrn reg1, reg2, reg3 - reg1 = multi-shift reg2 right by reg3 bits + set Carry to shifted bit
|
||||
asrn reg1, reg2, reg3 - reg1 = multi-shift reg2 right by reg3 bits (signed) + 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
|
||||
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
|
||||
@ -149,10 +149,7 @@ clc - clear Carry status bit
|
||||
sec - set Carry status bit
|
||||
nop - do nothing
|
||||
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)
|
||||
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)
|
||||
push [b, w] reg1 - push value in reg1 on the stack
|
||||
pop [b, w] reg1 - pop value from stack into reg1
|
||||
@ -169,14 +166,12 @@ enum class Opcode {
|
||||
STOREM,
|
||||
STOREI,
|
||||
STOREX,
|
||||
STOREZ,
|
||||
STOREZM,
|
||||
STOREZI,
|
||||
STOREZX,
|
||||
|
||||
JUMP,
|
||||
JUMPI,
|
||||
CALL,
|
||||
CALLI,
|
||||
SYSCALL,
|
||||
RETURN,
|
||||
|
||||
@ -190,14 +185,14 @@ enum class Opcode {
|
||||
BNZ,
|
||||
BEQ,
|
||||
BNE,
|
||||
BLT,
|
||||
BLTS,
|
||||
BGT,
|
||||
BGTS,
|
||||
BLE,
|
||||
BLES,
|
||||
BGE,
|
||||
BGES,
|
||||
BLT, // TODO not used in codegen??? <
|
||||
BLTS, // TODO not used in codegen??? <
|
||||
BGT, // TODO not used in codegen??? >
|
||||
BGTS, // TODO not used in codegen??? >
|
||||
BLE, // TODO should be used in codegen conditional branch too
|
||||
BLES, // TODO should be used in codegen conditional branch too
|
||||
BGE, // TODO not used in codegen??? >=
|
||||
BGES, // TODO not used in codegen??? >=
|
||||
SEQ,
|
||||
SNE,
|
||||
SLT,
|
||||
@ -229,12 +224,12 @@ enum class Opcode {
|
||||
AND,
|
||||
OR,
|
||||
XOR,
|
||||
ASRX,
|
||||
LSRX,
|
||||
LSLX,
|
||||
ASR,
|
||||
LSR,
|
||||
LSL,
|
||||
ASRN,
|
||||
LSRN,
|
||||
LSLN,
|
||||
ASR, // TODO not used in codegen of shift 1
|
||||
LSR, // TODO not used in codegen of shift 1
|
||||
LSL, // TODO not used in codegen of shift 1
|
||||
ROR,
|
||||
ROXR,
|
||||
ROL,
|
||||
@ -266,7 +261,6 @@ enum class Opcode {
|
||||
PUSH,
|
||||
POP,
|
||||
MSIG,
|
||||
SWAPREG,
|
||||
CONCAT,
|
||||
BREAKPOINT
|
||||
}
|
||||
@ -276,7 +270,7 @@ val OpcodesWithAddress = setOf(
|
||||
Opcode.LOADX,
|
||||
Opcode.STOREM,
|
||||
Opcode.STOREX,
|
||||
Opcode.STOREZ,
|
||||
Opcode.STOREZM,
|
||||
Opcode.STOREZX
|
||||
)
|
||||
|
||||
@ -443,17 +437,14 @@ val instructionFormats = mutableMapOf(
|
||||
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.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.STOREI to InstructionFormat.from("BW,r1,r2 | F,fr1,r1"),
|
||||
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.STOREZX to InstructionFormat.from("BW,r1,v | F,r1,v"),
|
||||
Opcode.JUMP to InstructionFormat.from("N,v"),
|
||||
Opcode.JUMPI to InstructionFormat.from("N,r1"),
|
||||
Opcode.CALL to InstructionFormat.from("N,v"),
|
||||
Opcode.CALLI to InstructionFormat.from("N,r1"),
|
||||
Opcode.SYSCALL to InstructionFormat.from("N,v"),
|
||||
Opcode.RETURN to InstructionFormat.from("N"),
|
||||
Opcode.BSTCC to InstructionFormat.from("N,v"),
|
||||
@ -503,9 +494,9 @@ val instructionFormats = mutableMapOf(
|
||||
Opcode.AND 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.ASRX to InstructionFormat.from("BW,r1,r2,r3"),
|
||||
Opcode.LSRX to InstructionFormat.from("BW,r1,r2,r3"),
|
||||
Opcode.LSLX to InstructionFormat.from("BW,r1,r2,r3"),
|
||||
Opcode.ASRN to InstructionFormat.from("BW,r1,r2,r3"),
|
||||
Opcode.LSRN to InstructionFormat.from("BW,r1,r2,r3"),
|
||||
Opcode.LSLN to InstructionFormat.from("BW,r1,r2,r3"),
|
||||
Opcode.ASR to InstructionFormat.from("BW,r1"),
|
||||
Opcode.LSR to InstructionFormat.from("BW,r1"),
|
||||
Opcode.LSL to InstructionFormat.from("BW,r1"),
|
||||
|
@ -92,17 +92,14 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
Opcode.LOADX -> InsLOADX(ins)
|
||||
Opcode.LOADI -> InsLOADI(ins)
|
||||
Opcode.LOADR -> InsLOADR(ins)
|
||||
Opcode.SWAPREG -> InsSWAPREG(ins)
|
||||
Opcode.STOREM -> InsSTOREM(ins)
|
||||
Opcode.STOREX -> InsSTOREX(ins)
|
||||
Opcode.STOREI -> InsSTOREI(ins)
|
||||
Opcode.STOREZ -> InsSTOREZ(ins)
|
||||
Opcode.STOREZM -> InsSTOREZ(ins)
|
||||
Opcode.STOREZX -> InsSTOREZX(ins)
|
||||
Opcode.STOREZI -> InsSTOREZI(ins)
|
||||
Opcode.JUMP -> InsJUMP(ins)
|
||||
Opcode.JUMPI -> InsJUMPI(ins)
|
||||
Opcode.CALL -> InsCALL(ins)
|
||||
Opcode.CALLI -> InsCALLI(ins)
|
||||
Opcode.SYSCALL -> InsSYSCALL(ins)
|
||||
Opcode.RETURN -> InsRETURN()
|
||||
Opcode.BSTCC -> InsBSTCC(ins)
|
||||
@ -153,9 +150,9 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
Opcode.AND -> InsAND(ins)
|
||||
Opcode.OR -> InsOR(ins)
|
||||
Opcode.XOR -> InsXOR(ins)
|
||||
Opcode.ASRX -> InsASRM(ins)
|
||||
Opcode.LSRX -> InsLSRM(ins)
|
||||
Opcode.LSLX -> InsLSLM(ins)
|
||||
Opcode.ASRN -> InsASRM(ins)
|
||||
Opcode.LSRN -> InsLSRM(ins)
|
||||
Opcode.LSLN -> InsLSLM(ins)
|
||||
Opcode.ASR -> InsASR(ins)
|
||||
Opcode.LSR -> InsLSR(ins)
|
||||
Opcode.LSL -> InsLSL(ins)
|
||||
@ -297,27 +294,6 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
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) {
|
||||
when(i.type!!) {
|
||||
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.FLOAT -> memory.setFloat(i.value!!, 0f)
|
||||
}
|
||||
pc++
|
||||
}
|
||||
|
||||
private fun InsSTOREZI(i: Instruction) {
|
||||
@ -375,20 +352,11 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
pc = i.value!!
|
||||
}
|
||||
|
||||
private fun InsJUMPI(i: Instruction) {
|
||||
pc = registers.getUW(i.reg1!!).toInt()
|
||||
}
|
||||
|
||||
private fun InsCALL(i: Instruction) {
|
||||
callStack.push(pc+1)
|
||||
pc = i.value!!
|
||||
}
|
||||
|
||||
private fun InsCALLI(i: Instruction) {
|
||||
callStack.push(pc+1)
|
||||
pc = registers.getUW(i.reg1!!).toInt()
|
||||
}
|
||||
|
||||
private fun InsRETURN() {
|
||||
if(callStack.isEmpty())
|
||||
exit()
|
||||
|
Loading…
Reference in New Issue
Block a user