2022-03-30 19:44:48 +00:00
|
|
|
import io.kotest.assertions.throwables.shouldThrow
|
2022-09-26 23:50:00 +00:00
|
|
|
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
|
2022-08-27 11:06:44 +00:00
|
|
|
import prog8.intermediate.*
|
2022-03-30 19:44:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
class TestInstructions: FunSpec({
|
|
|
|
|
|
|
|
test("simple") {
|
2022-09-26 17:46:44 +00:00
|
|
|
val ins = IRInstruction(Opcode.NOP)
|
2022-03-30 19:44:48 +00:00
|
|
|
ins.opcode shouldBe Opcode.NOP
|
|
|
|
ins.type shouldBe null
|
2022-09-30 18:18:14 +00:00
|
|
|
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
|
2023-04-09 13:06:40 +00:00
|
|
|
ins.address shouldBe null
|
|
|
|
ins.immediate shouldBe null
|
|
|
|
ins.immediateFp shouldBe null
|
2022-05-18 20:15:42 +00:00
|
|
|
ins.labelSymbol shouldBe null
|
2022-03-30 19:44:48 +00:00
|
|
|
ins.toString() shouldBe "nop"
|
|
|
|
}
|
|
|
|
|
|
|
|
test("with value") {
|
2023-04-09 13:06:40 +00:00
|
|
|
val ins = IRInstruction(Opcode.BZ, IRDataType.BYTE, reg1=42, address = 99)
|
2022-03-30 19:44:48 +00:00
|
|
|
ins.opcode shouldBe Opcode.BZ
|
2022-09-30 13:27:03 +00:00
|
|
|
ins.type shouldBe IRDataType.BYTE
|
2023-03-12 19:08:42 +00:00
|
|
|
ins.reg1direction shouldBe OperandDirection.READ
|
2022-09-30 18:18:14 +00:00
|
|
|
ins.fpReg1direction shouldBe OperandDirection.UNUSED
|
2022-03-30 19:44:48 +00:00
|
|
|
ins.reg1 shouldBe 42
|
|
|
|
ins.reg2 shouldBe null
|
2023-04-09 13:06:40 +00:00
|
|
|
ins.address shouldBe 99
|
|
|
|
ins.immediate shouldBe null
|
|
|
|
ins.immediateFp shouldBe null
|
2022-05-18 20:15:42 +00:00
|
|
|
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") {
|
2022-09-30 13:27:03 +00:00
|
|
|
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
|
2022-09-30 13:27:03 +00:00
|
|
|
ins.type shouldBe IRDataType.WORD
|
2023-03-12 19:08:42 +00:00
|
|
|
ins.reg1direction shouldBe OperandDirection.READ
|
2022-09-30 18:18:14 +00:00
|
|
|
ins.fpReg1direction shouldBe OperandDirection.UNUSED
|
2022-03-30 19:44:48 +00:00
|
|
|
ins.reg1 shouldBe 11
|
2022-04-10 13:09:12 +00:00
|
|
|
ins.reg2 shouldBe null
|
2023-04-09 13:06:40 +00:00
|
|
|
ins.address shouldBe null
|
|
|
|
ins.immediate shouldBe null
|
|
|
|
ins.immediateFp shouldBe null
|
2022-09-26 17:46:44 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2022-08-07 15:43:40 +00:00
|
|
|
test("with output registers") {
|
2022-09-30 13:27:03 +00:00
|
|
|
val ins = IRInstruction(Opcode.ADDR, IRDataType.WORD, reg1=11, reg2=22)
|
2022-08-07 15:43:40 +00:00
|
|
|
ins.opcode shouldBe Opcode.ADDR
|
2022-09-30 13:27:03 +00:00
|
|
|
ins.type shouldBe IRDataType.WORD
|
2023-03-12 19:08:42 +00:00
|
|
|
ins.reg1direction shouldBe OperandDirection.READWRITE
|
|
|
|
ins.reg2direction shouldBe OperandDirection.READ
|
2022-09-30 18:18:14 +00:00
|
|
|
ins.fpReg1direction shouldBe OperandDirection.UNUSED
|
|
|
|
ins.fpReg2direction shouldBe OperandDirection.UNUSED
|
2022-08-07 15:43:40 +00:00
|
|
|
ins.reg1 shouldBe 11
|
|
|
|
ins.reg2 shouldBe 22
|
2023-04-09 13:06:40 +00:00
|
|
|
ins.address shouldBe null
|
|
|
|
ins.immediate shouldBe null
|
|
|
|
ins.immediateFp shouldBe null
|
2022-08-07 15:43:40 +00:00
|
|
|
ins.labelSymbol shouldBe null
|
|
|
|
ins.toString() shouldBe "addr.w r11,r22"
|
|
|
|
|
2022-09-30 13:27:03 +00:00
|
|
|
val ins2 = IRInstruction(Opcode.SQRT, IRDataType.BYTE, reg1=11, reg2=22)
|
2022-08-07 15:43:40 +00:00
|
|
|
ins2.opcode shouldBe Opcode.SQRT
|
2022-09-30 13:27:03 +00:00
|
|
|
ins2.type shouldBe IRDataType.BYTE
|
2023-03-12 19:08:42 +00:00
|
|
|
ins2.reg1direction shouldBe OperandDirection.WRITE
|
|
|
|
ins2.reg2direction shouldBe OperandDirection.READ
|
2022-09-30 18:18:14 +00:00
|
|
|
ins2.fpReg1direction shouldBe OperandDirection.UNUSED
|
|
|
|
ins2.fpReg2direction shouldBe OperandDirection.UNUSED
|
2022-08-07 15:43:40 +00:00
|
|
|
ins2.reg1 shouldBe 11
|
|
|
|
ins2.reg2 shouldBe 22
|
2023-04-09 13:06:40 +00:00
|
|
|
ins.address shouldBe null
|
|
|
|
ins.immediate shouldBe null
|
|
|
|
ins.immediateFp shouldBe null
|
2022-08-07 15:43:40 +00:00
|
|
|
ins2.labelSymbol shouldBe null
|
|
|
|
ins2.toString() shouldBe "sqrt.b r11,r22"
|
|
|
|
}
|
|
|
|
|
2022-09-30 18:18:14 +00:00
|
|
|
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
|
2023-03-12 19:08:42 +00:00
|
|
|
ins.fpReg1direction shouldBe OperandDirection.WRITE
|
|
|
|
ins.fpReg2direction shouldBe OperandDirection.READ
|
2022-09-30 18:18:14 +00:00
|
|
|
ins.fpReg1 shouldBe 1
|
|
|
|
ins.fpReg2 shouldBe 2
|
|
|
|
ins.reg1 shouldBe null
|
|
|
|
ins.reg2 shouldBe null
|
2023-04-09 13:06:40 +00:00
|
|
|
ins.address shouldBe null
|
|
|
|
ins.immediate shouldBe null
|
|
|
|
ins.immediateFp shouldBe null
|
2022-09-30 18:18:14 +00:00
|
|
|
ins.labelSymbol shouldBe null
|
|
|
|
ins.toString() shouldBe "fsin.f fr1,fr2"
|
|
|
|
}
|
|
|
|
|
2022-08-07 15:43:40 +00:00
|
|
|
|
2022-03-30 19:44:48 +00:00
|
|
|
test("missing type should fail") {
|
|
|
|
shouldThrow<IllegalArgumentException> {
|
2023-04-09 13:06:40 +00:00
|
|
|
IRInstruction(Opcode.BZ, reg1=42, address=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") {
|
2023-04-09 13:06:40 +00:00
|
|
|
IRInstruction(Opcode.BZ, IRDataType.BYTE, address=99)
|
2022-03-30 19:44:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-09 13:06:40 +00:00
|
|
|
test("missing address should fail") {
|
|
|
|
shouldThrowWithMessage<IllegalArgumentException>("missing an address or labelsymbol") {
|
2022-09-30 13:27:03 +00:00
|
|
|
IRInstruction(Opcode.BZ, IRDataType.BYTE, reg1=42)
|
2022-03-30 19:44:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
test("all instructionformats") {
|
2022-09-26 23:50:00 +00:00
|
|
|
instructionFormats.size shouldBe Opcode.values().size
|
2022-03-30 19:44:48 +00:00
|
|
|
Opcode.values().forEach {
|
2022-09-30 18:18:14 +00:00
|
|
|
val fmt = instructionFormats.getValue(it)
|
|
|
|
fmt.values.forEach { format ->
|
2023-03-12 19:08:42 +00:00
|
|
|
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-09-30 18:18:14 +00:00
|
|
|
}
|
2022-03-30 19:44:48 +00:00
|
|
|
}
|
2022-09-26 23:50:00 +00:00
|
|
|
}
|
2022-03-30 19:44:48 +00:00
|
|
|
})
|