prog8/intermediate/test/TestInstructions.kt

136 lines
5.1 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
2023-04-09 13:06:40 +00:00
ins.address shouldBe null
ins.immediate shouldBe null
ins.immediateFp 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.BEQ, IRDataType.BYTE, reg1=42, immediate = 0, address = 99)
ins.opcode shouldBe Opcode.BEQ
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
2023-04-09 13:06:40 +00:00
ins.address shouldBe 99
ins.immediate shouldBe 0
2023-04-09 13:06:40 +00:00
ins.immediateFp shouldBe null
ins.labelSymbol shouldBe null
ins.toString() shouldBe "beq.b r42,0,$63"
2022-03-30 19:44:48 +00:00
}
test("with label") {
val ins = IRInstruction(Opcode.BEQ, IRDataType.WORD, reg1=11, immediate = 0, labelSymbol = "a.b.c")
ins.opcode shouldBe Opcode.BEQ
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
2023-04-09 13:06:40 +00:00
ins.address shouldBe null
ins.immediate shouldBe 0
2023-04-09 13:06:40 +00:00
ins.immediateFp shouldBe null
ins.labelSymbol shouldBe "a.b.c"
ins.toString() shouldBe "beq.w r11,0,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
2023-04-09 13:06:40 +00:00
ins.address shouldBe null
ins.immediate shouldBe null
ins.immediateFp 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
2023-04-09 13:06:40 +00:00
ins.address shouldBe null
ins.immediate shouldBe null
ins.immediateFp 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
2023-04-09 13:06:40 +00:00
ins.address shouldBe null
ins.immediate shouldBe null
ins.immediateFp 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.BEQ, 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") {
IRInstruction(Opcode.BEQ, IRDataType.BYTE, immediate = 0, 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") {
IRInstruction(Opcode.BEQ, IRDataType.BYTE, immediate = 0, reg1=42)
2022-03-30 19:44:48 +00:00
}
}
test("all instructionformats") {
2023-07-06 21:03:47 +00:00
instructionFormats.size shouldBe Opcode.entries.size
Opcode.entries.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
})