diff --git a/codeCore/src/prog8/code/target/virtual/VirtualMachineDefinition.kt b/codeCore/src/prog8/code/target/virtual/VirtualMachineDefinition.kt index 6f4e5aec4..20fdec132 100644 --- a/codeCore/src/prog8/code/target/virtual/VirtualMachineDefinition.kt +++ b/codeCore/src/prog8/code/target/virtual/VirtualMachineDefinition.kt @@ -32,7 +32,7 @@ class VirtualMachineDefinition: IMachineDefinition { override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) { println("\nStarting Virtual Machine...") - // to not have external module dependencies we launch the virtual machine via reflection + // to not have external module dependencies in our own module, we launch the virtual machine via reflection val vm = Class.forName("prog8.vm.VmRunner").getDeclaredConstructor().newInstance() as IVirtualMachineRunner val filename = programNameWithPath.name if(filename.endsWith(".p8virt")) { diff --git a/codeGenIntermediate/build.gradle b/codeGenIntermediate/build.gradle index d0181b0ec..95b41d291 100644 --- a/codeGenIntermediate/build.gradle +++ b/codeGenIntermediate/build.gradle @@ -26,7 +26,6 @@ compileTestKotlin { dependencies { implementation project(':codeCore') implementation project(':intermediate') - implementation project(':virtualmachine') implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" // implementation "org.jetbrains.kotlin:kotlin-reflect" implementation "com.michael-bull.kotlin-result:kotlin-result-jvm:1.1.16" diff --git a/codeGenIntermediate/codeGenIntermediate.iml b/codeGenIntermediate/codeGenIntermediate.iml index 0016695ca..893f7df14 100644 --- a/codeGenIntermediate/codeGenIntermediate.iml +++ b/codeGenIntermediate/codeGenIntermediate.iml @@ -12,7 +12,6 @@ - diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt index c1dbdebb1..3676ad40d 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt @@ -6,7 +6,6 @@ import prog8.code.core.AssemblyError import prog8.code.core.DataType import prog8.code.core.Position import prog8.intermediate.* -import prog8.vm.Syscall internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGen: ExpressionGen) { @@ -67,10 +66,10 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe val syscall = when (array.dt) { DataType.ARRAY_UB, - DataType.ARRAY_B -> Syscall.ANY_BYTE + DataType.ARRAY_B -> IMSyscall.ANY_BYTE DataType.ARRAY_UW, - DataType.ARRAY_W -> Syscall.ANY_WORD - DataType.ARRAY_F -> Syscall.ANY_FLOAT + DataType.ARRAY_W -> IMSyscall.ANY_WORD + DataType.ARRAY_F -> IMSyscall.ANY_FLOAT else -> throw IllegalArgumentException("weird type") } code += exprGen.translateExpression(call.args[0], 0, -1) @@ -87,10 +86,10 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe val syscall = when(array.dt) { DataType.ARRAY_UB, - DataType.ARRAY_B -> Syscall.ALL_BYTE + DataType.ARRAY_B -> IMSyscall.ALL_BYTE DataType.ARRAY_UW, - DataType.ARRAY_W -> Syscall.ALL_WORD - DataType.ARRAY_F -> Syscall.ALL_FLOAT + DataType.ARRAY_W -> IMSyscall.ALL_WORD + DataType.ARRAY_F -> IMSyscall.ALL_FLOAT else -> throw IllegalArgumentException("weird type") } val code = IRCodeChunk(call.position) @@ -187,37 +186,37 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe private fun funcReverse(call: PtBuiltinFunctionCall): IRCodeChunk { val arrayName = call.args[0] as PtIdentifier val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable - val sortSyscall = + val syscall = when(array.dt) { - DataType.ARRAY_UB, DataType.ARRAY_B, DataType.STR -> Syscall.REVERSE_BYTES - DataType.ARRAY_UW, DataType.ARRAY_W -> Syscall.REVERSE_WORDS - DataType.ARRAY_F -> Syscall.REVERSE_FLOATS + DataType.ARRAY_UB, DataType.ARRAY_B, DataType.STR -> IMSyscall.REVERSE_BYTES + DataType.ARRAY_UW, DataType.ARRAY_W -> IMSyscall.REVERSE_WORDS + DataType.ARRAY_F -> IMSyscall.REVERSE_FLOATS else -> throw IllegalArgumentException("weird type to reverse") } val code = IRCodeChunk(call.position) code += exprGen.translateExpression(call.args[0], 0, -1) code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length) - code += IRCodeInstruction(Opcode.SYSCALL, value=sortSyscall.ordinal) + code += IRCodeInstruction(Opcode.SYSCALL, value=syscall.ordinal) return code } private fun funcSort(call: PtBuiltinFunctionCall): IRCodeChunk { val arrayName = call.args[0] as PtIdentifier val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable - val sortSyscall = + val syscall = when(array.dt) { - DataType.ARRAY_UB -> Syscall.SORT_UBYTE - DataType.ARRAY_B -> Syscall.SORT_BYTE - DataType.ARRAY_UW -> Syscall.SORT_UWORD - DataType.ARRAY_W -> Syscall.SORT_WORD - DataType.STR -> Syscall.SORT_UBYTE + DataType.ARRAY_UB -> IMSyscall.SORT_UBYTE + DataType.ARRAY_B -> IMSyscall.SORT_BYTE + DataType.ARRAY_UW -> IMSyscall.SORT_UWORD + DataType.ARRAY_W -> IMSyscall.SORT_WORD + DataType.STR -> IMSyscall.SORT_UBYTE DataType.ARRAY_F -> throw IllegalArgumentException("sorting a floating point array is not supported") else -> throw IllegalArgumentException("weird type to sort") } val code = IRCodeChunk(call.position) code += exprGen.translateExpression(call.args[0], 0, -1) code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length) - code += IRCodeInstruction(Opcode.SYSCALL, value=sortSyscall.ordinal) + code += IRCodeInstruction(Opcode.SYSCALL, value=syscall.ordinal) return code } diff --git a/codeGenVirtual/build.gradle b/codeGenVirtual/build.gradle index e8005360e..d2803c867 100644 --- a/codeGenVirtual/build.gradle +++ b/codeGenVirtual/build.gradle @@ -28,6 +28,7 @@ dependencies { implementation project(':codeCore') implementation project(':intermediate') implementation project(':codeGenIntermediate') + implementation project(':virtualmachine') implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" // implementation "org.jetbrains.kotlin:kotlin-reflect" implementation "com.michael-bull.kotlin-result:kotlin-result-jvm:1.1.16" diff --git a/codeGenVirtual/codeGenVirtual.iml b/codeGenVirtual/codeGenVirtual.iml index 74eb9baf8..8a466fb93 100644 --- a/codeGenVirtual/codeGenVirtual.iml +++ b/codeGenVirtual/codeGenVirtual.iml @@ -16,5 +16,6 @@ + \ No newline at end of file diff --git a/codeGenVirtual/src/prog8/codegen/virtual/VmAssemblyProgram.kt b/codeGenVirtual/src/prog8/codegen/virtual/VmAssemblyProgram.kt index 2e2673fd7..b1ca60f17 100644 --- a/codeGenVirtual/src/prog8/codegen/virtual/VmAssemblyProgram.kt +++ b/codeGenVirtual/src/prog8/codegen/virtual/VmAssemblyProgram.kt @@ -4,6 +4,7 @@ import prog8.code.core.AssemblyError import prog8.code.core.CompilationOptions import prog8.code.core.IAssemblyProgram import prog8.intermediate.* +import prog8.vm.Syscall import java.io.BufferedWriter import kotlin.io.path.bufferedWriter import kotlin.io.path.div @@ -84,7 +85,28 @@ private fun BufferedWriter.writeLine(line: IRCodeLine) { write("; ${line.comment}\n") } is IRCodeInstruction -> { - write(line.ins.toString() + "\n") + if(line.ins.opcode==Opcode.SYSCALL) { + // convert IM Syscall to VM Syscall + val vmSyscall = when(line.ins.value!!) { + IMSyscall.SORT_UBYTE.ordinal -> Syscall.SORT_UBYTE + IMSyscall.SORT_BYTE.ordinal -> Syscall.SORT_BYTE + IMSyscall.SORT_UWORD.ordinal -> Syscall.SORT_UWORD + IMSyscall.SORT_WORD.ordinal -> Syscall.SORT_WORD + IMSyscall.ANY_BYTE.ordinal -> Syscall.ANY_BYTE + IMSyscall.ANY_WORD.ordinal -> Syscall.ANY_WORD + IMSyscall.ANY_FLOAT.ordinal -> Syscall.ANY_FLOAT + IMSyscall.ALL_BYTE.ordinal -> Syscall.ALL_BYTE + IMSyscall.ALL_WORD.ordinal -> Syscall.ALL_WORD + IMSyscall.ALL_FLOAT.ordinal -> Syscall.ALL_FLOAT + IMSyscall.REVERSE_BYTES.ordinal -> Syscall.REVERSE_BYTES + IMSyscall.REVERSE_WORDS.ordinal -> Syscall.REVERSE_WORDS + IMSyscall.REVERSE_FLOATS.ordinal -> Syscall.REVERSE_FLOATS + else -> throw IllegalArgumentException("invalid IM syscall number ${line.ins.value}") + } + val newIns = line.ins.copy(value = vmSyscall.ordinal) + write(newIns.toString() + "\n") + } else + write(line.ins.toString() + "\n") } is IRCodeInlineBinary -> { write("!binary ") diff --git a/compiler/build.gradle b/compiler/build.gradle index 12fa1af93..c74d14b12 100644 --- a/compiler/build.gradle +++ b/compiler/build.gradle @@ -33,6 +33,7 @@ dependencies { implementation project(':codeGenCpu6502') implementation project(':codeGenVirtual') implementation project(':codeGenExperimental') + implementation project(':virtualmachine') implementation 'org.antlr:antlr4-runtime:4.10.1' implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" // implementation "org.jetbrains.kotlin:kotlin-reflect" diff --git a/compiler/compiler.iml b/compiler/compiler.iml index c2b444f50..7d5c118e1 100644 --- a/compiler/compiler.iml +++ b/compiler/compiler.iml @@ -22,5 +22,6 @@ + \ No newline at end of file diff --git a/compiler/test/TestLaunchEmu.kt b/compiler/test/TestLaunchEmu.kt new file mode 100644 index 000000000..c27600eaf --- /dev/null +++ b/compiler/test/TestLaunchEmu.kt @@ -0,0 +1,18 @@ +package prog8tests + +import io.kotest.core.spec.style.FunSpec +import prog8.code.target.VMTarget +import kotlin.io.path.deleteExisting +import kotlin.io.path.writeText + + +class TestLaunchEmu: FunSpec({ + + test("test launch virtualmachine via target") { + val target = VMTarget() + val tmpfile = kotlin.io.path.createTempFile(suffix=".p8virt") + tmpfile.writeText(";comment\n------PROGRAM------\n;comment\n") + target.machine.launchEmulator(0, tmpfile) + tmpfile.deleteExisting() + } +}) diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 7a7033704..94a2f1f08 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -17,7 +17,6 @@ Future Things and Ideas ^^^^^^^^^^^^^^^^^^^^^^^ Compiler: -- vm/ir: all(), any(), reverse() and sort() still depend on a VM Syscall. Get rid of this. (maybe use a IR 'builtin' function?) - vm/ir: put variables and arrays in BSS section (unless -noreinit is specified) - vm: Jumps go to a code block rather than a specific address(label) -> also helps future dead code elimination? - vm: the above means that every label introduces a new code block. This eliminates the use of actual labels altogether. @@ -51,8 +50,8 @@ Libraries: - fix the problems in atari target, and flesh out its libraries. - c64: make the graphics.BITMAP_ADDRESS configurable (VIC banking) - optimize several inner loops in gfx2 even further? -- add modes 3 and perhaps even 2 to gfx2 (16 color and 4 color)? -- add a flood fill routine to gfx2? +- add modes 3 and perhaps even 2 to gfx2 (lores 16 color and 4 color)? +- add a flood fill (span fill/scanline fill) routine to gfx2? Expressions: diff --git a/examples/test.p8 b/examples/test.p8 index 73a08f559..ff45dfe83 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,115 +1,32 @@ +%import textio +%zeropage basicsafe main { sub start() { - %asm {{ - loadcpu.b r1,_a - loadcpu.b r1,_x - loadcpu.b r1,_y - loadcpu.w r1,_ax - loadcpu.w r1,_ay - loadcpu.w r1,_xy - loadcpu.b r1,_pc - loadcpu.b r1,_pn - loadcpu.b r1,_pz - loadcpu.w r1,_r0 - loadcpu.w r1,_r15 + uword[] words = [1111,2222,0,4444,3333] + + txt.print_ub(all(words)) + txt.nl() + txt.print_ub(any(words)) + txt.nl() + sort(words) + + uword ww + for ww in words { + txt.print_uw(ww) + txt.spc() + } + txt.nl() + + reverse(words) + for ww in words { + txt.print_uw(ww) + txt.spc() + } + txt.nl() - storezcpu.b _a - storezcpu.b _x - storezcpu.b _y - storezcpu.w _ax - storezcpu.w _ay - storezcpu.w _xy - storezcpu.b _pc - storezcpu.b _pn - storezcpu.b _pz - storezcpu.b _r0 - storezcpu.w _r15 - }} } } -; uword @shared global1 = 1234 -; str @shared globalstring = "irmen" -; -; %asm {{ -; nop -; nop -; return -; }} -; -; romsub $ee33 = myromsub(ubyte arg1 @A) clobbers() -> ubyte @Y -; romsub $ee44 = myromsubmulti(ubyte arg1 @A) clobbers() -> ubyte @Y, ubyte @X, ubyte @Pc -; -; asmsub testasmsub(ubyte arg1 @A) clobbers(Y) -> uword @AX { -; %asm {{ -; nop -; return -; }} -; } -; -; sub start() { -; void myromsubmulti(44) -; global1 = myromsub(44) -; sys.wait(1) -; -; cx16.r0 = 11111 -; cx16.r0L = 22 -; cx16.r0H = 33 -; -; %asm {{ -; nop -; jump main.start.a_label -; }} -;a_label: -; -; %asmbinary "LICENSE", 200, 513 -; -;; TODO add proper memory SLAB support to IR+VM -; uword @shared slab1 = memory("slab 1", 2000, 0) -; uword @shared slab2 = memory("slab 1", 2000, 0) -; uword @shared slab3 = memory("other # slab", 2000, 64) -; -; &uword mapped = $c000 -; &ubyte[20] mappedarray = $c100 -; -; uword @shared zz -; zz = slab1+slab2+slab3 -; -; uword @shared @zp qq = zz -; uword @shared @zp qq2 = &zz -; -; str @shared namestring = "irmen" -; uword[] @shared wordarray1 = [1111,2222,3333,4444] -; uword[4] @shared wordarray2 = 12345 -; uword[4] @shared wordzeroarray -; -; qq=4242 ; TODO should generate symbol not allocated address???? -; mapped = 99 ; TODO wrong VMASM code generated... should generate mapped memory address????? -; mappedarray[1]=99 ; TODO check code???? -; -; qq=global1 -; qq=other.global2 -; nested(11,22) -; main.start.nested.nested2() -; -; sub nested(ubyte a1, ubyte a2) { -; qq++ -; txt.print("zzz") -; nested2() -; -; sub nested2() { -; txt.print("zzz2") -; qq++ -; } -; } -; } -;} -; -;other { -; -; uword global2 = 9999 -; -;} diff --git a/intermediate/src/prog8/intermediate/IMSyscall.kt b/intermediate/src/prog8/intermediate/IMSyscall.kt new file mode 100644 index 000000000..df2ee468e --- /dev/null +++ b/intermediate/src/prog8/intermediate/IMSyscall.kt @@ -0,0 +1,20 @@ +package prog8.intermediate + +// calls to builtin operations that are too complex to be implemented as an IR instruction +// these use the SYSCALL instruction instead. + +enum class IMSyscall { + SORT_UBYTE, + SORT_BYTE, + SORT_UWORD, + SORT_WORD, + ANY_BYTE, + ANY_WORD, + ANY_FLOAT, + ALL_BYTE, + ALL_WORD, + ALL_FLOAT, + REVERSE_BYTES, + REVERSE_WORDS, + REVERSE_FLOATS +} \ No newline at end of file diff --git a/intermediate/test/TestInstructions.kt b/intermediate/test/TestInstructions.kt index 814fb154e..a3f3b5313 100644 --- a/intermediate/test/TestInstructions.kt +++ b/intermediate/test/TestInstructions.kt @@ -2,7 +2,6 @@ import io.kotest.assertions.throwables.shouldThrow import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe -import org.junit.jupiter.api.fail import prog8.intermediate.*