diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index 71537784e..9164d9db3 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -4833,7 +4833,7 @@ $endLabel""") pointergen.assignLongReg(IndexedPtrTarget(target), pairedRegisters) return } - asmgen.loadScaledArrayIndexIntoRegister(target.array!!, CpuRegister.Y) + asmgen.loadScaledArrayIndexIntoRegister(target.array, CpuRegister.Y) val arrayVarName = asmgen.asmSymbolName(target.array.variable!!) val startreg = pairedRegisters.startregname() // Unrolled copy to preserve array index in Y diff --git a/codeGenIntermediate/src/prog8/codegen/vm/VmCodeGen.kt b/codeGenIntermediate/src/prog8/codegen/vm/VmCodeGen.kt index 348b24752..746f81ab3 100644 --- a/codeGenIntermediate/src/prog8/codegen/vm/VmCodeGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/vm/VmCodeGen.kt @@ -9,6 +9,7 @@ import prog8.code.core.IErrorReporter import prog8.codegen.intermediate.IRCodeGen import prog8.intermediate.IRFileWriter import prog8.intermediate.IRProgram +import prog8.intermediate.dumpVariables class VmCodeGen(val retainSSA: Boolean, private val preassignedCallSiteIds: Map = emptyMap() @@ -24,6 +25,9 @@ class VmCodeGen(val retainSSA: Boolean, irProgram.verifyRegisterTypes(irCodeGen.registerTypes()) + if (options.dumpVariables) + dumpVariables(irProgram) + return VmAssemblyProgram(irProgram.name, irProgram) } } diff --git a/codeGenM68k/src/prog8/codegen/m68k/M68kCodeGenerator.kt b/codeGenM68k/src/prog8/codegen/m68k/M68kCodeGenerator.kt index 51ccd90d6..d35f2f92c 100644 --- a/codeGenM68k/src/prog8/codegen/m68k/M68kCodeGenerator.kt +++ b/codeGenM68k/src/prog8/codegen/m68k/M68kCodeGenerator.kt @@ -8,6 +8,7 @@ import prog8.code.core.CompilationOptions import prog8.code.core.IErrorReporter import prog8.codegen.intermediate.IRCodeGen import prog8.intermediate.IRFileWriter +import prog8.intermediate.dumpVariables class M68kCodeGenerator(val retainSSA: Boolean): ICodeGeneratorBackend { override fun generate( @@ -21,6 +22,9 @@ class M68kCodeGenerator(val retainSSA: Boolean): ICodeGeneratorBackend { val irProgram = irCodeGen.generate() irProgram.verifyRegisterTypes(irCodeGen.registerTypes()) + if (options.dumpVariables) + dumpVariables(irProgram) + IRFileWriter(irProgram, null).write() val gen = AsmGen(irProgram, irProgram.options.compTarget) diff --git a/codeGenNew6502/src/prog8/codegen/new6502/AsmGen.kt b/codeGenNew6502/src/prog8/codegen/new6502/AsmGen.kt index 88ded822c..f73618b68 100644 --- a/codeGenNew6502/src/prog8/codegen/new6502/AsmGen.kt +++ b/codeGenNew6502/src/prog8/codegen/new6502/AsmGen.kt @@ -123,6 +123,9 @@ internal class AsmGen(val program: IRProgram, private val target: ICompilationTa return false } + if (options.dumpVariables) + dumpVariables(program) { name -> zpAllocator.getAllocation(name)?.address } + if (!options.quiet) println("Assembly written to $asmFile") diff --git a/docs/source/compiling.rst b/docs/source/compiling.rst index 3ad175f87..119ccea7e 100644 --- a/docs/source/compiling.rst +++ b/docs/source/compiling.rst @@ -111,6 +111,18 @@ It's easy to compile yourself, but a recent precompiled .exe (only for Windows) *You need at least version 1.58.0 of this assembler.* If you are on Linux, there's probably a "64tass" package in the repositories, but check if it is a recent enough version. +For the **m68k targets** (``amiga500`` and ``qemu68k``), the following additional tools are required when assembling programs: + +`vasm `_ - cross assembler. Prog8 uses the ``vasmm68k_mot`` executable, which must be installed somewhere on your shell's search path. + +`vlink `_ - linker. This is required for the ``qemu68k`` target, which produces ELF executables. The ``amiga500`` target produces Amiga Hunk executables directly with vasm. + +The ``-emu`` option has these additional optional dependencies for the m68k targets: + +`QEMU `_ - install the ``qemu-system-m68k`` executable to run ``qemu68k`` programs. + +`Amitools `_ - install the ``vamos`` executable to run ``amiga500`` programs. + A **Java runtime (jre or jdk), version 17 or newer** is required to run the prog8 compiler itself. If you're scared of Oracle's licensing terms, get one of the versions of another vendor. Even Microsoft provides their own version. Other OpenJDK builds can be found at `Adoptium `_ . diff --git a/intermediate/src/prog8/intermediate/VariableDump.kt b/intermediate/src/prog8/intermediate/VariableDump.kt new file mode 100644 index 000000000..7ba627a6e --- /dev/null +++ b/intermediate/src/prog8/intermediate/VariableDump.kt @@ -0,0 +1,43 @@ +package prog8.intermediate + +/** + * Print a dump of all variables in the IR program. + * Target-independent parts (static variables, memory mapped variables, memory slabs) are + * always shown; zero-page placement is only shown when a [zpAddress] resolver is supplied + * (zero-page allocation is backend/target specific and doesn't exist for all targets). + */ +fun dumpVariables(program: IRProgram, zpAddress: (String) -> UInt? = { null }) { + println("---- VARIABLES DUMP ----") + val st = program.st + + val zpVars = st.allVariables().filter { zpAddress(it.name) != null }.sortedBy { it.name } + if (zpVars.toList().isNotEmpty()) { + println("ZeroPage:") + zpVars.sortedBy { zpAddress(it.name) }.forEach { + println(" $${zpAddress(it.name)!!.toString(16).padStart(2, '0')}\t${it.dt}\t${it.name}") + } + st.allMemMappedVariables().filter { it.address <= 255u }.sortedBy { it.address }.forEach { + println(" $${it.address.toString(16).padStart(2, '0')}\t${it.dt}\t${it.name}") + } + } + + val plain = st.allVariables().filter { zpAddress(it.name) == null }.sortedBy { it.name } + if (plain.toList().isNotEmpty()) { + println("Static variables (not in ZeroPage):") + plain.forEach { println(" ${it.dt}\t${it.name}\t") } + } + + val memmap = st.allMemMappedVariables().sortedWith(compareBy({ it.address }, { it.name })) + if (memmap.toList().isNotEmpty()) { + println("Memory mapped:") + memmap.forEach { println(" $${it.address.toString(16).padStart(4, '0')}\t${it.dt}\t${it.name}") } + } + + val slabs = st.allMemorySlabs().sortedBy { it.name } + if (slabs.toList().isNotEmpty()) { + println("Memory slabs:") + slabs.forEach { println(" ${it.name} ${it.size} align ${it.align}") } + } + + println("---- VARIABLES DUMP END ----") +}