prog8/intermediate/test/TestInstructions.kt

124 lines
4.6 KiB
Kotlin
Raw Normal View History

2022-03-30 19:44:48 +00:00
import io.kotest.assertions.throwables.shouldThrow
import io.kotest.assertions.throwables.shouldThrowWithMessage
2022-03-30 19:44:48 +00:00
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe
import prog8.intermediate.*
2022-03-30 19:44:48 +00:00
class TestInstructions: FunSpec({
test("simple") {
val ins = IRInstruction(Opcode.NOP)
2022-03-30 19:44:48 +00:00
ins.opcode shouldBe Opcode.NOP
ins.type shouldBe null
ins.reg1direction shouldBe OperandDirection.UNUSED
ins.fpReg1direction shouldBe OperandDirection.UNUSED
2022-03-30 19:44:48 +00:00
ins.reg1 shouldBe null
ins.reg2 shouldBe null
ins.value shouldBe null
ins.labelSymbol shouldBe null
2022-03-30 19:44:48 +00:00
ins.toString() shouldBe "nop"
}
test("with value") {
val ins = IRInstruction(Opcode.BZ, IRDataType.BYTE, reg1=42, value = 99)
2022-03-30 19:44:48 +00:00
ins.opcode shouldBe Opcode.BZ
ins.type shouldBe IRDataType.BYTE
ins.reg1direction shouldBe OperandDirection.READ
ins.fpReg1direction shouldBe OperandDirection.UNUSED
2022-03-30 19:44:48 +00:00
ins.reg1 shouldBe 42
ins.reg2 shouldBe null
ins.value shouldBe 99
ins.labelSymbol shouldBe null
2022-11-07 23:06:43 +00:00
ins.toString() shouldBe "bz.b r42,$63"
2022-03-30 19:44:48 +00:00
}
test("with label") {
val ins = IRInstruction(Opcode.BZ, IRDataType.WORD, reg1=11, labelSymbol = "a.b.c")
2022-03-30 19:44:48 +00:00
ins.opcode shouldBe Opcode.BZ
ins.type shouldBe IRDataType.WORD
ins.reg1direction shouldBe OperandDirection.READ
ins.fpReg1direction shouldBe OperandDirection.UNUSED
2022-03-30 19:44:48 +00:00
ins.reg1 shouldBe 11
ins.reg2 shouldBe null
2022-03-30 19:44:48 +00:00
ins.value shouldBe null
ins.labelSymbol shouldBe "a.b.c"
2022-11-03 19:17:55 +00:00
ins.toString() shouldBe "bz.w r11,a.b.c"
2022-03-30 19:44:48 +00:00
}
test("with output registers") {
val ins = IRInstruction(Opcode.ADDR, IRDataType.WORD, reg1=11, reg2=22)
ins.opcode shouldBe Opcode.ADDR
ins.type shouldBe IRDataType.WORD
ins.reg1direction shouldBe OperandDirection.READWRITE
ins.reg2direction shouldBe OperandDirection.READ
ins.fpReg1direction shouldBe OperandDirection.UNUSED
ins.fpReg2direction shouldBe OperandDirection.UNUSED
ins.reg1 shouldBe 11
ins.reg2 shouldBe 22
ins.value shouldBe null
ins.labelSymbol shouldBe null
ins.toString() shouldBe "addr.w r11,r22"
val ins2 = IRInstruction(Opcode.SQRT, IRDataType.BYTE, reg1=11, reg2=22)
ins2.opcode shouldBe Opcode.SQRT
ins2.type shouldBe IRDataType.BYTE
ins2.reg1direction shouldBe OperandDirection.WRITE
ins2.reg2direction shouldBe OperandDirection.READ
ins2.fpReg1direction shouldBe OperandDirection.UNUSED
ins2.fpReg2direction shouldBe OperandDirection.UNUSED
ins2.reg1 shouldBe 11
ins2.reg2 shouldBe 22
ins2.value shouldBe null
ins2.labelSymbol shouldBe null
ins2.toString() shouldBe "sqrt.b r11,r22"
}
test("with float regs") {
val ins = IRInstruction(Opcode.FSIN, IRDataType.FLOAT, fpReg1 = 1, fpReg2 = 2)
ins.opcode shouldBe Opcode.FSIN
ins.type shouldBe IRDataType.FLOAT
ins.reg1direction shouldBe OperandDirection.UNUSED
ins.reg2direction shouldBe OperandDirection.UNUSED
ins.fpReg1direction shouldBe OperandDirection.WRITE
ins.fpReg2direction shouldBe OperandDirection.READ
ins.fpReg1 shouldBe 1
ins.fpReg2 shouldBe 2
ins.reg1 shouldBe null
ins.reg2 shouldBe null
ins.value shouldBe null
ins.labelSymbol shouldBe null
ins.toString() shouldBe "fsin.f fr1,fr2"
}
2022-03-30 19:44:48 +00:00
test("missing type should fail") {
shouldThrow<IllegalArgumentException> {
IRInstruction(Opcode.BZ, reg1=42, value=99)
2022-03-30 19:44:48 +00:00
}
}
test("missing registers should fail") {
2022-09-27 16:27:55 +00:00
shouldThrowWithMessage<IllegalArgumentException>("missing reg1") {
IRInstruction(Opcode.BZ, IRDataType.BYTE, value=99)
2022-03-30 19:44:48 +00:00
}
}
test("missing value should fail") {
shouldThrowWithMessage<IllegalArgumentException>("missing a value or labelsymbol") {
IRInstruction(Opcode.BZ, IRDataType.BYTE, reg1=42)
2022-03-30 19:44:48 +00:00
}
}
test("all instructionformats") {
instructionFormats.size shouldBe Opcode.values().size
2022-03-30 19:44:48 +00:00
Opcode.values().forEach {
val fmt = instructionFormats.getValue(it)
fmt.values.forEach { format ->
require(format.reg2==OperandDirection.UNUSED || format.reg2==OperandDirection.READ) {"reg2 can only be used as input"}
require(format.fpReg2==OperandDirection.UNUSED || format.fpReg2==OperandDirection.READ) {"fpReg2 can only be used as input"}
}
2022-03-30 19:44:48 +00:00
}
}
2022-03-30 19:44:48 +00:00
})