From 8c2e602cc723567fe2ac9af4ae09258d0faaf823 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sat, 26 Oct 2019 23:27:27 +0200 Subject: [PATCH] preparing for multiple compiler backends/targets --- compiler/res/version.txt | 2 +- compiler/src/prog8/CompilerMain.kt | 28 ++++- compiler/src/prog8/ast/antlr/Antr2Kotlin.kt | 5 +- compiler/src/prog8/ast/base/Base.kt | 5 +- compiler/src/prog8/ast/base/Extensions.kt | 1 - .../prog8/ast/expressions/AstExpressions.kt | 6 +- .../processing}/AnonymousScopeVarsCleanup.kt | 3 +- .../src/prog8/ast/processing/AstChecker.kt | 5 +- .../ast/processing/AstIdentifiersChecker.kt | 8 +- compiler/src/prog8/compiler/AssemblyError.kt | 3 + compiler/src/prog8/compiler/Main.kt | 7 +- .../compiler/target/CompilationTarget.kt | 15 +++ .../compiler/target/IAssemblyGenerator.kt | 12 ++ .../compiler/target/IMachineDefinition.kt | 15 +++ .../compiler/target/c64/AssemblyProgram.kt | 19 +--- ...eDefinition.kt => C64MachineDefinition.kt} | 25 +++-- .../compiler/target/c64/codegen/AsmGen.kt | 29 +++-- .../target/c64/codegen/AsmOptimizer.kt | 4 +- .../target/c64/codegen/AssignmentAsmGen.kt | 105 +++++++++--------- .../c64/codegen/BuiltinFunctionsAsmGen.kt | 11 +- .../target/c64/codegen/ExpressionsAsmGen.kt | 73 ++++++------ .../target/c64/codegen/ForLoopsAsmGen.kt | 7 +- .../target/c64/codegen/FunctionCallAsmGen.kt | 13 ++- .../target/c64/codegen/PostIncrDecrAsmGen.kt | 8 +- .../src/prog8/optimizer/ConstantFolding.kt | 8 +- .../src/prog8/optimizer/StatementOptimizer.kt | 7 +- compiler/src/prog8/vm/RuntimeValue.kt | 4 +- compiler/src/prog8/vm/astvm/AstVm.kt | 8 +- compiler/src/prog8/vm/astvm/Memory.kt | 6 +- compiler/src/prog8/vm/astvm/ScreenDialog.kt | 28 ++--- compiler/test/LiteralValueTests.kt | 4 +- compiler/test/UnitTests.kt | 34 +++--- 32 files changed, 293 insertions(+), 215 deletions(-) rename compiler/src/prog8/{compiler/target/c64/codegen => ast/processing}/AnonymousScopeVarsCleanup.kt (94%) create mode 100644 compiler/src/prog8/compiler/AssemblyError.kt create mode 100644 compiler/src/prog8/compiler/target/CompilationTarget.kt create mode 100644 compiler/src/prog8/compiler/target/IAssemblyGenerator.kt create mode 100644 compiler/src/prog8/compiler/target/IMachineDefinition.kt rename compiler/src/prog8/compiler/target/c64/{MachineDefinition.kt => C64MachineDefinition.kt} (89%) diff --git a/compiler/res/version.txt b/compiler/res/version.txt index 0a03ace41..d3bdbdf1f 100644 --- a/compiler/res/version.txt +++ b/compiler/res/version.txt @@ -1 +1 @@ -1.62 +1.7 diff --git a/compiler/src/prog8/CompilerMain.kt b/compiler/src/prog8/CompilerMain.kt index 46d3a1ac5..610da73fb 100644 --- a/compiler/src/prog8/CompilerMain.kt +++ b/compiler/src/prog8/CompilerMain.kt @@ -2,8 +2,11 @@ package prog8 import kotlinx.cli.* import prog8.ast.base.AstException -import prog8.compiler.CompilationResult -import prog8.compiler.compileProgram +import prog8.compiler.* +import prog8.compiler.target.CompilationTarget +import prog8.compiler.target.c64.C64MachineDefinition +import prog8.compiler.target.c64.Petscii +import prog8.compiler.target.c64.codegen.AsmGen import prog8.parser.ParsingFailedError import prog8.vm.astvm.AstVm import java.nio.file.FileSystems @@ -38,6 +41,7 @@ private fun compileMain(args: Array) { val dontOptimize by cli.flagArgument("-noopt", "don't perform any optimizations") val launchSimulator by cli.flagArgument("-sim", "launch the prog8 virtual machine/simulator after compilation") val watchMode by cli.flagArgument("-watch", "continuous compilation mode (watches for file changes)") + val compilationTarget by cli.flagValueArgument("-target", "compilationtgt", "target output of the compiler, one of: c64, clang. default=c64", "c64") val moduleFiles by cli.positionalArgumentsList("modules", "main module file(s) to compile", minArgs = 1) try { @@ -46,6 +50,24 @@ private fun compileMain(args: Array) { exitProcess(1) } + when(compilationTarget) { + "c64" -> { + with(CompilationTarget) { + name = "c64" + machine = C64MachineDefinition + encodeString = { str -> Petscii.encodePetscii(str, true) } + asmGenerator = ::AsmGen + } + } + "clang" -> { + TODO("clang target") + } + else -> { + System.err.println("invalid compilation target") + exitProcess(1) + } + } + val outputPath = pathFrom(outputDir) if(!outputPath.toFile().isDirectory) { System.err.println("Output path doesn't exist") @@ -96,7 +118,7 @@ private fun compileMain(args: Array) { if (launchSimulator) { println("\nLaunching AST-based simulator...") - val vm = AstVm(compilationResult.programAst) + val vm = AstVm(compilationResult.programAst, compilationTarget) vm.run() } diff --git a/compiler/src/prog8/ast/antlr/Antr2Kotlin.kt b/compiler/src/prog8/ast/antlr/Antr2Kotlin.kt index cae647f27..007194999 100644 --- a/compiler/src/prog8/ast/antlr/Antr2Kotlin.kt +++ b/compiler/src/prog8/ast/antlr/Antr2Kotlin.kt @@ -7,7 +7,7 @@ import prog8.ast.Module import prog8.ast.base.* import prog8.ast.expressions.* import prog8.ast.statements.* -import prog8.compiler.target.c64.Petscii +import prog8.compiler.target.CompilationTarget import prog8.parser.CustomLexer import prog8.parser.prog8Parser import java.io.CharConversionException @@ -432,7 +432,8 @@ private fun prog8Parser.ExpressionContext.toAst() : Expression { litval.stringliteral()!=null -> StringLiteralValue(DataType.STR, unescape(litval.stringliteral().text, litval.toPosition()), litval.toPosition()) litval.charliteral()!=null -> { try { - NumericLiteralValue(DataType.UBYTE, Petscii.encodePetscii(unescape(litval.charliteral().text, litval.toPosition()), true)[0], litval.toPosition()) + NumericLiteralValue(DataType.UBYTE, CompilationTarget.encodeString( + unescape(litval.charliteral().text, litval.toPosition()))[0], litval.toPosition()) } catch (ce: CharConversionException) { throw SyntaxError(ce.message ?: ce.toString(), litval.toPosition()) } diff --git a/compiler/src/prog8/ast/base/Base.kt b/compiler/src/prog8/ast/base/Base.kt index cc811df01..cb19224f9 100644 --- a/compiler/src/prog8/ast/base/Base.kt +++ b/compiler/src/prog8/ast/base/Base.kt @@ -1,7 +1,8 @@ package prog8.ast.base import prog8.ast.Node -import prog8.compiler.target.c64.MachineDefinition +import prog8.compiler.target.CompilationTarget + /**************************** AST Data classes ****************************/ @@ -58,7 +59,7 @@ enum class DataType { return when(this) { in ByteDatatypes -> 1 in WordDatatypes -> 2 - FLOAT -> MachineDefinition.Mflpt5.MemorySize + FLOAT -> CompilationTarget.machine.FLOAT_MEM_SIZE in PassByReferenceDatatypes -> 2 else -> -9999999 } diff --git a/compiler/src/prog8/ast/base/Extensions.kt b/compiler/src/prog8/ast/base/Extensions.kt index 2e8d6dc09..5d88070f7 100644 --- a/compiler/src/prog8/ast/base/Extensions.kt +++ b/compiler/src/prog8/ast/base/Extensions.kt @@ -4,7 +4,6 @@ import prog8.ast.Module import prog8.ast.Program import prog8.ast.processing.* import prog8.compiler.CompilationOptions -import prog8.compiler.target.c64.codegen.AnonymousScopeVarsCleanup import prog8.optimizer.FlattenAnonymousScopesAndRemoveNops diff --git a/compiler/src/prog8/ast/expressions/AstExpressions.kt b/compiler/src/prog8/ast/expressions/AstExpressions.kt index 75b0c9a60..992c13c05 100644 --- a/compiler/src/prog8/ast/expressions/AstExpressions.kt +++ b/compiler/src/prog8/ast/expressions/AstExpressions.kt @@ -9,7 +9,7 @@ import prog8.ast.statements.ArrayIndex import prog8.ast.statements.BuiltinFunctionStatementPlaceholder import prog8.ast.statements.Subroutine import prog8.ast.statements.VarDecl -import prog8.compiler.target.c64.Petscii +import prog8.compiler.target.CompilationTarget import prog8.functions.BuiltinFunctions import prog8.functions.NotConstArgumentException import prog8.functions.builtinFunctionReturnType @@ -549,8 +549,8 @@ class RangeExpr(var from: Expression, val toString = to as? StringLiteralValue if(fromString!=null && toString!=null ) { // string range -> int range over petscii values - fromVal = Petscii.encodePetscii(fromString.value, true)[0].toInt() - toVal = Petscii.encodePetscii(toString.value, true)[0].toInt() + fromVal = CompilationTarget.encodeString(fromString.value)[0].toInt() + toVal = CompilationTarget.encodeString(toString.value)[0].toInt() } else { val fromLv = from as? NumericLiteralValue val toLv = to as? NumericLiteralValue diff --git a/compiler/src/prog8/compiler/target/c64/codegen/AnonymousScopeVarsCleanup.kt b/compiler/src/prog8/ast/processing/AnonymousScopeVarsCleanup.kt similarity index 94% rename from compiler/src/prog8/compiler/target/c64/codegen/AnonymousScopeVarsCleanup.kt rename to compiler/src/prog8/ast/processing/AnonymousScopeVarsCleanup.kt index 0907e426e..38537525b 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/AnonymousScopeVarsCleanup.kt +++ b/compiler/src/prog8/ast/processing/AnonymousScopeVarsCleanup.kt @@ -1,9 +1,8 @@ -package prog8.compiler.target.c64.codegen +package prog8.ast.processing import prog8.ast.Program import prog8.ast.base.AstException import prog8.ast.base.NameError -import prog8.ast.processing.IAstModifyingVisitor import prog8.ast.statements.AnonymousScope import prog8.ast.statements.Statement import prog8.ast.statements.VarDecl diff --git a/compiler/src/prog8/ast/processing/AstChecker.kt b/compiler/src/prog8/ast/processing/AstChecker.kt index f590300bc..c368c7de0 100644 --- a/compiler/src/prog8/ast/processing/AstChecker.kt +++ b/compiler/src/prog8/ast/processing/AstChecker.kt @@ -10,8 +10,7 @@ import prog8.ast.base.* import prog8.ast.expressions.* import prog8.ast.statements.* import prog8.compiler.CompilationOptions -import prog8.compiler.target.c64.MachineDefinition.FLOAT_MAX_NEGATIVE -import prog8.compiler.target.c64.MachineDefinition.FLOAT_MAX_POSITIVE +import prog8.compiler.target.CompilationTarget import prog8.functions.BuiltinFunctions import java.io.File @@ -1136,7 +1135,7 @@ internal class AstChecker(private val program: Program, // check if the floating point values are all within range val doubles = value.value.map {it.constValue(program)?.number!!.toDouble()}.toDoubleArray() - if(doubles.any { it < FLOAT_MAX_NEGATIVE || it> FLOAT_MAX_POSITIVE }) + if(doubles.any { it < CompilationTarget.machine.FLOAT_MAX_NEGATIVE || it > CompilationTarget.machine.FLOAT_MAX_POSITIVE }) return err("floating point value overflow") return true } diff --git a/compiler/src/prog8/ast/processing/AstIdentifiersChecker.kt b/compiler/src/prog8/ast/processing/AstIdentifiersChecker.kt index 033ff82a1..68c08cd65 100644 --- a/compiler/src/prog8/ast/processing/AstIdentifiersChecker.kt +++ b/compiler/src/prog8/ast/processing/AstIdentifiersChecker.kt @@ -7,7 +7,7 @@ import prog8.ast.Program import prog8.ast.base.* import prog8.ast.expressions.* import prog8.ast.statements.* -import prog8.compiler.target.c64.AssemblyProgram +import prog8.compiler.target.CompilationTarget import prog8.functions.BuiltinFunctions @@ -66,7 +66,7 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi // the builtin functions can't be redefined checkResult.add(NameError("builtin function cannot be redefined", decl.position)) - if(decl.name in AssemblyProgram.opcodeNames) + if(decl.name in CompilationTarget.machine.opcodeNames) checkResult.add(NameError("can't use a cpu opcode name as a symbol: '${decl.name}'", decl.position)) // is it a struct variable? then define all its struct members as mangled names, @@ -103,7 +103,7 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi } override fun visit(subroutine: Subroutine): Statement { - if(subroutine.name in AssemblyProgram.opcodeNames) { + if(subroutine.name in CompilationTarget.machine.opcodeNames) { checkResult.add(NameError("can't use a cpu opcode name as a symbol: '${subroutine.name}'", subroutine.position)) } else if(subroutine.name in BuiltinFunctions) { // the builtin functions can't be redefined @@ -164,7 +164,7 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi } override fun visit(label: Label): Statement { - if(label.name in AssemblyProgram.opcodeNames) + if(label.name in CompilationTarget.machine.opcodeNames) checkResult.add(NameError("can't use a cpu opcode name as a symbol: '${label.name}'", label.position)) if(label.name in BuiltinFunctions) { diff --git a/compiler/src/prog8/compiler/AssemblyError.kt b/compiler/src/prog8/compiler/AssemblyError.kt new file mode 100644 index 000000000..123d6c13b --- /dev/null +++ b/compiler/src/prog8/compiler/AssemblyError.kt @@ -0,0 +1,3 @@ +package prog8.compiler + +internal class AssemblyError(msg: String) : RuntimeException(msg) diff --git a/compiler/src/prog8/compiler/Main.kt b/compiler/src/prog8/compiler/Main.kt index 441285bc5..a632ffbd5 100644 --- a/compiler/src/prog8/compiler/Main.kt +++ b/compiler/src/prog8/compiler/Main.kt @@ -4,8 +4,7 @@ import prog8.ast.AstToSourceCode import prog8.ast.Program import prog8.ast.base.* import prog8.ast.statements.Directive -import prog8.compiler.target.c64.MachineDefinition -import prog8.compiler.target.c64.codegen.AsmGen +import prog8.compiler.target.CompilationTarget import prog8.optimizer.constantFold import prog8.optimizer.optimizeStatements import prog8.optimizer.simplifyExpressions @@ -101,9 +100,9 @@ fun compileProgram(filepath: Path, if(writeAssembly) { // asm generation directly from the Ast, no need for intermediate code - val zeropage = MachineDefinition.C64Zeropage(compilerOptions) + val zeropage = CompilationTarget.machine.getZeropage(compilerOptions) programAst.anonscopeVarsCleanup() - val assembly = AsmGen(programAst, zeropage, compilerOptions, outputDir).compileToAssembly(optimize) + val assembly = CompilationTarget.asmGenerator(programAst, zeropage, compilerOptions, outputDir).compileToAssembly(optimize) assembly.assemble(compilerOptions) programName = assembly.name } diff --git a/compiler/src/prog8/compiler/target/CompilationTarget.kt b/compiler/src/prog8/compiler/target/CompilationTarget.kt new file mode 100644 index 000000000..f14f85dfd --- /dev/null +++ b/compiler/src/prog8/compiler/target/CompilationTarget.kt @@ -0,0 +1,15 @@ +package prog8.compiler.target + +import prog8.ast.Program +import prog8.compiler.CompilationOptions +import prog8.compiler.Zeropage +import java.nio.file.Path + +internal interface CompilationTarget { + companion object { + lateinit var name: String + lateinit var machine: IMachineDefinition + lateinit var encodeString: (str: String) -> List + lateinit var asmGenerator: (Program, Zeropage, CompilationOptions, Path) -> IAssemblyGenerator + } +} diff --git a/compiler/src/prog8/compiler/target/IAssemblyGenerator.kt b/compiler/src/prog8/compiler/target/IAssemblyGenerator.kt new file mode 100644 index 000000000..e050d27fe --- /dev/null +++ b/compiler/src/prog8/compiler/target/IAssemblyGenerator.kt @@ -0,0 +1,12 @@ +package prog8.compiler.target + +import prog8.compiler.CompilationOptions + +internal interface IAssemblyGenerator { + fun compileToAssembly(optimize: Boolean): IAssemblyProgram +} + +internal interface IAssemblyProgram { + val name: String + fun assemble(options: CompilationOptions) +} diff --git a/compiler/src/prog8/compiler/target/IMachineDefinition.kt b/compiler/src/prog8/compiler/target/IMachineDefinition.kt new file mode 100644 index 000000000..ef338dece --- /dev/null +++ b/compiler/src/prog8/compiler/target/IMachineDefinition.kt @@ -0,0 +1,15 @@ +package prog8.compiler.target + +import prog8.compiler.CompilationOptions +import prog8.compiler.Zeropage + + +interface IMachineDefinition { + val FLOAT_MAX_NEGATIVE: Double + val FLOAT_MAX_POSITIVE: Double + val FLOAT_MEM_SIZE: Int + + val opcodeNames: Set + + fun getZeropage(compilerOptions: CompilationOptions): Zeropage +} diff --git a/compiler/src/prog8/compiler/target/c64/AssemblyProgram.kt b/compiler/src/prog8/compiler/target/c64/AssemblyProgram.kt index fea79476a..08ce35de0 100644 --- a/compiler/src/prog8/compiler/target/c64/AssemblyProgram.kt +++ b/compiler/src/prog8/compiler/target/c64/AssemblyProgram.kt @@ -2,30 +2,17 @@ package prog8.compiler.target.c64 import prog8.compiler.CompilationOptions import prog8.compiler.OutputType +import prog8.compiler.target.IAssemblyProgram import java.nio.file.Path import kotlin.system.exitProcess -class AssemblyProgram(val name: String, outputDir: Path) { +class AssemblyProgram(override val name: String, outputDir: Path): IAssemblyProgram { private val assemblyFile = outputDir.resolve("$name.asm") private val prgFile = outputDir.resolve("$name.prg") private val binFile = outputDir.resolve("$name.bin") private val viceMonListFile = outputDir.resolve("$name.vice-mon-list") - companion object { - // 6502 opcodes (including aliases and illegal opcodes), these cannot be used as variable or label names - val opcodeNames = setOf("adc", "ahx", "alr", "anc", "and", "ane", "arr", "asl", "asr", "axs", "bcc", "bcs", - "beq", "bge", "bit", "blt", "bmi", "bne", "bpl", "brk", "bvc", "bvs", "clc", - "cld", "cli", "clv", "cmp", "cpx", "cpy", "dcm", "dcp", "dec", "dex", "dey", - "eor", "gcc", "gcs", "geq", "gge", "glt", "gmi", "gne", "gpl", "gvc", "gvs", - "inc", "ins", "inx", "iny", "isb", "isc", "jam", "jmp", "jsr", "lae", "las", - "lax", "lda", "lds", "ldx", "ldy", "lsr", "lxa", "nop", "ora", "pha", "php", - "pla", "plp", "rla", "rol", "ror", "rra", "rti", "rts", "sax", "sbc", "sbx", - "sec", "sed", "sei", "sha", "shl", "shr", "shs", "shx", "shy", "slo", "sre", - "sta", "stx", "sty", "tas", "tax", "tay", "tsx", "txa", "txs", "tya", "xaa") - } - - - fun assemble(options: CompilationOptions) { + override fun assemble(options: CompilationOptions) { // add "-Wlong-branch" to see warnings about conversion of branch instructions to jumps val command = mutableListOf("64tass", "--ascii", "--case-sensitive", "--long-branch", "-Wall", "-Wno-strict-bool", "-Wno-shadow", "-Werror", "-Wno-error=long-branch", diff --git a/compiler/src/prog8/compiler/target/c64/MachineDefinition.kt b/compiler/src/prog8/compiler/target/c64/C64MachineDefinition.kt similarity index 89% rename from compiler/src/prog8/compiler/target/c64/MachineDefinition.kt rename to compiler/src/prog8/compiler/target/c64/C64MachineDefinition.kt index 235c334a2..cfcc53fae 100644 --- a/compiler/src/prog8/compiler/target/c64/MachineDefinition.kt +++ b/compiler/src/prog8/compiler/target/c64/C64MachineDefinition.kt @@ -4,18 +4,19 @@ import prog8.compiler.CompilationOptions import prog8.compiler.CompilerException import prog8.compiler.Zeropage import prog8.compiler.ZeropageType +import prog8.compiler.target.IMachineDefinition import java.awt.Color import java.awt.image.BufferedImage import javax.imageio.ImageIO import kotlin.math.absoluteValue import kotlin.math.pow -object MachineDefinition { +object C64MachineDefinition: IMachineDefinition { // 5-byte cbm MFLPT format limitations: - const val FLOAT_MAX_POSITIVE = 1.7014118345e+38 // bytes: 255,127,255,255,255 - const val FLOAT_MAX_NEGATIVE = -1.7014118345e+38 // bytes: 255,255,255,255,255 - + override val FLOAT_MAX_POSITIVE = 1.7014118345e+38 // bytes: 255,127,255,255,255 + override val FLOAT_MAX_NEGATIVE = -1.7014118345e+38 // bytes: 255,255,255,255,255 + override val FLOAT_MEM_SIZE = 5 const val BASIC_LOAD_ADDRESS = 0x0801 const val RAW_LOAD_ADDRESS = 0xc000 @@ -30,6 +31,19 @@ object MachineDefinition { const val ESTACK_HI_PLUS1_HEX = "\$cf01" const val ESTACK_HI_PLUS2_HEX = "\$cf02" + override fun getZeropage(compilerOptions: CompilationOptions) = C64Zeropage(compilerOptions) + + // 6502 opcodes (including aliases and illegal opcodes), these cannot be used as variable or label names + override val opcodeNames = setOf("adc", "ahx", "alr", "anc", "and", "ane", "arr", "asl", "asr", "axs", "bcc", "bcs", + "beq", "bge", "bit", "blt", "bmi", "bne", "bpl", "brk", "bvc", "bvs", "clc", + "cld", "cli", "clv", "cmp", "cpx", "cpy", "dcm", "dcp", "dec", "dex", "dey", + "eor", "gcc", "gcs", "geq", "gge", "glt", "gmi", "gne", "gpl", "gvc", "gvs", + "inc", "ins", "inx", "iny", "isb", "isc", "jam", "jmp", "jsr", "lae", "las", + "lax", "lda", "lds", "ldx", "ldy", "lsr", "lxa", "nop", "ora", "pha", "php", + "pla", "plp", "rla", "rol", "ror", "rra", "rti", "rts", "sax", "sbc", "sbx", + "sec", "sed", "sei", "sha", "shl", "shr", "shs", "shx", "shy", "slo", "sre", + "sta", "stx", "sty", "tas", "tax", "tay", "tsx", "txa", "txs", "tya", "xaa") + class C64Zeropage(options: CompilationOptions) : Zeropage(options) { @@ -110,8 +124,6 @@ object MachineDefinition { data class Mflpt5(val b0: Short, val b1: Short, val b2: Short, val b3: Short, val b4: Short) { companion object { - const val MemorySize = 5 - val zero = Mflpt5(0, 0, 0, 0, 0) fun fromNumber(num: Number): Mflpt5 { // see https://en.wikipedia.org/wiki/Microsoft_Binary_Format @@ -232,7 +244,6 @@ object MachineDefinition { return bcopy } - val colorPalette = listOf( // this is Pepto's Commodore-64 palette http://www.pepto.de/projects/colorvic/ Color(0x000000), // 0 = black Color(0xFFFFFF), // 1 = white diff --git a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt index 4ec908e4d..905f81bc1 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt @@ -7,10 +7,12 @@ import prog8.ast.base.* import prog8.ast.expressions.* import prog8.ast.statements.* import prog8.compiler.* +import prog8.compiler.target.IAssemblyGenerator +import prog8.compiler.target.IAssemblyProgram import prog8.compiler.target.c64.AssemblyProgram -import prog8.compiler.target.c64.MachineDefinition -import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_HEX -import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_HEX +import prog8.compiler.target.c64.C64MachineDefinition +import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_LO_HEX +import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_HI_HEX import prog8.compiler.target.c64.Petscii import prog8.functions.BuiltinFunctions import prog8.functions.FunctionSignature @@ -22,13 +24,10 @@ import java.util.ArrayDeque import kotlin.math.absoluteValue -internal class AssemblyError(msg: String) : RuntimeException(msg) - - internal class AsmGen(private val program: Program, - private val zeropage: Zeropage, - private val options: CompilationOptions, - private val outputDir: Path) { + private val zeropage: Zeropage, + private val options: CompilationOptions, + private val outputDir: Path): IAssemblyGenerator { private val assemblyLines = mutableListOf() private val globalFloatConsts = mutableMapOf() // all float values in the entire program (value -> varname) @@ -43,7 +42,7 @@ internal class AsmGen(private val program: Program, internal val loopEndLabels = ArrayDeque() internal val loopContinueLabels = ArrayDeque() - internal fun compileToAssembly(optimize: Boolean): AssemblyProgram { + override fun compileToAssembly(optimize: Boolean): IAssemblyProgram { assemblyLines.clear() loopEndLabels.clear() loopContinueLabels.clear() @@ -84,7 +83,7 @@ internal class AsmGen(private val program: Program, program.actualLoadAddress = program.definedLoadAddress if (program.actualLoadAddress == 0) // fix load address program.actualLoadAddress = if (options.launcher == LauncherType.BASIC) - MachineDefinition.BASIC_LOAD_ADDRESS else MachineDefinition.RAW_LOAD_ADDRESS + C64MachineDefinition.BASIC_LOAD_ADDRESS else C64MachineDefinition.RAW_LOAD_ADDRESS when { options.launcher == LauncherType.BASIC -> { @@ -145,7 +144,7 @@ internal class AsmGen(private val program: Program, // the global list of all floating point constants for the whole program out("; global float constants") for (flt in globalFloatConsts) { - val mflpt5 = MachineDefinition.Mflpt5.fromNumber(flt.key) + val mflpt5 = C64MachineDefinition.Mflpt5.fromNumber(flt.key) val floatFill = makeFloatFill(mflpt5) val floatvalue = flt.key out("${flt.value}\t.byte $floatFill ; float $floatvalue") @@ -198,7 +197,7 @@ internal class AsmGen(private val program: Program, } else assemblyLines.add(fragment) } - private fun makeFloatFill(flt: MachineDefinition.Mflpt5): String { + private fun makeFloatFill(flt: C64MachineDefinition.Mflpt5): String { val b0 = "$" + flt.b0.toString(16).padStart(2, '0') val b1 = "$" + flt.b1.toString(16).padStart(2, '0') val b2 = "$" + flt.b2.toString(16).padStart(2, '0') @@ -304,7 +303,7 @@ internal class AsmGen(private val program: Program, val array = (decl.value as ArrayLiteralValue).value val floatFills = array.map { val number = (it as NumericLiteralValue).number - makeFloatFill(MachineDefinition.Mflpt5.fromNumber(number)) + makeFloatFill(C64MachineDefinition.Mflpt5.fromNumber(number)) } out(decl.name) for (f in array.zip(floatFills)) @@ -425,7 +424,7 @@ internal class AsmGen(private val program: Program, internal fun getFloatConst(number: Double): String { // try to match the ROM float constants to save memory - val mflpt5 = MachineDefinition.Mflpt5.fromNumber(number) + val mflpt5 = C64MachineDefinition.Mflpt5.fromNumber(number) val floatbytes = shortArrayOf(mflpt5.b0, mflpt5.b1, mflpt5.b2, mflpt5.b3, mflpt5.b4) when { floatbytes.contentEquals(shortArrayOf(0x00, 0x00, 0x00, 0x00, 0x00)) -> return "c64flt.FL_ZERO" diff --git a/compiler/src/prog8/compiler/target/c64/codegen/AsmOptimizer.kt b/compiler/src/prog8/compiler/target/c64/codegen/AsmOptimizer.kt index e1b020eb5..1f760fc96 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/AsmOptimizer.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/AsmOptimizer.kt @@ -1,7 +1,7 @@ package prog8.compiler.target.c64.codegen -import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_HEX -import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_PLUS1_HEX +import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_LO_HEX +import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_LO_PLUS1_HEX // note: see https://wiki.nesdev.com/w/index.php/6502_assembly_optimisations diff --git a/compiler/src/prog8/compiler/target/c64/codegen/AssignmentAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/AssignmentAsmGen.kt index cf8f6eda6..13580737d 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/AssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/AssignmentAsmGen.kt @@ -7,8 +7,13 @@ import prog8.ast.statements.AssignTarget import prog8.ast.statements.Assignment import prog8.ast.statements.DirectMemoryWrite import prog8.ast.statements.VarDecl -import prog8.compiler.target.c64.MachineDefinition import prog8.compiler.toHex +import prog8.compiler.AssemblyError +import prog8.compiler.target.c64.C64MachineDefinition +import prog8.compiler.target.c64.C64MachineDefinition.C64Zeropage +import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_HI_HEX +import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_LO_HEX + internal class AssignmentAsmGen(private val program: Program, private val asmgen: AsmGen) { @@ -79,9 +84,9 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen val indexValue = index.number.toInt() * ArrayElementTypes.getValue(arrayDt).memorySize() when (arrayDt) { DataType.STR, DataType.STR_S, DataType.ARRAY_UB, DataType.ARRAY_B -> - asmgen.out(" lda $arrayVarName+$indexValue | sta ${MachineDefinition.ESTACK_LO_HEX},x | dex") + asmgen.out(" lda $arrayVarName+$indexValue | sta $ESTACK_LO_HEX,x | dex") DataType.ARRAY_UW, DataType.ARRAY_W -> - asmgen.out(" lda $arrayVarName+$indexValue | sta ${MachineDefinition.ESTACK_LO_HEX},x | lda $arrayVarName+$indexValue+1 | sta ${MachineDefinition.ESTACK_HI_HEX},x | dex") + asmgen.out(" lda $arrayVarName+$indexValue | sta $ESTACK_LO_HEX,x | lda $arrayVarName+$indexValue+1 | sta $ESTACK_HI_HEX,x | dex") DataType.ARRAY_F -> asmgen.out(" lda #<$arrayVarName+$indexValue | ldy #>$arrayVarName+$indexValue | jsr c64flt.push_float") else -> @@ -124,21 +129,21 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen target.register!=null -> { if(target.register== Register.X) throw AssemblyError("can't pop into X register - use variable instead") - asmgen.out(" inx | ld${target.register.name.toLowerCase()} ${MachineDefinition.ESTACK_LO_HEX},x ") + asmgen.out(" inx | ld${target.register.name.toLowerCase()} $ESTACK_LO_HEX,x ") } targetIdent!=null -> { val targetName = asmgen.asmIdentifierName(targetIdent) val targetDt = targetIdent.inferType(program).typeOrElse(DataType.STRUCT) when(targetDt) { DataType.UBYTE, DataType.BYTE -> { - asmgen.out(" inx | lda ${MachineDefinition.ESTACK_LO_HEX},x | sta $targetName") + asmgen.out(" inx | lda $ESTACK_LO_HEX,x | sta $targetName") } DataType.UWORD, DataType.WORD -> { asmgen.out(""" inx - lda ${MachineDefinition.ESTACK_LO_HEX},x + lda $ESTACK_LO_HEX,x sta $targetName - lda ${MachineDefinition.ESTACK_HI_HEX},x + lda $ESTACK_HI_HEX,x sta $targetName+1 """) } @@ -153,14 +158,14 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } } target.memoryAddress!=null -> { - asmgen.out(" inx | ldy ${MachineDefinition.ESTACK_LO_HEX},x") + asmgen.out(" inx | ldy $ESTACK_LO_HEX,x") storeRegisterInMemoryAddress(Register.Y, target.memoryAddress) } target.arrayindexed!=null -> { val arrayDt = target.arrayindexed!!.identifier.targetVarDecl(program.namespace)!!.datatype val arrayVarName = asmgen.asmIdentifierName(target.arrayindexed!!.identifier) asmgen.translateExpression(target.arrayindexed!!.arrayspec.index) - asmgen.out(" inx | lda ${MachineDefinition.ESTACK_LO_HEX},x") + asmgen.out(" inx | lda $ESTACK_LO_HEX,x") popAndWriteArrayvalueWithIndexA(arrayDt, arrayVarName) } else -> throw AssemblyError("weird assignment target $target") @@ -225,9 +230,9 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen targetArrayIdx!=null -> { val index = targetArrayIdx.arrayspec.index val targetName = asmgen.asmIdentifierName(targetArrayIdx.identifier) - asmgen.out(" lda $sourceName | sta ${MachineDefinition.ESTACK_LO_HEX},x | lda $sourceName+1 | sta ${MachineDefinition.ESTACK_HI_HEX},x | dex") + asmgen.out(" lda $sourceName | sta $ESTACK_LO_HEX,x | lda $sourceName+1 | sta $ESTACK_HI_HEX,x | dex") asmgen.translateExpression(index) - asmgen.out(" inx | lda ${MachineDefinition.ESTACK_LO_HEX},x") + asmgen.out(" inx | lda $ESTACK_LO_HEX,x") val arrayDt = targetArrayIdx.identifier.inferType(program).typeOrElse(DataType.STRUCT) popAndWriteArrayvalueWithIndexA(arrayDt, targetName) } @@ -285,9 +290,9 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen val index = targetArrayIdx.arrayspec.index val targetName = asmgen.asmIdentifierName(targetArrayIdx.identifier) val arrayDt = targetArrayIdx.identifier.inferType(program).typeOrElse(DataType.STRUCT) - asmgen.out(" lda $sourceName | sta ${MachineDefinition.ESTACK_LO_HEX},x | dex") + asmgen.out(" lda $sourceName | sta $ESTACK_LO_HEX,x | dex") asmgen.translateExpression(index) - asmgen.out(" inx | lda ${MachineDefinition.ESTACK_LO_HEX},x") + asmgen.out(" inx | lda $ESTACK_LO_HEX,x") popAndWriteArrayvalueWithIndexA(arrayDt, targetName) } target.memoryAddress != null -> { @@ -303,8 +308,8 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen asmgen.translateExpression(addressExpr) asmgen.out(""" inx - lda ${MachineDefinition.ESTACK_LO_HEX},x - ldy ${MachineDefinition.ESTACK_HI_HEX},x + lda $ESTACK_LO_HEX,x + ldy $ESTACK_HI_HEX,x sta (+) +1 sty (+) +2 lda $sourceName @@ -361,9 +366,9 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } is RegisterExpr -> { when(register) { - Register.A -> asmgen.out(" sta ${MachineDefinition.C64Zeropage.SCRATCH_B1}") - Register.X -> asmgen.out(" stx ${MachineDefinition.C64Zeropage.SCRATCH_B1}") - Register.Y -> asmgen.out(" sty ${MachineDefinition.C64Zeropage.SCRATCH_B1}") + Register.A -> asmgen.out(" sta ${C64Zeropage.SCRATCH_B1}") + Register.X -> asmgen.out(" stx ${C64Zeropage.SCRATCH_B1}") + Register.Y -> asmgen.out(" sty ${C64Zeropage.SCRATCH_B1}") } when(index.register) { Register.A -> {} @@ -372,20 +377,20 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } asmgen.out(""" tay - lda ${MachineDefinition.C64Zeropage.SCRATCH_B1} + lda ${C64Zeropage.SCRATCH_B1} sta $targetName,y """) } is IdentifierReference -> { when(register) { - Register.A -> asmgen.out(" sta ${MachineDefinition.C64Zeropage.SCRATCH_B1}") - Register.X -> asmgen.out(" stx ${MachineDefinition.C64Zeropage.SCRATCH_B1}") - Register.Y -> asmgen.out(" sty ${MachineDefinition.C64Zeropage.SCRATCH_B1}") + Register.A -> asmgen.out(" sta ${C64Zeropage.SCRATCH_B1}") + Register.X -> asmgen.out(" stx ${C64Zeropage.SCRATCH_B1}") + Register.Y -> asmgen.out(" sty ${C64Zeropage.SCRATCH_B1}") } asmgen.out(""" lda ${asmgen.asmIdentifierName(index)} tay - lda ${MachineDefinition.C64Zeropage.SCRATCH_B1} + lda ${C64Zeropage.SCRATCH_B1} sta $targetName,y """) } @@ -394,15 +399,15 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen asmgen.translateExpression(index) asmgen.restoreRegister(register) when(register) { - Register.A -> asmgen.out(" sta ${MachineDefinition.C64Zeropage.SCRATCH_B1}") - Register.X -> asmgen.out(" stx ${MachineDefinition.C64Zeropage.SCRATCH_B1}") - Register.Y -> asmgen.out(" sty ${MachineDefinition.C64Zeropage.SCRATCH_B1}") + Register.A -> asmgen.out(" sta ${C64Zeropage.SCRATCH_B1}") + Register.X -> asmgen.out(" stx ${C64Zeropage.SCRATCH_B1}") + Register.Y -> asmgen.out(" sty ${C64Zeropage.SCRATCH_B1}") } asmgen.out(""" inx - lda ${MachineDefinition.ESTACK_LO_HEX},x + lda $ESTACK_LO_HEX,x tay - lda ${MachineDefinition.C64Zeropage.SCRATCH_B1} + lda ${C64Zeropage.SCRATCH_B1} sta $targetName,y """) } @@ -423,29 +428,29 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen when(register) { Register.A -> asmgen.out(""" ldy $targetName - sty ${MachineDefinition.C64Zeropage.SCRATCH_W1} + sty ${C64Zeropage.SCRATCH_W1} ldy $targetName+1 - sty ${MachineDefinition.C64Zeropage.SCRATCH_W1+1} + sty ${C64Zeropage.SCRATCH_W1+1} ldy #0 - sta (${MachineDefinition.C64Zeropage.SCRATCH_W1}),y + sta (${C64Zeropage.SCRATCH_W1}),y """) Register.X -> asmgen.out(""" txa ldy $targetName - sty ${MachineDefinition.C64Zeropage.SCRATCH_W1} + sty ${C64Zeropage.SCRATCH_W1} ldy $targetName+1 - sty ${MachineDefinition.C64Zeropage.SCRATCH_W1+1} + sty ${C64Zeropage.SCRATCH_W1+1} ldy #0 - sta (${MachineDefinition.C64Zeropage.SCRATCH_W1}),y + sta (${C64Zeropage.SCRATCH_W1}),y """) Register.Y -> asmgen.out(""" tya ldy $targetName - sty ${MachineDefinition.C64Zeropage.SCRATCH_W1} + sty ${C64Zeropage.SCRATCH_W1} ldy $targetName+1 - sty ${MachineDefinition.C64Zeropage.SCRATCH_W1+1} + sty ${C64Zeropage.SCRATCH_W1+1} ldy #0 - sta (${MachineDefinition.C64Zeropage.SCRATCH_W1}),y + sta (${C64Zeropage.SCRATCH_W1}),y """) } } @@ -460,9 +465,9 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } asmgen.out(""" inx - lda ${MachineDefinition.ESTACK_LO_HEX},x + lda $ESTACK_LO_HEX,x sta (+) +1 - lda ${MachineDefinition.ESTACK_HI_HEX},x + lda $ESTACK_HI_HEX,x sta (+) +2 + sty ${65535.toHex()} ; modified """) @@ -502,7 +507,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen asmgen.translateExpression(index) asmgen.out(""" inx - lda ${MachineDefinition.ESTACK_LO_HEX},x + lda $ESTACK_LO_HEX,x asl a tay lda #<${word.toHex()} @@ -537,7 +542,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen asmgen.translateExpression(index) asmgen.out(""" inx - ldy ${MachineDefinition.ESTACK_LO_HEX},x + ldy $ESTACK_LO_HEX,x lda #${byte.toHex()} sta $targetName,y """) @@ -567,7 +572,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen val index = targetArrayIdx.arrayspec.index val targetName = asmgen.asmIdentifierName(targetArrayIdx.identifier) if(index is NumericLiteralValue) { - val indexValue = index.number.toInt() * MachineDefinition.Mflpt5.MemorySize + val indexValue = index.number.toInt() * C64MachineDefinition.FLOAT_MEM_SIZE asmgen.out(""" lda #0 sta $targetName+$indexValue @@ -580,11 +585,11 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen asmgen.translateExpression(index) asmgen.out(""" inx - lda ${MachineDefinition.ESTACK_LO_HEX},x + lda $ESTACK_LO_HEX,x asl a asl a clc - adc ${MachineDefinition.ESTACK_LO_HEX},x + adc $ESTACK_LO_HEX,x tay lda #0 sta $targetName,y @@ -620,7 +625,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen val index = targetArrayIdx.arrayspec.index val arrayVarName = asmgen.asmIdentifierName(targetArrayIdx.identifier) if(index is NumericLiteralValue) { - val indexValue = index.number.toInt() * MachineDefinition.Mflpt5.MemorySize + val indexValue = index.number.toInt() * C64MachineDefinition.FLOAT_MEM_SIZE asmgen.out(""" lda $constFloat sta $arrayVarName+$indexValue @@ -636,11 +641,11 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } else { asmgen.translateArrayIndexIntoA(targetArrayIdx) asmgen.out(""" - sta ${MachineDefinition.C64Zeropage.SCRATCH_REG} + sta ${C64Zeropage.SCRATCH_REG} asl a asl a clc - adc ${MachineDefinition.C64Zeropage.SCRATCH_REG} + adc ${C64Zeropage.SCRATCH_REG} tay lda $constFloat sta $arrayVarName,y @@ -726,13 +731,13 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen private fun popAndWriteArrayvalueWithIndexA(arrayDt: DataType, variablename: String) { when (arrayDt) { DataType.STR, DataType.STR_S, DataType.ARRAY_UB, DataType.ARRAY_B -> - asmgen.out(" tay | inx | lda ${MachineDefinition.ESTACK_LO_HEX},x | sta $variablename,y") + asmgen.out(" tay | inx | lda $ESTACK_LO_HEX,x | sta $variablename,y") DataType.ARRAY_UW, DataType.ARRAY_W -> - asmgen.out(" asl a | tay | inx | lda ${MachineDefinition.ESTACK_LO_HEX},x | sta $variablename,y | lda ${MachineDefinition.ESTACK_HI_HEX},x | sta $variablename+1,y") + asmgen.out(" asl a | tay | inx | lda $ESTACK_LO_HEX,x | sta $variablename,y | lda $ESTACK_HI_HEX,x | sta $variablename+1,y") DataType.ARRAY_F -> // index * 5 is done in the subroutine that's called asmgen.out(""" - sta ${MachineDefinition.ESTACK_LO_HEX},x + sta $ESTACK_LO_HEX,x dex lda #<$variablename ldy #>$variablename diff --git a/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt index a17afb20b..85c1d02ca 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt @@ -9,12 +9,13 @@ import prog8.ast.base.WordDatatypes import prog8.ast.expressions.* import prog8.ast.statements.AssignTarget import prog8.ast.statements.FunctionCallStatement -import prog8.compiler.target.c64.MachineDefinition.C64Zeropage -import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_HEX -import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_PLUS1_HEX -import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_HEX -import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_PLUS1_HEX +import prog8.compiler.target.c64.C64MachineDefinition.C64Zeropage +import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_HI_HEX +import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_HI_PLUS1_HEX +import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_LO_HEX +import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_LO_PLUS1_HEX import prog8.compiler.toHex +import prog8.compiler.AssemblyError import prog8.functions.FunctionSignature internal class BuiltinFunctionsAsmGen(private val program: Program, private val asmgen: AsmGen) { diff --git a/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt index c91cceccd..3a68fa2dc 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt @@ -3,8 +3,13 @@ package prog8.compiler.target.c64.codegen import prog8.ast.Program import prog8.ast.base.* import prog8.ast.expressions.* -import prog8.compiler.target.c64.MachineDefinition import prog8.compiler.toHex +import prog8.compiler.AssemblyError +import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_HI_HEX +import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_HI_PLUS1_HEX +import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_LO_HEX +import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_LO_PLUS1_HEX +import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_LO_PLUS2_HEX import prog8.functions.BuiltinFunctions import kotlin.math.absoluteValue @@ -42,9 +47,9 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge // result value in cpu or status registers, put it on the stack if (reg.registerOrPair != null) { when (reg.registerOrPair) { - RegisterOrPair.A -> asmgen.out(" sta ${MachineDefinition.ESTACK_LO_HEX},x | dex") - RegisterOrPair.Y -> asmgen.out(" tya | sta ${MachineDefinition.ESTACK_LO_HEX},x | dex") - RegisterOrPair.AY -> asmgen.out(" sta ${MachineDefinition.ESTACK_LO_HEX},x | tya | sta ${MachineDefinition.ESTACK_HI_HEX},x | dex") + RegisterOrPair.A -> asmgen.out(" sta $ESTACK_LO_HEX,x | dex") + RegisterOrPair.Y -> asmgen.out(" tya | sta $ESTACK_LO_HEX,x | dex") + RegisterOrPair.AY -> asmgen.out(" sta $ESTACK_LO_HEX,x | tya | sta $ESTACK_HI_HEX,x | dex") RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY -> throw AssemblyError("can't push X register - use a variable") } } @@ -60,7 +65,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge DataType.UBYTE -> { when(expr.type) { DataType.UBYTE, DataType.BYTE -> {} - DataType.UWORD, DataType.WORD -> asmgen.out(" lda #0 | sta ${MachineDefinition.ESTACK_HI_PLUS1_HEX},x") + DataType.UWORD, DataType.WORD -> asmgen.out(" lda #0 | sta $ESTACK_HI_PLUS1_HEX,x") DataType.FLOAT -> asmgen.out(" jsr c64flt.stack_ub2float") in PassByReferenceDatatypes -> throw AssemblyError("cannot cast to a pass-by-reference datatype") else -> throw AssemblyError("weird type") @@ -69,7 +74,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge DataType.BYTE -> { when(expr.type) { DataType.UBYTE, DataType.BYTE -> {} - DataType.UWORD, DataType.WORD -> asmgen.out(" lda ${MachineDefinition.ESTACK_LO_PLUS1_HEX},x | ${asmgen.signExtendAtoMsb("${MachineDefinition.ESTACK_HI_PLUS1_HEX},x")}") + DataType.UWORD, DataType.WORD -> asmgen.out(" lda $ESTACK_LO_PLUS1_HEX,x | ${asmgen.signExtendAtoMsb("$ESTACK_HI_PLUS1_HEX,x")}") DataType.FLOAT -> asmgen.out(" jsr c64flt.stack_b2float") in PassByReferenceDatatypes -> throw AssemblyError("cannot cast to a pass-by-reference datatype") else -> throw AssemblyError("weird type") @@ -111,35 +116,35 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge private fun translateExpression(expr: AddressOf) { val name = asmgen.asmIdentifierName(expr.identifier) - asmgen.out(" lda #<$name | sta ${MachineDefinition.ESTACK_LO_HEX},x | lda #>$name | sta ${MachineDefinition.ESTACK_HI_HEX},x | dex") + asmgen.out(" lda #<$name | sta $ESTACK_LO_HEX,x | lda #>$name | sta $ESTACK_HI_HEX,x | dex") } private fun translateExpression(expr: DirectMemoryRead) { when(expr.addressExpression) { is NumericLiteralValue -> { val address = (expr.addressExpression as NumericLiteralValue).number.toInt() - asmgen.out(" lda ${address.toHex()} | sta ${MachineDefinition.ESTACK_LO_HEX},x | dex") + asmgen.out(" lda ${address.toHex()} | sta $ESTACK_LO_HEX,x | dex") } is IdentifierReference -> { val sourceName = asmgen.asmIdentifierName(expr.addressExpression as IdentifierReference) - asmgen.out(" lda $sourceName | sta ${MachineDefinition.ESTACK_LO_HEX},x | dex") + asmgen.out(" lda $sourceName | sta $ESTACK_LO_HEX,x | dex") } else -> { translateExpression(expr.addressExpression) asmgen.out(" jsr prog8_lib.read_byte_from_address") - asmgen.out(" sta ${MachineDefinition.ESTACK_LO_PLUS1_HEX},x") + asmgen.out(" sta $ESTACK_LO_PLUS1_HEX,x") } } } private fun translateExpression(expr: NumericLiteralValue) { when(expr.type) { - DataType.UBYTE, DataType.BYTE -> asmgen.out(" lda #${expr.number.toHex()} | sta ${MachineDefinition.ESTACK_LO_HEX},x | dex") + DataType.UBYTE, DataType.BYTE -> asmgen.out(" lda #${expr.number.toHex()} | sta $ESTACK_LO_HEX,x | dex") DataType.UWORD, DataType.WORD -> asmgen.out(""" lda #<${expr.number.toHex()} - sta ${MachineDefinition.ESTACK_LO_HEX},x + sta $ESTACK_LO_HEX,x lda #>${expr.number.toHex()} - sta ${MachineDefinition.ESTACK_HI_HEX},x + sta $ESTACK_HI_HEX,x dex """) DataType.FLOAT -> { @@ -152,9 +157,9 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge private fun translateExpression(expr: RegisterExpr) { when(expr.register) { - Register.A -> asmgen.out(" sta ${MachineDefinition.ESTACK_LO_HEX},x | dex") + Register.A -> asmgen.out(" sta $ESTACK_LO_HEX,x | dex") Register.X -> throw AssemblyError("cannot push X - use a variable instead of the X register") - Register.Y -> asmgen.out(" tya | sta ${MachineDefinition.ESTACK_LO_HEX},x | dex") + Register.Y -> asmgen.out(" tya | sta $ESTACK_LO_HEX,x | dex") } } @@ -162,13 +167,13 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge val varname = asmgen.asmIdentifierName(expr) when(expr.inferType(program).typeOrElse(DataType.STRUCT)) { DataType.UBYTE, DataType.BYTE -> { - asmgen.out(" lda $varname | sta ${MachineDefinition.ESTACK_LO_HEX},x | dex") + asmgen.out(" lda $varname | sta $ESTACK_LO_HEX,x | dex") } DataType.UWORD, DataType.WORD -> { - asmgen.out(" lda $varname | sta ${MachineDefinition.ESTACK_LO_HEX},x | lda $varname+1 | sta ${MachineDefinition.ESTACK_HI_HEX},x | dex") + asmgen.out(" lda $varname | sta $ESTACK_LO_HEX,x | lda $varname+1 | sta $ESTACK_HI_HEX,x | dex") } in ArrayDatatypes, in StringDatatypes -> { - asmgen.out(" lda #<$varname | sta ${MachineDefinition.ESTACK_LO_HEX},x | lda #>$varname | sta ${MachineDefinition.ESTACK_HI_HEX},x | dex") + asmgen.out(" lda #<$varname | sta $ESTACK_LO_HEX,x | lda #>$varname | sta $ESTACK_HI_HEX,x | dex") } DataType.FLOAT -> { asmgen.out(" lda #<$varname | ldy #>$varname| jsr c64flt.push_float") @@ -196,10 +201,10 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge translateExpression(expr.left) val amount = expr.right.constValue(program)!!.number.toInt() when (leftDt) { - DataType.UBYTE -> repeat(amount) { asmgen.out(" lsr ${MachineDefinition.ESTACK_LO_PLUS1_HEX},x") } - DataType.BYTE -> repeat(amount) { asmgen.out(" lda ${MachineDefinition.ESTACK_LO_PLUS1_HEX},x | asl a | ror ${MachineDefinition.ESTACK_LO_PLUS1_HEX},x") } - DataType.UWORD -> repeat(amount) { asmgen.out(" lsr ${MachineDefinition.ESTACK_HI_PLUS1_HEX},x | ror ${MachineDefinition.ESTACK_LO_PLUS1_HEX},x") } - DataType.WORD -> repeat(amount) { asmgen.out(" lda ${MachineDefinition.ESTACK_HI_PLUS1_HEX},x | asl a | ror ${MachineDefinition.ESTACK_HI_PLUS1_HEX},x | ror ${MachineDefinition.ESTACK_LO_PLUS1_HEX},x") } + DataType.UBYTE -> repeat(amount) { asmgen.out(" lsr $ESTACK_LO_PLUS1_HEX,x") } + DataType.BYTE -> repeat(amount) { asmgen.out(" lda $ESTACK_LO_PLUS1_HEX,x | asl a | ror $ESTACK_LO_PLUS1_HEX,x") } + DataType.UWORD -> repeat(amount) { asmgen.out(" lsr $ESTACK_HI_PLUS1_HEX,x | ror $ESTACK_LO_PLUS1_HEX,x") } + DataType.WORD -> repeat(amount) { asmgen.out(" lda $ESTACK_HI_PLUS1_HEX,x | asl a | ror $ESTACK_HI_PLUS1_HEX,x | ror $ESTACK_LO_PLUS1_HEX,x") } else -> throw AssemblyError("weird type") } return @@ -209,9 +214,9 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge translateExpression(expr.left) val amount = expr.right.constValue(program)!!.number.toInt() if (leftDt in ByteDatatypes) - repeat(amount) { asmgen.out(" asl ${MachineDefinition.ESTACK_LO_PLUS1_HEX},x") } + repeat(amount) { asmgen.out(" asl $ESTACK_LO_PLUS1_HEX,x") } else - repeat(amount) { asmgen.out(" asl ${MachineDefinition.ESTACK_LO_PLUS1_HEX},x | rol ${MachineDefinition.ESTACK_HI_PLUS1_HEX},x") } + repeat(amount) { asmgen.out(" asl $ESTACK_LO_PLUS1_HEX,x | rol $ESTACK_HI_PLUS1_HEX,x") } return } "*" -> { @@ -297,9 +302,9 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge when(type) { in ByteDatatypes -> asmgen.out(""" - lda ${MachineDefinition.ESTACK_LO_PLUS1_HEX},x + lda $ESTACK_LO_PLUS1_HEX,x eor #255 - sta ${MachineDefinition.ESTACK_LO_PLUS1_HEX},x + sta $ESTACK_LO_PLUS1_HEX,x """) in WordDatatypes -> asmgen.out(" jsr prog8_lib.inv_word") else -> throw AssemblyError("weird type") @@ -326,10 +331,10 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge val indexValue = index.number.toInt() * elementDt.memorySize() when(elementDt) { in ByteDatatypes -> { - asmgen.out(" lda $arrayVarName+$indexValue | sta ${MachineDefinition.ESTACK_LO_HEX},x | dex") + asmgen.out(" lda $arrayVarName+$indexValue | sta $ESTACK_LO_HEX,x | dex") } in WordDatatypes -> { - asmgen.out(" lda $arrayVarName+$indexValue | sta ${MachineDefinition.ESTACK_LO_HEX},x | lda $arrayVarName+$indexValue+1 | sta ${MachineDefinition.ESTACK_HI_HEX},x | dex") + asmgen.out(" lda $arrayVarName+$indexValue | sta $ESTACK_LO_HEX,x | lda $arrayVarName+$indexValue+1 | sta $ESTACK_HI_HEX,x | dex") } DataType.FLOAT -> { asmgen.out(" lda #<$arrayVarName+$indexValue | ldy #>$arrayVarName+$indexValue | jsr c64flt.push_float") @@ -353,18 +358,18 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge asmgen.out(" jsr prog8_lib.remainder_ub") } "+" -> asmgen.out(""" - lda ${MachineDefinition.ESTACK_LO_PLUS2_HEX},x + lda $ESTACK_LO_PLUS2_HEX,x clc - adc ${MachineDefinition.ESTACK_LO_PLUS1_HEX},x + adc $ESTACK_LO_PLUS1_HEX,x inx - sta ${MachineDefinition.ESTACK_LO_PLUS1_HEX},x + sta $ESTACK_LO_PLUS1_HEX,x """) "-" -> asmgen.out(""" - lda ${MachineDefinition.ESTACK_LO_PLUS2_HEX},x + lda $ESTACK_LO_PLUS2_HEX,x sec - sbc ${MachineDefinition.ESTACK_LO_PLUS1_HEX},x + sbc $ESTACK_LO_PLUS1_HEX,x inx - sta ${MachineDefinition.ESTACK_LO_PLUS1_HEX},x + sta $ESTACK_LO_PLUS1_HEX,x """) "<<", ">>" -> throw AssemblyError("bit-shifts not via stack") "<" -> asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.less_ub" else " jsr prog8_lib.less_b") diff --git a/compiler/src/prog8/compiler/target/c64/codegen/ForLoopsAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/ForLoopsAsmGen.kt index 95f26f558..4cc089ee5 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/ForLoopsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/ForLoopsAsmGen.kt @@ -8,10 +8,11 @@ import prog8.ast.expressions.RangeExpr import prog8.ast.statements.AssignTarget import prog8.ast.statements.Assignment import prog8.ast.statements.ForLoop -import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_HEX -import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_PLUS1_HEX -import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_PLUS1_HEX +import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_LO_HEX +import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_LO_PLUS1_HEX +import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_HI_PLUS1_HEX import prog8.compiler.toHex +import prog8.compiler.AssemblyError import kotlin.math.absoluteValue // todo choose more efficient comparisons to avoid needless lda's diff --git a/compiler/src/prog8/compiler/target/c64/codegen/FunctionCallAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/FunctionCallAsmGen.kt index 1d8deda7d..e9e4046ae 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/FunctionCallAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/FunctionCallAsmGen.kt @@ -7,8 +7,11 @@ import prog8.ast.expressions.* import prog8.ast.statements.AssignTarget import prog8.ast.statements.Subroutine import prog8.ast.statements.SubroutineParameter -import prog8.compiler.target.c64.MachineDefinition import prog8.compiler.toHex +import prog8.compiler.AssemblyError +import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_HI_HEX +import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_LO_HEX + internal class FunctionCallAsmGen(private val program: Program, private val asmgen: AsmGen) { @@ -139,7 +142,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg asmgen.translateExpression(value) asmgen.out(""" inx - lda ${MachineDefinition.ESTACK_LO_HEX},x + lda $ESTACK_LO_HEX,x beq + sec bcs ++ @@ -166,9 +169,9 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg else -> { asmgen.translateExpression(value) when(register) { - RegisterOrPair.A -> asmgen.out(" inx | lda ${MachineDefinition.ESTACK_LO_HEX},x") + RegisterOrPair.A -> asmgen.out(" inx | lda $ESTACK_LO_HEX,x") RegisterOrPair.X -> throw AssemblyError("can't pop into X register - use a variable instead") - RegisterOrPair.Y -> asmgen.out(" inx | ldy ${MachineDefinition.ESTACK_LO_HEX},x") + RegisterOrPair.Y -> asmgen.out(" inx | ldy $ESTACK_LO_HEX,x") else -> throw AssemblyError("cannot assign to register pair") } } @@ -211,7 +214,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg if (register == RegisterOrPair.AX || register == RegisterOrPair.XY) throw AssemblyError("can't use X register here - use a variable") else if (register == RegisterOrPair.AY) - asmgen.out(" inx | lda ${MachineDefinition.ESTACK_LO_HEX},x | ldy ${MachineDefinition.ESTACK_HI_HEX},x") + asmgen.out(" inx | lda $ESTACK_LO_HEX,x | ldy $ESTACK_HI_HEX,x") } } } diff --git a/compiler/src/prog8/compiler/target/c64/codegen/PostIncrDecrAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/PostIncrDecrAsmGen.kt index d9e73e520..dd0dfa722 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/PostIncrDecrAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/PostIncrDecrAsmGen.kt @@ -6,8 +6,10 @@ import prog8.ast.expressions.IdentifierReference import prog8.ast.expressions.NumericLiteralValue import prog8.ast.expressions.RegisterExpr import prog8.ast.statements.PostIncrDecr -import prog8.compiler.target.c64.MachineDefinition import prog8.compiler.toHex +import prog8.compiler.AssemblyError +import prog8.compiler.target.c64.C64MachineDefinition.C64Zeropage + internal class PostIncrDecrAsmGen(private val program: Program, private val asmgen: AsmGen) { internal fun translate(stmt: PostIncrDecr) { @@ -119,7 +121,7 @@ internal class PostIncrDecrAsmGen(private val program: Program, private val asmg } private fun incrDecrArrayvalueWithIndexA(incr: Boolean, arrayDt: DataType, arrayVarName: String) { - asmgen.out(" stx ${MachineDefinition.C64Zeropage.SCRATCH_REG_X} | tax") + asmgen.out(" stx ${C64Zeropage.SCRATCH_REG_X} | tax") when(arrayDt) { DataType.STR, DataType.STR_S, DataType.ARRAY_UB, DataType.ARRAY_B -> { @@ -142,7 +144,7 @@ internal class PostIncrDecrAsmGen(private val program: Program, private val asmg } else -> throw AssemblyError("weird array dt") } - asmgen.out(" ldx ${MachineDefinition.C64Zeropage.SCRATCH_REG_X}") + asmgen.out(" ldx ${C64Zeropage.SCRATCH_REG_X}") } } diff --git a/compiler/src/prog8/optimizer/ConstantFolding.kt b/compiler/src/prog8/optimizer/ConstantFolding.kt index 09a843c1a..a89651323 100644 --- a/compiler/src/prog8/optimizer/ConstantFolding.kt +++ b/compiler/src/prog8/optimizer/ConstantFolding.kt @@ -7,9 +7,7 @@ import prog8.ast.expressions.* import prog8.ast.processing.IAstModifyingVisitor import prog8.ast.processing.fixupArrayDatatype import prog8.ast.statements.* -import prog8.compiler.target.c64.MachineDefinition.FLOAT_MAX_NEGATIVE -import prog8.compiler.target.c64.MachineDefinition.FLOAT_MAX_POSITIVE -import prog8.compiler.target.c64.codegen.AssemblyError +import prog8.compiler.target.CompilationTarget import prog8.functions.BuiltinFunctions import kotlin.math.floor @@ -140,7 +138,7 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor { } else { // arraysize initializer is a single int, and we know the size. val fillvalue = litval.number.toDouble() - if (fillvalue < FLOAT_MAX_NEGATIVE || fillvalue > FLOAT_MAX_POSITIVE) + if (fillvalue < CompilationTarget.machine.FLOAT_MAX_NEGATIVE || fillvalue > CompilationTarget.machine.FLOAT_MAX_POSITIVE) errors.add(ExpressionError("float value overflow", litval.position)) else { // create the array itself, filled with the fillvalue. @@ -184,7 +182,7 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor { copy.parent = identifier.parent copy } - cval.type in PassByReferenceDatatypes -> throw AssemblyError("pass-by-reference type should not be considered a constant") + cval.type in PassByReferenceDatatypes -> throw FatalAstException("pass-by-reference type should not be considered a constant") else -> identifier } } catch (ax: AstException) { diff --git a/compiler/src/prog8/optimizer/StatementOptimizer.kt b/compiler/src/prog8/optimizer/StatementOptimizer.kt index d9ea58b10..8afc08e39 100644 --- a/compiler/src/prog8/optimizer/StatementOptimizer.kt +++ b/compiler/src/prog8/optimizer/StatementOptimizer.kt @@ -9,8 +9,7 @@ import prog8.ast.expressions.* import prog8.ast.processing.IAstModifyingVisitor import prog8.ast.processing.IAstVisitor import prog8.ast.statements.* -import prog8.compiler.target.c64.Petscii -import prog8.compiler.target.c64.codegen.AssemblyError +import prog8.compiler.target.CompilationTarget import prog8.functions.BuiltinFunctions import kotlin.math.floor @@ -180,7 +179,7 @@ internal class StatementOptimizer(private val program: Program) : IAstModifyingV if(stringVar!=null) { val vardecl = stringVar.targetVarDecl(program.namespace)!! val string = vardecl.value!! as StringLiteralValue - val encodedString = Petscii.encodePetscii(string.value, true) + val encodedString = CompilationTarget.encodeString(string.value) if(string.value.length==1) { functionCallStatement.arglist.clear() functionCallStatement.arglist.add(NumericLiteralValue.optimalInteger(encodedString[0].toInt(), functionCallStatement.position)) @@ -430,7 +429,7 @@ internal class StatementOptimizer(private val program: Program) : IAstModifyingV } val targetIDt = assignment.target.inferType(program, assignment) if(!targetIDt.isKnown) - throw AssemblyError("can't infer type of assignment target") + throw FatalAstException("can't infer type of assignment target") val targetDt = targetIDt.typeOrElse(DataType.STRUCT) val bexpr=assignment.value as? BinaryExpression if(bexpr!=null) { diff --git a/compiler/src/prog8/vm/RuntimeValue.kt b/compiler/src/prog8/vm/RuntimeValue.kt index d6b64c96d..34933f2fe 100644 --- a/compiler/src/prog8/vm/RuntimeValue.kt +++ b/compiler/src/prog8/vm/RuntimeValue.kt @@ -6,7 +6,7 @@ import prog8.ast.base.WordDatatypes import prog8.ast.expressions.ArrayLiteralValue import prog8.ast.expressions.NumericLiteralValue import prog8.ast.expressions.StringLiteralValue -import prog8.compiler.target.c64.Petscii +import prog8.compiler.target.CompilationTarget import prog8.vm.astvm.VmExecutionException import java.util.Objects import kotlin.math.abs @@ -594,7 +594,7 @@ class RuntimeValueString(type: DataType, val str: String, val heapId: Int?): Run return type == other.type && str == other.str } - fun iterator(): Iterator = Petscii.encodePetscii(str, true).iterator() + fun iterator(): Iterator = CompilationTarget.encodeString(str).iterator() override fun numericValue(): Number { throw VmExecutionException("string is not a number") diff --git a/compiler/src/prog8/vm/astvm/AstVm.kt b/compiler/src/prog8/vm/astvm/AstVm.kt index 5f36993d8..53e75e1d0 100644 --- a/compiler/src/prog8/vm/astvm/AstVm.kt +++ b/compiler/src/prog8/vm/astvm/AstVm.kt @@ -7,7 +7,7 @@ import prog8.ast.expressions.Expression import prog8.ast.expressions.IdentifierReference import prog8.ast.expressions.NumericLiteralValue import prog8.ast.statements.* -import prog8.compiler.target.c64.MachineDefinition +import prog8.compiler.target.c64.C64MachineDefinition import prog8.compiler.target.c64.Petscii import prog8.vm.* import java.awt.EventQueue @@ -129,7 +129,7 @@ class RuntimeVariables { } -class AstVm(val program: Program) { +class AstVm(val program: Program, compilationTarget: String) { val mem = Memory(::memread, ::memwrite) val statusflags = StatusFlags() @@ -147,6 +147,8 @@ class AstVm(val program: Program) { init { + require(compilationTarget == "c64") {"using the AstVm only works for the C64 compiler target"} + // observe the jiffyclock and screen matrix mem.observe(0xa0, 0xa1, 0xa2) for(i in 1024..2023) @@ -643,7 +645,7 @@ class AstVm(val program: Program) { DataType.BYTE -> mem.setSByte(address+index, value.byteval!!) DataType.UWORD -> mem.setUWord(address+index*2, value.wordval!!) DataType.WORD -> mem.setSWord(address+index*2, value.wordval!!) - DataType.FLOAT -> mem.setFloat(address+index* MachineDefinition.Mflpt5.MemorySize, value.floatval!!) + DataType.FLOAT -> mem.setFloat(address+index* C64MachineDefinition.FLOAT_MEM_SIZE, value.floatval!!) else -> throw VmExecutionException("strange array elt type $elementType") } } diff --git a/compiler/src/prog8/vm/astvm/Memory.kt b/compiler/src/prog8/vm/astvm/Memory.kt index d10b23561..72a9a0147 100644 --- a/compiler/src/prog8/vm/astvm/Memory.kt +++ b/compiler/src/prog8/vm/astvm/Memory.kt @@ -1,6 +1,6 @@ package prog8.vm.astvm -import prog8.compiler.target.c64.MachineDefinition +import prog8.compiler.target.c64.C64MachineDefinition import prog8.compiler.target.c64.Petscii import kotlin.math.abs @@ -80,7 +80,7 @@ class Memory(private val readObserver: (address: Int, value: Short) -> Short, } fun setFloat(address: Int, value: Double) { - val mflpt5 = MachineDefinition.Mflpt5.fromNumber(value) + val mflpt5 = C64MachineDefinition.Mflpt5.fromNumber(value) setUByte(address, mflpt5.b0) setUByte(address+1, mflpt5.b1) setUByte(address+2, mflpt5.b2) @@ -89,7 +89,7 @@ class Memory(private val readObserver: (address: Int, value: Short) -> Short, } fun getFloat(address: Int): Double { - return MachineDefinition.Mflpt5(getUByte(address), getUByte(address + 1), getUByte(address + 2), + return C64MachineDefinition.Mflpt5(getUByte(address), getUByte(address + 1), getUByte(address + 2), getUByte(address + 3), getUByte(address + 4)).toDouble() } diff --git a/compiler/src/prog8/vm/astvm/ScreenDialog.kt b/compiler/src/prog8/vm/astvm/ScreenDialog.kt index f3aae4553..0225672c9 100644 --- a/compiler/src/prog8/vm/astvm/ScreenDialog.kt +++ b/compiler/src/prog8/vm/astvm/ScreenDialog.kt @@ -1,6 +1,6 @@ package prog8.vm.astvm -import prog8.compiler.target.c64.MachineDefinition +import prog8.compiler.target.c64.C64MachineDefinition import prog8.compiler.target.c64.Petscii import java.awt.* import java.awt.event.KeyEvent @@ -50,16 +50,16 @@ class BitmapScreenPanel : KeyListener, JPanel() { } fun clearScreen(color: Short) { - g2d.background = MachineDefinition.colorPalette[color % MachineDefinition.colorPalette.size] + g2d.background = C64MachineDefinition.colorPalette[color % C64MachineDefinition.colorPalette.size] g2d.clearRect(0, 0, SCREENWIDTH, SCREENHEIGHT) cursorX = 0 cursorY = 0 } fun setPixel(x: Int, y: Int, color: Short) { - image.setRGB(x, y, MachineDefinition.colorPalette[color % MachineDefinition.colorPalette.size].rgb) + image.setRGB(x, y, C64MachineDefinition.colorPalette[color % C64MachineDefinition.colorPalette.size].rgb) } fun drawLine(x1: Int, y1: Int, x2: Int, y2: Int, color: Short) { - g2d.color = MachineDefinition.colorPalette[color % MachineDefinition.colorPalette.size] + g2d.color = C64MachineDefinition.colorPalette[color % C64MachineDefinition.colorPalette.size] g2d.drawLine(x1, y1, x2, y2) } @@ -98,7 +98,7 @@ class BitmapScreenPanel : KeyListener, JPanel() { val graphics = image.graphics as Graphics2D graphics.drawImage(screen, 0, -8, null) val color = graphics.color - graphics.color = MachineDefinition.colorPalette[6] + graphics.color = C64MachineDefinition.colorPalette[6] graphics.fillRect(0, 24*8, SCREENWIDTH, 25*8) graphics.color=color cursorY-- @@ -106,7 +106,7 @@ class BitmapScreenPanel : KeyListener, JPanel() { } fun writeTextAt(x: Int, y: Int, text: String, color: Short, lowercase: Boolean, inverseVideo: Boolean=false) { - val colorIdx = (color % MachineDefinition.colorPalette.size).toShort() + val colorIdx = (color % C64MachineDefinition.colorPalette.size).toShort() var xx=x for(clearx in xx until xx+text.length) { g2d.clearRect(8*clearx, 8*y, 8, 8) @@ -120,16 +120,16 @@ class BitmapScreenPanel : KeyListener, JPanel() { fun setPetscii(x: Int, y: Int, petscii: Short, color: Short, inverseVideo: Boolean) { g2d.clearRect(8*x, 8*y, 8, 8) - val colorIdx = (color % MachineDefinition.colorPalette.size).toShort() + val colorIdx = (color % C64MachineDefinition.colorPalette.size).toShort() val screencode = Petscii.petscii2scr(petscii, inverseVideo) - val coloredImage = MachineDefinition.Charset.getColoredChar(screencode, colorIdx) + val coloredImage = C64MachineDefinition.Charset.getColoredChar(screencode, colorIdx) g2d.drawImage(coloredImage, 8*x, 8*y , null) } fun setChar(x: Int, y: Int, screencode: Short, color: Short) { g2d.clearRect(8*x, 8*y, 8, 8) - val colorIdx = (color % MachineDefinition.colorPalette.size).toShort() - val coloredImage = MachineDefinition.Charset.getColoredChar(screencode, colorIdx) + val colorIdx = (color % C64MachineDefinition.colorPalette.size).toShort() + val coloredImage = C64MachineDefinition.Charset.getColoredChar(screencode, colorIdx) g2d.drawImage(coloredImage, 8*x, 8*y , null) } @@ -163,19 +163,19 @@ class ScreenDialog(title: String) : JFrame(title) { // the borders (top, left, right, bottom) val borderTop = JPanel().apply { preferredSize = Dimension(BitmapScreenPanel.SCALING * (BitmapScreenPanel.SCREENWIDTH +2*borderWidth), BitmapScreenPanel.SCALING * borderWidth) - background = MachineDefinition.colorPalette[14] + background = C64MachineDefinition.colorPalette[14] } val borderBottom = JPanel().apply { preferredSize =Dimension(BitmapScreenPanel.SCALING * (BitmapScreenPanel.SCREENWIDTH +2*borderWidth), BitmapScreenPanel.SCALING * borderWidth) - background = MachineDefinition.colorPalette[14] + background = C64MachineDefinition.colorPalette[14] } val borderLeft = JPanel().apply { preferredSize =Dimension(BitmapScreenPanel.SCALING * borderWidth, BitmapScreenPanel.SCALING * BitmapScreenPanel.SCREENHEIGHT) - background = MachineDefinition.colorPalette[14] + background = C64MachineDefinition.colorPalette[14] } val borderRight = JPanel().apply { preferredSize =Dimension(BitmapScreenPanel.SCALING * borderWidth, BitmapScreenPanel.SCALING * BitmapScreenPanel.SCREENHEIGHT) - background = MachineDefinition.colorPalette[14] + background = C64MachineDefinition.colorPalette[14] } var c = GridBagConstraints() c.gridx=0; c.gridy=1; c.gridwidth=3 diff --git a/compiler/test/LiteralValueTests.kt b/compiler/test/LiteralValueTests.kt index 26420ca1b..431a3383d 100644 --- a/compiler/test/LiteralValueTests.kt +++ b/compiler/test/LiteralValueTests.kt @@ -83,8 +83,8 @@ class TestParserNumericLiteralValue { @Test fun testEqualsRef() { - assertTrue(StringLiteralValue(DataType.STR, "hello", dummyPos) == StringLiteralValue(DataType.STR, "hello", dummyPos)) - assertFalse(StringLiteralValue(DataType.STR, "hello", dummyPos) == StringLiteralValue(DataType.STR, "bye", dummyPos)) + assertEquals(StringLiteralValue(DataType.STR, "hello", dummyPos), StringLiteralValue(DataType.STR, "hello", dummyPos)) + assertNotEquals(StringLiteralValue(DataType.STR, "hello", dummyPos), StringLiteralValue(DataType.STR, "bye", dummyPos)) val lvOne = NumericLiteralValue(DataType.UBYTE, 1, dummyPos) val lvTwo = NumericLiteralValue(DataType.UBYTE, 2, dummyPos) diff --git a/compiler/test/UnitTests.kt b/compiler/test/UnitTests.kt index 5a14d83b0..e355885a5 100644 --- a/compiler/test/UnitTests.kt +++ b/compiler/test/UnitTests.kt @@ -10,10 +10,10 @@ import prog8.ast.base.Position import prog8.ast.expressions.NumericLiteralValue import prog8.ast.expressions.StringLiteralValue import prog8.compiler.* -import prog8.compiler.target.c64.MachineDefinition.C64Zeropage -import prog8.compiler.target.c64.MachineDefinition.FLOAT_MAX_NEGATIVE -import prog8.compiler.target.c64.MachineDefinition.FLOAT_MAX_POSITIVE -import prog8.compiler.target.c64.MachineDefinition.Mflpt5 +import prog8.compiler.target.c64.C64MachineDefinition.C64Zeropage +import prog8.compiler.target.c64.C64MachineDefinition.FLOAT_MAX_NEGATIVE +import prog8.compiler.target.c64.C64MachineDefinition.FLOAT_MAX_POSITIVE +import prog8.compiler.target.c64.C64MachineDefinition.Mflpt5 import prog8.compiler.target.c64.Petscii import prog8.vm.RuntimeValueNumeric import java.io.CharConversionException @@ -95,29 +95,29 @@ class TestCompiler { @Test fun testMflpt5ToFloat() { - val PRECISION=0.000000001 + val epsilon=0.000000001 assertThat(Mflpt5(0x00, 0x00, 0x00, 0x00, 0x00).toDouble(), equalTo(0.0)) - assertThat(Mflpt5(0x82, 0x49, 0x0F, 0xDA, 0xA1).toDouble(), closeTo(3.141592653, PRECISION)) - assertThat(Mflpt5(0x82, 0x49, 0x0F, 0xDA, 0xA2).toDouble(), closeTo(3.141592653589793, PRECISION)) + assertThat(Mflpt5(0x82, 0x49, 0x0F, 0xDA, 0xA1).toDouble(), closeTo(3.141592653, epsilon)) + assertThat(Mflpt5(0x82, 0x49, 0x0F, 0xDA, 0xA2).toDouble(), closeTo(3.141592653589793, epsilon)) assertThat(Mflpt5(0x90, 0x00, 0x00, 0x00, 0x00).toDouble(), equalTo(32768.0)) assertThat(Mflpt5(0x90, 0x80, 0x00, 0x00, 0x00).toDouble(), equalTo(-32768.0)) assertThat(Mflpt5(0x81, 0x00, 0x00, 0x00, 0x00).toDouble(), equalTo(1.0)) - assertThat(Mflpt5(0x80, 0x35, 0x04, 0xF3, 0x34).toDouble(), closeTo(0.7071067812, PRECISION)) - assertThat(Mflpt5(0x80, 0x35, 0x04, 0xF3, 0x33).toDouble(), closeTo(0.7071067811865476, PRECISION)) - assertThat(Mflpt5(0x81, 0x35, 0x04, 0xF3, 0x34).toDouble(), closeTo(1.4142135624, PRECISION)) - assertThat(Mflpt5(0x81, 0x35, 0x04, 0xF3, 0x33).toDouble(), closeTo(1.4142135623730951, PRECISION)) + assertThat(Mflpt5(0x80, 0x35, 0x04, 0xF3, 0x34).toDouble(), closeTo(0.7071067812, epsilon)) + assertThat(Mflpt5(0x80, 0x35, 0x04, 0xF3, 0x33).toDouble(), closeTo(0.7071067811865476, epsilon)) + assertThat(Mflpt5(0x81, 0x35, 0x04, 0xF3, 0x34).toDouble(), closeTo(1.4142135624, epsilon)) + assertThat(Mflpt5(0x81, 0x35, 0x04, 0xF3, 0x33).toDouble(), closeTo(1.4142135623730951, epsilon)) assertThat(Mflpt5(0x80, 0x80, 0x00, 0x00, 0x00).toDouble(), equalTo(-.5)) - assertThat(Mflpt5(0x80, 0x31, 0x72, 0x17, 0xF8).toDouble(), closeTo(0.69314718061, PRECISION)) - assertThat(Mflpt5(0x80, 0x31, 0x72, 0x17, 0xF7).toDouble(), closeTo(0.6931471805599453, PRECISION)) + assertThat(Mflpt5(0x80, 0x31, 0x72, 0x17, 0xF8).toDouble(), closeTo(0.69314718061, epsilon)) + assertThat(Mflpt5(0x80, 0x31, 0x72, 0x17, 0xF7).toDouble(), closeTo(0.6931471805599453, epsilon)) assertThat(Mflpt5(0x84, 0x20, 0x00, 0x00, 0x00).toDouble(), equalTo(10.0)) assertThat(Mflpt5(0x9E, 0x6E, 0x6B, 0x28, 0x00).toDouble(), equalTo(1000000000.0)) assertThat(Mflpt5(0x80, 0x00, 0x00, 0x00, 0x00).toDouble(), equalTo(.5)) - assertThat(Mflpt5(0x81, 0x38, 0xAA, 0x3B, 0x29).toDouble(), closeTo(1.4426950408889634, PRECISION)) - assertThat(Mflpt5(0x81, 0x49, 0x0F, 0xDA, 0xA2).toDouble(), closeTo(1.5707963267948966, PRECISION)) - assertThat(Mflpt5(0x83, 0x49, 0x0F, 0xDA, 0xA2).toDouble(), closeTo(6.283185307179586, PRECISION)) + assertThat(Mflpt5(0x81, 0x38, 0xAA, 0x3B, 0x29).toDouble(), closeTo(1.4426950408889634, epsilon)) + assertThat(Mflpt5(0x81, 0x49, 0x0F, 0xDA, 0xA2).toDouble(), closeTo(1.5707963267948966, epsilon)) + assertThat(Mflpt5(0x83, 0x49, 0x0F, 0xDA, 0xA2).toDouble(), closeTo(6.283185307179586, epsilon)) assertThat(Mflpt5(0x7F, 0x00, 0x00, 0x00, 0x00).toDouble(), equalTo(.25)) assertThat(Mflpt5(0xd1, 0x02, 0xb7, 0x06, 0xfb).toDouble(), closeTo(123.45678e22, 1.0e15)) - assertThat(Mflpt5(0x3e, 0xe9, 0x34, 0x09, 0x1b).toDouble(), closeTo(-123.45678e-22, PRECISION)) + assertThat(Mflpt5(0x3e, 0xe9, 0x34, 0x09, 0x1b).toDouble(), closeTo(-123.45678e-22, epsilon)) } }