prog8/virtualmachine/test/TestVm.kt

149 lines
5.0 KiB
Kotlin
Raw Normal View History

import io.kotest.assertions.throwables.shouldThrowWithMessage
2022-09-21 00:59:36 +00:00
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.collections.shouldBeEmpty
import io.kotest.matchers.shouldBe
2022-09-26 17:03:54 +00:00
import prog8.code.core.*
import prog8.code.target.VMTarget
2023-02-16 21:19:30 +00:00
import prog8.code.target.c64.C64MachineDefinition
import prog8.code.target.cx16.CX16MachineDefinition
import prog8.code.target.virtual.VirtualMachineDefinition
2022-09-26 17:03:54 +00:00
import prog8.intermediate.*
2022-09-21 00:59:36 +00:00
import prog8.vm.VirtualMachine
import prog8.vm.VmRunner
class TestVm: FunSpec( {
2022-09-26 17:03:54 +00:00
fun getTestOptions(): CompilationOptions {
val target = VMTarget()
return CompilationOptions(
OutputType.RAW,
CbmPrgLauncherType.NONE,
ZeropageType.DONTUSE,
zpReserved = emptyList(),
floats = true,
noSysInit = false,
compTarget = target,
loadAddress = target.machine.PROGRAM_LOAD_ADDRESS
)
}
2022-09-21 00:59:36 +00:00
test("vm execution: empty program") {
2022-09-26 17:03:54 +00:00
val program = IRProgram("test", IRSymbolTable(null), getTestOptions(), VMTarget())
val vm = VirtualMachine(program)
2022-09-21 00:59:36 +00:00
vm.callStack.shouldBeEmpty()
vm.valueStack.shouldBeEmpty()
2022-10-16 16:30:14 +00:00
vm.pcIndex shouldBe 0
2022-09-21 00:59:36 +00:00
vm.stepCount shouldBe 0
2022-09-24 14:00:25 +00:00
vm.run()
2022-09-21 00:59:36 +00:00
vm.callStack.shouldBeEmpty()
vm.valueStack.shouldBeEmpty()
2022-10-16 16:30:14 +00:00
vm.pcIndex shouldBe 0
vm.stepCount shouldBe 0
2022-09-21 00:59:36 +00:00
}
test("vm execution: modify memory") {
2022-09-26 17:03:54 +00:00
val program = IRProgram("test", IRSymbolTable(null), getTestOptions(), VMTarget())
val block = IRBlock("testmain", null, IRBlock.BlockAlignment.NONE, Position.DUMMY)
val startSub = IRSubroutine("testmain.testsub", emptyList(), null, Position.DUMMY)
2022-11-22 01:04:24 +00:00
val code = IRCodeChunk(startSub.label, null)
code += IRInstruction(Opcode.NOP)
2023-04-09 13:06:40 +00:00
code += IRInstruction(Opcode.LOAD, IRDataType.WORD, reg1=1, immediate=12345)
code += IRInstruction(Opcode.STOREM, IRDataType.WORD, reg1=1, address=1000)
code += IRInstruction(Opcode.RETURN)
2022-09-26 17:03:54 +00:00
startSub += code
block += startSub
program.addBlock(block)
val vm = VirtualMachine(program)
vm.memory.setUW(1000, 0u)
2022-09-21 00:59:36 +00:00
2022-09-26 17:03:54 +00:00
vm.memory.getUW(1000) shouldBe 0u
2022-09-21 00:59:36 +00:00
vm.callStack.shouldBeEmpty()
vm.valueStack.shouldBeEmpty()
2022-10-16 16:30:14 +00:00
vm.pcIndex shouldBe 0
2022-09-21 00:59:36 +00:00
vm.stepCount shouldBe 0
2022-09-24 14:00:25 +00:00
vm.run()
2022-10-16 16:30:14 +00:00
vm.stepCount shouldBe 4
2022-09-26 17:03:54 +00:00
vm.memory.getUW(1000) shouldBe 12345u
2022-09-21 00:59:36 +00:00
vm.callStack.shouldBeEmpty()
vm.valueStack.shouldBeEmpty()
2022-10-16 16:30:14 +00:00
vm.pcIndex shouldBe code.instructions.size-1
2022-10-04 20:54:14 +00:00
vm.stepCount shouldBe code.instructions.size
}
2022-10-16 16:30:14 +00:00
test("vm asmbinary not supported") {
2022-09-27 15:45:26 +00:00
val program = IRProgram("test", IRSymbolTable(null), getTestOptions(), VMTarget())
val block = IRBlock("testmain", null, IRBlock.BlockAlignment.NONE, Position.DUMMY)
val startSub = IRSubroutine("testmain.testsub", emptyList(), null, Position.DUMMY)
2022-11-22 01:04:24 +00:00
val code = IRCodeChunk(startSub.label, null)
2022-09-27 15:45:26 +00:00
code += IRInstruction(Opcode.BINARYDATA, binaryData = listOf(1u,2u,3u))
code += IRInstruction(Opcode.RETURN)
startSub += code
block += startSub
program.addBlock(block)
val vm = VirtualMachine(program)
shouldThrowWithMessage<NotImplementedError>("An operation is not implemented: BINARYDATA not yet supported in VM") {
vm.run()
}
}
test("asmsub not supported in vm even with IR") {
val program = IRProgram("test", IRSymbolTable(null), getTestOptions(), VMTarget())
val block = IRBlock("main", null, IRBlock.BlockAlignment.NONE, Position.DUMMY)
val startSub = IRAsmSubroutine(
"main.asmstart",
0x2000u,
emptySet(),
emptyList(),
emptyList(),
IRInlineAsmChunk("main.asmstart", "return", false, null),
2022-10-31 22:59:33 +00:00
Position.DUMMY
)
block += startSub
program.addBlock(block)
shouldThrowWithMessage<IRParseException>("vm does not support asmsubs (use normal sub): main.asmstart") {
VirtualMachine(program)
}
2022-09-21 00:59:36 +00:00
}
test("vmrunner") {
val runner = VmRunner()
2022-11-11 22:35:52 +00:00
val irSource="""<?xml version="1.0" encoding="utf-8"?>
<PROGRAM NAME="test">
2022-09-26 17:03:54 +00:00
<OPTIONS>
</OPTIONS>
<ASMSYMBOLS>
</ASMSYMBOLS>
2023-02-19 02:07:55 +00:00
<VARIABLESNOINIT>
</VARIABLESNOINIT>
<VARIABLESWITHINIT>
</VARIABLESWITHINIT>
2022-09-26 17:03:54 +00:00
<MEMORYMAPPEDVARIABLES>
</MEMORYMAPPEDVARIABLES>
<MEMORYSLABS>
</MEMORYSLABS>
<INITGLOBALS>
</INITGLOBALS>
<BLOCK NAME="main" ADDRESS="" ALIGN="NONE" POS="[unittest: line 42 col 1-9]">
2022-09-26 17:03:54 +00:00
</BLOCK>
</PROGRAM>
"""
runner.runProgram(irSource)
2022-09-21 00:59:36 +00:00
}
2023-02-16 21:19:30 +00:00
test("vm machine float bits") {
val cx16machine = CX16MachineDefinition()
cx16machine.getFloatAsmBytes(Math.PI) shouldBe "\$82, \$49, \$0f, \$da, \$a2"
val c64machine = C64MachineDefinition()
c64machine.getFloatAsmBytes(Math.PI) shouldBe "\$82, \$49, \$0f, \$da, \$a2"
val vm = VirtualMachineDefinition()
vm.getFloatAsmBytes(Math.PI) shouldBe "\$40, \$49, \$0f, \$db"
}
2022-09-21 00:59:36 +00:00
})