preparing for multiple compiler backends/targets

This commit is contained in:
Irmen de Jong 2019-10-26 23:27:27 +02:00
parent b68f141568
commit 8c2e602cc7
32 changed files with 293 additions and 215 deletions

View File

@ -1 +1 @@
1.62 1.7

View File

@ -2,8 +2,11 @@ package prog8
import kotlinx.cli.* import kotlinx.cli.*
import prog8.ast.base.AstException import prog8.ast.base.AstException
import prog8.compiler.CompilationResult import prog8.compiler.*
import prog8.compiler.compileProgram 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.parser.ParsingFailedError
import prog8.vm.astvm.AstVm import prog8.vm.astvm.AstVm
import java.nio.file.FileSystems import java.nio.file.FileSystems
@ -38,6 +41,7 @@ private fun compileMain(args: Array<String>) {
val dontOptimize by cli.flagArgument("-noopt", "don't perform any optimizations") 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 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 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) val moduleFiles by cli.positionalArgumentsList("modules", "main module file(s) to compile", minArgs = 1)
try { try {
@ -46,6 +50,24 @@ private fun compileMain(args: Array<String>) {
exitProcess(1) 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) val outputPath = pathFrom(outputDir)
if(!outputPath.toFile().isDirectory) { if(!outputPath.toFile().isDirectory) {
System.err.println("Output path doesn't exist") System.err.println("Output path doesn't exist")
@ -96,7 +118,7 @@ private fun compileMain(args: Array<String>) {
if (launchSimulator) { if (launchSimulator) {
println("\nLaunching AST-based simulator...") println("\nLaunching AST-based simulator...")
val vm = AstVm(compilationResult.programAst) val vm = AstVm(compilationResult.programAst, compilationTarget)
vm.run() vm.run()
} }

View File

@ -7,7 +7,7 @@ import prog8.ast.Module
import prog8.ast.base.* import prog8.ast.base.*
import prog8.ast.expressions.* import prog8.ast.expressions.*
import prog8.ast.statements.* import prog8.ast.statements.*
import prog8.compiler.target.c64.Petscii import prog8.compiler.target.CompilationTarget
import prog8.parser.CustomLexer import prog8.parser.CustomLexer
import prog8.parser.prog8Parser import prog8.parser.prog8Parser
import java.io.CharConversionException 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.stringliteral()!=null -> StringLiteralValue(DataType.STR, unescape(litval.stringliteral().text, litval.toPosition()), litval.toPosition())
litval.charliteral()!=null -> { litval.charliteral()!=null -> {
try { 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) { } catch (ce: CharConversionException) {
throw SyntaxError(ce.message ?: ce.toString(), litval.toPosition()) throw SyntaxError(ce.message ?: ce.toString(), litval.toPosition())
} }

View File

@ -1,7 +1,8 @@
package prog8.ast.base package prog8.ast.base
import prog8.ast.Node import prog8.ast.Node
import prog8.compiler.target.c64.MachineDefinition import prog8.compiler.target.CompilationTarget
/**************************** AST Data classes ****************************/ /**************************** AST Data classes ****************************/
@ -58,7 +59,7 @@ enum class DataType {
return when(this) { return when(this) {
in ByteDatatypes -> 1 in ByteDatatypes -> 1
in WordDatatypes -> 2 in WordDatatypes -> 2
FLOAT -> MachineDefinition.Mflpt5.MemorySize FLOAT -> CompilationTarget.machine.FLOAT_MEM_SIZE
in PassByReferenceDatatypes -> 2 in PassByReferenceDatatypes -> 2
else -> -9999999 else -> -9999999
} }

View File

@ -4,7 +4,6 @@ import prog8.ast.Module
import prog8.ast.Program import prog8.ast.Program
import prog8.ast.processing.* import prog8.ast.processing.*
import prog8.compiler.CompilationOptions import prog8.compiler.CompilationOptions
import prog8.compiler.target.c64.codegen.AnonymousScopeVarsCleanup
import prog8.optimizer.FlattenAnonymousScopesAndRemoveNops import prog8.optimizer.FlattenAnonymousScopesAndRemoveNops

View File

@ -9,7 +9,7 @@ import prog8.ast.statements.ArrayIndex
import prog8.ast.statements.BuiltinFunctionStatementPlaceholder import prog8.ast.statements.BuiltinFunctionStatementPlaceholder
import prog8.ast.statements.Subroutine import prog8.ast.statements.Subroutine
import prog8.ast.statements.VarDecl import prog8.ast.statements.VarDecl
import prog8.compiler.target.c64.Petscii import prog8.compiler.target.CompilationTarget
import prog8.functions.BuiltinFunctions import prog8.functions.BuiltinFunctions
import prog8.functions.NotConstArgumentException import prog8.functions.NotConstArgumentException
import prog8.functions.builtinFunctionReturnType import prog8.functions.builtinFunctionReturnType
@ -549,8 +549,8 @@ class RangeExpr(var from: Expression,
val toString = to as? StringLiteralValue val toString = to as? StringLiteralValue
if(fromString!=null && toString!=null ) { if(fromString!=null && toString!=null ) {
// string range -> int range over petscii values // string range -> int range over petscii values
fromVal = Petscii.encodePetscii(fromString.value, true)[0].toInt() fromVal = CompilationTarget.encodeString(fromString.value)[0].toInt()
toVal = Petscii.encodePetscii(toString.value, true)[0].toInt() toVal = CompilationTarget.encodeString(toString.value)[0].toInt()
} else { } else {
val fromLv = from as? NumericLiteralValue val fromLv = from as? NumericLiteralValue
val toLv = to as? NumericLiteralValue val toLv = to as? NumericLiteralValue

View File

@ -1,9 +1,8 @@
package prog8.compiler.target.c64.codegen package prog8.ast.processing
import prog8.ast.Program import prog8.ast.Program
import prog8.ast.base.AstException import prog8.ast.base.AstException
import prog8.ast.base.NameError import prog8.ast.base.NameError
import prog8.ast.processing.IAstModifyingVisitor
import prog8.ast.statements.AnonymousScope import prog8.ast.statements.AnonymousScope
import prog8.ast.statements.Statement import prog8.ast.statements.Statement
import prog8.ast.statements.VarDecl import prog8.ast.statements.VarDecl

View File

@ -10,8 +10,7 @@ import prog8.ast.base.*
import prog8.ast.expressions.* import prog8.ast.expressions.*
import prog8.ast.statements.* import prog8.ast.statements.*
import prog8.compiler.CompilationOptions import prog8.compiler.CompilationOptions
import prog8.compiler.target.c64.MachineDefinition.FLOAT_MAX_NEGATIVE import prog8.compiler.target.CompilationTarget
import prog8.compiler.target.c64.MachineDefinition.FLOAT_MAX_POSITIVE
import prog8.functions.BuiltinFunctions import prog8.functions.BuiltinFunctions
import java.io.File 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 // check if the floating point values are all within range
val doubles = value.value.map {it.constValue(program)?.number!!.toDouble()}.toDoubleArray() 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 err("floating point value overflow")
return true return true
} }

View File

@ -7,7 +7,7 @@ import prog8.ast.Program
import prog8.ast.base.* import prog8.ast.base.*
import prog8.ast.expressions.* import prog8.ast.expressions.*
import prog8.ast.statements.* import prog8.ast.statements.*
import prog8.compiler.target.c64.AssemblyProgram import prog8.compiler.target.CompilationTarget
import prog8.functions.BuiltinFunctions import prog8.functions.BuiltinFunctions
@ -66,7 +66,7 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi
// the builtin functions can't be redefined // the builtin functions can't be redefined
checkResult.add(NameError("builtin function cannot be redefined", decl.position)) 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)) 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, // 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 { 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)) checkResult.add(NameError("can't use a cpu opcode name as a symbol: '${subroutine.name}'", subroutine.position))
} else if(subroutine.name in BuiltinFunctions) { } else if(subroutine.name in BuiltinFunctions) {
// the builtin functions can't be redefined // 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 { 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)) checkResult.add(NameError("can't use a cpu opcode name as a symbol: '${label.name}'", label.position))
if(label.name in BuiltinFunctions) { if(label.name in BuiltinFunctions) {

View File

@ -0,0 +1,3 @@
package prog8.compiler
internal class AssemblyError(msg: String) : RuntimeException(msg)

View File

@ -4,8 +4,7 @@ import prog8.ast.AstToSourceCode
import prog8.ast.Program import prog8.ast.Program
import prog8.ast.base.* import prog8.ast.base.*
import prog8.ast.statements.Directive import prog8.ast.statements.Directive
import prog8.compiler.target.c64.MachineDefinition import prog8.compiler.target.CompilationTarget
import prog8.compiler.target.c64.codegen.AsmGen
import prog8.optimizer.constantFold import prog8.optimizer.constantFold
import prog8.optimizer.optimizeStatements import prog8.optimizer.optimizeStatements
import prog8.optimizer.simplifyExpressions import prog8.optimizer.simplifyExpressions
@ -101,9 +100,9 @@ fun compileProgram(filepath: Path,
if(writeAssembly) { if(writeAssembly) {
// asm generation directly from the Ast, no need for intermediate code // asm generation directly from the Ast, no need for intermediate code
val zeropage = MachineDefinition.C64Zeropage(compilerOptions) val zeropage = CompilationTarget.machine.getZeropage(compilerOptions)
programAst.anonscopeVarsCleanup() programAst.anonscopeVarsCleanup()
val assembly = AsmGen(programAst, zeropage, compilerOptions, outputDir).compileToAssembly(optimize) val assembly = CompilationTarget.asmGenerator(programAst, zeropage, compilerOptions, outputDir).compileToAssembly(optimize)
assembly.assemble(compilerOptions) assembly.assemble(compilerOptions)
programName = assembly.name programName = assembly.name
} }

View File

@ -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<Short>
lateinit var asmGenerator: (Program, Zeropage, CompilationOptions, Path) -> IAssemblyGenerator
}
}

View File

@ -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)
}

View File

@ -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<String>
fun getZeropage(compilerOptions: CompilationOptions): Zeropage
}

View File

@ -2,30 +2,17 @@ package prog8.compiler.target.c64
import prog8.compiler.CompilationOptions import prog8.compiler.CompilationOptions
import prog8.compiler.OutputType import prog8.compiler.OutputType
import prog8.compiler.target.IAssemblyProgram
import java.nio.file.Path import java.nio.file.Path
import kotlin.system.exitProcess 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 assemblyFile = outputDir.resolve("$name.asm")
private val prgFile = outputDir.resolve("$name.prg") private val prgFile = outputDir.resolve("$name.prg")
private val binFile = outputDir.resolve("$name.bin") private val binFile = outputDir.resolve("$name.bin")
private val viceMonListFile = outputDir.resolve("$name.vice-mon-list") private val viceMonListFile = outputDir.resolve("$name.vice-mon-list")
companion object { override fun assemble(options: CompilationOptions) {
// 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) {
// add "-Wlong-branch" to see warnings about conversion of branch instructions to jumps // add "-Wlong-branch" to see warnings about conversion of branch instructions to jumps
val command = mutableListOf("64tass", "--ascii", "--case-sensitive", "--long-branch", val command = mutableListOf("64tass", "--ascii", "--case-sensitive", "--long-branch",
"-Wall", "-Wno-strict-bool", "-Wno-shadow", "-Werror", "-Wno-error=long-branch", "-Wall", "-Wno-strict-bool", "-Wno-shadow", "-Werror", "-Wno-error=long-branch",

View File

@ -4,18 +4,19 @@ import prog8.compiler.CompilationOptions
import prog8.compiler.CompilerException import prog8.compiler.CompilerException
import prog8.compiler.Zeropage import prog8.compiler.Zeropage
import prog8.compiler.ZeropageType import prog8.compiler.ZeropageType
import prog8.compiler.target.IMachineDefinition
import java.awt.Color import java.awt.Color
import java.awt.image.BufferedImage import java.awt.image.BufferedImage
import javax.imageio.ImageIO import javax.imageio.ImageIO
import kotlin.math.absoluteValue import kotlin.math.absoluteValue
import kotlin.math.pow import kotlin.math.pow
object MachineDefinition { object C64MachineDefinition: IMachineDefinition {
// 5-byte cbm MFLPT format limitations: // 5-byte cbm MFLPT format limitations:
const val FLOAT_MAX_POSITIVE = 1.7014118345e+38 // bytes: 255,127,255,255,255 override 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_NEGATIVE = -1.7014118345e+38 // bytes: 255,255,255,255,255
override val FLOAT_MEM_SIZE = 5
const val BASIC_LOAD_ADDRESS = 0x0801 const val BASIC_LOAD_ADDRESS = 0x0801
const val RAW_LOAD_ADDRESS = 0xc000 const val RAW_LOAD_ADDRESS = 0xc000
@ -30,6 +31,19 @@ object MachineDefinition {
const val ESTACK_HI_PLUS1_HEX = "\$cf01" const val ESTACK_HI_PLUS1_HEX = "\$cf01"
const val ESTACK_HI_PLUS2_HEX = "\$cf02" 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) { 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) { data class Mflpt5(val b0: Short, val b1: Short, val b2: Short, val b3: Short, val b4: Short) {
companion object { companion object {
const val MemorySize = 5
val zero = Mflpt5(0, 0, 0, 0, 0) val zero = Mflpt5(0, 0, 0, 0, 0)
fun fromNumber(num: Number): Mflpt5 { fun fromNumber(num: Number): Mflpt5 {
// see https://en.wikipedia.org/wiki/Microsoft_Binary_Format // see https://en.wikipedia.org/wiki/Microsoft_Binary_Format
@ -232,7 +244,6 @@ object MachineDefinition {
return bcopy return bcopy
} }
val colorPalette = listOf( // this is Pepto's Commodore-64 palette http://www.pepto.de/projects/colorvic/ val colorPalette = listOf( // this is Pepto's Commodore-64 palette http://www.pepto.de/projects/colorvic/
Color(0x000000), // 0 = black Color(0x000000), // 0 = black
Color(0xFFFFFF), // 1 = white Color(0xFFFFFF), // 1 = white

View File

@ -7,10 +7,12 @@ import prog8.ast.base.*
import prog8.ast.expressions.* import prog8.ast.expressions.*
import prog8.ast.statements.* import prog8.ast.statements.*
import prog8.compiler.* import prog8.compiler.*
import prog8.compiler.target.IAssemblyGenerator
import prog8.compiler.target.IAssemblyProgram
import prog8.compiler.target.c64.AssemblyProgram import prog8.compiler.target.c64.AssemblyProgram
import prog8.compiler.target.c64.MachineDefinition import prog8.compiler.target.c64.C64MachineDefinition
import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_HEX import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_LO_HEX
import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_HEX import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_HI_HEX
import prog8.compiler.target.c64.Petscii import prog8.compiler.target.c64.Petscii
import prog8.functions.BuiltinFunctions import prog8.functions.BuiltinFunctions
import prog8.functions.FunctionSignature import prog8.functions.FunctionSignature
@ -22,13 +24,10 @@ import java.util.ArrayDeque
import kotlin.math.absoluteValue import kotlin.math.absoluteValue
internal class AssemblyError(msg: String) : RuntimeException(msg)
internal class AsmGen(private val program: Program, internal class AsmGen(private val program: Program,
private val zeropage: Zeropage, private val zeropage: Zeropage,
private val options: CompilationOptions, private val options: CompilationOptions,
private val outputDir: Path) { private val outputDir: Path): IAssemblyGenerator {
private val assemblyLines = mutableListOf<String>() private val assemblyLines = mutableListOf<String>()
private val globalFloatConsts = mutableMapOf<Double, String>() // all float values in the entire program (value -> varname) private val globalFloatConsts = mutableMapOf<Double, String>() // all float values in the entire program (value -> varname)
@ -43,7 +42,7 @@ internal class AsmGen(private val program: Program,
internal val loopEndLabels = ArrayDeque<String>() internal val loopEndLabels = ArrayDeque<String>()
internal val loopContinueLabels = ArrayDeque<String>() internal val loopContinueLabels = ArrayDeque<String>()
internal fun compileToAssembly(optimize: Boolean): AssemblyProgram { override fun compileToAssembly(optimize: Boolean): IAssemblyProgram {
assemblyLines.clear() assemblyLines.clear()
loopEndLabels.clear() loopEndLabels.clear()
loopContinueLabels.clear() loopContinueLabels.clear()
@ -84,7 +83,7 @@ internal class AsmGen(private val program: Program,
program.actualLoadAddress = program.definedLoadAddress program.actualLoadAddress = program.definedLoadAddress
if (program.actualLoadAddress == 0) // fix load address if (program.actualLoadAddress == 0) // fix load address
program.actualLoadAddress = if (options.launcher == LauncherType.BASIC) 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 { when {
options.launcher == LauncherType.BASIC -> { 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 // the global list of all floating point constants for the whole program
out("; global float constants") out("; global float constants")
for (flt in globalFloatConsts) { for (flt in globalFloatConsts) {
val mflpt5 = MachineDefinition.Mflpt5.fromNumber(flt.key) val mflpt5 = C64MachineDefinition.Mflpt5.fromNumber(flt.key)
val floatFill = makeFloatFill(mflpt5) val floatFill = makeFloatFill(mflpt5)
val floatvalue = flt.key val floatvalue = flt.key
out("${flt.value}\t.byte $floatFill ; float $floatvalue") out("${flt.value}\t.byte $floatFill ; float $floatvalue")
@ -198,7 +197,7 @@ internal class AsmGen(private val program: Program,
} else assemblyLines.add(fragment) } 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 b0 = "$" + flt.b0.toString(16).padStart(2, '0')
val b1 = "$" + flt.b1.toString(16).padStart(2, '0') val b1 = "$" + flt.b1.toString(16).padStart(2, '0')
val b2 = "$" + flt.b2.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 array = (decl.value as ArrayLiteralValue).value
val floatFills = array.map { val floatFills = array.map {
val number = (it as NumericLiteralValue).number val number = (it as NumericLiteralValue).number
makeFloatFill(MachineDefinition.Mflpt5.fromNumber(number)) makeFloatFill(C64MachineDefinition.Mflpt5.fromNumber(number))
} }
out(decl.name) out(decl.name)
for (f in array.zip(floatFills)) for (f in array.zip(floatFills))
@ -425,7 +424,7 @@ internal class AsmGen(private val program: Program,
internal fun getFloatConst(number: Double): String { internal fun getFloatConst(number: Double): String {
// try to match the ROM float constants to save memory // 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) val floatbytes = shortArrayOf(mflpt5.b0, mflpt5.b1, mflpt5.b2, mflpt5.b3, mflpt5.b4)
when { when {
floatbytes.contentEquals(shortArrayOf(0x00, 0x00, 0x00, 0x00, 0x00)) -> return "c64flt.FL_ZERO" floatbytes.contentEquals(shortArrayOf(0x00, 0x00, 0x00, 0x00, 0x00)) -> return "c64flt.FL_ZERO"

View File

@ -1,7 +1,7 @@
package prog8.compiler.target.c64.codegen package prog8.compiler.target.c64.codegen
import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_HEX import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_LO_HEX
import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_PLUS1_HEX import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_LO_PLUS1_HEX
// note: see https://wiki.nesdev.com/w/index.php/6502_assembly_optimisations // note: see https://wiki.nesdev.com/w/index.php/6502_assembly_optimisations

View File

@ -7,8 +7,13 @@ import prog8.ast.statements.AssignTarget
import prog8.ast.statements.Assignment import prog8.ast.statements.Assignment
import prog8.ast.statements.DirectMemoryWrite import prog8.ast.statements.DirectMemoryWrite
import prog8.ast.statements.VarDecl import prog8.ast.statements.VarDecl
import prog8.compiler.target.c64.MachineDefinition
import prog8.compiler.toHex 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) { 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() val indexValue = index.number.toInt() * ArrayElementTypes.getValue(arrayDt).memorySize()
when (arrayDt) { when (arrayDt) {
DataType.STR, DataType.STR_S, DataType.ARRAY_UB, DataType.ARRAY_B -> 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 -> 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 -> DataType.ARRAY_F ->
asmgen.out(" lda #<$arrayVarName+$indexValue | ldy #>$arrayVarName+$indexValue | jsr c64flt.push_float") asmgen.out(" lda #<$arrayVarName+$indexValue | ldy #>$arrayVarName+$indexValue | jsr c64flt.push_float")
else -> else ->
@ -124,21 +129,21 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
target.register!=null -> { target.register!=null -> {
if(target.register== Register.X) if(target.register== Register.X)
throw AssemblyError("can't pop into X register - use variable instead") 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 -> { targetIdent!=null -> {
val targetName = asmgen.asmIdentifierName(targetIdent) val targetName = asmgen.asmIdentifierName(targetIdent)
val targetDt = targetIdent.inferType(program).typeOrElse(DataType.STRUCT) val targetDt = targetIdent.inferType(program).typeOrElse(DataType.STRUCT)
when(targetDt) { when(targetDt) {
DataType.UBYTE, DataType.BYTE -> { 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 -> { DataType.UWORD, DataType.WORD -> {
asmgen.out(""" asmgen.out("""
inx inx
lda ${MachineDefinition.ESTACK_LO_HEX},x lda $ESTACK_LO_HEX,x
sta $targetName sta $targetName
lda ${MachineDefinition.ESTACK_HI_HEX},x lda $ESTACK_HI_HEX,x
sta $targetName+1 sta $targetName+1
""") """)
} }
@ -153,14 +158,14 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
} }
} }
target.memoryAddress!=null -> { 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) storeRegisterInMemoryAddress(Register.Y, target.memoryAddress)
} }
target.arrayindexed!=null -> { target.arrayindexed!=null -> {
val arrayDt = target.arrayindexed!!.identifier.targetVarDecl(program.namespace)!!.datatype val arrayDt = target.arrayindexed!!.identifier.targetVarDecl(program.namespace)!!.datatype
val arrayVarName = asmgen.asmIdentifierName(target.arrayindexed!!.identifier) val arrayVarName = asmgen.asmIdentifierName(target.arrayindexed!!.identifier)
asmgen.translateExpression(target.arrayindexed!!.arrayspec.index) 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) popAndWriteArrayvalueWithIndexA(arrayDt, arrayVarName)
} }
else -> throw AssemblyError("weird assignment target $target") else -> throw AssemblyError("weird assignment target $target")
@ -225,9 +230,9 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
targetArrayIdx!=null -> { targetArrayIdx!=null -> {
val index = targetArrayIdx.arrayspec.index val index = targetArrayIdx.arrayspec.index
val targetName = asmgen.asmIdentifierName(targetArrayIdx.identifier) 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.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) val arrayDt = targetArrayIdx.identifier.inferType(program).typeOrElse(DataType.STRUCT)
popAndWriteArrayvalueWithIndexA(arrayDt, targetName) popAndWriteArrayvalueWithIndexA(arrayDt, targetName)
} }
@ -285,9 +290,9 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
val index = targetArrayIdx.arrayspec.index val index = targetArrayIdx.arrayspec.index
val targetName = asmgen.asmIdentifierName(targetArrayIdx.identifier) val targetName = asmgen.asmIdentifierName(targetArrayIdx.identifier)
val arrayDt = targetArrayIdx.identifier.inferType(program).typeOrElse(DataType.STRUCT) 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.translateExpression(index)
asmgen.out(" inx | lda ${MachineDefinition.ESTACK_LO_HEX},x") asmgen.out(" inx | lda $ESTACK_LO_HEX,x")
popAndWriteArrayvalueWithIndexA(arrayDt, targetName) popAndWriteArrayvalueWithIndexA(arrayDt, targetName)
} }
target.memoryAddress != null -> { target.memoryAddress != null -> {
@ -303,8 +308,8 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
asmgen.translateExpression(addressExpr) asmgen.translateExpression(addressExpr)
asmgen.out(""" asmgen.out("""
inx inx
lda ${MachineDefinition.ESTACK_LO_HEX},x lda $ESTACK_LO_HEX,x
ldy ${MachineDefinition.ESTACK_HI_HEX},x ldy $ESTACK_HI_HEX,x
sta (+) +1 sta (+) +1
sty (+) +2 sty (+) +2
lda $sourceName lda $sourceName
@ -361,9 +366,9 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
} }
is RegisterExpr -> { is RegisterExpr -> {
when(register) { when(register) {
Register.A -> asmgen.out(" sta ${MachineDefinition.C64Zeropage.SCRATCH_B1}") Register.A -> asmgen.out(" sta ${C64Zeropage.SCRATCH_B1}")
Register.X -> asmgen.out(" stx ${MachineDefinition.C64Zeropage.SCRATCH_B1}") Register.X -> asmgen.out(" stx ${C64Zeropage.SCRATCH_B1}")
Register.Y -> asmgen.out(" sty ${MachineDefinition.C64Zeropage.SCRATCH_B1}") Register.Y -> asmgen.out(" sty ${C64Zeropage.SCRATCH_B1}")
} }
when(index.register) { when(index.register) {
Register.A -> {} Register.A -> {}
@ -372,20 +377,20 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
} }
asmgen.out(""" asmgen.out("""
tay tay
lda ${MachineDefinition.C64Zeropage.SCRATCH_B1} lda ${C64Zeropage.SCRATCH_B1}
sta $targetName,y sta $targetName,y
""") """)
} }
is IdentifierReference -> { is IdentifierReference -> {
when(register) { when(register) {
Register.A -> asmgen.out(" sta ${MachineDefinition.C64Zeropage.SCRATCH_B1}") Register.A -> asmgen.out(" sta ${C64Zeropage.SCRATCH_B1}")
Register.X -> asmgen.out(" stx ${MachineDefinition.C64Zeropage.SCRATCH_B1}") Register.X -> asmgen.out(" stx ${C64Zeropage.SCRATCH_B1}")
Register.Y -> asmgen.out(" sty ${MachineDefinition.C64Zeropage.SCRATCH_B1}") Register.Y -> asmgen.out(" sty ${C64Zeropage.SCRATCH_B1}")
} }
asmgen.out(""" asmgen.out("""
lda ${asmgen.asmIdentifierName(index)} lda ${asmgen.asmIdentifierName(index)}
tay tay
lda ${MachineDefinition.C64Zeropage.SCRATCH_B1} lda ${C64Zeropage.SCRATCH_B1}
sta $targetName,y sta $targetName,y
""") """)
} }
@ -394,15 +399,15 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
asmgen.translateExpression(index) asmgen.translateExpression(index)
asmgen.restoreRegister(register) asmgen.restoreRegister(register)
when(register) { when(register) {
Register.A -> asmgen.out(" sta ${MachineDefinition.C64Zeropage.SCRATCH_B1}") Register.A -> asmgen.out(" sta ${C64Zeropage.SCRATCH_B1}")
Register.X -> asmgen.out(" stx ${MachineDefinition.C64Zeropage.SCRATCH_B1}") Register.X -> asmgen.out(" stx ${C64Zeropage.SCRATCH_B1}")
Register.Y -> asmgen.out(" sty ${MachineDefinition.C64Zeropage.SCRATCH_B1}") Register.Y -> asmgen.out(" sty ${C64Zeropage.SCRATCH_B1}")
} }
asmgen.out(""" asmgen.out("""
inx inx
lda ${MachineDefinition.ESTACK_LO_HEX},x lda $ESTACK_LO_HEX,x
tay tay
lda ${MachineDefinition.C64Zeropage.SCRATCH_B1} lda ${C64Zeropage.SCRATCH_B1}
sta $targetName,y sta $targetName,y
""") """)
} }
@ -423,29 +428,29 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
when(register) { when(register) {
Register.A -> asmgen.out(""" Register.A -> asmgen.out("""
ldy $targetName ldy $targetName
sty ${MachineDefinition.C64Zeropage.SCRATCH_W1} sty ${C64Zeropage.SCRATCH_W1}
ldy $targetName+1 ldy $targetName+1
sty ${MachineDefinition.C64Zeropage.SCRATCH_W1+1} sty ${C64Zeropage.SCRATCH_W1+1}
ldy #0 ldy #0
sta (${MachineDefinition.C64Zeropage.SCRATCH_W1}),y sta (${C64Zeropage.SCRATCH_W1}),y
""") """)
Register.X -> asmgen.out(""" Register.X -> asmgen.out("""
txa txa
ldy $targetName ldy $targetName
sty ${MachineDefinition.C64Zeropage.SCRATCH_W1} sty ${C64Zeropage.SCRATCH_W1}
ldy $targetName+1 ldy $targetName+1
sty ${MachineDefinition.C64Zeropage.SCRATCH_W1+1} sty ${C64Zeropage.SCRATCH_W1+1}
ldy #0 ldy #0
sta (${MachineDefinition.C64Zeropage.SCRATCH_W1}),y sta (${C64Zeropage.SCRATCH_W1}),y
""") """)
Register.Y -> asmgen.out(""" Register.Y -> asmgen.out("""
tya tya
ldy $targetName ldy $targetName
sty ${MachineDefinition.C64Zeropage.SCRATCH_W1} sty ${C64Zeropage.SCRATCH_W1}
ldy $targetName+1 ldy $targetName+1
sty ${MachineDefinition.C64Zeropage.SCRATCH_W1+1} sty ${C64Zeropage.SCRATCH_W1+1}
ldy #0 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(""" asmgen.out("""
inx inx
lda ${MachineDefinition.ESTACK_LO_HEX},x lda $ESTACK_LO_HEX,x
sta (+) +1 sta (+) +1
lda ${MachineDefinition.ESTACK_HI_HEX},x lda $ESTACK_HI_HEX,x
sta (+) +2 sta (+) +2
+ sty ${65535.toHex()} ; modified + sty ${65535.toHex()} ; modified
""") """)
@ -502,7 +507,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
asmgen.translateExpression(index) asmgen.translateExpression(index)
asmgen.out(""" asmgen.out("""
inx inx
lda ${MachineDefinition.ESTACK_LO_HEX},x lda $ESTACK_LO_HEX,x
asl a asl a
tay tay
lda #<${word.toHex()} lda #<${word.toHex()}
@ -537,7 +542,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
asmgen.translateExpression(index) asmgen.translateExpression(index)
asmgen.out(""" asmgen.out("""
inx inx
ldy ${MachineDefinition.ESTACK_LO_HEX},x ldy $ESTACK_LO_HEX,x
lda #${byte.toHex()} lda #${byte.toHex()}
sta $targetName,y sta $targetName,y
""") """)
@ -567,7 +572,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
val index = targetArrayIdx.arrayspec.index val index = targetArrayIdx.arrayspec.index
val targetName = asmgen.asmIdentifierName(targetArrayIdx.identifier) val targetName = asmgen.asmIdentifierName(targetArrayIdx.identifier)
if(index is NumericLiteralValue) { if(index is NumericLiteralValue) {
val indexValue = index.number.toInt() * MachineDefinition.Mflpt5.MemorySize val indexValue = index.number.toInt() * C64MachineDefinition.FLOAT_MEM_SIZE
asmgen.out(""" asmgen.out("""
lda #0 lda #0
sta $targetName+$indexValue sta $targetName+$indexValue
@ -580,11 +585,11 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
asmgen.translateExpression(index) asmgen.translateExpression(index)
asmgen.out(""" asmgen.out("""
inx inx
lda ${MachineDefinition.ESTACK_LO_HEX},x lda $ESTACK_LO_HEX,x
asl a asl a
asl a asl a
clc clc
adc ${MachineDefinition.ESTACK_LO_HEX},x adc $ESTACK_LO_HEX,x
tay tay
lda #0 lda #0
sta $targetName,y sta $targetName,y
@ -620,7 +625,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
val index = targetArrayIdx.arrayspec.index val index = targetArrayIdx.arrayspec.index
val arrayVarName = asmgen.asmIdentifierName(targetArrayIdx.identifier) val arrayVarName = asmgen.asmIdentifierName(targetArrayIdx.identifier)
if(index is NumericLiteralValue) { if(index is NumericLiteralValue) {
val indexValue = index.number.toInt() * MachineDefinition.Mflpt5.MemorySize val indexValue = index.number.toInt() * C64MachineDefinition.FLOAT_MEM_SIZE
asmgen.out(""" asmgen.out("""
lda $constFloat lda $constFloat
sta $arrayVarName+$indexValue sta $arrayVarName+$indexValue
@ -636,11 +641,11 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
} else { } else {
asmgen.translateArrayIndexIntoA(targetArrayIdx) asmgen.translateArrayIndexIntoA(targetArrayIdx)
asmgen.out(""" asmgen.out("""
sta ${MachineDefinition.C64Zeropage.SCRATCH_REG} sta ${C64Zeropage.SCRATCH_REG}
asl a asl a
asl a asl a
clc clc
adc ${MachineDefinition.C64Zeropage.SCRATCH_REG} adc ${C64Zeropage.SCRATCH_REG}
tay tay
lda $constFloat lda $constFloat
sta $arrayVarName,y sta $arrayVarName,y
@ -726,13 +731,13 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
private fun popAndWriteArrayvalueWithIndexA(arrayDt: DataType, variablename: String) { private fun popAndWriteArrayvalueWithIndexA(arrayDt: DataType, variablename: String) {
when (arrayDt) { when (arrayDt) {
DataType.STR, DataType.STR_S, DataType.ARRAY_UB, DataType.ARRAY_B -> 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 -> 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 -> DataType.ARRAY_F ->
// index * 5 is done in the subroutine that's called // index * 5 is done in the subroutine that's called
asmgen.out(""" asmgen.out("""
sta ${MachineDefinition.ESTACK_LO_HEX},x sta $ESTACK_LO_HEX,x
dex dex
lda #<$variablename lda #<$variablename
ldy #>$variablename ldy #>$variablename

View File

@ -9,12 +9,13 @@ import prog8.ast.base.WordDatatypes
import prog8.ast.expressions.* import prog8.ast.expressions.*
import prog8.ast.statements.AssignTarget import prog8.ast.statements.AssignTarget
import prog8.ast.statements.FunctionCallStatement import prog8.ast.statements.FunctionCallStatement
import prog8.compiler.target.c64.MachineDefinition.C64Zeropage import prog8.compiler.target.c64.C64MachineDefinition.C64Zeropage
import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_HEX import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_HI_HEX
import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_PLUS1_HEX import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_HI_PLUS1_HEX
import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_HEX import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_LO_HEX
import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_PLUS1_HEX import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_LO_PLUS1_HEX
import prog8.compiler.toHex import prog8.compiler.toHex
import prog8.compiler.AssemblyError
import prog8.functions.FunctionSignature import prog8.functions.FunctionSignature
internal class BuiltinFunctionsAsmGen(private val program: Program, private val asmgen: AsmGen) { internal class BuiltinFunctionsAsmGen(private val program: Program, private val asmgen: AsmGen) {

View File

@ -3,8 +3,13 @@ package prog8.compiler.target.c64.codegen
import prog8.ast.Program import prog8.ast.Program
import prog8.ast.base.* import prog8.ast.base.*
import prog8.ast.expressions.* import prog8.ast.expressions.*
import prog8.compiler.target.c64.MachineDefinition
import prog8.compiler.toHex 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 prog8.functions.BuiltinFunctions
import kotlin.math.absoluteValue 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 // result value in cpu or status registers, put it on the stack
if (reg.registerOrPair != null) { if (reg.registerOrPair != null) {
when (reg.registerOrPair) { when (reg.registerOrPair) {
RegisterOrPair.A -> asmgen.out(" sta ${MachineDefinition.ESTACK_LO_HEX},x | dex") RegisterOrPair.A -> asmgen.out(" sta $ESTACK_LO_HEX,x | dex")
RegisterOrPair.Y -> asmgen.out(" tya | sta ${MachineDefinition.ESTACK_LO_HEX},x | dex") RegisterOrPair.Y -> asmgen.out(" tya | sta $ESTACK_LO_HEX,x | dex")
RegisterOrPair.AY -> asmgen.out(" sta ${MachineDefinition.ESTACK_LO_HEX},x | tya | sta ${MachineDefinition.ESTACK_HI_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") 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 -> { DataType.UBYTE -> {
when(expr.type) { when(expr.type) {
DataType.UBYTE, DataType.BYTE -> {} 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") DataType.FLOAT -> asmgen.out(" jsr c64flt.stack_ub2float")
in PassByReferenceDatatypes -> throw AssemblyError("cannot cast to a pass-by-reference datatype") in PassByReferenceDatatypes -> throw AssemblyError("cannot cast to a pass-by-reference datatype")
else -> throw AssemblyError("weird type") else -> throw AssemblyError("weird type")
@ -69,7 +74,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
DataType.BYTE -> { DataType.BYTE -> {
when(expr.type) { when(expr.type) {
DataType.UBYTE, DataType.BYTE -> {} 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") DataType.FLOAT -> asmgen.out(" jsr c64flt.stack_b2float")
in PassByReferenceDatatypes -> throw AssemblyError("cannot cast to a pass-by-reference datatype") in PassByReferenceDatatypes -> throw AssemblyError("cannot cast to a pass-by-reference datatype")
else -> throw AssemblyError("weird type") else -> throw AssemblyError("weird type")
@ -111,35 +116,35 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
private fun translateExpression(expr: AddressOf) { private fun translateExpression(expr: AddressOf) {
val name = asmgen.asmIdentifierName(expr.identifier) 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) { private fun translateExpression(expr: DirectMemoryRead) {
when(expr.addressExpression) { when(expr.addressExpression) {
is NumericLiteralValue -> { is NumericLiteralValue -> {
val address = (expr.addressExpression as NumericLiteralValue).number.toInt() 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 -> { is IdentifierReference -> {
val sourceName = asmgen.asmIdentifierName(expr.addressExpression as 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 -> { else -> {
translateExpression(expr.addressExpression) translateExpression(expr.addressExpression)
asmgen.out(" jsr prog8_lib.read_byte_from_address") 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) { private fun translateExpression(expr: NumericLiteralValue) {
when(expr.type) { 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(""" DataType.UWORD, DataType.WORD -> asmgen.out("""
lda #<${expr.number.toHex()} lda #<${expr.number.toHex()}
sta ${MachineDefinition.ESTACK_LO_HEX},x sta $ESTACK_LO_HEX,x
lda #>${expr.number.toHex()} lda #>${expr.number.toHex()}
sta ${MachineDefinition.ESTACK_HI_HEX},x sta $ESTACK_HI_HEX,x
dex dex
""") """)
DataType.FLOAT -> { DataType.FLOAT -> {
@ -152,9 +157,9 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
private fun translateExpression(expr: RegisterExpr) { private fun translateExpression(expr: RegisterExpr) {
when(expr.register) { 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.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) val varname = asmgen.asmIdentifierName(expr)
when(expr.inferType(program).typeOrElse(DataType.STRUCT)) { when(expr.inferType(program).typeOrElse(DataType.STRUCT)) {
DataType.UBYTE, DataType.BYTE -> { 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 -> { 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 -> { 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 -> { DataType.FLOAT -> {
asmgen.out(" lda #<$varname | ldy #>$varname| jsr c64flt.push_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) translateExpression(expr.left)
val amount = expr.right.constValue(program)!!.number.toInt() val amount = expr.right.constValue(program)!!.number.toInt()
when (leftDt) { when (leftDt) {
DataType.UBYTE -> repeat(amount) { asmgen.out(" lsr ${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 ${MachineDefinition.ESTACK_LO_PLUS1_HEX},x | asl a | ror ${MachineDefinition.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 ${MachineDefinition.ESTACK_HI_PLUS1_HEX},x | ror ${MachineDefinition.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 ${MachineDefinition.ESTACK_HI_PLUS1_HEX},x | asl a | ror ${MachineDefinition.ESTACK_HI_PLUS1_HEX},x | ror ${MachineDefinition.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") else -> throw AssemblyError("weird type")
} }
return return
@ -209,9 +214,9 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
translateExpression(expr.left) translateExpression(expr.left)
val amount = expr.right.constValue(program)!!.number.toInt() val amount = expr.right.constValue(program)!!.number.toInt()
if (leftDt in ByteDatatypes) 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 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 return
} }
"*" -> { "*" -> {
@ -297,9 +302,9 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
when(type) { when(type) {
in ByteDatatypes -> in ByteDatatypes ->
asmgen.out(""" asmgen.out("""
lda ${MachineDefinition.ESTACK_LO_PLUS1_HEX},x lda $ESTACK_LO_PLUS1_HEX,x
eor #255 eor #255
sta ${MachineDefinition.ESTACK_LO_PLUS1_HEX},x sta $ESTACK_LO_PLUS1_HEX,x
""") """)
in WordDatatypes -> asmgen.out(" jsr prog8_lib.inv_word") in WordDatatypes -> asmgen.out(" jsr prog8_lib.inv_word")
else -> throw AssemblyError("weird type") 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() val indexValue = index.number.toInt() * elementDt.memorySize()
when(elementDt) { when(elementDt) {
in ByteDatatypes -> { 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 -> { 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 -> { DataType.FLOAT -> {
asmgen.out(" lda #<$arrayVarName+$indexValue | ldy #>$arrayVarName+$indexValue | jsr c64flt.push_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(" jsr prog8_lib.remainder_ub")
} }
"+" -> asmgen.out(""" "+" -> asmgen.out("""
lda ${MachineDefinition.ESTACK_LO_PLUS2_HEX},x lda $ESTACK_LO_PLUS2_HEX,x
clc clc
adc ${MachineDefinition.ESTACK_LO_PLUS1_HEX},x adc $ESTACK_LO_PLUS1_HEX,x
inx inx
sta ${MachineDefinition.ESTACK_LO_PLUS1_HEX},x sta $ESTACK_LO_PLUS1_HEX,x
""") """)
"-" -> asmgen.out(""" "-" -> asmgen.out("""
lda ${MachineDefinition.ESTACK_LO_PLUS2_HEX},x lda $ESTACK_LO_PLUS2_HEX,x
sec sec
sbc ${MachineDefinition.ESTACK_LO_PLUS1_HEX},x sbc $ESTACK_LO_PLUS1_HEX,x
inx inx
sta ${MachineDefinition.ESTACK_LO_PLUS1_HEX},x sta $ESTACK_LO_PLUS1_HEX,x
""") """)
"<<", ">>" -> throw AssemblyError("bit-shifts not via stack") "<<", ">>" -> throw AssemblyError("bit-shifts not via stack")
"<" -> asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.less_ub" else " jsr prog8_lib.less_b") "<" -> asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.less_ub" else " jsr prog8_lib.less_b")

View File

@ -8,10 +8,11 @@ import prog8.ast.expressions.RangeExpr
import prog8.ast.statements.AssignTarget import prog8.ast.statements.AssignTarget
import prog8.ast.statements.Assignment import prog8.ast.statements.Assignment
import prog8.ast.statements.ForLoop import prog8.ast.statements.ForLoop
import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_HEX import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_LO_HEX
import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_PLUS1_HEX import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_LO_PLUS1_HEX
import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_PLUS1_HEX import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_HI_PLUS1_HEX
import prog8.compiler.toHex import prog8.compiler.toHex
import prog8.compiler.AssemblyError
import kotlin.math.absoluteValue import kotlin.math.absoluteValue
// todo choose more efficient comparisons to avoid needless lda's // todo choose more efficient comparisons to avoid needless lda's

View File

@ -7,8 +7,11 @@ import prog8.ast.expressions.*
import prog8.ast.statements.AssignTarget import prog8.ast.statements.AssignTarget
import prog8.ast.statements.Subroutine import prog8.ast.statements.Subroutine
import prog8.ast.statements.SubroutineParameter import prog8.ast.statements.SubroutineParameter
import prog8.compiler.target.c64.MachineDefinition
import prog8.compiler.toHex 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) { 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.translateExpression(value)
asmgen.out(""" asmgen.out("""
inx inx
lda ${MachineDefinition.ESTACK_LO_HEX},x lda $ESTACK_LO_HEX,x
beq + beq +
sec sec
bcs ++ bcs ++
@ -166,9 +169,9 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
else -> { else -> {
asmgen.translateExpression(value) asmgen.translateExpression(value)
when(register) { 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.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") 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) if (register == RegisterOrPair.AX || register == RegisterOrPair.XY)
throw AssemblyError("can't use X register here - use a variable") throw AssemblyError("can't use X register here - use a variable")
else if (register == RegisterOrPair.AY) 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")
} }
} }
} }

View File

@ -6,8 +6,10 @@ import prog8.ast.expressions.IdentifierReference
import prog8.ast.expressions.NumericLiteralValue import prog8.ast.expressions.NumericLiteralValue
import prog8.ast.expressions.RegisterExpr import prog8.ast.expressions.RegisterExpr
import prog8.ast.statements.PostIncrDecr import prog8.ast.statements.PostIncrDecr
import prog8.compiler.target.c64.MachineDefinition
import prog8.compiler.toHex 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 class PostIncrDecrAsmGen(private val program: Program, private val asmgen: AsmGen) {
internal fun translate(stmt: PostIncrDecr) { 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) { 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) { when(arrayDt) {
DataType.STR, DataType.STR_S, DataType.STR, DataType.STR_S,
DataType.ARRAY_UB, DataType.ARRAY_B -> { 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") else -> throw AssemblyError("weird array dt")
} }
asmgen.out(" ldx ${MachineDefinition.C64Zeropage.SCRATCH_REG_X}") asmgen.out(" ldx ${C64Zeropage.SCRATCH_REG_X}")
} }
} }

View File

@ -7,9 +7,7 @@ import prog8.ast.expressions.*
import prog8.ast.processing.IAstModifyingVisitor import prog8.ast.processing.IAstModifyingVisitor
import prog8.ast.processing.fixupArrayDatatype import prog8.ast.processing.fixupArrayDatatype
import prog8.ast.statements.* import prog8.ast.statements.*
import prog8.compiler.target.c64.MachineDefinition.FLOAT_MAX_NEGATIVE import prog8.compiler.target.CompilationTarget
import prog8.compiler.target.c64.MachineDefinition.FLOAT_MAX_POSITIVE
import prog8.compiler.target.c64.codegen.AssemblyError
import prog8.functions.BuiltinFunctions import prog8.functions.BuiltinFunctions
import kotlin.math.floor import kotlin.math.floor
@ -140,7 +138,7 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
} else { } else {
// arraysize initializer is a single int, and we know the size. // arraysize initializer is a single int, and we know the size.
val fillvalue = litval.number.toDouble() 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)) errors.add(ExpressionError("float value overflow", litval.position))
else { else {
// create the array itself, filled with the fillvalue. // create the array itself, filled with the fillvalue.
@ -184,7 +182,7 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
copy.parent = identifier.parent copy.parent = identifier.parent
copy 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 else -> identifier
} }
} catch (ax: AstException) { } catch (ax: AstException) {

View File

@ -9,8 +9,7 @@ import prog8.ast.expressions.*
import prog8.ast.processing.IAstModifyingVisitor import prog8.ast.processing.IAstModifyingVisitor
import prog8.ast.processing.IAstVisitor import prog8.ast.processing.IAstVisitor
import prog8.ast.statements.* import prog8.ast.statements.*
import prog8.compiler.target.c64.Petscii import prog8.compiler.target.CompilationTarget
import prog8.compiler.target.c64.codegen.AssemblyError
import prog8.functions.BuiltinFunctions import prog8.functions.BuiltinFunctions
import kotlin.math.floor import kotlin.math.floor
@ -180,7 +179,7 @@ internal class StatementOptimizer(private val program: Program) : IAstModifyingV
if(stringVar!=null) { if(stringVar!=null) {
val vardecl = stringVar.targetVarDecl(program.namespace)!! val vardecl = stringVar.targetVarDecl(program.namespace)!!
val string = vardecl.value!! as StringLiteralValue val string = vardecl.value!! as StringLiteralValue
val encodedString = Petscii.encodePetscii(string.value, true) val encodedString = CompilationTarget.encodeString(string.value)
if(string.value.length==1) { if(string.value.length==1) {
functionCallStatement.arglist.clear() functionCallStatement.arglist.clear()
functionCallStatement.arglist.add(NumericLiteralValue.optimalInteger(encodedString[0].toInt(), functionCallStatement.position)) 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) val targetIDt = assignment.target.inferType(program, assignment)
if(!targetIDt.isKnown) 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 targetDt = targetIDt.typeOrElse(DataType.STRUCT)
val bexpr=assignment.value as? BinaryExpression val bexpr=assignment.value as? BinaryExpression
if(bexpr!=null) { if(bexpr!=null) {

View File

@ -6,7 +6,7 @@ import prog8.ast.base.WordDatatypes
import prog8.ast.expressions.ArrayLiteralValue import prog8.ast.expressions.ArrayLiteralValue
import prog8.ast.expressions.NumericLiteralValue import prog8.ast.expressions.NumericLiteralValue
import prog8.ast.expressions.StringLiteralValue import prog8.ast.expressions.StringLiteralValue
import prog8.compiler.target.c64.Petscii import prog8.compiler.target.CompilationTarget
import prog8.vm.astvm.VmExecutionException import prog8.vm.astvm.VmExecutionException
import java.util.Objects import java.util.Objects
import kotlin.math.abs 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 return type == other.type && str == other.str
} }
fun iterator(): Iterator<Number> = Petscii.encodePetscii(str, true).iterator() fun iterator(): Iterator<Number> = CompilationTarget.encodeString(str).iterator()
override fun numericValue(): Number { override fun numericValue(): Number {
throw VmExecutionException("string is not a number") throw VmExecutionException("string is not a number")

View File

@ -7,7 +7,7 @@ import prog8.ast.expressions.Expression
import prog8.ast.expressions.IdentifierReference import prog8.ast.expressions.IdentifierReference
import prog8.ast.expressions.NumericLiteralValue import prog8.ast.expressions.NumericLiteralValue
import prog8.ast.statements.* import prog8.ast.statements.*
import prog8.compiler.target.c64.MachineDefinition import prog8.compiler.target.c64.C64MachineDefinition
import prog8.compiler.target.c64.Petscii import prog8.compiler.target.c64.Petscii
import prog8.vm.* import prog8.vm.*
import java.awt.EventQueue 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 mem = Memory(::memread, ::memwrite)
val statusflags = StatusFlags() val statusflags = StatusFlags()
@ -147,6 +147,8 @@ class AstVm(val program: Program) {
init { init {
require(compilationTarget == "c64") {"using the AstVm only works for the C64 compiler target"}
// observe the jiffyclock and screen matrix // observe the jiffyclock and screen matrix
mem.observe(0xa0, 0xa1, 0xa2) mem.observe(0xa0, 0xa1, 0xa2)
for(i in 1024..2023) for(i in 1024..2023)
@ -643,7 +645,7 @@ class AstVm(val program: Program) {
DataType.BYTE -> mem.setSByte(address+index, value.byteval!!) DataType.BYTE -> mem.setSByte(address+index, value.byteval!!)
DataType.UWORD -> mem.setUWord(address+index*2, value.wordval!!) DataType.UWORD -> mem.setUWord(address+index*2, value.wordval!!)
DataType.WORD -> mem.setSWord(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") else -> throw VmExecutionException("strange array elt type $elementType")
} }
} }

View File

@ -1,6 +1,6 @@
package prog8.vm.astvm package prog8.vm.astvm
import prog8.compiler.target.c64.MachineDefinition import prog8.compiler.target.c64.C64MachineDefinition
import prog8.compiler.target.c64.Petscii import prog8.compiler.target.c64.Petscii
import kotlin.math.abs import kotlin.math.abs
@ -80,7 +80,7 @@ class Memory(private val readObserver: (address: Int, value: Short) -> Short,
} }
fun setFloat(address: Int, value: Double) { fun setFloat(address: Int, value: Double) {
val mflpt5 = MachineDefinition.Mflpt5.fromNumber(value) val mflpt5 = C64MachineDefinition.Mflpt5.fromNumber(value)
setUByte(address, mflpt5.b0) setUByte(address, mflpt5.b0)
setUByte(address+1, mflpt5.b1) setUByte(address+1, mflpt5.b1)
setUByte(address+2, mflpt5.b2) setUByte(address+2, mflpt5.b2)
@ -89,7 +89,7 @@ class Memory(private val readObserver: (address: Int, value: Short) -> Short,
} }
fun getFloat(address: Int): Double { 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() getUByte(address + 3), getUByte(address + 4)).toDouble()
} }

View File

@ -1,6 +1,6 @@
package prog8.vm.astvm package prog8.vm.astvm
import prog8.compiler.target.c64.MachineDefinition import prog8.compiler.target.c64.C64MachineDefinition
import prog8.compiler.target.c64.Petscii import prog8.compiler.target.c64.Petscii
import java.awt.* import java.awt.*
import java.awt.event.KeyEvent import java.awt.event.KeyEvent
@ -50,16 +50,16 @@ class BitmapScreenPanel : KeyListener, JPanel() {
} }
fun clearScreen(color: Short) { 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) g2d.clearRect(0, 0, SCREENWIDTH, SCREENHEIGHT)
cursorX = 0 cursorX = 0
cursorY = 0 cursorY = 0
} }
fun setPixel(x: Int, y: Int, color: Short) { 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) { 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) g2d.drawLine(x1, y1, x2, y2)
} }
@ -98,7 +98,7 @@ class BitmapScreenPanel : KeyListener, JPanel() {
val graphics = image.graphics as Graphics2D val graphics = image.graphics as Graphics2D
graphics.drawImage(screen, 0, -8, null) graphics.drawImage(screen, 0, -8, null)
val color = graphics.color val color = graphics.color
graphics.color = MachineDefinition.colorPalette[6] graphics.color = C64MachineDefinition.colorPalette[6]
graphics.fillRect(0, 24*8, SCREENWIDTH, 25*8) graphics.fillRect(0, 24*8, SCREENWIDTH, 25*8)
graphics.color=color graphics.color=color
cursorY-- cursorY--
@ -106,7 +106,7 @@ class BitmapScreenPanel : KeyListener, JPanel() {
} }
fun writeTextAt(x: Int, y: Int, text: String, color: Short, lowercase: Boolean, inverseVideo: Boolean=false) { 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 var xx=x
for(clearx in xx until xx+text.length) { for(clearx in xx until xx+text.length) {
g2d.clearRect(8*clearx, 8*y, 8, 8) 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) { fun setPetscii(x: Int, y: Int, petscii: Short, color: Short, inverseVideo: Boolean) {
g2d.clearRect(8*x, 8*y, 8, 8) 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 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) g2d.drawImage(coloredImage, 8*x, 8*y , null)
} }
fun setChar(x: Int, y: Int, screencode: Short, color: Short) { fun setChar(x: Int, y: Int, screencode: Short, color: Short) {
g2d.clearRect(8*x, 8*y, 8, 8) g2d.clearRect(8*x, 8*y, 8, 8)
val colorIdx = (color % MachineDefinition.colorPalette.size).toShort() val colorIdx = (color % C64MachineDefinition.colorPalette.size).toShort()
val coloredImage = MachineDefinition.Charset.getColoredChar(screencode, colorIdx) val coloredImage = C64MachineDefinition.Charset.getColoredChar(screencode, colorIdx)
g2d.drawImage(coloredImage, 8*x, 8*y , null) g2d.drawImage(coloredImage, 8*x, 8*y , null)
} }
@ -163,19 +163,19 @@ class ScreenDialog(title: String) : JFrame(title) {
// the borders (top, left, right, bottom) // the borders (top, left, right, bottom)
val borderTop = JPanel().apply { val borderTop = JPanel().apply {
preferredSize = Dimension(BitmapScreenPanel.SCALING * (BitmapScreenPanel.SCREENWIDTH +2*borderWidth), BitmapScreenPanel.SCALING * borderWidth) preferredSize = Dimension(BitmapScreenPanel.SCALING * (BitmapScreenPanel.SCREENWIDTH +2*borderWidth), BitmapScreenPanel.SCALING * borderWidth)
background = MachineDefinition.colorPalette[14] background = C64MachineDefinition.colorPalette[14]
} }
val borderBottom = JPanel().apply { val borderBottom = JPanel().apply {
preferredSize =Dimension(BitmapScreenPanel.SCALING * (BitmapScreenPanel.SCREENWIDTH +2*borderWidth), BitmapScreenPanel.SCALING * borderWidth) preferredSize =Dimension(BitmapScreenPanel.SCALING * (BitmapScreenPanel.SCREENWIDTH +2*borderWidth), BitmapScreenPanel.SCALING * borderWidth)
background = MachineDefinition.colorPalette[14] background = C64MachineDefinition.colorPalette[14]
} }
val borderLeft = JPanel().apply { val borderLeft = JPanel().apply {
preferredSize =Dimension(BitmapScreenPanel.SCALING * borderWidth, BitmapScreenPanel.SCALING * BitmapScreenPanel.SCREENHEIGHT) preferredSize =Dimension(BitmapScreenPanel.SCALING * borderWidth, BitmapScreenPanel.SCALING * BitmapScreenPanel.SCREENHEIGHT)
background = MachineDefinition.colorPalette[14] background = C64MachineDefinition.colorPalette[14]
} }
val borderRight = JPanel().apply { val borderRight = JPanel().apply {
preferredSize =Dimension(BitmapScreenPanel.SCALING * borderWidth, BitmapScreenPanel.SCALING * BitmapScreenPanel.SCREENHEIGHT) preferredSize =Dimension(BitmapScreenPanel.SCALING * borderWidth, BitmapScreenPanel.SCALING * BitmapScreenPanel.SCREENHEIGHT)
background = MachineDefinition.colorPalette[14] background = C64MachineDefinition.colorPalette[14]
} }
var c = GridBagConstraints() var c = GridBagConstraints()
c.gridx=0; c.gridy=1; c.gridwidth=3 c.gridx=0; c.gridy=1; c.gridwidth=3

View File

@ -83,8 +83,8 @@ class TestParserNumericLiteralValue {
@Test @Test
fun testEqualsRef() { fun testEqualsRef() {
assertTrue(StringLiteralValue(DataType.STR, "hello", dummyPos) == StringLiteralValue(DataType.STR, "hello", dummyPos)) assertEquals(StringLiteralValue(DataType.STR, "hello", dummyPos), StringLiteralValue(DataType.STR, "hello", dummyPos))
assertFalse(StringLiteralValue(DataType.STR, "hello", dummyPos) == StringLiteralValue(DataType.STR, "bye", dummyPos)) assertNotEquals(StringLiteralValue(DataType.STR, "hello", dummyPos), StringLiteralValue(DataType.STR, "bye", dummyPos))
val lvOne = NumericLiteralValue(DataType.UBYTE, 1, dummyPos) val lvOne = NumericLiteralValue(DataType.UBYTE, 1, dummyPos)
val lvTwo = NumericLiteralValue(DataType.UBYTE, 2, dummyPos) val lvTwo = NumericLiteralValue(DataType.UBYTE, 2, dummyPos)

View File

@ -10,10 +10,10 @@ import prog8.ast.base.Position
import prog8.ast.expressions.NumericLiteralValue import prog8.ast.expressions.NumericLiteralValue
import prog8.ast.expressions.StringLiteralValue import prog8.ast.expressions.StringLiteralValue
import prog8.compiler.* import prog8.compiler.*
import prog8.compiler.target.c64.MachineDefinition.C64Zeropage import prog8.compiler.target.c64.C64MachineDefinition.C64Zeropage
import prog8.compiler.target.c64.MachineDefinition.FLOAT_MAX_NEGATIVE import prog8.compiler.target.c64.C64MachineDefinition.FLOAT_MAX_NEGATIVE
import prog8.compiler.target.c64.MachineDefinition.FLOAT_MAX_POSITIVE import prog8.compiler.target.c64.C64MachineDefinition.FLOAT_MAX_POSITIVE
import prog8.compiler.target.c64.MachineDefinition.Mflpt5 import prog8.compiler.target.c64.C64MachineDefinition.Mflpt5
import prog8.compiler.target.c64.Petscii import prog8.compiler.target.c64.Petscii
import prog8.vm.RuntimeValueNumeric import prog8.vm.RuntimeValueNumeric
import java.io.CharConversionException import java.io.CharConversionException
@ -95,29 +95,29 @@ class TestCompiler {
@Test @Test
fun testMflpt5ToFloat() { fun testMflpt5ToFloat() {
val PRECISION=0.000000001 val epsilon=0.000000001
assertThat(Mflpt5(0x00, 0x00, 0x00, 0x00, 0x00).toDouble(), equalTo(0.0)) 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, 0xA1).toDouble(), closeTo(3.141592653, epsilon))
assertThat(Mflpt5(0x82, 0x49, 0x0F, 0xDA, 0xA2).toDouble(), closeTo(3.141592653589793, PRECISION)) 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, 0x00, 0x00, 0x00, 0x00).toDouble(), equalTo(32768.0))
assertThat(Mflpt5(0x90, 0x80, 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(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, 0x34).toDouble(), closeTo(0.7071067812, epsilon))
assertThat(Mflpt5(0x80, 0x35, 0x04, 0xF3, 0x33).toDouble(), closeTo(0.7071067811865476, PRECISION)) assertThat(Mflpt5(0x80, 0x35, 0x04, 0xF3, 0x33).toDouble(), closeTo(0.7071067811865476, epsilon))
assertThat(Mflpt5(0x81, 0x35, 0x04, 0xF3, 0x34).toDouble(), closeTo(1.4142135624, PRECISION)) assertThat(Mflpt5(0x81, 0x35, 0x04, 0xF3, 0x34).toDouble(), closeTo(1.4142135624, epsilon))
assertThat(Mflpt5(0x81, 0x35, 0x04, 0xF3, 0x33).toDouble(), closeTo(1.4142135623730951, PRECISION)) 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, 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, 0xF8).toDouble(), closeTo(0.69314718061, epsilon))
assertThat(Mflpt5(0x80, 0x31, 0x72, 0x17, 0xF7).toDouble(), closeTo(0.6931471805599453, PRECISION)) 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(0x84, 0x20, 0x00, 0x00, 0x00).toDouble(), equalTo(10.0))
assertThat(Mflpt5(0x9E, 0x6E, 0x6B, 0x28, 0x00).toDouble(), equalTo(1000000000.0)) assertThat(Mflpt5(0x9E, 0x6E, 0x6B, 0x28, 0x00).toDouble(), equalTo(1000000000.0))
assertThat(Mflpt5(0x80, 0x00, 0x00, 0x00, 0x00).toDouble(), equalTo(.5)) 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, 0x38, 0xAA, 0x3B, 0x29).toDouble(), closeTo(1.4426950408889634, epsilon))
assertThat(Mflpt5(0x81, 0x49, 0x0F, 0xDA, 0xA2).toDouble(), closeTo(1.5707963267948966, PRECISION)) assertThat(Mflpt5(0x81, 0x49, 0x0F, 0xDA, 0xA2).toDouble(), closeTo(1.5707963267948966, epsilon))
assertThat(Mflpt5(0x83, 0x49, 0x0F, 0xDA, 0xA2).toDouble(), closeTo(6.283185307179586, PRECISION)) assertThat(Mflpt5(0x83, 0x49, 0x0F, 0xDA, 0xA2).toDouble(), closeTo(6.283185307179586, epsilon))
assertThat(Mflpt5(0x7F, 0x00, 0x00, 0x00, 0x00).toDouble(), equalTo(.25)) 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(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))
} }
} }