2022-09-26 23:50:00 +00:00
|
|
|
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(),
|
2023-11-02 22:45:10 +00:00
|
|
|
zpAllowed = CompilationOptions.AllZeropageAllowed,
|
2022-09-26 17:03:54 +00:00
|
|
|
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") {
|
2023-12-11 21:51:33 +00:00
|
|
|
val program = IRProgram("test", IRSymbolTable(), getTestOptions(), VMTarget())
|
2022-09-26 17:03:54 +00:00
|
|
|
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") {
|
2023-12-11 21:51:33 +00:00
|
|
|
val program = IRProgram("test", IRSymbolTable(), getTestOptions(), VMTarget())
|
2023-05-01 21:00:51 +00:00
|
|
|
val block = IRBlock("testmain", null, false, false, IRBlock.BlockAlignment.NONE, Position.DUMMY)
|
2022-09-26 23:50:00 +00:00
|
|
|
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-26 23:50:00 +00:00
|
|
|
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)
|
2022-09-26 17:46:44 +00:00
|
|
|
code += IRInstruction(Opcode.RETURN)
|
2022-09-26 17:03:54 +00:00
|
|
|
startSub += code
|
|
|
|
block += startSub
|
|
|
|
program.addBlock(block)
|
|
|
|
val vm = VirtualMachine(program)
|
2022-12-03 16:46:06 +00:00
|
|
|
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-09-26 23:50:00 +00:00
|
|
|
}
|
|
|
|
|
2023-01-26 00:38:13 +00:00
|
|
|
test("asmsub not supported in vm even with IR") {
|
2023-12-11 21:51:33 +00:00
|
|
|
val program = IRProgram("test", IRSymbolTable(), getTestOptions(), VMTarget())
|
2023-05-01 21:00:51 +00:00
|
|
|
val block = IRBlock("main", null, false, false, IRBlock.BlockAlignment.NONE, Position.DUMMY)
|
2022-09-30 12:05:11 +00:00
|
|
|
val startSub = IRAsmSubroutine(
|
|
|
|
"main.asmstart",
|
|
|
|
0x2000u,
|
|
|
|
emptySet(),
|
|
|
|
emptyList(),
|
|
|
|
emptyList(),
|
2023-01-26 00:38:13 +00:00
|
|
|
IRInlineAsmChunk("main.asmstart", "return", false, null),
|
2022-10-31 22:59:33 +00:00
|
|
|
Position.DUMMY
|
2022-09-30 12:05:11 +00:00
|
|
|
)
|
2022-09-26 23:50:00 +00:00
|
|
|
block += startSub
|
|
|
|
program.addBlock(block)
|
2023-12-26 13:47:31 +00:00
|
|
|
shouldThrowWithMessage<IRParseException>("vm does not support non-inlined asmsubs (use normal sub): main.asmstart") {
|
2022-09-26 23:50:00 +00:00
|
|
|
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>
|
|
|
|
|
2022-09-30 13:27:03 +00:00
|
|
|
<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>
|
|
|
|
|
2023-05-01 21:00:51 +00:00
|
|
|
<BLOCK NAME="main" ADDRESS="" LIBRARY="false" FORCEOUTPUT="false" 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()
|
2023-11-20 22:19:08 +00:00
|
|
|
vm.getFloatAsmBytes(Math.PI) shouldBe "\$40, \$09, \$21, \$fb, \$54, \$44, \$2d, \$18"
|
2023-02-16 21:19:30 +00:00
|
|
|
}
|
2022-09-21 00:59:36 +00:00
|
|
|
})
|