diff --git a/codeCore/src/prog8/code/target/virtual/VirtualMachineDefinition.kt b/codeCore/src/prog8/code/target/virtual/VirtualMachineDefinition.kt index e16ffc4e1..6f4e5aec4 100644 --- a/codeCore/src/prog8/code/target/virtual/VirtualMachineDefinition.kt +++ b/codeCore/src/prog8/code/target/virtual/VirtualMachineDefinition.kt @@ -6,6 +6,8 @@ import prog8.code.core.IMachineDefinition import prog8.code.core.Zeropage import java.io.File import java.nio.file.Path +import kotlin.io.path.name +import kotlin.io.path.readText class VirtualMachineDefinition: IMachineDefinition { @@ -32,8 +34,15 @@ class VirtualMachineDefinition: IMachineDefinition { println("\nStarting Virtual Machine...") // to not have external module dependencies we launch the virtual machine via reflection val vm = Class.forName("prog8.vm.VmRunner").getDeclaredConstructor().newInstance() as IVirtualMachineRunner - val source = File("$programNameWithPath.p8virt").readText() - vm.runProgram(source, true) + val filename = programNameWithPath.name + if(filename.endsWith(".p8virt")) { + vm.runProgram(programNameWithPath.readText(), true) + } else if(File("$filename.p8virt").isFile) { + val source = File("$filename.p8virt").readText() + vm.runProgram(source, true) + } + else + throw IllegalArgumentException("vm can only run .p8virt or .p8ir files") } override fun isIOAddress(address: UInt): Boolean = false diff --git a/codeGenVirtual/src/prog8/codegen/virtual/VmAssemblyProgram.kt b/codeGenVirtual/src/prog8/codegen/virtual/VmAssemblyProgram.kt index d79412207..2e2673fd7 100644 --- a/codeGenVirtual/src/prog8/codegen/virtual/VmAssemblyProgram.kt +++ b/codeGenVirtual/src/prog8/codegen/virtual/VmAssemblyProgram.kt @@ -8,10 +8,10 @@ import java.io.BufferedWriter import kotlin.io.path.bufferedWriter import kotlin.io.path.div -internal class VmAssemblyProgram(override val name: String, val irProgram: IRProgram): IAssemblyProgram { +internal class VmAssemblyProgram(override val name: String, private val irProgram: IRProgram): IAssemblyProgram { - override fun assemble(options: CompilationOptions): Boolean { - val outfile = options.outputDir / ("$name.p8virt") + override fun assemble(dummyOptions: CompilationOptions): Boolean { + val outfile = irProgram.options.outputDir / ("$name.p8virt") println("write code to $outfile") // at last, allocate the variables in memory. @@ -24,7 +24,7 @@ internal class VmAssemblyProgram(override val name: String, val irProgram: IRPro out.write("------PROGRAM------\n") - if(!options.dontReinitGlobals) { + if(!irProgram.options.dontReinitGlobals) { out.write("; global var inits\n") irProgram.globalInits.forEach { out.writeLine(it) } } diff --git a/codeGenVirtual/src/prog8/codegen/virtual/VmCodeGen.kt b/codeGenVirtual/src/prog8/codegen/virtual/VmCodeGen.kt index 931c22da0..00a782cbd 100644 --- a/codeGenVirtual/src/prog8/codegen/virtual/VmCodeGen.kt +++ b/codeGenVirtual/src/prog8/codegen/virtual/VmCodeGen.kt @@ -9,6 +9,7 @@ import prog8.code.core.IErrorReporter import prog8.codegen.intermediate.IRCodeGen import prog8.intermediate.IRFileReader import prog8.intermediate.IRFileWriter +import java.nio.file.Path class VmCodeGen(private val program: PtProgram, private val symbolTable: SymbolTable, @@ -26,4 +27,11 @@ class VmCodeGen(private val program: PtProgram, val irProgram2 = IRFileReader(options.outputDir, irProgram.name).readFile() return VmAssemblyProgram(irProgram2.name, irProgram2) } + + companion object { + fun compileIR(listingFilename: String): IAssemblyProgram { + val irProgram = IRFileReader(Path.of(""), listingFilename).readFile() + return VmAssemblyProgram(irProgram.name, irProgram) + } + } } \ No newline at end of file diff --git a/compiler/src/prog8/CompilerMain.kt b/compiler/src/prog8/CompilerMain.kt index 4aa07c3cd..dc807d5c8 100644 --- a/compiler/src/prog8/CompilerMain.kt +++ b/compiler/src/prog8/CompilerMain.kt @@ -2,10 +2,10 @@ package prog8 import kotlinx.cli.* import prog8.ast.base.AstException -import prog8.code.core.CbmPrgLauncherType -import prog8.code.core.toHex +import prog8.code.core.* import prog8.code.target.* import prog8.code.target.virtual.VirtualMachineDefinition +import prog8.codegen.virtual.VmCodeGen import prog8.compiler.CompilationResult import prog8.compiler.CompilerArguments import prog8.compiler.compileProgram @@ -45,7 +45,7 @@ private fun compileMain(args: Array): Boolean { val experimentalCodegen by cli.option(ArgType.Boolean, fullName = "expericodegen", description = "use experimental/alternative codegen") val compilationTarget by cli.option(ArgType.String, fullName = "target", description = "target output of the compiler (one of '${C64Target.NAME}', '${C128Target.NAME}', '${Cx16Target.NAME}', '${AtariTarget.NAME}', '${VMTarget.NAME}')").default(C64Target.NAME) val sourceDirs by cli.option(ArgType.String, fullName="srcdirs", description = "list of extra paths, separated with ${File.pathSeparator}, to search in for imported modules").multiple().delimiter(File.pathSeparator) - val startVm by cli.option(ArgType.Boolean, fullName = "vm", description = "load and run a p8-virt listing in the VM instead") + val startVm by cli.option(ArgType.Boolean, fullName = "vm", description = "load and run a p8-virt or p8-ir listing in the VM instead") val symbolDefs by cli.option(ArgType.String, fullName = "D", description = "define assembly symbol(s) with -D SYMBOL=VALUE").multiple() val evalStackAddrString by cli.option(ArgType.String, fullName = "esa", description = "override the eval-stack base address (must be page aligned)") val moduleFiles by cli.argument(ArgType.String, fullName = "modules", description = "main module file(s) to compile").multiple(999) @@ -242,12 +242,27 @@ private fun processSymbolDefs(symbolDefs: List): Map? { } fun runVm(listingFilename: String): Boolean { - val name = - if(listingFilename.endsWith(".p8virt")) - listingFilename.substring(0, listingFilename.length-7) - else - listingFilename + if(listingFilename.endsWith(".p8ir")) { + val withoutSuffix = listingFilename.substring(0, listingFilename.length-5) + val compiled = VmCodeGen.compileIR(withoutSuffix) + if (!compiled.assemble(CompilationOptions( // these are just dummy options, the actual options are inside the .p8ir file itself: + OutputType.PRG, + CbmPrgLauncherType.NONE, + ZeropageType.DONTUSE, + emptyList(), + floats = true, + noSysInit = true, + compTarget = VMTarget(), + loadAddress = VMTarget().machine.PROGRAM_LOAD_ADDRESS + )) + ) { + return false + } + val vmdef = VirtualMachineDefinition() + vmdef.launchEmulator(0, Paths.get(withoutSuffix)) + return true + } val vmdef = VirtualMachineDefinition() - vmdef.launchEmulator(0, Paths.get(name)) + vmdef.launchEmulator(0, Paths.get(listingFilename)) return true } diff --git a/docs/source/building.rst b/docs/source/building.rst index f3e95f346..650d82e06 100644 --- a/docs/source/building.rst +++ b/docs/source/building.rst @@ -170,7 +170,7 @@ One or more .p8 module files Use experimental code generation backend (*incomplete*). ``-vm`` - load and run a p8-virt listing in the internal VirtualMachine instead of compiling a prog8 program file.. + load and run a p8-virt or p8-ir listing in the internal VirtualMachine instead of compiling a prog8 program file.. ``-D SYMBOLNAME=VALUE`` Add this user-defined symbol directly to the beginning of the generated assembly file.