vm instructions now contain info on input/output registers

This commit is contained in:
Irmen de Jong 2022-08-07 17:43:40 +02:00
parent 1e441c2ddf
commit e560e2ab3f
9 changed files with 251 additions and 198 deletions

View File

@ -68,7 +68,7 @@ class CodeGen(internal val program: PtProgram,
}
if(options.optimize) {
val optimizer = VmPeepholeOptimizer(vmprog, allocations)
val optimizer = VmPeepholeOptimizer(vmprog)
optimizer.optimize()
}

View File

@ -4,10 +4,8 @@ import prog8.vm.Instruction
import prog8.vm.Opcode
import prog8.vm.VmDataType
internal class VmOptimizerException(msg: String): Exception(msg)
class VmPeepholeOptimizer(private val vmprog: AssemblyProgram, private val allocations: VariableAllocator) {
class VmPeepholeOptimizer(private val vmprog: AssemblyProgram) {
fun optimize() {
vmprog.getBlocks().forEach { block ->
do {

View File

@ -26,19 +26,19 @@ class TestVmPeepholeOpt: FunSpec({
fun AssemblyProgram.lines(): List<VmCodeLine> = this.getBlocks().flatMap { it.lines }
test("remove nops") {
val(asm, allocations) = makeVmProgram(listOf(
val(asm, _) = makeVmProgram(listOf(
VmCodeInstruction(Opcode.JUMP, labelSymbol = listOf("dummy")),
VmCodeInstruction(Opcode.NOP),
VmCodeInstruction(Opcode.NOP)
))
asm.lines().size shouldBe 3
val opt = VmPeepholeOptimizer(asm, allocations)
val opt = VmPeepholeOptimizer(asm)
opt.optimize()
asm.lines().size shouldBe 1
}
test("remove jmp to label below") {
val(asm, allocations) = makeVmProgram(listOf(
val(asm, _) = makeVmProgram(listOf(
VmCodeInstruction(Opcode.JUMP, labelSymbol = listOf("label")), // removed
VmCodeLabel(listOf("label")),
VmCodeInstruction(Opcode.JUMP, labelSymbol = listOf("label2")), // removed
@ -49,7 +49,7 @@ class TestVmPeepholeOpt: FunSpec({
VmCodeLabel(listOf("label3"))
))
asm.lines().size shouldBe 8
val opt = VmPeepholeOptimizer(asm, allocations)
val opt = VmPeepholeOptimizer(asm)
opt.optimize()
val lines = asm.lines()
lines.size shouldBe 5
@ -61,7 +61,7 @@ class TestVmPeepholeOpt: FunSpec({
}
test("remove double sec/clc") {
val(asm, allocations) = makeVmProgram(listOf(
val(asm, _) = makeVmProgram(listOf(
VmCodeInstruction(Opcode.SEC),
VmCodeInstruction(Opcode.SEC),
VmCodeInstruction(Opcode.SEC),
@ -70,7 +70,7 @@ class TestVmPeepholeOpt: FunSpec({
VmCodeInstruction(Opcode.CLC)
))
asm.lines().size shouldBe 6
val opt = VmPeepholeOptimizer(asm, allocations)
val opt = VmPeepholeOptimizer(asm)
opt.optimize()
val lines = asm.lines()
lines.size shouldBe 1
@ -78,14 +78,14 @@ class TestVmPeepholeOpt: FunSpec({
}
test("push followed by pop") {
val(asm, allocations) = makeVmProgram(listOf(
val(asm, _) = makeVmProgram(listOf(
VmCodeInstruction(Opcode.PUSH, VmDataType.BYTE, reg1=42),
VmCodeInstruction(Opcode.POP, VmDataType.BYTE, reg1=42),
VmCodeInstruction(Opcode.PUSH, VmDataType.BYTE, reg1=99),
VmCodeInstruction(Opcode.POP, VmDataType.BYTE, reg1=222)
))
asm.lines().size shouldBe 4
val opt = VmPeepholeOptimizer(asm, allocations)
val opt = VmPeepholeOptimizer(asm)
opt.optimize()
val lines = asm.lines()
lines.size shouldBe 1
@ -95,7 +95,7 @@ class TestVmPeepholeOpt: FunSpec({
}
test("remove useless div/mul, add/sub") {
val(asm, allocations) = makeVmProgram(listOf(
val(asm, _) = makeVmProgram(listOf(
VmCodeInstruction(Opcode.DIV, VmDataType.BYTE, reg1=42, value = 1),
VmCodeInstruction(Opcode.DIVS, VmDataType.BYTE, reg1=42, value = 1),
VmCodeInstruction(Opcode.MUL, VmDataType.BYTE, reg1=42, value = 1),
@ -108,19 +108,19 @@ class TestVmPeepholeOpt: FunSpec({
VmCodeInstruction(Opcode.SUB, VmDataType.BYTE, reg1=42, value = 0)
))
asm.lines().size shouldBe 10
val opt = VmPeepholeOptimizer(asm, allocations)
val opt = VmPeepholeOptimizer(asm)
opt.optimize()
val lines = asm.lines()
lines.size shouldBe 4
}
test("replace add/sub 1 by inc/dec") {
val(asm, allocations) = makeVmProgram(listOf(
val(asm, _) = makeVmProgram(listOf(
VmCodeInstruction(Opcode.ADD, VmDataType.BYTE, reg1=42, value = 1),
VmCodeInstruction(Opcode.SUB, VmDataType.BYTE, reg1=42, value = 1)
))
asm.lines().size shouldBe 2
val opt = VmPeepholeOptimizer(asm, allocations)
val opt = VmPeepholeOptimizer(asm)
opt.optimize()
val lines = asm.lines()
lines.size shouldBe 2
@ -129,7 +129,7 @@ class TestVmPeepholeOpt: FunSpec({
}
test("remove useless and/or/xor") {
val(asm, allocations) = makeVmProgram(listOf(
val(asm, _) = makeVmProgram(listOf(
VmCodeInstruction(Opcode.AND, VmDataType.BYTE, reg1=42, value = 255),
VmCodeInstruction(Opcode.AND, VmDataType.WORD, reg1=42, value = 65535),
VmCodeInstruction(Opcode.OR, VmDataType.BYTE, reg1=42, value = 0),
@ -140,21 +140,21 @@ class TestVmPeepholeOpt: FunSpec({
VmCodeInstruction(Opcode.XOR, VmDataType.BYTE, reg1=42, value = 1)
))
asm.lines().size shouldBe 8
val opt = VmPeepholeOptimizer(asm, allocations)
val opt = VmPeepholeOptimizer(asm)
opt.optimize()
val lines = asm.lines()
lines.size shouldBe 4
}
test("replace and/or/xor by constant number") {
val(asm, allocations) = makeVmProgram(listOf(
val(asm, _) = makeVmProgram(listOf(
VmCodeInstruction(Opcode.AND, VmDataType.BYTE, reg1=42, value = 0),
VmCodeInstruction(Opcode.AND, VmDataType.WORD, reg1=42, value = 0),
VmCodeInstruction(Opcode.OR, VmDataType.BYTE, reg1=42, value = 255),
VmCodeInstruction(Opcode.OR, VmDataType.WORD, reg1=42, value = 65535)
))
asm.lines().size shouldBe 4
val opt = VmPeepholeOptimizer(asm, allocations)
val opt = VmPeepholeOptimizer(asm)
opt.optimize()
val lines = asm.lines()
lines.size shouldBe 4

View File

@ -84,7 +84,7 @@ sub log2(float value) -> float {
sub sqrt(float value) -> float {
%asm {{
loadm.f fr0,{floats.sqrt.value}
fsqrt.f fr0,fr0
sqrt.f fr0,fr0
return
}}
}

View File

@ -16,7 +16,6 @@ Need help with
Future Things and Ideas
^^^^^^^^^^^^^^^^^^^^^^^
Compiler:
- vm Instructions needs to know what the read-registers/memory are, and what the write-register/memory is. This info is needed for more advanced optimizations and later code generation steps.
- vm: implement remaining sin/cos functions in math.p8
- vm: find a solution for the cx16.r0..r15 that "overlap" (r0, r0L, r0H etc) but in the vm each get their own separate variable location now
- vm: encode romsub & romsub call in VM IR (but just crash in virtualmachine itself.) ExpressionGen.kt
@ -29,7 +28,7 @@ Compiler:
How is it for the vm target? -> just 2 special cases in CodeGen.
- when the vm is stable and *if* its language can get promoted to prog8 IL, the variable allocation should be changed.
It's now done before the vm code generation, but the IL should probably not depend on the allocations already performed.
So the CodeGen doesn't do VariableAlloc *before* the codegen, but as a last step.
So the CodeGen doesn't do VariableAlloc *before* the codegen, but as a last step instead.
- generate WASM from the new ast (or from vm code?) to run prog8 on a browser canvas?
- createAssemblyAndAssemble(): make it possible to actually get rid of the VarDecl nodes by fixing the rest of the code mentioned there.
but probably better to rewrite the 6502 codegen on top of the new Ast.

View File

@ -208,7 +208,7 @@ class Assembler {
if(format.fpValue)
floatValue = value!!
program.add(Instruction(opcode, type, reg1, reg2, fpReg1, fpReg2, value = intValue, fpValue = floatValue))
program.add(Instruction(opcode, type, reg1, reg2, fpReg1, fpReg2, intValue, floatValue))
}
}

View File

@ -128,31 +128,31 @@ All have type b or w.
andr reg1, reg2 - reg1 = reg1 bitwise and reg2
and reg1, value - reg1 = reg1 bitwise and value
andm reg1 address - memory = memory bitwise and reg1
orr reg1, reg2 - reg1 = reg1 bitwise or reg2
or reg1, value - reg1 = reg1 bitwise or value
orm reg1, address - memory = memory bitwise or reg1
xorr reg1, reg2 - reg1 = reg1 bitwise xor reg2
xor reg1, value - reg1 = reg1 bitwise xor value
xorm reg1, address - memory = memory bitwise xor reg1
inv reg1 - reg1 = bitwise invert of reg1 (all bits flipped)
lsrn reg1, reg2 - reg1 = multi-shift reg1 right by reg2 bits + set Carry to shifted bit
invm address - memory = bitwise invert of that memory (all bits flipped)
asrn reg1, reg2 - reg1 = multi-shift reg1 right by reg2 bits (signed) + set Carry to shifted bit
lsrn reg1, reg2 - reg1 = multi-shift reg1 right by reg2 bits + set Carry to shifted bit
lsln reg1, reg2 - reg1 = multi-shift reg1 left by reg2 bits + set Carry to shifted bit
lsr reg1 - shift reg1 right by 1 bits + set Carry to shifted bit
asrnm reg1, address - multi-shift memory right by reg1 bits (signed) + set Carry to shifted bit
lsrnm reg1, address - multi-shift memoryright by reg1 bits + set Carry to shifted bit
lslnm reg1, address - multi-shift memory left by reg1 bits + set Carry to shifted bit
asr reg1 - shift reg1 right by 1 bits (signed) + set Carry to shifted bit
lsr reg1 - shift reg1 right by 1 bits + set Carry to shifted bit
lsl reg1 - shift reg1 left by 1 bits + set Carry to shifted bit
lsrm address - shift memory right by 1 bits + set Carry to shifted bit
asrm address - shift memory right by 1 bits (signed) + set Carry to shifted bit
lslm address - shift memory left by 1 bits + set Carry to shifted bit
ror reg1 - rotate reg1 right by 1 bits, not using carry + set Carry to shifted bit
roxr reg1 - rotate reg1 right by 1 bits, using carry + set Carry to shifted bit
rol reg1 - rotate reg1 left by 1 bits, not using carry + set Carry to shifted bit
roxl reg1 - rotate reg1 left by 1 bits, using carry, + set Carry to shifted bit
andm reg1 address - memory = memory bitwise and reg1
orm reg1, address - memory = memory bitwise or reg1
xorm reg1, address - memory = memory bitwise xor reg1
invm address - memory = bitwise invert of that memory (all bits flipped)
lsrnm reg1, address - multi-shift memoryright by reg1 bits + set Carry to shifted bit
asrnm reg1, address - multi-shift memory right by reg1 bits (signed) + set Carry to shifted bit
lslnm reg1, address - multi-shift memory left by reg1 bits + set Carry to shifted bit
lsrm address - shift memory right by 1 bits + set Carry to shifted bit
asrm address - shift memory right by 1 bits (signed) + set Carry to shifted bit
lslm address - shift memory left by 1 bits + set Carry to shifted bit
rorm address - rotate memory right by 1 bits, not using carry + set Carry to shifted bit
roxrm address - rotate memory right by 1 bits, using carry + set Carry to shifted bit
rolm address - rotate memory left by 1 bits, not using carry + set Carry to shifted bit
@ -172,6 +172,15 @@ ftosw reg1, fpreg1 - reg1 = fpreg1 as signed word
fpow fpreg1, fpreg2 - fpreg1 = fpreg1 to the power of fpreg2
fabs fpreg1, fpreg2 - fpreg1 = abs(fpreg2)
fcomp reg1, fpreg1, fpreg2 - reg1 = result of comparison of fpreg1 and fpreg2: 0=equal, 1=fpreg1 is greater, -1=fpreg1 is smaller
fsin fpreg1, fpreg2 - fpreg1 = sin(fpreg2)
fcos fpreg1, fpreg2 - fpreg1 = cos(fpreg2)
ftan fpreg1, fpreg2 - fpreg1 = tan(fpreg2)
fatan fpreg1, fpreg2 - fpreg1 = atan(fpreg2)
fln fpreg1, fpreg2 - fpreg1 = ln(fpreg2) ; natural logarithm
flog fpreg1, fpreg2 - fpreg1 = log(fpreg2) ; base 2 logarithm
fround fpreg1, fpreg2 - fpreg1 = round(fpreg2)
ffloor fpreg1, fpreg2 - fpreg1 = floor(fpreg2)
fceil fpreg1, fpreg2 - fpreg1 = ceil(fpreg2)
MISC
@ -316,7 +325,6 @@ enum class Opcode {
FATAN,
FLN,
FLOG,
FSQRT,
FROUND,
FFLOOR,
FCEIL,
@ -382,6 +390,11 @@ data class Instruction(
val fpValue: Float?=null,
val labelSymbol: List<String>?=null // symbolic label name as alternative to value (so only for Branch/jump/call Instructions!)
) {
// reg1 and fpreg1 can be IN/OUT/INOUT (all others are readonly INPUT)
// This knowledge is useful in IL assembly optimizers to see how registers are used.
val reg1direction: OperandDirection
val fpReg1direction: OperandDirection
init {
val formats = instructionFormats.getValue(opcode)
if(type==null && !formats.containsKey(null))
@ -410,6 +423,9 @@ data class Instruction(
throw IllegalArgumentException("$opcode: integer point instruction can't use floating point registers")
}
reg1direction = format.reg1direction
fpReg1direction = format.fpReg1direction
if(opcode in setOf(Opcode.BEQ, Opcode.BNE, Opcode.BLT, Opcode.BLTS,
Opcode.BGT, Opcode.BGTS, Opcode.BLE, Opcode.BLES,
Opcode.BGE, Opcode.BGES,
@ -464,184 +480,203 @@ data class Instruction(
}
}
enum class OperandDirection {
INPUT,
OUTPUT,
INOUT
}
data class InstructionFormat(val datatype: VmDataType?,
val reg1: Boolean, val reg2: Boolean,
val fpReg1: Boolean, val fpReg2: Boolean,
val value: Boolean,
val fpValue: Boolean) {
val reg1: Boolean, val reg1direction: OperandDirection, // reg1 can be IN/OUT/INOUT
val reg2: Boolean, // always only IN
val fpReg1: Boolean, val fpReg1direction: OperandDirection, // fpreg1 can be IN/OUT/INOUT
val fpReg2: Boolean, // always only IN
val value: Boolean, // always only IN
val fpValue: Boolean // always only IN
) {
companion object {
fun from(spec: String): Map<VmDataType?, InstructionFormat> {
val result = mutableMapOf<VmDataType?, InstructionFormat>()
for(part in spec.split('|').map{ it.trim() }) {
var reg1 = false
var reg2 = false
var fpreg1 = false
var fpreg2 = false
var value = false
var fpvalue = false
var reg1 = false // read/write/modify possible
var reg1Direction = OperandDirection.INPUT
var reg2 = false // strictly read-only
var fpreg1 = false // read/write/modify possible
var fpreg1Direction = OperandDirection.INPUT
var fpreg2 = false // strictly read-only
var value = false // strictly read-only
var fpvalue = false // strictly read-only
val splits = part.splitToSequence(',').iterator()
val typespec = splits.next()
while(splits.hasNext()) {
when(splits.next()) {
"r1" -> reg1=true
"r2" -> reg2=true
"fr1" -> fpreg1=true
"fr2" -> fpreg2=true
"v" -> value = true
"fv" -> fpvalue = true
"<r1" -> { reg1=true; reg1Direction=OperandDirection.INPUT }
">r1" -> { reg1=true; reg1Direction=OperandDirection.OUTPUT }
"<>r1" -> { reg1=true; reg1Direction=OperandDirection.INOUT }
"<r2" -> reg2 = true
"<fr1" -> { fpreg1=true; fpreg1Direction=OperandDirection.INPUT }
">fr1" -> { fpreg1=true; fpreg1Direction=OperandDirection.OUTPUT }
"<>fr1" -> { fpreg1=true; fpreg1Direction=OperandDirection.INOUT }
"<fr2" -> fpreg2=true
"<v" -> value = true
"<fv" -> fpvalue = true
else -> throw IllegalArgumentException(spec)
}
}
if(typespec=="N")
result[null] = InstructionFormat(null, reg1=reg1, reg2=reg2, fpReg1=fpreg1, fpReg2=fpreg2, value=value, fpValue=fpvalue)
result[null] = InstructionFormat(null, reg1, reg1Direction, reg2, fpreg1, fpreg1Direction, fpreg2, value, fpvalue)
if('B' in typespec)
result[VmDataType.BYTE] = InstructionFormat(VmDataType.BYTE, reg1=reg1, reg2=reg2, fpReg1=fpreg1, fpReg2=fpreg2, value=value, fpValue=fpvalue)
result[VmDataType.BYTE] = InstructionFormat(VmDataType.BYTE, reg1, reg1Direction, reg2, fpreg1, fpreg1Direction, fpreg2, value, fpvalue)
if('W' in typespec)
result[VmDataType.WORD] = InstructionFormat(VmDataType.WORD, reg1=reg1, reg2=reg2, fpReg1=fpreg1, fpReg2=fpreg2, value=value, fpValue=fpvalue)
result[VmDataType.WORD] = InstructionFormat(VmDataType.WORD, reg1, reg1Direction, reg2, fpreg1, fpreg1Direction, fpreg2, value, fpvalue)
if('F' in typespec)
result[VmDataType.FLOAT] = InstructionFormat(VmDataType.FLOAT, reg1=reg1, reg2=reg2, fpReg1=fpreg1, fpReg2=fpreg2, value=value, fpValue=fpvalue)
result[VmDataType.FLOAT] = InstructionFormat(VmDataType.FLOAT, reg1, reg1Direction, reg2, fpreg1, fpreg1Direction, fpreg2, value, fpvalue)
}
return result
}
}
}
/*
<X = X is not modified (input/readonly value)
>X = X is overwritten with output value (output value)
<>X = X is modified (input + output)
TODO: also encode if memory is read/written/modified?
*/
@Suppress("BooleanLiteralArgument")
val instructionFormats = mutableMapOf(
Opcode.NOP to InstructionFormat.from("N"),
Opcode.LOAD to InstructionFormat.from("BW,r1,v | F,fr1,fv"),
Opcode.LOADM to InstructionFormat.from("BW,r1,v | F,fr1,v"),
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.LOADIX to InstructionFormat.from("BW,r1,r2,v | F,fr1,r1,v"),
Opcode.LOADR 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.STOREIX to InstructionFormat.from("BW,r1,r2,v | F,fr1,r1,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.CALL to InstructionFormat.from("N,v"),
Opcode.SYSCALL to InstructionFormat.from("N,v"),
Opcode.LOAD to InstructionFormat.from("BW,>r1,<v | F,>fr1,<fv"),
Opcode.LOADM to InstructionFormat.from("BW,>r1,<v | F,>fr1,<v"),
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.LOADIX to InstructionFormat.from("BW,>r1,<r2,<v | F,>fr1,<r1,<v"),
Opcode.LOADR 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.STOREIX to InstructionFormat.from("BW,<r1,<r2,<v | F,<fr1,<r1,<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.CALL to InstructionFormat.from("N,<v"),
Opcode.SYSCALL to InstructionFormat.from("N,<v"),
Opcode.RETURN to InstructionFormat.from("N"),
Opcode.BSTCC to InstructionFormat.from("N,v"),
Opcode.BSTCS to InstructionFormat.from("N,v"),
Opcode.BSTEQ to InstructionFormat.from("N,v"),
Opcode.BSTNE to InstructionFormat.from("N,v"),
Opcode.BSTNEG to InstructionFormat.from("N,v"),
Opcode.BSTPOS to InstructionFormat.from("N,v"),
Opcode.BZ to InstructionFormat.from("BW,r1,v"),
Opcode.BNZ to InstructionFormat.from("BW,r1,v"),
Opcode.BEQ to InstructionFormat.from("BW,r1,r2,v"),
Opcode.BNE to InstructionFormat.from("BW,r1,r2,v"),
Opcode.BLT to InstructionFormat.from("BW,r1,r2,v"),
Opcode.BLTS to InstructionFormat.from("BW,r1,r2,v"),
Opcode.BGT to InstructionFormat.from("BW,r1,r2,v"),
Opcode.BGTS to InstructionFormat.from("BW,r1,r2,v"),
Opcode.BLE to InstructionFormat.from("BW,r1,r2,v"),
Opcode.BLES to InstructionFormat.from("BW,r1,r2,v"),
Opcode.BGE to InstructionFormat.from("BW,r1,r2,v"),
Opcode.BGES to InstructionFormat.from("BW,r1,r2,v"),
Opcode.SEQ to InstructionFormat.from("BW,r1,r2"),
Opcode.SNE to InstructionFormat.from("BW,r1,r2"),
Opcode.SLT to InstructionFormat.from("BW,r1,r2"),
Opcode.SLTS to InstructionFormat.from("BW,r1,r2"),
Opcode.SGT to InstructionFormat.from("BW,r1,r2"),
Opcode.SGTS to InstructionFormat.from("BW,r1,r2"),
Opcode.SLE to InstructionFormat.from("BW,r1,r2"),
Opcode.SLES to InstructionFormat.from("BW,r1,r2"),
Opcode.SGE to InstructionFormat.from("BW,r1,r2"),
Opcode.SGES to InstructionFormat.from("BW,r1,r2"),
Opcode.INC to InstructionFormat.from("BW,r1"),
Opcode.INCM to InstructionFormat.from("BW,v"),
Opcode.DEC to InstructionFormat.from("BW,r1"),
Opcode.DECM to InstructionFormat.from("BW,v"),
Opcode.NEG to InstructionFormat.from("BW,r1 | F,fr1"),
Opcode.NEGM to InstructionFormat.from("BW,v | F,v"),
Opcode.ADDR to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
Opcode.ADD to InstructionFormat.from("BW,r1,v | F,fr1,v"),
Opcode.ADDM to InstructionFormat.from("BW,r1,v | F,fr1,v"),
Opcode.SUBR to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
Opcode.SUB to InstructionFormat.from("BW,r1,v | F,fr1,v"),
Opcode.SUBM to InstructionFormat.from("BW,r1,v | F,fr1,v"),
Opcode.MULR to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
Opcode.MUL to InstructionFormat.from("BW,r1,v | F,fr1,v"),
Opcode.MULM to InstructionFormat.from("BW,r1,v | F,fr1,v"),
Opcode.DIVR to InstructionFormat.from("BW,r1,r2"),
Opcode.DIV to InstructionFormat.from("BW,r1,v"),
Opcode.DIVM to InstructionFormat.from("BW,r1,v"),
Opcode.DIVSR to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
Opcode.DIVS to InstructionFormat.from("BW,r1,v | F,fr1,v"),
Opcode.DIVSM to InstructionFormat.from("BW,r1,v | F,fr1,v"),
Opcode.SQRT to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
Opcode.SGN to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
Opcode.RND to InstructionFormat.from("BW,r1 | F,fr1"),
Opcode.MODR to InstructionFormat.from("BW,r1,r2"),
Opcode.MOD to InstructionFormat.from("BW,r1,v"),
Opcode.CMP to InstructionFormat.from("BW,r1,r2"),
Opcode.EXT to InstructionFormat.from("BW,r1"),
Opcode.EXTS to InstructionFormat.from("BW,r1"),
Opcode.ANDR to InstructionFormat.from("BW,r1,r2"),
Opcode.AND to InstructionFormat.from("BW,r1,v"),
Opcode.ANDM to InstructionFormat.from("BW,r1,v"),
Opcode.ORR to InstructionFormat.from("BW,r1,r2"),
Opcode.OR to InstructionFormat.from("BW,r1,v"),
Opcode.ORM to InstructionFormat.from("BW,r1,v"),
Opcode.XORR to InstructionFormat.from("BW,r1,r2"),
Opcode.XOR to InstructionFormat.from("BW,r1,v"),
Opcode.XORM to InstructionFormat.from("BW,r1,v"),
Opcode.INV to InstructionFormat.from("BW,r1"),
Opcode.INVM to InstructionFormat.from("BW,v"),
Opcode.ASRN to InstructionFormat.from("BW,r1,r2"),
Opcode.ASRNM to InstructionFormat.from("BW,r1,v"),
Opcode.LSRN to InstructionFormat.from("BW,r1,r2"),
Opcode.LSRNM to InstructionFormat.from("BW,r1,v"),
Opcode.LSLN to InstructionFormat.from("BW,r1,r2"),
Opcode.LSLNM to InstructionFormat.from("BW,r1,v"),
Opcode.ASR to InstructionFormat.from("BW,r1"),
Opcode.ASRM to InstructionFormat.from("BW,v"),
Opcode.LSR to InstructionFormat.from("BW,r1"),
Opcode.LSRM to InstructionFormat.from("BW,v"),
Opcode.LSL to InstructionFormat.from("BW,r1"),
Opcode.LSLM to InstructionFormat.from("BW,v"),
Opcode.ROR to InstructionFormat.from("BW,r1"),
Opcode.RORM to InstructionFormat.from("BW,v"),
Opcode.ROXR to InstructionFormat.from("BW,r1"),
Opcode.ROXRM to InstructionFormat.from("BW,v"),
Opcode.ROL to InstructionFormat.from("BW,r1"),
Opcode.ROLM to InstructionFormat.from("BW,v"),
Opcode.ROXL to InstructionFormat.from("BW,r1"),
Opcode.ROXLM to InstructionFormat.from("BW,v"),
Opcode.BSTCC to InstructionFormat.from("N,<v"),
Opcode.BSTCS to InstructionFormat.from("N,<v"),
Opcode.BSTEQ to InstructionFormat.from("N,<v"),
Opcode.BSTNE to InstructionFormat.from("N,<v"),
Opcode.BSTNEG to InstructionFormat.from("N,<v"),
Opcode.BSTPOS to InstructionFormat.from("N,<v"),
Opcode.BZ to InstructionFormat.from("BW,<r1,<v"),
Opcode.BNZ to InstructionFormat.from("BW,<r1,<v"),
Opcode.BEQ to InstructionFormat.from("BW,<r1,<r2,<v"),
Opcode.BNE to InstructionFormat.from("BW,<r1,<r2,<v"),
Opcode.BLT to InstructionFormat.from("BW,<r1,<r2,<v"),
Opcode.BLTS to InstructionFormat.from("BW,<r1,<r2,<v"),
Opcode.BGT to InstructionFormat.from("BW,<r1,<r2,<v"),
Opcode.BGTS to InstructionFormat.from("BW,<r1,<r2,<v"),
Opcode.BLE to InstructionFormat.from("BW,<r1,<r2,<v"),
Opcode.BLES to InstructionFormat.from("BW,<r1,<r2,<v"),
Opcode.BGE to InstructionFormat.from("BW,<r1,<r2,<v"),
Opcode.BGES to InstructionFormat.from("BW,<r1,<r2,<v"),
Opcode.SEQ to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.SNE to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.SLT to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.SLTS to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.SGT to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.SGTS to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.SLE to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.SLES to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.SGE to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.SGES to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.INC to InstructionFormat.from("BW,<>r1"),
Opcode.INCM to InstructionFormat.from("BW,<v"),
Opcode.DEC to InstructionFormat.from("BW,<>r1"),
Opcode.DECM to InstructionFormat.from("BW,<v"),
Opcode.NEG to InstructionFormat.from("BW,<>r1 | F,<>fr1"),
Opcode.NEGM to InstructionFormat.from("BW,<v | F,<v"),
Opcode.ADDR to InstructionFormat.from("BW,<>r1,<r2 | F,<>fr1,<fr2"),
Opcode.ADD to InstructionFormat.from("BW,<>r1,<v | F,<>fr1,<v"),
Opcode.ADDM to InstructionFormat.from("BW,<r1,<v | F,<fr1,<v"),
Opcode.SUBR to InstructionFormat.from("BW,<>r1,<r2 | F,<>fr1,<fr2"),
Opcode.SUB to InstructionFormat.from("BW,<>r1,<v | F,<>fr1,<v"),
Opcode.SUBM to InstructionFormat.from("BW,<r1,<v | F,<fr1,<v"),
Opcode.MULR to InstructionFormat.from("BW,<>r1,<r2 | F,<>fr1,<fr2"),
Opcode.MUL to InstructionFormat.from("BW,<>r1,<v | F,<>fr1,<v"),
Opcode.MULM to InstructionFormat.from("BW,<r1,<v | F,<fr1,<v"),
Opcode.DIVR to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.DIV to InstructionFormat.from("BW,<>r1,<v"),
Opcode.DIVM to InstructionFormat.from("BW,<r1,<v"),
Opcode.DIVSR to InstructionFormat.from("BW,<>r1,<r2 | F,<>fr1,<fr2"),
Opcode.DIVS to InstructionFormat.from("BW,<>r1,<v | F,<>fr1,<v"),
Opcode.DIVSM to InstructionFormat.from("BW,<r1,<v | F,<fr1,<v"),
Opcode.SQRT to InstructionFormat.from("BW,>r1,<r2 | F,>fr1,<fr2"),
Opcode.SGN to InstructionFormat.from("BW,>r1,<r2 | F,>fr1,<fr2"),
Opcode.RND to InstructionFormat.from("BW,>r1 | F,>fr1"),
Opcode.MODR to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.MOD to InstructionFormat.from("BW,<>r1,<v"),
Opcode.CMP to InstructionFormat.from("BW,<r1,<r2"),
Opcode.EXT to InstructionFormat.from("BW,<>r1"),
Opcode.EXTS to InstructionFormat.from("BW,<>r1"),
Opcode.ANDR to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.AND to InstructionFormat.from("BW,<>r1,<v"),
Opcode.ANDM to InstructionFormat.from("BW,<r1,<v"),
Opcode.ORR to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.OR to InstructionFormat.from("BW,<>r1,<v"),
Opcode.ORM to InstructionFormat.from("BW,<r1,<v"),
Opcode.XORR to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.XOR to InstructionFormat.from("BW,<>r1,<v"),
Opcode.XORM to InstructionFormat.from("BW,<r1,<v"),
Opcode.INV to InstructionFormat.from("BW,<>r1"),
Opcode.INVM to InstructionFormat.from("BW,<v"),
Opcode.ASRN to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.ASRNM to InstructionFormat.from("BW,<r1,<v"),
Opcode.LSRN to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.LSRNM to InstructionFormat.from("BW,<r1,<v"),
Opcode.LSLN to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.LSLNM to InstructionFormat.from("BW,<r1,<v"),
Opcode.ASR to InstructionFormat.from("BW,<>r1"),
Opcode.ASRM to InstructionFormat.from("BW,<v"),
Opcode.LSR to InstructionFormat.from("BW,<>r1"),
Opcode.LSRM to InstructionFormat.from("BW,<v"),
Opcode.LSL to InstructionFormat.from("BW,<>r1"),
Opcode.LSLM to InstructionFormat.from("BW,<v"),
Opcode.ROR to InstructionFormat.from("BW,<>r1"),
Opcode.RORM to InstructionFormat.from("BW,<v"),
Opcode.ROXR to InstructionFormat.from("BW,<>r1"),
Opcode.ROXRM to InstructionFormat.from("BW,<v"),
Opcode.ROL to InstructionFormat.from("BW,<>r1"),
Opcode.ROLM to InstructionFormat.from("BW,<v"),
Opcode.ROXL to InstructionFormat.from("BW,<>r1"),
Opcode.ROXLM to InstructionFormat.from("BW,<v"),
Opcode.FFROMUB to InstructionFormat.from("F,fr1,r1"),
Opcode.FFROMSB to InstructionFormat.from("F,fr1,r1"),
Opcode.FFROMUW to InstructionFormat.from("F,fr1,r1"),
Opcode.FFROMSW to InstructionFormat.from("F,fr1,r1"),
Opcode.FTOUB to InstructionFormat.from("F,r1,fr1"),
Opcode.FTOSB to InstructionFormat.from("F,r1,fr1"),
Opcode.FTOUW to InstructionFormat.from("F,r1,fr1"),
Opcode.FTOSW to InstructionFormat.from("F,r1,fr1"),
Opcode.FPOW to InstructionFormat.from("F,fr1,fr2"),
Opcode.FABS to InstructionFormat.from("F,fr1,fr2"),
Opcode.FSIN to InstructionFormat.from("F,fr1,fr2"),
Opcode.FCOS to InstructionFormat.from("F,fr1,fr2"),
Opcode.FTAN to InstructionFormat.from("F,fr1,fr2"),
Opcode.FATAN to InstructionFormat.from("F,fr1,fr2"),
Opcode.FLN to InstructionFormat.from("F,fr1,fr2"),
Opcode.FLOG to InstructionFormat.from("F,fr1,fr2"),
Opcode.FSQRT to InstructionFormat.from("F,fr1,fr2"),
Opcode.FROUND to InstructionFormat.from("F,fr1,fr2"),
Opcode.FFLOOR to InstructionFormat.from("F,fr1,fr2"),
Opcode.FCEIL to InstructionFormat.from("F,fr1,fr2"),
Opcode.FCOMP to InstructionFormat.from("F,r1,fr1,fr2"),
Opcode.FFROMUB to InstructionFormat.from("F,>fr1,<r1"),
Opcode.FFROMSB to InstructionFormat.from("F,>fr1,<r1"),
Opcode.FFROMUW to InstructionFormat.from("F,>fr1,<r1"),
Opcode.FFROMSW to InstructionFormat.from("F,>fr1,<r1"),
Opcode.FTOUB to InstructionFormat.from("F,>r1,<fr1"),
Opcode.FTOSB to InstructionFormat.from("F,>r1,<fr1"),
Opcode.FTOUW to InstructionFormat.from("F,>r1,<fr1"),
Opcode.FTOSW to InstructionFormat.from("F,>r1,<fr1"),
Opcode.FPOW to InstructionFormat.from("F,<>fr1,<fr2"),
Opcode.FABS to InstructionFormat.from("F,>fr1,<fr2"),
Opcode.FCOMP to InstructionFormat.from("F,>r1,<fr1,<fr2"),
Opcode.FSIN to InstructionFormat.from("F,>fr1,<fr2"),
Opcode.FCOS to InstructionFormat.from("F,>fr1,<fr2"),
Opcode.FTAN to InstructionFormat.from("F,>fr1,<fr2"),
Opcode.FATAN to InstructionFormat.from("F,>fr1,<fr2"),
Opcode.FLN to InstructionFormat.from("F,>fr1,<fr2"),
Opcode.FLOG to InstructionFormat.from("F,>fr1,<fr2"),
Opcode.FROUND to InstructionFormat.from("F,>fr1,<fr2"),
Opcode.FFLOOR to InstructionFormat.from("F,>fr1,<fr2"),
Opcode.FCEIL to InstructionFormat.from("F,>fr1,<fr2"),
Opcode.MSIG to InstructionFormat.from("BW,r1,r2"),
Opcode.PUSH to InstructionFormat.from("BW,r1"),
Opcode.POP to InstructionFormat.from("BW,r1"),
Opcode.CONCAT to InstructionFormat.from("BW,r1,r2"),
Opcode.MSIG to InstructionFormat.from("BW,>r1,<r2"),
Opcode.PUSH to InstructionFormat.from("BW,<r1"),
Opcode.POP to InstructionFormat.from("BW,>r1"),
Opcode.CONCAT to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.CLC to InstructionFormat.from("N"),
Opcode.SEC to InstructionFormat.from("N"),
Opcode.BREAKPOINT to InstructionFormat.from("N"),

View File

@ -218,7 +218,6 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
Opcode.FATAN -> InsFATAN(ins)
Opcode.FLN -> InsFLN(ins)
Opcode.FLOG -> InsFLOG(ins)
Opcode.FSQRT -> InsFSQRT(ins)
Opcode.FROUND -> InsFROUND(ins)
Opcode.FFLOOR -> InsFFLOOR(ins)
Opcode.FCEIL -> InsFCEIL(ins)
@ -1887,12 +1886,6 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
pc++
}
private fun InsFSQRT(i: Instruction) {
val value = registers.getFloat(i.fpReg2!!)
registers.setFloat(i.fpReg1!!, sqrt(value))
pc++
}
private fun InsFCOMP(i: Instruction) {
val left = registers.getFloat(i.fpReg1!!)
val right = registers.getFloat(i.fpReg2!!)

View File

@ -2,10 +2,7 @@ import io.kotest.assertions.throwables.shouldThrow
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe
import prog8.vm.Instruction
import prog8.vm.Opcode
import prog8.vm.VmDataType
import prog8.vm.instructionFormats
import prog8.vm.*
class TestInstructions: FunSpec({
@ -18,6 +15,8 @@ class TestInstructions: FunSpec({
ins.reg2 shouldBe null
ins.value shouldBe null
ins.labelSymbol shouldBe null
ins.reg1direction shouldBe OperandDirection.INPUT
ins.fpReg1direction shouldBe OperandDirection.INPUT
ins.toString() shouldBe "nop"
}
@ -29,6 +28,8 @@ class TestInstructions: FunSpec({
ins.reg2 shouldBe null
ins.value shouldBe 9999
ins.labelSymbol shouldBe null
ins.reg1direction shouldBe OperandDirection.INPUT
ins.fpReg1direction shouldBe OperandDirection.INPUT
ins.toString() shouldBe "bz.b r42,9999"
}
@ -40,9 +41,36 @@ class TestInstructions: FunSpec({
ins.reg2 shouldBe null
ins.value shouldBe null
ins.labelSymbol shouldBe listOf("a","b","c")
ins.reg1direction shouldBe OperandDirection.INPUT
ins.fpReg1direction shouldBe OperandDirection.INPUT
ins.toString() shouldBe "bz.w r11,_a.b.c"
}
test("with output registers") {
val ins = Instruction(Opcode.ADDR, VmDataType.WORD, reg1=11, reg2=22)
ins.opcode shouldBe Opcode.ADDR
ins.type shouldBe VmDataType.WORD
ins.reg1 shouldBe 11
ins.reg2 shouldBe 22
ins.value shouldBe null
ins.labelSymbol shouldBe null
ins.reg1direction shouldBe OperandDirection.INOUT
ins.fpReg1direction shouldBe OperandDirection.INPUT
ins.toString() shouldBe "addr.w r11,r22"
val ins2 = Instruction(Opcode.SQRT, VmDataType.BYTE, reg1=11, reg2=22)
ins2.opcode shouldBe Opcode.SQRT
ins2.type shouldBe VmDataType.BYTE
ins2.reg1 shouldBe 11
ins2.reg2 shouldBe 22
ins2.value shouldBe null
ins2.labelSymbol shouldBe null
ins2.reg1direction shouldBe OperandDirection.OUTPUT
ins2.fpReg1direction shouldBe OperandDirection.INPUT
ins2.toString() shouldBe "sqrt.b r11,r22"
}
test("missing type should fail") {
shouldThrow<IllegalArgumentException> {
Instruction(Opcode.BZ, reg1=42, value=9999)