2022-09-24 11:54:00 +00:00
|
|
|
package prog8tests.vm
|
|
|
|
|
2022-10-31 22:59:33 +00:00
|
|
|
import io.kotest.assertions.throwables.shouldThrow
|
2022-09-24 11:54:00 +00:00
|
|
|
import io.kotest.core.spec.style.FunSpec
|
2022-09-24 15:06:47 +00:00
|
|
|
import io.kotest.matchers.shouldBe
|
2022-09-24 11:54:00 +00:00
|
|
|
import io.kotest.matchers.shouldNotBe
|
2022-10-31 22:59:33 +00:00
|
|
|
import io.kotest.matchers.string.shouldContain
|
2022-09-27 14:32:44 +00:00
|
|
|
import prog8.ast.expressions.BuiltinFunctionCall
|
|
|
|
import prog8.ast.statements.Assignment
|
2022-10-30 13:16:16 +00:00
|
|
|
import prog8.code.target.C64Target
|
2022-09-24 11:54:00 +00:00
|
|
|
import prog8.code.target.Cx16Target
|
|
|
|
import prog8.code.target.VMTarget
|
|
|
|
import prog8.vm.VmRunner
|
|
|
|
import prog8tests.helpers.compileText
|
|
|
|
import kotlin.io.path.readText
|
|
|
|
|
|
|
|
class TestCompilerVirtual: FunSpec({
|
|
|
|
test("compile virtual: any all sort reverse builtin funcs") {
|
|
|
|
val src = """
|
|
|
|
main {
|
|
|
|
|
|
|
|
sub start() {
|
|
|
|
uword[] words = [1111,2222,0,4444,3333]
|
|
|
|
ubyte result = all(words)
|
|
|
|
result++
|
|
|
|
result = any(words)
|
|
|
|
result++
|
|
|
|
sort(words)
|
|
|
|
reverse(words)
|
|
|
|
}
|
|
|
|
}"""
|
|
|
|
val target = VMTarget()
|
2022-09-26 23:50:00 +00:00
|
|
|
val result = compileText(target, true, src, writeAssembly = true)!!
|
2022-09-26 17:03:54 +00:00
|
|
|
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8ir")
|
2022-09-24 14:00:25 +00:00
|
|
|
VmRunner().runProgram(virtfile.readText())
|
2022-09-24 11:54:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
test("compile virtual: array with pointers") {
|
|
|
|
val src = """
|
|
|
|
main {
|
|
|
|
sub start() {
|
2022-09-24 15:06:47 +00:00
|
|
|
str localstr = "hello"
|
|
|
|
ubyte[] otherarray = [1,2,3]
|
|
|
|
uword[] words = [1111,2222,"three",&localstr,&otherarray]
|
|
|
|
uword @shared zz = &words
|
|
|
|
ubyte result = 2222 in words
|
|
|
|
zz = words[2]
|
|
|
|
zz++
|
|
|
|
zz = words[3]
|
2022-09-24 11:54:00 +00:00
|
|
|
}
|
|
|
|
}"""
|
|
|
|
val othertarget = Cx16Target()
|
|
|
|
compileText(othertarget, true, src, writeAssembly = true, keepIR=true) shouldNotBe null
|
|
|
|
val target = VMTarget()
|
2022-09-26 23:50:00 +00:00
|
|
|
val result = compileText(target, true, src, writeAssembly = true)!!
|
2022-09-26 17:03:54 +00:00
|
|
|
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8ir")
|
2022-09-24 14:00:25 +00:00
|
|
|
VmRunner().runProgram(virtfile.readText())
|
2022-09-24 11:54:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
test("compile virtual: str args and return type") {
|
|
|
|
val src = """
|
|
|
|
main {
|
|
|
|
|
|
|
|
sub start() {
|
|
|
|
sub testsub(str s1) -> str {
|
|
|
|
return "result"
|
|
|
|
}
|
|
|
|
|
|
|
|
uword result = testsub("arg")
|
|
|
|
}
|
|
|
|
}"""
|
|
|
|
val target = VMTarget()
|
2022-10-30 10:09:32 +00:00
|
|
|
var result = compileText(target, false, src, writeAssembly = true)!!
|
|
|
|
var virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8ir")
|
|
|
|
VmRunner().runProgram(virtfile.readText())
|
|
|
|
|
|
|
|
result = compileText(target, true, src, writeAssembly = true)!!
|
|
|
|
virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8ir")
|
2022-09-24 14:00:25 +00:00
|
|
|
VmRunner().runProgram(virtfile.readText())
|
2022-09-24 11:54:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
test("compile virtual: nested labels") {
|
|
|
|
val src = """
|
|
|
|
main {
|
|
|
|
sub start() {
|
|
|
|
uword i
|
|
|
|
uword k
|
|
|
|
|
2022-10-30 15:44:13 +00:00
|
|
|
repeat {
|
|
|
|
mylabel0:
|
|
|
|
goto mylabel0
|
|
|
|
}
|
|
|
|
|
|
|
|
while cx16.r0 {
|
|
|
|
mylabel1:
|
|
|
|
goto mylabel1
|
|
|
|
}
|
|
|
|
|
|
|
|
do {
|
|
|
|
mylabel2:
|
|
|
|
goto mylabel2
|
|
|
|
} until cx16.r0
|
|
|
|
|
|
|
|
repeat cx16.r0 {
|
|
|
|
mylabel3:
|
|
|
|
goto mylabel3
|
|
|
|
}
|
|
|
|
|
|
|
|
for cx16.r0L in 0 to 2 {
|
|
|
|
mylabel4:
|
|
|
|
goto mylabel4
|
|
|
|
}
|
|
|
|
|
|
|
|
for cx16.r0L in cx16.r1L to cx16.r2L {
|
|
|
|
mylabel5:
|
|
|
|
goto mylabel5
|
2022-09-24 14:00:25 +00:00
|
|
|
}
|
|
|
|
|
2022-09-24 11:54:00 +00:00
|
|
|
mylabel_outside:
|
|
|
|
for i in 0 to 10 {
|
|
|
|
mylabel_inside:
|
|
|
|
if i==100 {
|
|
|
|
goto mylabel_outside
|
|
|
|
goto mylabel_inside
|
|
|
|
}
|
|
|
|
while k <= 10 {
|
|
|
|
k++
|
|
|
|
}
|
|
|
|
do {
|
|
|
|
k--
|
|
|
|
} until k==0
|
|
|
|
for k in 0 to 5 {
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
repeat 10 {
|
|
|
|
k++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}"""
|
|
|
|
|
2022-10-30 13:16:16 +00:00
|
|
|
val target1 = C64Target()
|
2022-10-30 15:44:13 +00:00
|
|
|
compileText(target1, false, src, writeAssembly = false) shouldNotBe null
|
2022-10-30 13:16:16 +00:00
|
|
|
|
2022-09-24 11:54:00 +00:00
|
|
|
val target = VMTarget()
|
2022-10-30 15:44:13 +00:00
|
|
|
compileText(target, false, src, writeAssembly = true) shouldNotBe null
|
2022-09-24 11:54:00 +00:00
|
|
|
}
|
|
|
|
|
2022-09-24 15:06:47 +00:00
|
|
|
test("case sensitive symbols") {
|
|
|
|
val src = """
|
|
|
|
main {
|
|
|
|
sub start() {
|
|
|
|
ubyte bytevar = 11 ; var at 0
|
|
|
|
ubyte byteVAR = 22 ; var at 1
|
|
|
|
ubyte ByteVar = 33 ; var at 2
|
|
|
|
ubyte @shared total = bytevar+byteVAR+ByteVar ; var at 3
|
|
|
|
goto skipLABEL
|
|
|
|
SkipLabel:
|
|
|
|
return
|
|
|
|
skipLABEL:
|
|
|
|
bytevar = 42
|
|
|
|
}
|
|
|
|
}"""
|
|
|
|
val othertarget = Cx16Target()
|
|
|
|
compileText(othertarget, true, src, writeAssembly = true, keepIR=true) shouldNotBe null
|
|
|
|
val target = VMTarget()
|
2022-09-26 23:50:00 +00:00
|
|
|
val result = compileText(target, true, src, writeAssembly = true)!!
|
2022-09-26 17:03:54 +00:00
|
|
|
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8ir")
|
2022-09-24 15:06:47 +00:00
|
|
|
VmRunner().runAndTestProgram(virtfile.readText()) { vm ->
|
|
|
|
vm.memory.getUB(0) shouldBe 42u
|
|
|
|
vm.memory.getUB(3) shouldBe 66u
|
|
|
|
}
|
|
|
|
}
|
2022-09-27 14:32:44 +00:00
|
|
|
|
|
|
|
test("memory slabs") {
|
|
|
|
val src = """
|
|
|
|
main {
|
|
|
|
sub start() {
|
|
|
|
uword slab1 = memory("slab1", 2000, 64)
|
|
|
|
slab1[10]=42
|
|
|
|
slab1[11]=43
|
|
|
|
ubyte @shared value1 = slab1[10] ; var at 2
|
|
|
|
ubyte @shared value2 = slab1[11] ; var at 3
|
|
|
|
}
|
|
|
|
}"""
|
|
|
|
val target = VMTarget()
|
|
|
|
val result = compileText(target, true, src, writeAssembly = true)!!
|
|
|
|
val start = result.program.entrypoint
|
|
|
|
start.statements.size shouldBe 9
|
|
|
|
((start.statements[1] as Assignment).value as BuiltinFunctionCall).name shouldBe "memory"
|
|
|
|
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8ir")
|
|
|
|
VmRunner().runAndTestProgram(virtfile.readText()) { vm ->
|
|
|
|
vm.memory.getUB(2) shouldBe 42u
|
|
|
|
vm.memory.getUB(3) shouldBe 43u
|
|
|
|
}
|
|
|
|
}
|
2022-10-30 13:16:16 +00:00
|
|
|
|
|
|
|
test("memory mapped var as for loop counter") {
|
|
|
|
val src = """
|
|
|
|
main {
|
|
|
|
sub start() {
|
|
|
|
for cx16.r0 in 0 to 10 {
|
|
|
|
cx16.r1++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}"""
|
|
|
|
val othertarget = Cx16Target()
|
|
|
|
compileText(othertarget, true, src, writeAssembly = true, keepIR=true) shouldNotBe null
|
|
|
|
|
|
|
|
val target = VMTarget()
|
|
|
|
val result = compileText(target, false, src, writeAssembly = true)!!
|
|
|
|
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8ir")
|
|
|
|
VmRunner().runAndTestProgram(virtfile.readText()) { vm ->
|
2022-10-30 13:54:47 +00:00
|
|
|
vm.stepCount shouldBe 49
|
2022-10-30 13:16:16 +00:00
|
|
|
}
|
|
|
|
}
|
2022-10-31 22:59:33 +00:00
|
|
|
|
|
|
|
test("asmsub for virtual target") {
|
|
|
|
val src = """
|
|
|
|
main {
|
|
|
|
sub start() {
|
|
|
|
void test(42)
|
|
|
|
}
|
|
|
|
|
|
|
|
asmsub test(ubyte xx @A) -> ubyte @Y {
|
|
|
|
%asm {{
|
|
|
|
lda #99
|
|
|
|
tay
|
|
|
|
rts
|
|
|
|
return
|
|
|
|
}}
|
|
|
|
}
|
|
|
|
}"""
|
|
|
|
val othertarget = Cx16Target()
|
|
|
|
compileText(othertarget, true, src, writeAssembly = true, keepIR=true) shouldNotBe null
|
|
|
|
|
|
|
|
val target = VMTarget()
|
|
|
|
val result = compileText(target, false, src, writeAssembly = true)!!
|
|
|
|
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8ir")
|
|
|
|
val exc = shouldThrow<Exception> {
|
|
|
|
VmRunner().runProgram(virtfile.readText())
|
|
|
|
}
|
2022-10-31 23:15:39 +00:00
|
|
|
exc.message shouldContain("does not support non-IR asmsubs")
|
2022-10-31 22:59:33 +00:00
|
|
|
}
|
2022-11-12 12:45:02 +00:00
|
|
|
|
|
|
|
test("addresses from labels/subroutines not yet supported in VM") {
|
|
|
|
val src = """
|
|
|
|
main {
|
|
|
|
sub start() {
|
|
|
|
|
|
|
|
mylabel:
|
|
|
|
ubyte variable
|
|
|
|
uword @shared pointer1 = &main.start
|
|
|
|
uword @shared pointer2 = &start
|
|
|
|
uword @shared pointer3 = &main.start.mylabel
|
|
|
|
uword @shared pointer4 = &mylabel
|
|
|
|
uword[] @shared ptrs = [&variable, &start, &main.start, &mylabel, &main.start.mylabel]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
"""
|
|
|
|
val othertarget = Cx16Target()
|
|
|
|
compileText(othertarget, true, src, writeAssembly = true, keepIR=true) shouldNotBe null
|
|
|
|
|
|
|
|
val target = VMTarget()
|
|
|
|
val result = compileText(target, false, src, writeAssembly = true)!!
|
|
|
|
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8ir")
|
|
|
|
val exc = shouldThrow<Exception> {
|
|
|
|
VmRunner().runProgram(virtfile.readText())
|
|
|
|
}
|
|
|
|
exc.message shouldContain("cannot yet load a label address as a value")
|
|
|
|
}
|
2022-09-24 11:54:00 +00:00
|
|
|
})
|