mirror of
https://github.com/KarolS/millfork.git
synced 2025-08-07 12:25:40 +00:00
Refactoring for the upcoming Z80 support
This commit is contained in:
@@ -68,6 +68,17 @@ case class CompilationOptions(platform: Platform, commandLineFlags: Map[Compilat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object CpuFamily extends Enumeration {
|
||||||
|
val M6502, Z80, M6809, I8086, M65K, ARM = Value
|
||||||
|
|
||||||
|
def forType(cpu: Cpu.Value): CpuFamily.Value = {
|
||||||
|
import Cpu._
|
||||||
|
cpu match {
|
||||||
|
case Mos | StrictMos | Ricoh | StrictRicoh | Cmos | HuC6280 | CE02 | Sixteen => M6502
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
object Cpu extends Enumeration {
|
object Cpu extends Enumeration {
|
||||||
|
|
||||||
val Mos, StrictMos, Ricoh, StrictRicoh, Cmos, HuC6280, CE02, Sixteen = Value
|
val Mos, StrictMos, Ricoh, StrictRicoh, Cmos, HuC6280, CE02, Sixteen = Value
|
||||||
@@ -76,27 +87,27 @@ object Cpu extends Enumeration {
|
|||||||
|
|
||||||
import CompilationFlag._
|
import CompilationFlag._
|
||||||
|
|
||||||
private val alwaysDefaultFlags = Set(
|
private val mosAlwaysDefaultFlags = Set(
|
||||||
VariableOverlap, CompactReturnDispatchParams, ZeropagePseudoregister
|
VariableOverlap, CompactReturnDispatchParams, ZeropagePseudoregister
|
||||||
)
|
)
|
||||||
|
|
||||||
def defaultFlags(x: Cpu.Value): Set[CompilationFlag.Value] = x match {
|
def defaultFlags(x: Cpu.Value): Set[CompilationFlag.Value] = x match {
|
||||||
case StrictMos =>
|
case StrictMos =>
|
||||||
alwaysDefaultFlags ++ Set(DecimalMode, PreventJmpIndirectBug)
|
mosAlwaysDefaultFlags ++ Set(DecimalMode, PreventJmpIndirectBug)
|
||||||
case Mos =>
|
case Mos =>
|
||||||
alwaysDefaultFlags ++ Set(DecimalMode, PreventJmpIndirectBug)
|
mosAlwaysDefaultFlags ++ Set(DecimalMode, PreventJmpIndirectBug)
|
||||||
case Ricoh =>
|
case Ricoh =>
|
||||||
alwaysDefaultFlags ++ Set(PreventJmpIndirectBug)
|
mosAlwaysDefaultFlags ++ Set(PreventJmpIndirectBug)
|
||||||
case StrictRicoh =>
|
case StrictRicoh =>
|
||||||
alwaysDefaultFlags ++ Set(PreventJmpIndirectBug)
|
mosAlwaysDefaultFlags ++ Set(PreventJmpIndirectBug)
|
||||||
case Cmos =>
|
case Cmos =>
|
||||||
alwaysDefaultFlags ++ Set(DecimalMode, EmitCmosOpcodes)
|
mosAlwaysDefaultFlags ++ Set(DecimalMode, EmitCmosOpcodes)
|
||||||
case HuC6280 =>
|
case HuC6280 =>
|
||||||
alwaysDefaultFlags ++ Set(DecimalMode, EmitCmosOpcodes, EmitHudsonOpcodes)
|
mosAlwaysDefaultFlags ++ Set(DecimalMode, EmitCmosOpcodes, EmitHudsonOpcodes)
|
||||||
case CE02 =>
|
case CE02 =>
|
||||||
alwaysDefaultFlags ++ Set(DecimalMode, EmitCmosOpcodes, Emit65CE02Opcodes)
|
mosAlwaysDefaultFlags ++ Set(DecimalMode, EmitCmosOpcodes, Emit65CE02Opcodes)
|
||||||
case Sixteen =>
|
case Sixteen =>
|
||||||
alwaysDefaultFlags ++ Set(DecimalMode, EmitCmosOpcodes, EmitEmulation65816Opcodes, EmitNative65816Opcodes, ReturnWordsViaAccumulator)
|
mosAlwaysDefaultFlags ++ Set(DecimalMode, EmitCmosOpcodes, EmitEmulation65816Opcodes, EmitNative65816Opcodes, ReturnWordsViaAccumulator)
|
||||||
}
|
}
|
||||||
|
|
||||||
def fromString(name: String): Cpu.Value = name match {
|
def fromString(name: String): Cpu.Value = name match {
|
||||||
|
@@ -4,14 +4,16 @@ import java.nio.charset.StandardCharsets
|
|||||||
import java.nio.file.{Files, Paths}
|
import java.nio.file.{Files, Paths}
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
import millfork.assembly.opt._
|
import millfork.assembly.mos.AssemblyLine
|
||||||
|
import millfork.assembly.mos.opt._
|
||||||
import millfork.buildinfo.BuildInfo
|
import millfork.buildinfo.BuildInfo
|
||||||
import millfork.cli.{CliParser, CliStatus}
|
import millfork.cli.{CliParser, CliStatus}
|
||||||
|
import millfork.compiler.mos.MosCompiler
|
||||||
import millfork.env.Environment
|
import millfork.env.Environment
|
||||||
import millfork.error.ErrorReporting
|
import millfork.error.ErrorReporting
|
||||||
import millfork.node.StandardCallGraph
|
import millfork.node.StandardCallGraph
|
||||||
import millfork.output.Assembler
|
import millfork.output.{AbstractAssembler, AssemblerOutput, MosAssembler, MosInliningCalculator}
|
||||||
import millfork.parser.SourceLoadingQueue
|
import millfork.parser.MosSourceLoadingQueue
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Karol Stasiak
|
* @author Karol Stasiak
|
||||||
@@ -59,7 +61,6 @@ object Main {
|
|||||||
ErrorReporting.fatalQuit("No input files")
|
ErrorReporting.fatalQuit("No input files")
|
||||||
}
|
}
|
||||||
ErrorReporting.verbosity = c.verbosity.getOrElse(0)
|
ErrorReporting.verbosity = c.verbosity.getOrElse(0)
|
||||||
val optLevel = c.optimizationLevel.getOrElse(0)
|
|
||||||
val platform = Platform.lookupPlatformFile(c.includePath, c.platform.getOrElse {
|
val platform = Platform.lookupPlatformFile(c.includePath, c.platform.getOrElse {
|
||||||
ErrorReporting.info("No platform selected, defaulting to `c64`")
|
ErrorReporting.info("No platform selected, defaulting to `c64`")
|
||||||
"c64"
|
"c64"
|
||||||
@@ -84,52 +85,9 @@ object Main {
|
|||||||
// }
|
// }
|
||||||
// }).toMap
|
// }).toMap
|
||||||
|
|
||||||
val unoptimized = new SourceLoadingQueue(
|
val result: AssemblerOutput = CpuFamily.forType(platform.cpu) match {
|
||||||
initialFilenames = c.inputFileNames,
|
case CpuFamily.M6502 => assembleForMos(c, platform, options)
|
||||||
includePath = c.includePath,
|
|
||||||
options = options).run()
|
|
||||||
|
|
||||||
val program = if (optLevel > 0) {
|
|
||||||
OptimizationPresets.NodeOpt.foldLeft(unoptimized)((p, opt) => p.applyNodeOptimization(opt, options))
|
|
||||||
} else {
|
|
||||||
unoptimized
|
|
||||||
}
|
}
|
||||||
val callGraph = new StandardCallGraph(program)
|
|
||||||
|
|
||||||
val env = new Environment(None, "")
|
|
||||||
env.collectDeclarations(program, options)
|
|
||||||
|
|
||||||
val assemblyOptimizations = optLevel match {
|
|
||||||
case 0 => Nil
|
|
||||||
case 1 => OptimizationPresets.QuickPreset
|
|
||||||
case i if i >= 9 => List(SuperOptimizer)
|
|
||||||
case _ =>
|
|
||||||
val goodExtras = List(
|
|
||||||
if (options.flag(CompilationFlag.EmitEmulation65816Opcodes)) SixteenOptimizations.AllForEmulation else Nil,
|
|
||||||
if (options.flag(CompilationFlag.EmitNative65816Opcodes)) SixteenOptimizations.AllForNative else Nil,
|
|
||||||
if (options.flag(CompilationFlag.ZeropagePseudoregister)) ZeropageRegisterOptimizations.All else Nil,
|
|
||||||
).flatten
|
|
||||||
val extras = List(
|
|
||||||
if (options.flag(CompilationFlag.EmitIllegals)) UndocumentedOptimizations.All else Nil,
|
|
||||||
if (options.flag(CompilationFlag.Emit65CE02Opcodes)) CE02Optimizations.All else Nil,
|
|
||||||
if (options.flag(CompilationFlag.EmitCmosOpcodes)) CmosOptimizations.All else LaterOptimizations.Nmos,
|
|
||||||
if (options.flag(CompilationFlag.EmitHudsonOpcodes)) HudsonOptimizations.All else Nil,
|
|
||||||
if (options.flag(CompilationFlag.EmitEmulation65816Opcodes)) SixteenOptimizations.AllForEmulation else Nil,
|
|
||||||
if (options.flag(CompilationFlag.EmitNative65816Opcodes)) SixteenOptimizations.AllForNative else Nil,
|
|
||||||
if (options.flag(CompilationFlag.DangerousOptimizations)) DangerousOptimizations.All else Nil,
|
|
||||||
).flatten
|
|
||||||
val goodCycle = List.fill(optLevel - 2)(OptimizationPresets.Good ++ goodExtras).flatten
|
|
||||||
goodCycle ++ OptimizationPresets.AssOpt ++ extras ++ goodCycle
|
|
||||||
}
|
|
||||||
|
|
||||||
// compile
|
|
||||||
val assembler = new Assembler(program, env, platform)
|
|
||||||
val result = assembler.assemble(callGraph, assemblyOptimizations, options)
|
|
||||||
ErrorReporting.assertNoErrors("Codegen failed")
|
|
||||||
ErrorReporting.debug(f"Unoptimized code size: ${assembler.unoptimizedCodeSize}%5d B")
|
|
||||||
ErrorReporting.debug(f"Optimized code size: ${assembler.optimizedCodeSize}%5d B")
|
|
||||||
ErrorReporting.debug(f"Gain: ${(100L * (assembler.unoptimizedCodeSize - assembler.optimizedCodeSize) / assembler.unoptimizedCodeSize.toDouble).round}%5d%%")
|
|
||||||
ErrorReporting.debug(f"Initialized variables: ${assembler.initializedVariablesSize}%5d B")
|
|
||||||
|
|
||||||
if (c.outputAssembly) {
|
if (c.outputAssembly) {
|
||||||
val path = Paths.get(assOutput)
|
val path = Paths.get(assOutput)
|
||||||
@@ -174,6 +132,57 @@ object Main {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private def assembleForMos(c: Context, platform: Platform, options: CompilationOptions): AssemblerOutput = {
|
||||||
|
val optLevel = c.optimizationLevel.getOrElse(0)
|
||||||
|
val unoptimized = new MosSourceLoadingQueue(
|
||||||
|
initialFilenames = c.inputFileNames,
|
||||||
|
includePath = c.includePath,
|
||||||
|
options = options).run()
|
||||||
|
|
||||||
|
val program = if (optLevel > 0) {
|
||||||
|
OptimizationPresets.NodeOpt.foldLeft(unoptimized)((p, opt) => p.applyNodeOptimization(opt, options))
|
||||||
|
} else {
|
||||||
|
unoptimized
|
||||||
|
}
|
||||||
|
val callGraph = new StandardCallGraph(program)
|
||||||
|
|
||||||
|
val env = new Environment(None, "")
|
||||||
|
env.collectDeclarations(program, options)
|
||||||
|
|
||||||
|
val assemblyOptimizations = optLevel match {
|
||||||
|
case 0 => Nil
|
||||||
|
case 1 => OptimizationPresets.QuickPreset
|
||||||
|
case i if i >= 9 => List(SuperOptimizer)
|
||||||
|
case _ =>
|
||||||
|
val goodExtras = List(
|
||||||
|
if (options.flag(CompilationFlag.EmitEmulation65816Opcodes)) SixteenOptimizations.AllForEmulation else Nil,
|
||||||
|
if (options.flag(CompilationFlag.EmitNative65816Opcodes)) SixteenOptimizations.AllForNative else Nil,
|
||||||
|
if (options.flag(CompilationFlag.ZeropagePseudoregister)) ZeropageRegisterOptimizations.All else Nil,
|
||||||
|
).flatten
|
||||||
|
val extras = List(
|
||||||
|
if (options.flag(CompilationFlag.EmitIllegals)) UndocumentedOptimizations.All else Nil,
|
||||||
|
if (options.flag(CompilationFlag.Emit65CE02Opcodes)) CE02Optimizations.All else Nil,
|
||||||
|
if (options.flag(CompilationFlag.EmitCmosOpcodes)) CmosOptimizations.All else LaterOptimizations.Nmos,
|
||||||
|
if (options.flag(CompilationFlag.EmitHudsonOpcodes)) HudsonOptimizations.All else Nil,
|
||||||
|
if (options.flag(CompilationFlag.EmitEmulation65816Opcodes)) SixteenOptimizations.AllForEmulation else Nil,
|
||||||
|
if (options.flag(CompilationFlag.EmitNative65816Opcodes)) SixteenOptimizations.AllForNative else Nil,
|
||||||
|
if (options.flag(CompilationFlag.DangerousOptimizations)) DangerousOptimizations.All else Nil,
|
||||||
|
).flatten
|
||||||
|
val goodCycle = List.fill(optLevel - 2)(OptimizationPresets.Good ++ goodExtras).flatten
|
||||||
|
goodCycle ++ OptimizationPresets.AssOpt ++ extras ++ goodCycle
|
||||||
|
}
|
||||||
|
|
||||||
|
// compile
|
||||||
|
val assembler = new MosAssembler(program, env, platform)
|
||||||
|
val result = assembler.assemble(callGraph, assemblyOptimizations, options)
|
||||||
|
ErrorReporting.assertNoErrors("Codegen failed")
|
||||||
|
ErrorReporting.debug(f"Unoptimized code size: ${assembler.unoptimizedCodeSize}%5d B")
|
||||||
|
ErrorReporting.debug(f"Optimized code size: ${assembler.optimizedCodeSize}%5d B")
|
||||||
|
ErrorReporting.debug(f"Gain: ${(100L * (assembler.unoptimizedCodeSize - assembler.optimizedCodeSize) / assembler.unoptimizedCodeSize.toDouble).round}%5d%%")
|
||||||
|
ErrorReporting.debug(f"Initialized variables: ${assembler.initializedVariablesSize}%5d B")
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
private def parser = new CliParser[Context] {
|
private def parser = new CliParser[Context] {
|
||||||
|
|
||||||
fluff("Main options:", "")
|
fluff("Main options:", "")
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
package millfork
|
package millfork
|
||||||
|
|
||||||
import millfork.assembly.opt._
|
import millfork.assembly.AssemblyOptimization
|
||||||
|
import millfork.assembly.mos.AssemblyLine
|
||||||
|
import millfork.assembly.mos.opt._
|
||||||
import millfork.node.opt.{UnreachableCode, UnusedFunctions, UnusedGlobalVariables, UnusedLocalVariables}
|
import millfork.node.opt.{UnreachableCode, UnusedFunctions, UnusedGlobalVariables, UnusedLocalVariables}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -13,7 +15,7 @@ object OptimizationPresets {
|
|||||||
UnusedLocalVariables,
|
UnusedLocalVariables,
|
||||||
UnusedGlobalVariables,
|
UnusedGlobalVariables,
|
||||||
)
|
)
|
||||||
val AssOpt: List[AssemblyOptimization] = List[AssemblyOptimization](
|
val AssOpt: List[AssemblyOptimization[AssemblyLine]] = List[AssemblyOptimization[AssemblyLine]](
|
||||||
UnusedLabelRemoval,
|
UnusedLabelRemoval,
|
||||||
AlwaysGoodOptimizations.NonetAddition,
|
AlwaysGoodOptimizations.NonetAddition,
|
||||||
AlwaysGoodOptimizations.NonetBitOp,
|
AlwaysGoodOptimizations.NonetBitOp,
|
||||||
@@ -135,7 +137,7 @@ object OptimizationPresets {
|
|||||||
LaterOptimizations.UseBit,
|
LaterOptimizations.UseBit,
|
||||||
)
|
)
|
||||||
|
|
||||||
val Good: List[AssemblyOptimization] = List[AssemblyOptimization](
|
val Good: List[AssemblyOptimization[AssemblyLine]] = List[AssemblyOptimization[AssemblyLine]](
|
||||||
UnusedLabelRemoval,
|
UnusedLabelRemoval,
|
||||||
AlwaysGoodOptimizations.Adc0Optimization,
|
AlwaysGoodOptimizations.Adc0Optimization,
|
||||||
AlwaysGoodOptimizations.BitPackingUnpacking,
|
AlwaysGoodOptimizations.BitPackingUnpacking,
|
||||||
@@ -204,7 +206,7 @@ object OptimizationPresets {
|
|||||||
VariableToRegisterOptimization,
|
VariableToRegisterOptimization,
|
||||||
)
|
)
|
||||||
|
|
||||||
val QuickPreset: List[AssemblyOptimization] = List[AssemblyOptimization](
|
val QuickPreset: List[AssemblyOptimization[AssemblyLine]] = List[AssemblyOptimization[AssemblyLine]](
|
||||||
UnusedLabelRemoval,
|
UnusedLabelRemoval,
|
||||||
AlwaysGoodOptimizations.Adc0Optimization,
|
AlwaysGoodOptimizations.Adc0Optimization,
|
||||||
AlwaysGoodOptimizations.BranchInPlaceRemoval,
|
AlwaysGoodOptimizations.BranchInPlaceRemoval,
|
||||||
|
12
src/main/scala/millfork/assembly/AbstractCode.scala
Normal file
12
src/main/scala/millfork/assembly/AbstractCode.scala
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package millfork.assembly
|
||||||
|
|
||||||
|
import millfork.env.Constant
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Karol Stasiak
|
||||||
|
*/
|
||||||
|
trait AbstractCode {
|
||||||
|
def sizeInBytes: Int
|
||||||
|
def isPrintable: Boolean
|
||||||
|
def parameter: Constant
|
||||||
|
}
|
58
src/main/scala/millfork/assembly/AddrMode.scala
Normal file
58
src/main/scala/millfork/assembly/AddrMode.scala
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
package millfork.assembly
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Karol Stasiak
|
||||||
|
*/
|
||||||
|
object AddrMode extends Enumeration {
|
||||||
|
val Implied,
|
||||||
|
Immediate,
|
||||||
|
WordImmediate,
|
||||||
|
Relative,
|
||||||
|
LongRelative,
|
||||||
|
ZeroPage,
|
||||||
|
ZeroPageX,
|
||||||
|
ZeroPageY,
|
||||||
|
Absolute,
|
||||||
|
AbsoluteX,
|
||||||
|
AbsoluteY,
|
||||||
|
LongAbsolute,
|
||||||
|
LongAbsoluteX,
|
||||||
|
Indirect,
|
||||||
|
LongIndirect,
|
||||||
|
IndexedX,
|
||||||
|
IndexedY,
|
||||||
|
IndexedSY,
|
||||||
|
IndexedZ,
|
||||||
|
Stack,
|
||||||
|
LongIndexedY,
|
||||||
|
LongIndexedZ,
|
||||||
|
AbsoluteIndexedX,
|
||||||
|
TripleAbsolute,
|
||||||
|
Undecided,
|
||||||
|
RawByte,
|
||||||
|
DoesNotExist = Value
|
||||||
|
|
||||||
|
|
||||||
|
def addrModeToMosString(am: AddrMode.Value, argument: String): String = {
|
||||||
|
am match {
|
||||||
|
case Implied => ""
|
||||||
|
case Immediate => "#" + argument
|
||||||
|
case WordImmediate => "##" + argument
|
||||||
|
case AbsoluteX | ZeroPageX => argument + ", X"
|
||||||
|
case AbsoluteY | ZeroPageY => argument + ", Y"
|
||||||
|
case IndexedX | AbsoluteIndexedX => "(" + argument + ", X)"
|
||||||
|
case Stack => argument + ", S"
|
||||||
|
case IndexedY => "(" + argument + "), Y"
|
||||||
|
case IndexedSY => "(" + argument + ", S), Y"
|
||||||
|
case IndexedZ => "(" + argument + "), Z"
|
||||||
|
case Indirect => "(" + argument + ")"
|
||||||
|
case LongIndexedY => "[" + argument + "], Y"
|
||||||
|
case LongIndexedZ => "[" + argument + "], Z"
|
||||||
|
case LongIndirect => "[" + argument + "]"
|
||||||
|
case ZeroPage => argument // + "\t;zp"
|
||||||
|
case LongAbsolute => "FAR " + argument
|
||||||
|
case LongAbsoluteX => "FAR " + argument + ", X"
|
||||||
|
case _ => argument;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
13
src/main/scala/millfork/assembly/AssemblyOptimization.scala
Normal file
13
src/main/scala/millfork/assembly/AssemblyOptimization.scala
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package millfork.assembly
|
||||||
|
|
||||||
|
import millfork.CompilationOptions
|
||||||
|
import millfork.env.NormalFunction
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Karol Stasiak
|
||||||
|
*/
|
||||||
|
trait AssemblyOptimization[T <: AbstractCode] {
|
||||||
|
def name: String
|
||||||
|
|
||||||
|
def optimize(f: NormalFunction, code: List[T], options: CompilationOptions): List[T]
|
||||||
|
}
|
@@ -1,9 +1,10 @@
|
|||||||
package millfork.assembly
|
package millfork.assembly.mos
|
||||||
|
|
||||||
import millfork.{CompilationFlag, CompilationOptions}
|
import millfork.assembly.{AbstractCode, AddrMode}
|
||||||
import millfork.assembly.Opcode._
|
import millfork.assembly.mos.Opcode._
|
||||||
import millfork.compiler.{CompilationContext, MfCompiler}
|
import millfork.compiler.mos.{CompilationContext, MosCompiler}
|
||||||
import millfork.env._
|
import millfork.env._
|
||||||
|
import millfork.{CompilationFlag, CompilationOptions}
|
||||||
|
|
||||||
//noinspection TypeAnnotation
|
//noinspection TypeAnnotation
|
||||||
object OpcodeClasses {
|
object OpcodeClasses {
|
||||||
@@ -378,7 +379,7 @@ object AssemblyLine {
|
|||||||
List(AssemblyLine.immediate(opcode, 0))
|
List(AssemblyLine.immediate(opcode, 0))
|
||||||
} else if (opcodesForZeroedOrSignExtendedVariableOperation(opcode)) {
|
} else if (opcodesForZeroedOrSignExtendedVariableOperation(opcode)) {
|
||||||
if (variable.typ.isSigned) {
|
if (variable.typ.isSigned) {
|
||||||
val label = MfCompiler.nextLabel("sx")
|
val label = MosCompiler.nextLabel("sx")
|
||||||
AssemblyLine.variable(ctx, opcode, variable, variable.typ.size - 1) ++ List(
|
AssemblyLine.variable(ctx, opcode, variable, variable.typ.size - 1) ++ List(
|
||||||
AssemblyLine.immediate(ORA, 0x7f),
|
AssemblyLine.immediate(ORA, 0x7f),
|
||||||
AssemblyLine.relative(BMI, label),
|
AssemblyLine.relative(BMI, label),
|
||||||
@@ -453,12 +454,12 @@ object AssemblyLine {
|
|||||||
AssemblyLine(opcode, AddrMode.Stack, NumericConstant(addr & 0xff, 1))
|
AssemblyLine(opcode, AddrMode.Stack, NumericConstant(addr & 0xff, 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
case class AssemblyLine(opcode: Opcode.Value, addrMode: AddrMode.Value, var parameter: Constant, elidable: Boolean = true) {
|
case class AssemblyLine(opcode: Opcode.Value, addrMode: AddrMode.Value, var parameter: Constant, elidable: Boolean = true) extends AbstractCode {
|
||||||
|
|
||||||
|
|
||||||
import AddrMode._
|
import AddrMode._
|
||||||
import State._
|
|
||||||
import OpcodeClasses._
|
import OpcodeClasses._
|
||||||
|
import State._
|
||||||
import Treatment._
|
import Treatment._
|
||||||
|
|
||||||
def reads(state: State.Value): Boolean = state match {
|
def reads(state: State.Value): Boolean = state match {
|
||||||
@@ -521,7 +522,7 @@ case class AssemblyLine(opcode: Opcode.Value, addrMode: AddrMode.Value, var para
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def sizeInBytes: Int = addrMode match {
|
override def sizeInBytes: Int = addrMode match {
|
||||||
case Implied | RawByte => 1
|
case Implied | RawByte => 1
|
||||||
case Relative | ZeroPageX | ZeroPage | ZeroPageY | IndexedZ | IndexedX | IndexedY | IndexedSY | Stack | LongIndexedY | LongIndexedZ | Immediate => 2
|
case Relative | ZeroPageX | ZeroPage | ZeroPageY | IndexedZ | IndexedX | IndexedY | IndexedSY | Stack | LongIndexedY | LongIndexedZ | Immediate => 2
|
||||||
case AbsoluteIndexedX | AbsoluteX | Absolute | AbsoluteY | Indirect | LongRelative | WordImmediate => 3
|
case AbsoluteIndexedX | AbsoluteX | Absolute | AbsoluteY | Indirect | LongRelative | WordImmediate => 3
|
||||||
@@ -561,6 +562,6 @@ case class AssemblyLine(opcode: Opcode.Value, addrMode: AddrMode.Value, var para
|
|||||||
case HuSAX => "SAX"
|
case HuSAX => "SAX"
|
||||||
case _ => opcode.toString
|
case _ => opcode.toString
|
||||||
}
|
}
|
||||||
s" $op ${AddrMode.addrModeToString(addrMode, parameter.toString)}"
|
s" $op ${AddrMode.addrModeToMosString(addrMode, parameter.toString)}"
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
package millfork.assembly
|
package millfork.assembly.mos
|
||||||
|
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
@@ -301,56 +301,3 @@ object Opcode extends Enumeration {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object AddrMode extends Enumeration {
|
|
||||||
val Implied,
|
|
||||||
Immediate,
|
|
||||||
WordImmediate,
|
|
||||||
Relative,
|
|
||||||
LongRelative,
|
|
||||||
ZeroPage,
|
|
||||||
ZeroPageX,
|
|
||||||
ZeroPageY,
|
|
||||||
Absolute,
|
|
||||||
AbsoluteX,
|
|
||||||
AbsoluteY,
|
|
||||||
LongAbsolute,
|
|
||||||
LongAbsoluteX,
|
|
||||||
Indirect,
|
|
||||||
LongIndirect,
|
|
||||||
IndexedX,
|
|
||||||
IndexedY,
|
|
||||||
IndexedSY,
|
|
||||||
IndexedZ,
|
|
||||||
Stack,
|
|
||||||
LongIndexedY,
|
|
||||||
LongIndexedZ,
|
|
||||||
AbsoluteIndexedX,
|
|
||||||
TripleAbsolute,
|
|
||||||
Undecided,
|
|
||||||
RawByte,
|
|
||||||
DoesNotExist = Value
|
|
||||||
|
|
||||||
|
|
||||||
def addrModeToString(am: AddrMode.Value, argument: String): String = {
|
|
||||||
am match {
|
|
||||||
case Implied => ""
|
|
||||||
case Immediate => "#" + argument
|
|
||||||
case WordImmediate => "##" + argument
|
|
||||||
case AbsoluteX | ZeroPageX => argument + ", X"
|
|
||||||
case AbsoluteY | ZeroPageY => argument + ", Y"
|
|
||||||
case IndexedX | AbsoluteIndexedX => "(" + argument + ", X)"
|
|
||||||
case Stack => argument + ", S"
|
|
||||||
case IndexedY => "(" + argument + "), Y"
|
|
||||||
case IndexedSY => "(" + argument + ", S), Y"
|
|
||||||
case IndexedZ => "(" + argument + "), Z"
|
|
||||||
case Indirect => "(" + argument + ")"
|
|
||||||
case LongIndexedY => "[" + argument + "], Y"
|
|
||||||
case LongIndexedZ => "[" + argument + "], Z"
|
|
||||||
case LongIndirect => "[" + argument + "]"
|
|
||||||
case ZeroPage => argument // + "\t;zp"
|
|
||||||
case LongAbsolute => "FAR " + argument
|
|
||||||
case LongAbsoluteX => "FAR " + argument + ", X"
|
|
||||||
case _ => argument;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,11 +1,12 @@
|
|||||||
package millfork.assembly.opt
|
package millfork.assembly.mos.opt
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
|
|
||||||
|
import millfork.assembly.AddrMode
|
||||||
import millfork.assembly.AddrMode._
|
import millfork.assembly.AddrMode._
|
||||||
import millfork.assembly.Opcode._
|
import millfork.assembly.mos.Opcode._
|
||||||
import millfork.assembly.OpcodeClasses._
|
import millfork.assembly.mos.OpcodeClasses._
|
||||||
import millfork.assembly.{opt, _}
|
import millfork.assembly.mos.{opt, _}
|
||||||
import millfork.env._
|
import millfork.env._
|
||||||
|
|
||||||
/**
|
/**
|
@@ -1,9 +1,8 @@
|
|||||||
package millfork.assembly.opt
|
package millfork.assembly.mos.opt
|
||||||
|
|
||||||
import millfork.assembly.AddrMode._
|
import millfork.assembly.AssemblyOptimization
|
||||||
import millfork.assembly.AssemblyLine
|
import millfork.assembly.mos.AssemblyLine
|
||||||
import millfork.assembly.Opcode._
|
import millfork.assembly.mos.Opcode._
|
||||||
import millfork.assembly.OpcodeClasses._
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Karol Stasiak
|
* @author Karol Stasiak
|
||||||
@@ -16,5 +15,5 @@ object CE02Optimizations {
|
|||||||
(Elidable & HasOpcode(ROR)) ~~> (_ => List(AssemblyLine.implied(ASR))),
|
(Elidable & HasOpcode(ROR)) ~~> (_ => List(AssemblyLine.implied(ASR))),
|
||||||
)
|
)
|
||||||
|
|
||||||
val All: List[AssemblyOptimization] = List(UseAsr)
|
val All: List[AssemblyOptimization[AssemblyLine]] = List(UseAsr)
|
||||||
}
|
}
|
@@ -1,7 +1,8 @@
|
|||||||
package millfork.assembly.opt
|
package millfork.assembly.mos.opt
|
||||||
|
|
||||||
import millfork.CompilationOptions
|
import millfork.CompilationOptions
|
||||||
import millfork.assembly.{AssemblyLine, OpcodeClasses}
|
import millfork.assembly.mos.{AssemblyLine, OpcodeClasses}
|
||||||
|
import millfork.assembly.AssemblyOptimization
|
||||||
import millfork.env.NormalFunction
|
import millfork.env.NormalFunction
|
||||||
import millfork.error.ErrorReporting
|
import millfork.error.ErrorReporting
|
||||||
|
|
||||||
@@ -12,7 +13,7 @@ import millfork.error.ErrorReporting
|
|||||||
object ChangeIndexRegisterOptimizationPreferringX2Y extends ChangeIndexRegisterOptimization(true)
|
object ChangeIndexRegisterOptimizationPreferringX2Y extends ChangeIndexRegisterOptimization(true)
|
||||||
object ChangeIndexRegisterOptimizationPreferringY2X extends ChangeIndexRegisterOptimization(false)
|
object ChangeIndexRegisterOptimizationPreferringY2X extends ChangeIndexRegisterOptimization(false)
|
||||||
|
|
||||||
class ChangeIndexRegisterOptimization(preferX2Y: Boolean) extends AssemblyOptimization {
|
class ChangeIndexRegisterOptimization(preferX2Y: Boolean) extends AssemblyOptimization[AssemblyLine] {
|
||||||
|
|
||||||
object IndexReg extends Enumeration {
|
object IndexReg extends Enumeration {
|
||||||
val X, Y = Value
|
val X, Y = Value
|
||||||
@@ -25,7 +26,7 @@ class ChangeIndexRegisterOptimization(preferX2Y: Boolean) extends AssemblyOptimi
|
|||||||
import IndexReg._
|
import IndexReg._
|
||||||
import IndexDirection._
|
import IndexDirection._
|
||||||
import millfork.assembly.AddrMode._
|
import millfork.assembly.AddrMode._
|
||||||
import millfork.assembly.Opcode._
|
import millfork.assembly.mos.Opcode._
|
||||||
|
|
||||||
type IndexReg = IndexReg.Value
|
type IndexReg = IndexReg.Value
|
||||||
type IndexDirection = IndexDirection.Value
|
type IndexDirection = IndexDirection.Value
|
@@ -1,9 +1,10 @@
|
|||||||
package millfork.assembly.opt
|
package millfork.assembly.mos.opt
|
||||||
|
|
||||||
import millfork.assembly.{AssemblyLine, Opcode, State}
|
import millfork.assembly.AssemblyOptimization
|
||||||
import millfork.assembly.Opcode._
|
import millfork.assembly.mos.{AssemblyLine, Opcode, State}
|
||||||
|
import millfork.assembly.mos.Opcode._
|
||||||
import millfork.assembly.AddrMode._
|
import millfork.assembly.AddrMode._
|
||||||
import millfork.assembly.OpcodeClasses._
|
import millfork.assembly.mos.OpcodeClasses._
|
||||||
import millfork.env._
|
import millfork.env._
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -49,5 +50,5 @@ object CmosOptimizations {
|
|||||||
(Elidable & HasX(0) & HasZ(0) & HasAddrMode(AbsoluteIndexedX) & HasOpcode(JMP)) ~~> (code => code.map(_.copy(addrMode = Indirect))),
|
(Elidable & HasX(0) & HasZ(0) & HasAddrMode(AbsoluteIndexedX) & HasOpcode(JMP)) ~~> (code => code.map(_.copy(addrMode = Indirect))),
|
||||||
)
|
)
|
||||||
|
|
||||||
val All: List[AssemblyOptimization] = List(OptimizeZeroIndex, SimplerBitFlipping, ZeroStoreAsStz)
|
val All: List[AssemblyOptimization[AssemblyLine]] = List(OptimizeZeroIndex, SimplerBitFlipping, ZeroStoreAsStz)
|
||||||
}
|
}
|
@@ -1,7 +1,8 @@
|
|||||||
package millfork.assembly.opt
|
package millfork.assembly.mos.opt
|
||||||
|
|
||||||
import millfork.{CompilationFlag, CompilationOptions}
|
import millfork.{CompilationFlag, CompilationOptions}
|
||||||
import millfork.assembly._
|
import millfork.assembly.mos.AssemblyLine
|
||||||
|
import millfork.assembly.mos.OpcodeClasses
|
||||||
import millfork.env.{Label, MemoryAddressConstant, NormalFunction, NumericConstant}
|
import millfork.env.{Label, MemoryAddressConstant, NormalFunction, NumericConstant}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -32,7 +33,7 @@ object CoarseFlowAnalyzer {
|
|||||||
changed = false
|
changed = false
|
||||||
var currentStatus: CpuStatus = functionStartStatus
|
var currentStatus: CpuStatus = functionStartStatus
|
||||||
for (i <- codeArray.indices) {
|
for (i <- codeArray.indices) {
|
||||||
import millfork.assembly.Opcode._
|
import millfork.assembly.mos.Opcode._
|
||||||
import millfork.assembly.AddrMode._
|
import millfork.assembly.AddrMode._
|
||||||
if (flagArray(i) != currentStatus) {
|
if (flagArray(i) != currentStatus) {
|
||||||
changed = true
|
changed = true
|
@@ -1,6 +1,6 @@
|
|||||||
package millfork.assembly.opt
|
package millfork.assembly.mos.opt
|
||||||
|
|
||||||
import millfork.assembly.State
|
import millfork.assembly.mos.State
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Karol Stasiak
|
* @author Karol Stasiak
|
@@ -1,7 +1,8 @@
|
|||||||
package millfork.assembly.opt
|
package millfork.assembly.mos.opt
|
||||||
|
|
||||||
import millfork.assembly._
|
import millfork.assembly._
|
||||||
import millfork.assembly.Opcode._
|
import millfork.assembly.mos._
|
||||||
|
import millfork.assembly.mos.Opcode._
|
||||||
import millfork.assembly.AddrMode._
|
import millfork.assembly.AddrMode._
|
||||||
import millfork.env._
|
import millfork.env._
|
||||||
|
|
||||||
@@ -55,5 +56,5 @@ object DangerousOptimizations {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
val All: List[AssemblyOptimization] = List(ConstantIndexOffsetPropagation)
|
val All: List[AssemblyOptimization[AssemblyLine]] = List(ConstantIndexOffsetPropagation)
|
||||||
}
|
}
|
@@ -1,9 +1,10 @@
|
|||||||
package millfork.assembly.opt
|
package millfork.assembly.mos.opt
|
||||||
|
|
||||||
import millfork.CompilationOptions
|
import millfork.CompilationOptions
|
||||||
import millfork.assembly.AssemblyLine
|
import millfork.assembly.AssemblyOptimization
|
||||||
|
import millfork.assembly.mos.AssemblyLine
|
||||||
import millfork.env._
|
import millfork.env._
|
||||||
import millfork.assembly.Opcode._
|
import millfork.assembly.mos.Opcode._
|
||||||
import millfork.assembly.AddrMode._
|
import millfork.assembly.AddrMode._
|
||||||
import millfork.error.ErrorReporting
|
import millfork.error.ErrorReporting
|
||||||
|
|
||||||
@@ -12,7 +13,7 @@ import scala.collection.{immutable, mutable}
|
|||||||
/**
|
/**
|
||||||
* @author Karol Stasiak
|
* @author Karol Stasiak
|
||||||
*/
|
*/
|
||||||
object EmptyMemoryStoreRemoval extends AssemblyOptimization {
|
object EmptyMemoryStoreRemoval extends AssemblyOptimization[AssemblyLine] {
|
||||||
override def name = "Removing pointless stores to automatic variables"
|
override def name = "Removing pointless stores to automatic variables"
|
||||||
|
|
||||||
private val storeAddrModes = Set(Absolute, ZeroPage, AbsoluteX, AbsoluteY, ZeroPageX, ZeroPageY)
|
private val storeAddrModes = Set(Absolute, ZeroPage, AbsoluteX, AbsoluteY, ZeroPageX, ZeroPageY)
|
@@ -1,7 +1,7 @@
|
|||||||
package millfork.assembly.opt
|
package millfork.assembly.mos.opt
|
||||||
|
|
||||||
import millfork.{CompilationFlag, CompilationOptions}
|
import millfork.CompilationOptions
|
||||||
import millfork.assembly.{AssemblyLine, Opcode, State}
|
import millfork.assembly.mos.{AssemblyLine, Opcode, State}
|
||||||
import millfork.env.{Label, MemoryAddressConstant, NormalFunction}
|
import millfork.env.{Label, MemoryAddressConstant, NormalFunction}
|
||||||
|
|
||||||
/**
|
/**
|
@@ -1,7 +1,7 @@
|
|||||||
package millfork.assembly.opt
|
package millfork.assembly.mos.opt
|
||||||
|
|
||||||
import millfork.assembly.Opcode
|
import millfork.assembly.mos.Opcode
|
||||||
import millfork.assembly.Opcode._
|
import millfork.assembly.mos.Opcode._
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Karol Stasiak
|
* @author Karol Stasiak
|
@@ -1,7 +1,7 @@
|
|||||||
package millfork.assembly.opt
|
package millfork.assembly.mos.opt
|
||||||
|
|
||||||
import millfork.assembly.Opcode
|
import millfork.assembly.mos.Opcode
|
||||||
import millfork.assembly.Opcode._
|
import millfork.assembly.mos.Opcode._
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Karol Stasiak
|
* @author Karol Stasiak
|
@@ -1,7 +1,7 @@
|
|||||||
package millfork.assembly.opt
|
package millfork.assembly.mos.opt
|
||||||
|
|
||||||
import millfork.assembly.Opcode
|
import millfork.assembly.mos.Opcode
|
||||||
import millfork.assembly.Opcode._
|
import millfork.assembly.mos.Opcode._
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Karol Stasiak
|
* @author Karol Stasiak
|
@@ -1,7 +1,8 @@
|
|||||||
package millfork.assembly.opt
|
package millfork.assembly.mos.opt
|
||||||
|
|
||||||
import millfork.assembly.AssemblyLine
|
import millfork.assembly.AssemblyOptimization
|
||||||
import millfork.assembly.Opcode._
|
import millfork.assembly.mos.AssemblyLine
|
||||||
|
import millfork.assembly.mos.Opcode._
|
||||||
import millfork.assembly.AddrMode._
|
import millfork.assembly.AddrMode._
|
||||||
import millfork.env.NumericConstant
|
import millfork.env.NumericConstant
|
||||||
|
|
||||||
@@ -10,7 +11,7 @@ import millfork.env.NumericConstant
|
|||||||
*/
|
*/
|
||||||
object HudsonOptimizations {
|
object HudsonOptimizations {
|
||||||
|
|
||||||
val All: List[AssemblyOptimization] = List()
|
val All: List[AssemblyOptimization[AssemblyLine]] = List()
|
||||||
|
|
||||||
def removeLoadZero(code: List[AssemblyLine]): List[AssemblyLine] = code.map{
|
def removeLoadZero(code: List[AssemblyLine]): List[AssemblyLine] = code.map{
|
||||||
case AssemblyLine(LDA, Immediate, NumericConstant(0, _), true) => AssemblyLine.implied(CLA)
|
case AssemblyLine(LDA, Immediate, NumericConstant(0, _), true) => AssemblyLine.implied(CLA)
|
@@ -1,13 +1,13 @@
|
|||||||
package millfork.assembly.opt
|
package millfork.assembly.mos.opt
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
|
|
||||||
import millfork.assembly.Opcode._
|
import millfork.assembly.mos.{AssemblyLine, Opcode}
|
||||||
import millfork.assembly.{AddrMode, AssemblyLine, Opcode}
|
import millfork.assembly.mos.Opcode._
|
||||||
import millfork.compiler.MfCompiler
|
import millfork.assembly.AddrMode
|
||||||
import millfork.env.{Label, MemoryAddressConstant, NormalFunction}
|
import millfork.env.{Label, MemoryAddressConstant, NormalFunction}
|
||||||
import millfork.error.ErrorReporting
|
import millfork.error.ErrorReporting
|
||||||
import millfork.{CompilationFlag, CompilationOptions}
|
import millfork.CompilationOptions
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Karol Stasiak
|
* @author Karol Stasiak
|
@@ -1,8 +1,9 @@
|
|||||||
package millfork.assembly.opt
|
package millfork.assembly.mos.opt
|
||||||
|
|
||||||
|
import millfork.assembly.mos.AssemblyLine
|
||||||
import millfork.{CompilationFlag, CompilationOptions}
|
import millfork.{CompilationFlag, CompilationOptions}
|
||||||
import millfork.assembly.{AddrMode, AssemblyLine, Opcode}
|
import millfork.assembly.AddrMode
|
||||||
import millfork.assembly.Opcode._
|
import millfork.assembly.mos.Opcode._
|
||||||
import millfork.env.{Label, MemoryAddressConstant, NormalFunction}
|
import millfork.env.{Label, MemoryAddressConstant, NormalFunction}
|
||||||
import millfork.error.ErrorReporting
|
import millfork.error.ErrorReporting
|
||||||
|
|
@@ -1,9 +1,10 @@
|
|||||||
package millfork.assembly.opt
|
package millfork.assembly.mos.opt
|
||||||
|
|
||||||
import millfork.assembly._
|
import millfork.assembly._
|
||||||
import millfork.assembly.Opcode._
|
import millfork.assembly.mos._
|
||||||
|
import millfork.assembly.mos.Opcode._
|
||||||
import millfork.assembly.AddrMode._
|
import millfork.assembly.AddrMode._
|
||||||
import millfork.assembly.OpcodeClasses._
|
import millfork.assembly.mos.OpcodeClasses._
|
||||||
import millfork.env.{Constant, NormalFunction, NumericConstant}
|
import millfork.env.{Constant, NormalFunction, NumericConstant}
|
||||||
|
|
||||||
/**
|
/**
|
@@ -1,19 +1,17 @@
|
|||||||
package millfork.assembly.opt
|
package millfork.assembly.mos.opt
|
||||||
|
|
||||||
import millfork.{CompilationFlag, CompilationOptions, NonOverlappingIntervals}
|
import millfork.CompilationOptions
|
||||||
import millfork.assembly.{AddrMode, AssemblyLine, OpcodeClasses}
|
import millfork.assembly.AssemblyOptimization
|
||||||
import millfork.assembly.Opcode._
|
import millfork.assembly.mos.Opcode._
|
||||||
import millfork.assembly.AddrMode._
|
import millfork.assembly.AddrMode._
|
||||||
|
import millfork.assembly.mos.{AssemblyLine, OpcodeClasses}
|
||||||
import millfork.env._
|
import millfork.env._
|
||||||
import millfork.error.ErrorReporting
|
import millfork.error.ErrorReporting
|
||||||
|
|
||||||
import scala.annotation.tailrec
|
|
||||||
import scala.collection.mutable.ListBuffer
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Karol Stasiak
|
* @author Karol Stasiak
|
||||||
*/
|
*/
|
||||||
object LocalVariableReadOptimization extends AssemblyOptimization {
|
object LocalVariableReadOptimization extends AssemblyOptimization[AssemblyLine] {
|
||||||
|
|
||||||
override def name: String = "Local variable read optimization"
|
override def name: String = "Local variable read optimization"
|
||||||
|
|
@@ -1,11 +1,11 @@
|
|||||||
package millfork.assembly.opt
|
package millfork.assembly.mos.opt
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
|
|
||||||
import millfork.{CompilationFlag, CompilationOptions}
|
import millfork.{CompilationFlag, CompilationOptions}
|
||||||
import millfork.assembly.AssemblyLine
|
import millfork.assembly.mos.AssemblyLine
|
||||||
import millfork.assembly.OpcodeClasses._
|
import millfork.assembly.mos.OpcodeClasses._
|
||||||
import millfork.assembly.Opcode._
|
import millfork.assembly.mos.Opcode._
|
||||||
import millfork.assembly.AddrMode._
|
import millfork.assembly.AddrMode._
|
||||||
import millfork.env.{Constant, Label, MemoryAddressConstant}
|
import millfork.env.{Constant, Label, MemoryAddressConstant}
|
||||||
|
|
@@ -1,10 +1,11 @@
|
|||||||
package millfork.assembly.opt
|
package millfork.assembly.mos.opt
|
||||||
|
|
||||||
import millfork.CompilationOptions
|
import millfork.CompilationOptions
|
||||||
import millfork.assembly._
|
import millfork.assembly._
|
||||||
|
import millfork.assembly.mos._
|
||||||
import millfork.env._
|
import millfork.env._
|
||||||
import millfork.error.ErrorReporting
|
import millfork.error.ErrorReporting
|
||||||
import millfork.node.Register
|
import millfork.node.MosRegister
|
||||||
|
|
||||||
import scala.collection.immutable
|
import scala.collection.immutable
|
||||||
|
|
||||||
@@ -112,7 +113,7 @@ object ReverseFlowAnalyzer {
|
|||||||
changed = false
|
changed = false
|
||||||
var currentImportance: CpuImportance = finalImportance
|
var currentImportance: CpuImportance = finalImportance
|
||||||
for (i <- codeArray.indices.reverse) {
|
for (i <- codeArray.indices.reverse) {
|
||||||
import millfork.assembly.Opcode._
|
import millfork.assembly.mos.Opcode._
|
||||||
import millfork.assembly.AddrMode._
|
import millfork.assembly.AddrMode._
|
||||||
if (importanceArray(i) != currentImportance) {
|
if (importanceArray(i) != currentImportance) {
|
||||||
changed = true
|
changed = true
|
||||||
@@ -151,19 +152,19 @@ object ReverseFlowAnalyzer {
|
|||||||
fun.params match {
|
fun.params match {
|
||||||
case AssemblyParamSignature(params) =>
|
case AssemblyParamSignature(params) =>
|
||||||
params.foreach(_.variable match {
|
params.foreach(_.variable match {
|
||||||
case RegisterVariable(Register.A, _) =>
|
case RegisterVariable(MosRegister.A, _) =>
|
||||||
result = result.copy(a = Important)
|
result = result.copy(a = Important)
|
||||||
case RegisterVariable(Register.AW, _) =>
|
case RegisterVariable(MosRegister.AW, _) =>
|
||||||
result = result.copy(a = Important, ah = Important)
|
result = result.copy(a = Important, ah = Important)
|
||||||
case RegisterVariable(Register.X, _) =>
|
case RegisterVariable(MosRegister.X, _) =>
|
||||||
result = result.copy(x = Important)
|
result = result.copy(x = Important)
|
||||||
case RegisterVariable(Register.Y, _) =>
|
case RegisterVariable(MosRegister.Y, _) =>
|
||||||
result = result.copy(y = Important)
|
result = result.copy(y = Important)
|
||||||
case RegisterVariable(Register.AX | Register.XA, _) =>
|
case RegisterVariable(MosRegister.AX | MosRegister.XA, _) =>
|
||||||
result = result.copy(a = Important, x = Important)
|
result = result.copy(a = Important, x = Important)
|
||||||
case RegisterVariable(Register.YA | Register.YA, _) =>
|
case RegisterVariable(MosRegister.YA | MosRegister.YA, _) =>
|
||||||
result = result.copy(a = Important, y = Important)
|
result = result.copy(a = Important, y = Important)
|
||||||
case RegisterVariable(Register.XY | Register.YX, _) =>
|
case RegisterVariable(MosRegister.XY | MosRegister.YX, _) =>
|
||||||
result = result.copy(x = Important, y = Important)
|
result = result.copy(x = Important, y = Important)
|
||||||
case _ =>
|
case _ =>
|
||||||
})
|
})
|
@@ -1,7 +1,7 @@
|
|||||||
package millfork.assembly.opt
|
package millfork.assembly.mos.opt
|
||||||
|
|
||||||
import millfork.assembly.Opcode
|
import millfork.assembly.mos.Opcode
|
||||||
import millfork.assembly.Opcode._
|
import millfork.assembly.mos.Opcode._
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Karol Stasiak
|
* @author Karol Stasiak
|
@@ -1,7 +1,8 @@
|
|||||||
package millfork.assembly.opt
|
package millfork.assembly.mos.opt
|
||||||
|
|
||||||
import millfork.{CompilationFlag, CompilationOptions}
|
import millfork.{CompilationFlag, CompilationOptions}
|
||||||
import millfork.assembly._
|
import millfork.assembly._
|
||||||
|
import millfork.assembly.mos._
|
||||||
import millfork.env._
|
import millfork.env._
|
||||||
import millfork.error.ErrorReporting
|
import millfork.error.ErrorReporting
|
||||||
|
|
||||||
@@ -26,7 +27,7 @@ object FlowInfoRequirement extends Enumeration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RuleBasedAssemblyOptimization(val name: String, val needsFlowInfo: FlowInfoRequirement.Value, val rules: AssemblyRule*) extends AssemblyOptimization {
|
class RuleBasedAssemblyOptimization(val name: String, val needsFlowInfo: FlowInfoRequirement.Value, val rules: AssemblyRule*) extends AssemblyOptimization[AssemblyLine] {
|
||||||
|
|
||||||
rules.foreach(_.pattern.validate(needsFlowInfo))
|
rules.foreach(_.pattern.validate(needsFlowInfo))
|
||||||
|
|
@@ -1,9 +1,10 @@
|
|||||||
package millfork.assembly.opt
|
package millfork.assembly.mos.opt
|
||||||
|
|
||||||
import millfork.{CompilationFlag, CompilationOptions, NonOverlappingIntervals}
|
import millfork.{CompilationFlag, CompilationOptions, NonOverlappingIntervals}
|
||||||
import millfork.assembly.{AddrMode, AssemblyLine, Opcode, OpcodeClasses}
|
import millfork.assembly._
|
||||||
import millfork.assembly.Opcode._
|
import millfork.assembly.mos.Opcode._
|
||||||
import millfork.assembly.AddrMode._
|
import millfork.assembly.AddrMode._
|
||||||
|
import millfork.assembly.mos.{AssemblyLine, Opcode}
|
||||||
import millfork.env._
|
import millfork.env._
|
||||||
import millfork.error.ErrorReporting
|
import millfork.error.ErrorReporting
|
||||||
|
|
||||||
@@ -13,7 +14,7 @@ import scala.collection.mutable.ListBuffer
|
|||||||
/**
|
/**
|
||||||
* @author Karol Stasiak
|
* @author Karol Stasiak
|
||||||
*/
|
*/
|
||||||
object SingleAssignmentVariableOptimization extends AssemblyOptimization {
|
object SingleAssignmentVariableOptimization extends AssemblyOptimization[AssemblyLine] {
|
||||||
|
|
||||||
private val BadOpcodes = Set(RTS, JSR, JMP, RTI)
|
private val BadOpcodes = Set(RTS, JSR, JMP, RTI)
|
||||||
private val GoodOpcodes = Set(
|
private val GoodOpcodes = Set(
|
@@ -1,8 +1,10 @@
|
|||||||
package millfork.assembly.opt
|
package millfork.assembly.mos.opt
|
||||||
import millfork.assembly.Opcode._
|
|
||||||
|
import millfork.assembly.mos.Opcode._
|
||||||
import millfork.assembly.AddrMode._
|
import millfork.assembly.AddrMode._
|
||||||
import millfork.assembly.OpcodeClasses._
|
import millfork.assembly.mos.OpcodeClasses._
|
||||||
import millfork.assembly.{AssemblyLine, OpcodeClasses, State}
|
import millfork.assembly.AssemblyOptimization
|
||||||
|
import millfork.assembly.mos.{AssemblyLine, OpcodeClasses, State}
|
||||||
import millfork.env.{Constant, NumericConstant}
|
import millfork.env.{Constant, NumericConstant}
|
||||||
/**
|
/**
|
||||||
* @author Karol Stasiak
|
* @author Karol Stasiak
|
||||||
@@ -216,7 +218,7 @@ object SixteenOptimizations {
|
|||||||
|
|
||||||
// TODO: rewrite most 8-bit optimizations that are applicable to 16-bit code
|
// TODO: rewrite most 8-bit optimizations that are applicable to 16-bit code
|
||||||
|
|
||||||
val AllForEmulation: List[AssemblyOptimization] = List(
|
val AllForEmulation: List[AssemblyOptimization[AssemblyLine]] = List(
|
||||||
AccumulatorSwapping,
|
AccumulatorSwapping,
|
||||||
OptimizeStackRelative,
|
OptimizeStackRelative,
|
||||||
OptimizeZeroIndex,
|
OptimizeZeroIndex,
|
||||||
@@ -224,9 +226,9 @@ object SixteenOptimizations {
|
|||||||
RepSepWeakening,
|
RepSepWeakening,
|
||||||
)
|
)
|
||||||
|
|
||||||
val AllForNative: List[AssemblyOptimization] = List(
|
val AllForNative: List[AssemblyOptimization[AssemblyLine]] = List(
|
||||||
PointlessLoadAfterLoadOrStore
|
PointlessLoadAfterLoadOrStore
|
||||||
)
|
)
|
||||||
|
|
||||||
val All: List[AssemblyOptimization] = AllForEmulation ++ AllForNative
|
val All: List[AssemblyOptimization[AssemblyLine]] = AllForEmulation ++ AllForNative
|
||||||
}
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
package millfork.assembly.opt
|
package millfork.assembly.mos.opt
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Karol Stasiak
|
* @author Karol Stasiak
|
@@ -1,7 +1,8 @@
|
|||||||
package millfork.assembly.opt
|
package millfork.assembly.mos.opt
|
||||||
|
|
||||||
import millfork.{CompilationFlag, CompilationOptions, OptimizationPresets}
|
import millfork.{CompilationFlag, CompilationOptions, OptimizationPresets}
|
||||||
import millfork.assembly.{AddrMode, AssemblyLine, Opcode}
|
import millfork.assembly.{AddrMode, AssemblyOptimization}
|
||||||
|
import millfork.assembly.mos.{AssemblyLine, Opcode}
|
||||||
import millfork.env.NormalFunction
|
import millfork.env.NormalFunction
|
||||||
import millfork.error.ErrorReporting
|
import millfork.error.ErrorReporting
|
||||||
|
|
||||||
@@ -10,7 +11,7 @@ import scala.collection.mutable
|
|||||||
/**
|
/**
|
||||||
* @author Karol Stasiak
|
* @author Karol Stasiak
|
||||||
*/
|
*/
|
||||||
object SuperOptimizer extends AssemblyOptimization {
|
object SuperOptimizer extends AssemblyOptimization[AssemblyLine] {
|
||||||
|
|
||||||
def optimize(m: NormalFunction, code: List[AssemblyLine], options: CompilationOptions): List[AssemblyLine] = {
|
def optimize(m: NormalFunction, code: List[AssemblyLine], options: CompilationOptions): List[AssemblyLine] = {
|
||||||
val oldVerbosity = ErrorReporting.verbosity
|
val oldVerbosity = ErrorReporting.verbosity
|
||||||
@@ -44,8 +45,8 @@ object SuperOptimizer extends AssemblyOptimization {
|
|||||||
ChangeIndexRegisterOptimizationPreferringX2Y,
|
ChangeIndexRegisterOptimizationPreferringX2Y,
|
||||||
ChangeIndexRegisterOptimizationPreferringY2X)
|
ChangeIndexRegisterOptimizationPreferringY2X)
|
||||||
val seenSoFar = mutable.Set[CodeView]()
|
val seenSoFar = mutable.Set[CodeView]()
|
||||||
val queue = mutable.Queue[(List[AssemblyOptimization], List[AssemblyLine])]()
|
val queue = mutable.Queue[(List[AssemblyOptimization[AssemblyLine]], List[AssemblyLine])]()
|
||||||
val leaves = mutable.ListBuffer[(List[AssemblyOptimization], List[AssemblyLine])]()
|
val leaves = mutable.ListBuffer[(List[AssemblyOptimization[AssemblyLine]], List[AssemblyLine])]()
|
||||||
|
|
||||||
val quickScrub = List(
|
val quickScrub = List(
|
||||||
UnusedLabelRemoval,
|
UnusedLabelRemoval,
|
@@ -1,11 +1,12 @@
|
|||||||
package millfork.assembly.opt
|
package millfork.assembly.mos.opt
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
|
|
||||||
import millfork.assembly._
|
import millfork.assembly._
|
||||||
import millfork.assembly.Opcode._
|
import millfork.assembly.mos._
|
||||||
|
import millfork.assembly.mos.Opcode._
|
||||||
import millfork.assembly.AddrMode._
|
import millfork.assembly.AddrMode._
|
||||||
import millfork.assembly.OpcodeClasses._
|
import millfork.assembly.mos.OpcodeClasses._
|
||||||
import millfork.env.{Constant, NormalFunction, NumericConstant}
|
import millfork.env.{Constant, NormalFunction, NumericConstant}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -515,7 +516,7 @@ object UndocumentedOptimizations {
|
|||||||
(Elidable & HasOpcode(ANC) & DoesntMatterWhatItDoesWith(State.C)) ~~> (_.map(_.copy(opcode = AND))),
|
(Elidable & HasOpcode(ANC) & DoesntMatterWhatItDoesWith(State.C)) ~~> (_.map(_.copy(opcode = AND))),
|
||||||
)
|
)
|
||||||
|
|
||||||
val All: List[AssemblyOptimization] = List(
|
val All: List[AssemblyOptimization[AssemblyLine]] = List(
|
||||||
UseLax,
|
UseLax,
|
||||||
UseSax,
|
UseSax,
|
||||||
UseSbx,
|
UseSbx,
|
@@ -1,16 +1,16 @@
|
|||||||
package millfork.assembly.opt
|
package millfork.assembly.mos.opt
|
||||||
|
|
||||||
import millfork.CompilationOptions
|
import millfork.CompilationOptions
|
||||||
import millfork.assembly.AddrMode._
|
import millfork.assembly.mos.AssemblyLine
|
||||||
import millfork.assembly.Opcode._
|
import millfork.assembly.mos.Opcode._
|
||||||
import millfork.assembly.{AddrMode, AssemblyLine}
|
import millfork.assembly.AssemblyOptimization
|
||||||
import millfork.env._
|
import millfork.env._
|
||||||
import millfork.error.ErrorReporting
|
import millfork.error.ErrorReporting
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Karol Stasiak
|
* @author Karol Stasiak
|
||||||
*/
|
*/
|
||||||
object UnusedLabelRemoval extends AssemblyOptimization {
|
object UnusedLabelRemoval extends AssemblyOptimization[AssemblyLine] {
|
||||||
|
|
||||||
override def optimize(f: NormalFunction, code: List[AssemblyLine], options: CompilationOptions): List[AssemblyLine] = {
|
override def optimize(f: NormalFunction, code: List[AssemblyLine], options: CompilationOptions): List[AssemblyLine] = {
|
||||||
val usedLabels = code.flatMap {
|
val usedLabels = code.flatMap {
|
@@ -1,6 +1,6 @@
|
|||||||
package millfork.assembly.opt
|
package millfork.assembly.mos.opt
|
||||||
|
|
||||||
import millfork.assembly.AssemblyLine
|
import millfork.assembly.mos.AssemblyLine
|
||||||
import millfork.env._
|
import millfork.env._
|
||||||
import millfork.error.ErrorReporting
|
import millfork.error.ErrorReporting
|
||||||
|
|
@@ -1,8 +1,9 @@
|
|||||||
package millfork.assembly.opt
|
package millfork.assembly.mos.opt
|
||||||
|
|
||||||
import millfork.{CompilationFlag, CompilationOptions, NonOverlappingIntervals}
|
import millfork.{CompilationFlag, CompilationOptions, NonOverlappingIntervals}
|
||||||
import millfork.assembly.{AddrMode, AssemblyLine, OpcodeClasses}
|
import millfork.assembly.{AddrMode, AssemblyOptimization}
|
||||||
import millfork.assembly.Opcode._
|
import millfork.assembly.mos._
|
||||||
|
import millfork.assembly.mos.Opcode._
|
||||||
import millfork.assembly.AddrMode._
|
import millfork.assembly.AddrMode._
|
||||||
import millfork.env._
|
import millfork.env._
|
||||||
import millfork.error.ErrorReporting
|
import millfork.error.ErrorReporting
|
||||||
@@ -12,7 +13,7 @@ import scala.collection.mutable.ListBuffer
|
|||||||
/**
|
/**
|
||||||
* @author Karol Stasiak
|
* @author Karol Stasiak
|
||||||
*/
|
*/
|
||||||
object VariableToRegisterOptimization extends AssemblyOptimization {
|
object VariableToRegisterOptimization extends AssemblyOptimization[AssemblyLine] {
|
||||||
|
|
||||||
object CyclesAndBytes {
|
object CyclesAndBytes {
|
||||||
val Zero = CyclesAndBytes(0, 0)
|
val Zero = CyclesAndBytes(0, 0)
|
@@ -1,8 +1,9 @@
|
|||||||
package millfork.assembly.opt
|
package millfork.assembly.mos.opt
|
||||||
|
|
||||||
import millfork.assembly.Opcode._
|
import millfork.assembly.mos.Opcode._
|
||||||
import millfork.assembly.AddrMode._
|
import millfork.assembly.AddrMode._
|
||||||
import millfork.assembly.AssemblyLine
|
import millfork.assembly.AssemblyOptimization
|
||||||
|
import millfork.assembly.mos.AssemblyLine
|
||||||
import millfork.env.{CompoundConstant, Constant, MathOperator}
|
import millfork.env.{CompoundConstant, Constant, MathOperator}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -74,7 +75,7 @@ object ZeropageRegisterOptimizations {
|
|||||||
(Elidable & HasOpcode(STA) & RefersTo("__reg", 1) & DoesntMatterWhatItDoesWithReg(1)) ~~> (_.tail),
|
(Elidable & HasOpcode(STA) & RefersTo("__reg", 1) & DoesntMatterWhatItDoesWithReg(1)) ~~> (_.tail),
|
||||||
)
|
)
|
||||||
|
|
||||||
val All: List[AssemblyOptimization] = List(
|
val All: List[AssemblyOptimization[AssemblyLine]] = List(
|
||||||
ConstantMultiplication,
|
ConstantMultiplication,
|
||||||
DeadRegStore,
|
DeadRegStore,
|
||||||
DeadRegStoreFromFlow,
|
DeadRegStoreFromFlow,
|
@@ -1,14 +0,0 @@
|
|||||||
package millfork.assembly.opt
|
|
||||||
|
|
||||||
import millfork.CompilationOptions
|
|
||||||
import millfork.assembly.AssemblyLine
|
|
||||||
import millfork.env.NormalFunction
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Karol Stasiak
|
|
||||||
*/
|
|
||||||
trait AssemblyOptimization {
|
|
||||||
def name: String
|
|
||||||
|
|
||||||
def optimize(f: NormalFunction, code: List[AssemblyLine], options: CompilationOptions): List[AssemblyLine]
|
|
||||||
}
|
|
12
src/main/scala/millfork/compiler/AbstractCompiler.scala
Normal file
12
src/main/scala/millfork/compiler/AbstractCompiler.scala
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package millfork.compiler
|
||||||
|
|
||||||
|
import millfork.assembly.AbstractCode
|
||||||
|
import millfork.compiler.mos.CompilationContext
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Karol Stasiak
|
||||||
|
*/
|
||||||
|
abstract class AbstractCompiler[T <: AbstractCode] {
|
||||||
|
def nextLabel(prefix: String): String
|
||||||
|
def compile(ctx: CompilationContext): List[T]
|
||||||
|
}
|
@@ -0,0 +1,99 @@
|
|||||||
|
package millfork.compiler
|
||||||
|
|
||||||
|
import millfork.env._
|
||||||
|
import millfork.node._
|
||||||
|
import millfork.error.ErrorReporting
|
||||||
|
import millfork.assembly.AbstractCode
|
||||||
|
import millfork.compiler.mos.CompilationContext
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Karol Stasiak
|
||||||
|
*/
|
||||||
|
class AbstractExpressionCompiler[T <: AbstractCode] {
|
||||||
|
|
||||||
|
def getExpressionType(ctx: CompilationContext, expr: Expression): Type = {
|
||||||
|
val env = ctx.env
|
||||||
|
val b = env.get[Type]("byte")
|
||||||
|
val bool = env.get[Type]("bool$")
|
||||||
|
val v = env.get[Type]("void")
|
||||||
|
val w = env.get[Type]("word")
|
||||||
|
expr match {
|
||||||
|
case LiteralExpression(value, size) =>
|
||||||
|
size match {
|
||||||
|
case 1 => b
|
||||||
|
case 2 => w
|
||||||
|
case 3 => env.get[Type]("farword")
|
||||||
|
case 4 => env.get[Type]("long")
|
||||||
|
}
|
||||||
|
case VariableExpression(name) =>
|
||||||
|
env.get[TypedThing](name, expr.position).typ
|
||||||
|
case HalfWordExpression(param, _) =>
|
||||||
|
getExpressionType(ctx, param)
|
||||||
|
b
|
||||||
|
case IndexedExpression(_, _) => b
|
||||||
|
case SeparateBytesExpression(hi, lo) =>
|
||||||
|
if (getExpressionType(ctx, hi).size > 1) ErrorReporting.error("Hi byte too large", hi.position)
|
||||||
|
if (getExpressionType(ctx, lo).size > 1) ErrorReporting.error("Lo byte too large", lo.position)
|
||||||
|
w
|
||||||
|
case SumExpression(params, _) => params.map { case (_, e) => getExpressionType(ctx, e).size }.max match {
|
||||||
|
case 1 => b
|
||||||
|
case 2 => w
|
||||||
|
case _ => ErrorReporting.error("Adding values bigger than words", expr.position); w
|
||||||
|
}
|
||||||
|
case FunctionCallExpression("nonet", params) => w
|
||||||
|
case FunctionCallExpression("not", params) => bool
|
||||||
|
case FunctionCallExpression("hi", params) => b
|
||||||
|
case FunctionCallExpression("lo", params) => b
|
||||||
|
case FunctionCallExpression("*", params) => b
|
||||||
|
case FunctionCallExpression("|" | "&" | "^", params) => params.map { e => getExpressionType(ctx, e).size }.max match {
|
||||||
|
case 1 => b
|
||||||
|
case 2 => w
|
||||||
|
case _ => ErrorReporting.error("Adding values bigger than words", expr.position); w
|
||||||
|
}
|
||||||
|
case FunctionCallExpression("<<", List(a1, a2)) =>
|
||||||
|
if (getExpressionType(ctx, a2).size > 1) ErrorReporting.error("Shift amount too large", a2.position)
|
||||||
|
getExpressionType(ctx, a1)
|
||||||
|
case FunctionCallExpression(">>", List(a1, a2)) =>
|
||||||
|
if (getExpressionType(ctx, a2).size > 1) ErrorReporting.error("Shift amount too large", a2.position)
|
||||||
|
getExpressionType(ctx, a1)
|
||||||
|
case FunctionCallExpression("<<'", params) => b
|
||||||
|
case FunctionCallExpression(">>'", params) => b
|
||||||
|
case FunctionCallExpression(">>>>", params) => b
|
||||||
|
case FunctionCallExpression("&&", params) => bool
|
||||||
|
case FunctionCallExpression("||", params) => bool
|
||||||
|
case FunctionCallExpression("^^", params) => bool
|
||||||
|
case FunctionCallExpression("==", params) => bool
|
||||||
|
case FunctionCallExpression("!=", params) => bool
|
||||||
|
case FunctionCallExpression("<", params) => bool
|
||||||
|
case FunctionCallExpression(">", params) => bool
|
||||||
|
case FunctionCallExpression("<=", params) => bool
|
||||||
|
case FunctionCallExpression(">=", params) => bool
|
||||||
|
case FunctionCallExpression("+=", params) => v
|
||||||
|
case FunctionCallExpression("-=", params) => v
|
||||||
|
case FunctionCallExpression("*=", params) => v
|
||||||
|
case FunctionCallExpression("+'=", params) => v
|
||||||
|
case FunctionCallExpression("-'=", params) => v
|
||||||
|
case FunctionCallExpression("*'=", params) => v
|
||||||
|
case FunctionCallExpression("|=", params) => v
|
||||||
|
case FunctionCallExpression("&=", params) => v
|
||||||
|
case FunctionCallExpression("^=", params) => v
|
||||||
|
case FunctionCallExpression("<<=", params) => v
|
||||||
|
case FunctionCallExpression(">>=", params) => v
|
||||||
|
case FunctionCallExpression("<<'=", params) => v
|
||||||
|
case FunctionCallExpression(">>'=", params) => v
|
||||||
|
case f@FunctionCallExpression(name, params) =>
|
||||||
|
ctx.env.maybeGet[Type](name) match {
|
||||||
|
case Some(typ) =>
|
||||||
|
typ
|
||||||
|
case None =>
|
||||||
|
lookupFunction(ctx, f).returnType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def lookupFunction(ctx: CompilationContext, f: FunctionCallExpression): MangledFunction = {
|
||||||
|
val paramsWithTypes = f.expressions.map(x => getExpressionType(ctx, x) -> x)
|
||||||
|
ctx.env.lookupFunction(f.functionName, paramsWithTypes).getOrElse(
|
||||||
|
ErrorReporting.fatal(s"Cannot find function `${f.functionName}` with given params `${paramsWithTypes.map(_._1).mkString("(", ",", ")")}`", f.position))
|
||||||
|
}
|
||||||
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
package millfork.compiler
|
package millfork.compiler.mos
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Karol Stasiak
|
* @author Karol Stasiak
|
@@ -1,13 +1,13 @@
|
|||||||
package millfork.compiler
|
package millfork.compiler.mos
|
||||||
|
|
||||||
import millfork.{CompilationFlag, CompilationOptions}
|
import millfork.CompilationFlag
|
||||||
|
import millfork.assembly.AddrMode._
|
||||||
|
import millfork.assembly.mos.Opcode._
|
||||||
|
import millfork.assembly.mos._
|
||||||
import millfork.assembly._
|
import millfork.assembly._
|
||||||
import millfork.env._
|
import millfork.env._
|
||||||
import millfork.node._
|
|
||||||
import millfork.assembly.Opcode._
|
|
||||||
import millfork.assembly.AddrMode._
|
|
||||||
import millfork.assembly.opt.ConcernsY
|
|
||||||
import millfork.error.ErrorReporting
|
import millfork.error.ErrorReporting
|
||||||
|
import millfork.node._
|
||||||
|
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
import scala.collection.mutable.ListBuffer
|
import scala.collection.mutable.ListBuffer
|
||||||
@@ -55,15 +55,15 @@ object BuiltIns {
|
|||||||
case (p: ConstantPointy, _, _, _, None) =>
|
case (p: ConstantPointy, _, _, _, None) =>
|
||||||
Nil -> List(AssemblyLine.absolute(opcode, p.value + constantPart))
|
Nil -> List(AssemblyLine.absolute(opcode, p.value + constantPart))
|
||||||
case (p: ConstantPointy, _, 1, IndexChoice.RequireX | IndexChoice.PreferX, Some(v)) =>
|
case (p: ConstantPointy, _, 1, IndexChoice.RequireX | IndexChoice.PreferX, Some(v)) =>
|
||||||
ExpressionCompiler.compile(ctx, v, Some(b -> RegisterVariable(Register.X, b)), NoBranching) -> List(AssemblyLine.absoluteX(opcode, p.value + constantPart))
|
MosExpressionCompiler.compile(ctx, v, Some(b -> RegisterVariable(MosRegister.X, b)), NoBranching) -> List(AssemblyLine.absoluteX(opcode, p.value + constantPart))
|
||||||
case (p: ConstantPointy, _, 1, IndexChoice.PreferY, Some(v)) =>
|
case (p: ConstantPointy, _, 1, IndexChoice.PreferY, Some(v)) =>
|
||||||
ExpressionCompiler.compile(ctx, v, Some(b -> RegisterVariable(Register.Y, b)), NoBranching) -> List(AssemblyLine.absoluteY(opcode, p.value + constantPart))
|
MosExpressionCompiler.compile(ctx, v, Some(b -> RegisterVariable(MosRegister.Y, b)), NoBranching) -> List(AssemblyLine.absoluteY(opcode, p.value + constantPart))
|
||||||
case (p: VariablePointy, 0 | 1, _, IndexChoice.PreferX | IndexChoice.PreferY, _) =>
|
case (p: VariablePointy, 0 | 1, _, IndexChoice.PreferX | IndexChoice.PreferY, _) =>
|
||||||
ExpressionCompiler.compile(ctx, index, Some(b -> RegisterVariable(Register.Y, b)), NoBranching) -> List(AssemblyLine.indexedY(opcode, p.addr))
|
MosExpressionCompiler.compile(ctx, index, Some(b -> RegisterVariable(MosRegister.Y, b)), NoBranching) -> List(AssemblyLine.indexedY(opcode, p.addr))
|
||||||
case (p: ConstantPointy, _, 2, IndexChoice.PreferX | IndexChoice.PreferY, Some(v)) =>
|
case (p: ConstantPointy, _, 2, IndexChoice.PreferX | IndexChoice.PreferY, Some(v)) =>
|
||||||
ExpressionCompiler.prepareWordIndexing(ctx, p, index) -> List(AssemblyLine.indexedY(opcode, env.get[VariableInMemory]("__reg")))
|
MosExpressionCompiler.prepareWordIndexing(ctx, p, index) -> List(AssemblyLine.indexedY(opcode, env.get[VariableInMemory]("__reg")))
|
||||||
case (p: VariablePointy, 2, _, IndexChoice.PreferX | IndexChoice.PreferY, _) =>
|
case (p: VariablePointy, 2, _, IndexChoice.PreferX | IndexChoice.PreferY, _) =>
|
||||||
ExpressionCompiler.prepareWordIndexing(ctx, p, index) -> List(AssemblyLine.indexedY(opcode, env.get[VariableInMemory]("__reg")))
|
MosExpressionCompiler.prepareWordIndexing(ctx, p, index) -> List(AssemblyLine.indexedY(opcode, env.get[VariableInMemory]("__reg")))
|
||||||
case _ =>
|
case _ =>
|
||||||
ErrorReporting.error("Invalid index for simple operation argument", index.position)
|
ErrorReporting.error("Invalid index for simple operation argument", index.position)
|
||||||
Nil -> Nil
|
Nil -> Nil
|
||||||
@@ -73,11 +73,11 @@ object BuiltIns {
|
|||||||
case _: FunctionCallExpression | _:SumExpression if commutative =>
|
case _: FunctionCallExpression | _:SumExpression if commutative =>
|
||||||
// TODO: is it ok?
|
// TODO: is it ok?
|
||||||
if (ctx.options.flag(CompilationFlag.EmitEmulation65816Opcodes)) {
|
if (ctx.options.flag(CompilationFlag.EmitEmulation65816Opcodes)) {
|
||||||
return List(AssemblyLine.implied(PHA)) ++ ExpressionCompiler.compile(ctx.addStack(1), source, Some(b -> RegisterVariable(Register.A, b)), NoBranching) ++ wrapInSedCldIfNeeded(decimal, List(
|
return List(AssemblyLine.implied(PHA)) ++ MosExpressionCompiler.compile(ctx.addStack(1), source, Some(b -> RegisterVariable(MosRegister.A, b)), NoBranching) ++ wrapInSedCldIfNeeded(decimal, List(
|
||||||
AssemblyLine.stackRelative(opcode, 1),
|
AssemblyLine.stackRelative(opcode, 1),
|
||||||
AssemblyLine.implied(PHX)))
|
AssemblyLine.implied(PHX)))
|
||||||
} else {
|
} else {
|
||||||
return List(AssemblyLine.implied(PHA)) ++ ExpressionCompiler.compile(ctx.addStack(1), source, Some(b -> RegisterVariable(Register.A, b)), NoBranching) ++ wrapInSedCldIfNeeded(decimal, List(
|
return List(AssemblyLine.implied(PHA)) ++ MosExpressionCompiler.compile(ctx.addStack(1), source, Some(b -> RegisterVariable(MosRegister.A, b)), NoBranching) ++ wrapInSedCldIfNeeded(decimal, List(
|
||||||
AssemblyLine.implied(TSX),
|
AssemblyLine.implied(TSX),
|
||||||
AssemblyLine.absoluteX(opcode, 0x101),
|
AssemblyLine.absoluteX(opcode, 0x101),
|
||||||
AssemblyLine.implied(INX),
|
AssemblyLine.implied(INX),
|
||||||
@@ -130,7 +130,7 @@ object BuiltIns {
|
|||||||
val normalizedParams = sortedParams
|
val normalizedParams = sortedParams
|
||||||
|
|
||||||
val h = normalizedParams.head
|
val h = normalizedParams.head
|
||||||
val firstParamCompiled = ExpressionCompiler.compile(ctx, h._2, Some(b -> RegisterVariable(Register.A, b)), NoBranching)
|
val firstParamCompiled = MosExpressionCompiler.compile(ctx, h._2, Some(b -> RegisterVariable(MosRegister.A, b)), NoBranching)
|
||||||
val firstParamSignCompiled = if (h._1) {
|
val firstParamSignCompiled = if (h._1) {
|
||||||
// TODO: check if decimal subtraction works correctly here
|
// TODO: check if decimal subtraction works correctly here
|
||||||
List(AssemblyLine.immediate(EOR, 0xff), AssemblyLine.implied(SEC), AssemblyLine.immediate(ADC, 0))
|
List(AssemblyLine.immediate(EOR, 0xff), AssemblyLine.implied(SEC), AssemblyLine.immediate(ADC, 0))
|
||||||
@@ -169,7 +169,7 @@ object BuiltIns {
|
|||||||
val sortedParams = params.sortBy { expr => simplicity(ctx.env, expr) }
|
val sortedParams = params.sortBy { expr => simplicity(ctx.env, expr) }
|
||||||
|
|
||||||
val h = sortedParams.head
|
val h = sortedParams.head
|
||||||
val firstParamCompiled = ExpressionCompiler.compile(ctx, h, Some(b -> RegisterVariable(Register.A, b)), NoBranching)
|
val firstParamCompiled = MosExpressionCompiler.compile(ctx, h, Some(b -> RegisterVariable(MosRegister.A, b)), NoBranching)
|
||||||
|
|
||||||
val remainingParamsCompiled = sortedParams.tail.flatMap { p =>
|
val remainingParamsCompiled = sortedParams.tail.flatMap { p =>
|
||||||
simpleOperation(opcode, ctx, p, IndexChoice.PreferY, preserveA = true, commutative = true)
|
simpleOperation(opcode, ctx, p, IndexChoice.PreferY, preserveA = true, commutative = true)
|
||||||
@@ -180,17 +180,17 @@ object BuiltIns {
|
|||||||
|
|
||||||
def compileShiftOps(opcode: Opcode.Value, ctx: CompilationContext, l: Expression, r: Expression): List[AssemblyLine] = {
|
def compileShiftOps(opcode: Opcode.Value, ctx: CompilationContext, l: Expression, r: Expression): List[AssemblyLine] = {
|
||||||
val b = ctx.env.get[Type]("byte")
|
val b = ctx.env.get[Type]("byte")
|
||||||
val firstParamCompiled = ExpressionCompiler.compile(ctx, l, Some(b -> RegisterVariable(Register.A, b)), NoBranching)
|
val firstParamCompiled = MosExpressionCompiler.compile(ctx, l, Some(b -> RegisterVariable(MosRegister.A, b)), NoBranching)
|
||||||
ctx.env.eval(r) match {
|
ctx.env.eval(r) match {
|
||||||
case Some(NumericConstant(0, _)) =>
|
case Some(NumericConstant(0, _)) =>
|
||||||
ExpressionCompiler.compile(ctx, l, None, NoBranching)
|
MosExpressionCompiler.compile(ctx, l, None, NoBranching)
|
||||||
case Some(NumericConstant(v, _)) if v > 0 =>
|
case Some(NumericConstant(v, _)) if v > 0 =>
|
||||||
firstParamCompiled ++ List.fill(v.toInt)(AssemblyLine.implied(opcode))
|
firstParamCompiled ++ List.fill(v.toInt)(AssemblyLine.implied(opcode))
|
||||||
case _ =>
|
case _ =>
|
||||||
val compileCounter = ExpressionCompiler.preserveRegisterIfNeeded(ctx, Register.A,
|
val compileCounter = MosExpressionCompiler.preserveRegisterIfNeeded(ctx, MosRegister.A,
|
||||||
ExpressionCompiler.compile(ctx, r, Some(b -> RegisterVariable(Register.X, b)), NoBranching))
|
MosExpressionCompiler.compile(ctx, r, Some(b -> RegisterVariable(MosRegister.X, b)), NoBranching))
|
||||||
val labelSkip = MfCompiler.nextLabel("ss")
|
val labelSkip = MosCompiler.nextLabel("ss")
|
||||||
val labelRepeat = MfCompiler.nextLabel("sr")
|
val labelRepeat = MosCompiler.nextLabel("sr")
|
||||||
val loop = List(
|
val loop = List(
|
||||||
AssemblyLine.relative(BEQ, labelSkip),
|
AssemblyLine.relative(BEQ, labelSkip),
|
||||||
AssemblyLine.label(labelRepeat),
|
AssemblyLine.label(labelRepeat),
|
||||||
@@ -216,7 +216,7 @@ object BuiltIns {
|
|||||||
}
|
}
|
||||||
env.eval(rhs) match {
|
env.eval(rhs) match {
|
||||||
case Some(NumericConstant(0, _)) =>
|
case Some(NumericConstant(0, _)) =>
|
||||||
ExpressionCompiler.compile(ctx, lhs, None, NoBranching)
|
MosExpressionCompiler.compile(ctx, lhs, None, NoBranching)
|
||||||
case Some(NumericConstant(shift, _)) if shift > 0 =>
|
case Some(NumericConstant(shift, _)) if shift > 0 =>
|
||||||
if (ctx.options.flag(CompilationFlag.RorWarning))
|
if (ctx.options.flag(CompilationFlag.RorWarning))
|
||||||
ErrorReporting.warn("ROR instruction generated", ctx.options, lhs.position)
|
ErrorReporting.warn("ROR instruction generated", ctx.options, lhs.position)
|
||||||
@@ -230,15 +230,15 @@ object BuiltIns {
|
|||||||
def compileInPlaceByteShiftOps(opcode: Opcode.Value, ctx: CompilationContext, lhs: LhsExpression, rhs: Expression): List[AssemblyLine] = {
|
def compileInPlaceByteShiftOps(opcode: Opcode.Value, ctx: CompilationContext, lhs: LhsExpression, rhs: Expression): List[AssemblyLine] = {
|
||||||
val env = ctx.env
|
val env = ctx.env
|
||||||
val b = env.get[Type]("byte")
|
val b = env.get[Type]("byte")
|
||||||
val firstParamCompiled = ExpressionCompiler.compile(ctx, lhs, Some(b -> RegisterVariable(Register.A, b)), NoBranching)
|
val firstParamCompiled = MosExpressionCompiler.compile(ctx, lhs, Some(b -> RegisterVariable(MosRegister.A, b)), NoBranching)
|
||||||
env.eval(rhs) match {
|
env.eval(rhs) match {
|
||||||
case Some(NumericConstant(0, _)) =>
|
case Some(NumericConstant(0, _)) =>
|
||||||
ExpressionCompiler.compile(ctx, lhs, None, NoBranching)
|
MosExpressionCompiler.compile(ctx, lhs, None, NoBranching)
|
||||||
case Some(NumericConstant(v, _)) if v > 0 =>
|
case Some(NumericConstant(v, _)) if v > 0 =>
|
||||||
val result = simpleOperation(opcode, ctx, lhs, IndexChoice.RequireX, preserveA = true, commutative = false)
|
val result = simpleOperation(opcode, ctx, lhs, IndexChoice.RequireX, preserveA = true, commutative = false)
|
||||||
result ++ List.fill(v.toInt - 1)(result.last)
|
result ++ List.fill(v.toInt - 1)(result.last)
|
||||||
case _ =>
|
case _ =>
|
||||||
compileShiftOps(opcode, ctx, lhs, rhs) ++ ExpressionCompiler.compileByteStorage(ctx, Register.A, lhs)
|
compileShiftOps(opcode, ctx, lhs, rhs) ++ MosExpressionCompiler.compileByteStorage(ctx, MosRegister.A, lhs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,7 +251,7 @@ object BuiltIns {
|
|||||||
// TODO: this probably breaks in case of complex split word expressions
|
// TODO: this probably breaks in case of complex split word expressions
|
||||||
env.eval(rhs) match {
|
env.eval(rhs) match {
|
||||||
case Some(NumericConstant(0, _)) =>
|
case Some(NumericConstant(0, _)) =>
|
||||||
ExpressionCompiler.compile(ctx, lhs, None, NoBranching)
|
MosExpressionCompiler.compile(ctx, lhs, None, NoBranching)
|
||||||
case Some(NumericConstant(shift, _)) if shift > 0 =>
|
case Some(NumericConstant(shift, _)) if shift > 0 =>
|
||||||
if (ctx.options.flags(CompilationFlag.EmitNative65816Opcodes)) {
|
if (ctx.options.flags(CompilationFlag.EmitNative65816Opcodes)) {
|
||||||
targetBytes match {
|
targetBytes match {
|
||||||
@@ -273,16 +273,16 @@ object BuiltIns {
|
|||||||
val usesX = targetBytes.exists(_.exists(_.concernsX))
|
val usesX = targetBytes.exists(_.exists(_.concernsX))
|
||||||
val usesY = targetBytes.exists(_.exists(_.concernsY))
|
val usesY = targetBytes.exists(_.exists(_.concernsY))
|
||||||
val (register, decrease) = (usesX, usesY) match {
|
val (register, decrease) = (usesX, usesY) match {
|
||||||
case (true, false) => Register.Y -> DEY
|
case (true, false) => MosRegister.Y -> DEY
|
||||||
case (false, true) => Register.X -> DEX
|
case (false, true) => MosRegister.X -> DEX
|
||||||
case (false, false) => Register.X -> DEX
|
case (false, false) => MosRegister.X -> DEX
|
||||||
case (true, true) => ???
|
case (true, true) => ???
|
||||||
}
|
}
|
||||||
|
|
||||||
val compileCounter = ExpressionCompiler.preserveRegisterIfNeeded(ctx, Register.A,
|
val compileCounter = MosExpressionCompiler.preserveRegisterIfNeeded(ctx, MosRegister.A,
|
||||||
ExpressionCompiler.compile(ctx, rhs, Some(b -> RegisterVariable(register, b)), NoBranching))
|
MosExpressionCompiler.compile(ctx, rhs, Some(b -> RegisterVariable(register, b)), NoBranching))
|
||||||
val labelSkip = MfCompiler.nextLabel("ss")
|
val labelSkip = MosCompiler.nextLabel("ss")
|
||||||
val labelRepeat = MfCompiler.nextLabel("sr")
|
val labelRepeat = MosCompiler.nextLabel("sr")
|
||||||
|
|
||||||
if (ctx.options.flags(CompilationFlag.EmitNative65816Opcodes)) {
|
if (ctx.options.flags(CompilationFlag.EmitNative65816Opcodes)) {
|
||||||
targetBytes match {
|
targetBytes match {
|
||||||
@@ -323,7 +323,7 @@ object BuiltIns {
|
|||||||
if (simplicity(env, lhs) >= 'J' && simplicity(env, rhs) < 'J') {
|
if (simplicity(env, lhs) >= 'J' && simplicity(env, rhs) < 'J') {
|
||||||
return compileByteComparison(ctx, ComparisonType.flip(compType), rhs, lhs, branches)
|
return compileByteComparison(ctx, ComparisonType.flip(compType), rhs, lhs, branches)
|
||||||
}
|
}
|
||||||
val firstParamCompiled = ExpressionCompiler.compile(ctx, lhs, Some(b -> RegisterVariable(Register.A, b)), NoBranching)
|
val firstParamCompiled = MosExpressionCompiler.compile(ctx, lhs, Some(b -> RegisterVariable(MosRegister.A, b)), NoBranching)
|
||||||
val maybeConstant = env.eval(rhs)
|
val maybeConstant = env.eval(rhs)
|
||||||
maybeConstant match {
|
maybeConstant match {
|
||||||
case Some(NumericConstant(0, _)) =>
|
case Some(NumericConstant(0, _)) =>
|
||||||
@@ -395,7 +395,7 @@ object BuiltIns {
|
|||||||
case ComparisonType.LessOrEqualUnsigned =>
|
case ComparisonType.LessOrEqualUnsigned =>
|
||||||
List(AssemblyLine.relative(BCC, Label(label)), AssemblyLine.relative(BEQ, Label(label)))
|
List(AssemblyLine.relative(BCC, Label(label)), AssemblyLine.relative(BEQ, Label(label)))
|
||||||
case ComparisonType.GreaterUnsigned =>
|
case ComparisonType.GreaterUnsigned =>
|
||||||
val x = MfCompiler.nextLabel("co")
|
val x = MosCompiler.nextLabel("co")
|
||||||
List(
|
List(
|
||||||
AssemblyLine.relative(BEQ, x),
|
AssemblyLine.relative(BEQ, x),
|
||||||
AssemblyLine.relative(BCS, Label(label)),
|
AssemblyLine.relative(BCS, Label(label)),
|
||||||
@@ -408,7 +408,7 @@ object BuiltIns {
|
|||||||
case ComparisonType.LessOrEqualSigned =>
|
case ComparisonType.LessOrEqualSigned =>
|
||||||
List(AssemblyLine.relative(BMI, Label(label)), AssemblyLine.relative(BEQ, Label(label)))
|
List(AssemblyLine.relative(BMI, Label(label)), AssemblyLine.relative(BEQ, Label(label)))
|
||||||
case ComparisonType.GreaterSigned =>
|
case ComparisonType.GreaterSigned =>
|
||||||
val x = MfCompiler.nextLabel("co")
|
val x = MosCompiler.nextLabel("co")
|
||||||
List(
|
List(
|
||||||
AssemblyLine.relative(BEQ, x),
|
AssemblyLine.relative(BEQ, x),
|
||||||
AssemblyLine.relative(BPL, Label(label)),
|
AssemblyLine.relative(BPL, Label(label)),
|
||||||
@@ -479,8 +479,8 @@ object BuiltIns {
|
|||||||
ErrorReporting.error("Too complex expressions in comparison", lhs.position)
|
ErrorReporting.error("Too complex expressions in comparison", lhs.position)
|
||||||
(Nil, Nil, Nil, Nil)
|
(Nil, Nil, Nil, Nil)
|
||||||
}
|
}
|
||||||
val lType = ExpressionCompiler.getExpressionType(ctx, lhs)
|
val lType = MosExpressionCompiler.getExpressionType(ctx, lhs)
|
||||||
val rType = ExpressionCompiler.getExpressionType(ctx, rhs)
|
val rType = MosExpressionCompiler.getExpressionType(ctx, rhs)
|
||||||
val compactEqualityComparison = if (ctx.options.flag(CompilationFlag.OptimizeForSpeed)) {
|
val compactEqualityComparison = if (ctx.options.flag(CompilationFlag.OptimizeForSpeed)) {
|
||||||
None
|
None
|
||||||
} else if (lType.size == 1 && !lType.isSigned) {
|
} else if (lType.size == 1 && !lType.isSigned) {
|
||||||
@@ -495,7 +495,7 @@ object BuiltIns {
|
|||||||
compactEqualityComparison match {
|
compactEqualityComparison match {
|
||||||
case Some(code) => code :+ AssemblyLine.relative(BEQ, Label(x))
|
case Some(code) => code :+ AssemblyLine.relative(BEQ, Label(x))
|
||||||
case None =>
|
case None =>
|
||||||
val innerLabel = MfCompiler.nextLabel("cp")
|
val innerLabel = MosCompiler.nextLabel("cp")
|
||||||
staTo(LDA, ll) ++
|
staTo(LDA, ll) ++
|
||||||
staTo(CMP, rl) ++
|
staTo(CMP, rl) ++
|
||||||
List(AssemblyLine.relative(BNE, innerLabel)) ++
|
List(AssemblyLine.relative(BNE, innerLabel)) ++
|
||||||
@@ -519,7 +519,7 @@ object BuiltIns {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case ComparisonType.LessUnsigned =>
|
case ComparisonType.LessUnsigned =>
|
||||||
val innerLabel = MfCompiler.nextLabel("cp")
|
val innerLabel = MosCompiler.nextLabel("cp")
|
||||||
staTo(LDA, lh) ++
|
staTo(LDA, lh) ++
|
||||||
staTo(CMP, rh) ++
|
staTo(CMP, rh) ++
|
||||||
List(
|
List(
|
||||||
@@ -532,7 +532,7 @@ object BuiltIns {
|
|||||||
AssemblyLine.label(innerLabel))
|
AssemblyLine.label(innerLabel))
|
||||||
|
|
||||||
case ComparisonType.LessOrEqualUnsigned =>
|
case ComparisonType.LessOrEqualUnsigned =>
|
||||||
val innerLabel = MfCompiler.nextLabel("cp")
|
val innerLabel = MosCompiler.nextLabel("cp")
|
||||||
staTo(LDA, rh) ++
|
staTo(LDA, rh) ++
|
||||||
staTo(CMP, lh) ++
|
staTo(CMP, lh) ++
|
||||||
List(AssemblyLine.relative(BCC, innerLabel),
|
List(AssemblyLine.relative(BCC, innerLabel),
|
||||||
@@ -543,7 +543,7 @@ object BuiltIns {
|
|||||||
AssemblyLine.label(innerLabel))
|
AssemblyLine.label(innerLabel))
|
||||||
|
|
||||||
case ComparisonType.GreaterUnsigned =>
|
case ComparisonType.GreaterUnsigned =>
|
||||||
val innerLabel = MfCompiler.nextLabel("cp")
|
val innerLabel = MosCompiler.nextLabel("cp")
|
||||||
staTo(LDA, rh) ++
|
staTo(LDA, rh) ++
|
||||||
staTo(CMP, lh) ++
|
staTo(CMP, lh) ++
|
||||||
List(AssemblyLine.relative(BCC, Label(x)),
|
List(AssemblyLine.relative(BCC, Label(x)),
|
||||||
@@ -554,7 +554,7 @@ object BuiltIns {
|
|||||||
AssemblyLine.label(innerLabel))
|
AssemblyLine.label(innerLabel))
|
||||||
|
|
||||||
case ComparisonType.GreaterOrEqualUnsigned =>
|
case ComparisonType.GreaterOrEqualUnsigned =>
|
||||||
val innerLabel = MfCompiler.nextLabel("cp")
|
val innerLabel = MosCompiler.nextLabel("cp")
|
||||||
staTo(LDA, lh) ++
|
staTo(LDA, lh) ++
|
||||||
staTo(CMP, rh) ++
|
staTo(CMP, rh) ++
|
||||||
List(AssemblyLine.relative(BCC, innerLabel),
|
List(AssemblyLine.relative(BCC, innerLabel),
|
||||||
@@ -570,7 +570,7 @@ object BuiltIns {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def compileLongComparison(ctx: CompilationContext, compType: ComparisonType.Value, lhs: Expression, rhs: Expression, size:Int, branches: BranchSpec, alreadyFlipped: Boolean = false): List[AssemblyLine] = {
|
def compileLongComparison(ctx: CompilationContext, compType: ComparisonType.Value, lhs: Expression, rhs: Expression, size:Int, branches: BranchSpec, alreadyFlipped: Boolean = false): List[AssemblyLine] = {
|
||||||
val rType = ExpressionCompiler.getExpressionType(ctx, rhs)
|
val rType = MosExpressionCompiler.getExpressionType(ctx, rhs)
|
||||||
if (rType.size < size && rType.isSigned) {
|
if (rType.size < size && rType.isSigned) {
|
||||||
if (alreadyFlipped) ???
|
if (alreadyFlipped) ???
|
||||||
else return compileLongComparison(ctx, ComparisonType.flip(compType), rhs, lhs, size, branches, alreadyFlipped = true)
|
else return compileLongComparison(ctx, ComparisonType.flip(compType), rhs, lhs, size, branches, alreadyFlipped = true)
|
||||||
@@ -617,7 +617,7 @@ object BuiltIns {
|
|||||||
case _ =>
|
case _ =>
|
||||||
effectiveComparisonType match {
|
effectiveComparisonType match {
|
||||||
case ComparisonType.Equal =>
|
case ComparisonType.Equal =>
|
||||||
val innerLabel = MfCompiler.nextLabel("cp")
|
val innerLabel = MosCompiler.nextLabel("cp")
|
||||||
val bytewise = l.zip(r).map{
|
val bytewise = l.zip(r).map{
|
||||||
case (staL, staR) => staTo(LDA, staL) ++ staTo(CMP, staR)
|
case (staL, staR) => staTo(LDA, staL) ++ staTo(CMP, staR)
|
||||||
}
|
}
|
||||||
@@ -658,13 +658,13 @@ object BuiltIns {
|
|||||||
val b = ctx.env.get[Type]("byte")
|
val b = ctx.env.get[Type]("byte")
|
||||||
ctx.env.eval(addend) match {
|
ctx.env.eval(addend) match {
|
||||||
case Some(NumericConstant(0, _)) =>
|
case Some(NumericConstant(0, _)) =>
|
||||||
ExpressionCompiler.compile(ctx, v, None, NoBranching) ++ (AssemblyLine.immediate(LDA, 0) :: ExpressionCompiler.compileByteStorage(ctx, Register.A, v))
|
MosExpressionCompiler.compile(ctx, v, None, NoBranching) ++ (AssemblyLine.immediate(LDA, 0) :: MosExpressionCompiler.compileByteStorage(ctx, MosRegister.A, v))
|
||||||
case Some(NumericConstant(1, _)) =>
|
case Some(NumericConstant(1, _)) =>
|
||||||
ExpressionCompiler.compile(ctx, v, None, NoBranching)
|
MosExpressionCompiler.compile(ctx, v, None, NoBranching)
|
||||||
case Some(NumericConstant(x, _)) =>
|
case Some(NumericConstant(x, _)) =>
|
||||||
compileByteMultiplication(ctx, v, x.toInt) ++ ExpressionCompiler.compileByteStorage(ctx, Register.A, v)
|
compileByteMultiplication(ctx, v, x.toInt) ++ MosExpressionCompiler.compileByteStorage(ctx, MosRegister.A, v)
|
||||||
case _ =>
|
case _ =>
|
||||||
PseudoregisterBuiltIns.compileByteMultiplication(ctx, Some(v), addend, storeInRegLo = false) ++ ExpressionCompiler.compileByteStorage(ctx, Register.A, v)
|
PseudoregisterBuiltIns.compileByteMultiplication(ctx, Some(v), addend, storeInRegLo = false) ++ MosExpressionCompiler.compileByteStorage(ctx, MosRegister.A, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -727,7 +727,7 @@ object BuiltIns {
|
|||||||
case _ => false
|
case _ => false
|
||||||
}
|
}
|
||||||
env.eval(addend) match {
|
env.eval(addend) match {
|
||||||
case Some(NumericConstant(0, _)) => ExpressionCompiler.compile(ctx, v, None, NoBranching)
|
case Some(NumericConstant(0, _)) => MosExpressionCompiler.compile(ctx, v, None, NoBranching)
|
||||||
case Some(NumericConstant(1, _)) if lhsIsDirectlyIncrementable && !decimal => if (subtract) {
|
case Some(NumericConstant(1, _)) if lhsIsDirectlyIncrementable && !decimal => if (subtract) {
|
||||||
simpleOperation(DEC, ctx, v, IndexChoice.RequireX, preserveA = false, commutative = true)
|
simpleOperation(DEC, ctx, v, IndexChoice.RequireX, preserveA = false, commutative = true)
|
||||||
} else {
|
} else {
|
||||||
@@ -741,25 +741,25 @@ object BuiltIns {
|
|||||||
}
|
}
|
||||||
case _ =>
|
case _ =>
|
||||||
if (!subtract && simplicity(env, v) > simplicity(env, addend)) {
|
if (!subtract && simplicity(env, v) > simplicity(env, addend)) {
|
||||||
val loadRhs = ExpressionCompiler.compile(ctx, addend, Some(b -> RegisterVariable(Register.A, b)), NoBranching)
|
val loadRhs = MosExpressionCompiler.compile(ctx, addend, Some(b -> RegisterVariable(MosRegister.A, b)), NoBranching)
|
||||||
val modifyAcc = insertBeforeLast(AssemblyLine.implied(CLC), simpleOperation(ADC, ctx, v, IndexChoice.PreferY, preserveA = true, commutative = true, decimal = decimal))
|
val modifyAcc = insertBeforeLast(AssemblyLine.implied(CLC), simpleOperation(ADC, ctx, v, IndexChoice.PreferY, preserveA = true, commutative = true, decimal = decimal))
|
||||||
val storeLhs = ExpressionCompiler.compileByteStorage(ctx, Register.A, v)
|
val storeLhs = MosExpressionCompiler.compileByteStorage(ctx, MosRegister.A, v)
|
||||||
loadRhs ++ modifyAcc ++ storeLhs
|
loadRhs ++ modifyAcc ++ storeLhs
|
||||||
} else {
|
} else {
|
||||||
val loadLhs = ExpressionCompiler.compile(ctx, v, Some(b -> RegisterVariable(Register.A, b)), NoBranching)
|
val loadLhs = MosExpressionCompiler.compile(ctx, v, Some(b -> RegisterVariable(MosRegister.A, b)), NoBranching)
|
||||||
val modifyLhs = if (subtract) {
|
val modifyLhs = if (subtract) {
|
||||||
insertBeforeLast(AssemblyLine.implied(SEC), simpleOperation(SBC, ctx, addend, IndexChoice.PreferY, preserveA = true, commutative = false, decimal = decimal))
|
insertBeforeLast(AssemblyLine.implied(SEC), simpleOperation(SBC, ctx, addend, IndexChoice.PreferY, preserveA = true, commutative = false, decimal = decimal))
|
||||||
} else {
|
} else {
|
||||||
insertBeforeLast(AssemblyLine.implied(CLC), simpleOperation(ADC, ctx, addend, IndexChoice.PreferY, preserveA = true, commutative = true, decimal = decimal))
|
insertBeforeLast(AssemblyLine.implied(CLC), simpleOperation(ADC, ctx, addend, IndexChoice.PreferY, preserveA = true, commutative = true, decimal = decimal))
|
||||||
}
|
}
|
||||||
val storeLhs = ExpressionCompiler.compileByteStorage(ctx, Register.A, v)
|
val storeLhs = MosExpressionCompiler.compileByteStorage(ctx, MosRegister.A, v)
|
||||||
loadLhs ++ modifyLhs ++ storeLhs
|
loadLhs ++ modifyLhs ++ storeLhs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private def getIndexerSize(ctx: CompilationContext, indexExpr: Expression) = {
|
private def getIndexerSize(ctx: CompilationContext, indexExpr: Expression) = {
|
||||||
ctx.env.evalVariableAndConstantSubParts(indexExpr)._1.map(v => ExpressionCompiler.getExpressionType(ctx, v)).size
|
ctx.env.evalVariableAndConstantSubParts(indexExpr)._1.map(v => MosExpressionCompiler.getExpressionType(ctx, v)).size
|
||||||
}
|
}
|
||||||
|
|
||||||
def compileInPlaceWordOrLongAddition(ctx: CompilationContext, lhs: LhsExpression, addend: Expression, subtract: Boolean, decimal: Boolean): List[AssemblyLine] = {
|
def compileInPlaceWordOrLongAddition(ctx: CompilationContext, lhs: LhsExpression, addend: Expression, subtract: Boolean, decimal: Boolean): List[AssemblyLine] = {
|
||||||
@@ -772,7 +772,7 @@ object BuiltIns {
|
|||||||
val targetBytes: List[List[AssemblyLine]] = getStorageForEachByte(ctx, lhs)
|
val targetBytes: List[List[AssemblyLine]] = getStorageForEachByte(ctx, lhs)
|
||||||
val lhsIsStack = targetBytes.head.head.opcode == TSX
|
val lhsIsStack = targetBytes.head.head.opcode == TSX
|
||||||
val targetSize = targetBytes.size
|
val targetSize = targetBytes.size
|
||||||
val addendType = ExpressionCompiler.getExpressionType(ctx, addend)
|
val addendType = MosExpressionCompiler.getExpressionType(ctx, addend)
|
||||||
var addendSize = addendType.size
|
var addendSize = addendType.size
|
||||||
|
|
||||||
def isRhsComplex(xs: List[AssemblyLine]): Boolean = xs match {
|
def isRhsComplex(xs: List[AssemblyLine]): Boolean = xs match {
|
||||||
@@ -795,7 +795,7 @@ object BuiltIns {
|
|||||||
case Nil => Nil
|
case Nil => Nil
|
||||||
case x :: Nil => staTo(DEC, x)
|
case x :: Nil => staTo(DEC, x)
|
||||||
case x :: xs =>
|
case x :: xs =>
|
||||||
val label = MfCompiler.nextLabel("de")
|
val label = MosCompiler.nextLabel("de")
|
||||||
staTo(LDA, x) ++
|
staTo(LDA, x) ++
|
||||||
List(AssemblyLine.relative(BNE, label)) ++
|
List(AssemblyLine.relative(BNE, label)) ++
|
||||||
doDec(xs) ++
|
doDec(xs) ++
|
||||||
@@ -805,7 +805,7 @@ object BuiltIns {
|
|||||||
|
|
||||||
val (calculateRhs, addendByteRead0): (List[AssemblyLine], List[List[AssemblyLine]]) = env.eval(addend) match {
|
val (calculateRhs, addendByteRead0): (List[AssemblyLine], List[List[AssemblyLine]]) = env.eval(addend) match {
|
||||||
case Some(NumericConstant(0, _)) =>
|
case Some(NumericConstant(0, _)) =>
|
||||||
return ExpressionCompiler.compile(ctx, lhs, None, NoBranching)
|
return MosExpressionCompiler.compile(ctx, lhs, None, NoBranching)
|
||||||
case Some(NumericConstant(1, _)) if canUseIncDec && !subtract =>
|
case Some(NumericConstant(1, _)) if canUseIncDec && !subtract =>
|
||||||
if (ctx.options.flags(CompilationFlag.Emit65CE02Opcodes)) {
|
if (ctx.options.flags(CompilationFlag.Emit65CE02Opcodes)) {
|
||||||
targetBytes match {
|
targetBytes match {
|
||||||
@@ -823,7 +823,7 @@ object BuiltIns {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val label = MfCompiler.nextLabel("in")
|
val label = MosCompiler.nextLabel("in")
|
||||||
return staTo(INC, targetBytes.head) ++ targetBytes.tail.flatMap(l => AssemblyLine.relative(BNE, label)::staTo(INC, l)) :+ AssemblyLine.label(label)
|
return staTo(INC, targetBytes.head) ++ targetBytes.tail.flatMap(l => AssemblyLine.relative(BNE, label)::staTo(INC, l)) :+ AssemblyLine.label(label)
|
||||||
case Some(NumericConstant(-1, _)) if canUseIncDec && subtract =>
|
case Some(NumericConstant(-1, _)) if canUseIncDec && subtract =>
|
||||||
if (ctx.options.flags(CompilationFlag.Emit65CE02Opcodes)) {
|
if (ctx.options.flags(CompilationFlag.Emit65CE02Opcodes)) {
|
||||||
@@ -842,7 +842,7 @@ object BuiltIns {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val label = MfCompiler.nextLabel("in")
|
val label = MosCompiler.nextLabel("in")
|
||||||
return staTo(INC, targetBytes.head) ++ targetBytes.tail.flatMap(l => AssemblyLine.relative(BNE, label)::staTo(INC, l)) :+ AssemblyLine.label(label)
|
return staTo(INC, targetBytes.head) ++ targetBytes.tail.flatMap(l => AssemblyLine.relative(BNE, label)::staTo(INC, l)) :+ AssemblyLine.label(label)
|
||||||
case Some(NumericConstant(1, _)) if canUseIncDec && subtract =>
|
case Some(NumericConstant(1, _)) if canUseIncDec && subtract =>
|
||||||
if (ctx.options.flags(CompilationFlag.Emit65CE02Opcodes)) {
|
if (ctx.options.flags(CompilationFlag.Emit65CE02Opcodes)) {
|
||||||
@@ -861,7 +861,7 @@ object BuiltIns {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val label = MfCompiler.nextLabel("de")
|
val label = MosCompiler.nextLabel("de")
|
||||||
return doDec(targetBytes)
|
return doDec(targetBytes)
|
||||||
case Some(NumericConstant(-1, _)) if canUseIncDec && !subtract =>
|
case Some(NumericConstant(-1, _)) if canUseIncDec && !subtract =>
|
||||||
if (ctx.options.flags(CompilationFlag.Emit65CE02Opcodes)) {
|
if (ctx.options.flags(CompilationFlag.Emit65CE02Opcodes)) {
|
||||||
@@ -880,7 +880,7 @@ object BuiltIns {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val label = MfCompiler.nextLabel("de")
|
val label = MosCompiler.nextLabel("de")
|
||||||
return doDec(targetBytes)
|
return doDec(targetBytes)
|
||||||
case Some(constant) =>
|
case Some(constant) =>
|
||||||
addendSize = targetSize
|
addendSize = targetSize
|
||||||
@@ -888,7 +888,7 @@ object BuiltIns {
|
|||||||
case None =>
|
case None =>
|
||||||
addendSize match {
|
addendSize match {
|
||||||
case 1 =>
|
case 1 =>
|
||||||
val base = ExpressionCompiler.compile(ctx, addend, Some(b -> RegisterVariable(Register.A, b)), NoBranching)
|
val base = MosExpressionCompiler.compile(ctx, addend, Some(b -> RegisterVariable(MosRegister.A, b)), NoBranching)
|
||||||
if (subtract) {
|
if (subtract) {
|
||||||
if (isRhsComplex(base)) {
|
if (isRhsComplex(base)) {
|
||||||
if (isRhsStack(base)) {
|
if (isRhsStack(base)) {
|
||||||
@@ -903,9 +903,9 @@ object BuiltIns {
|
|||||||
base -> List(Nil)
|
base -> List(Nil)
|
||||||
}
|
}
|
||||||
case 2 =>
|
case 2 =>
|
||||||
val base = ExpressionCompiler.compile(ctx, addend, Some(ExpressionCompiler.getExpressionType(ctx, addend) -> RegisterVariable(Register.AX, w)), NoBranching)
|
val base = MosExpressionCompiler.compile(ctx, addend, Some(MosExpressionCompiler.getExpressionType(ctx, addend) -> RegisterVariable(MosRegister.AX, w)), NoBranching)
|
||||||
if (isRhsStack(base)) {
|
if (isRhsStack(base)) {
|
||||||
val fixedBase = ExpressionCompiler.compile(ctx, addend, Some(ExpressionCompiler.getExpressionType(ctx, addend) -> RegisterVariable(Register.AY, w)), NoBranching)
|
val fixedBase = MosExpressionCompiler.compile(ctx, addend, Some(MosExpressionCompiler.getExpressionType(ctx, addend) -> RegisterVariable(MosRegister.AY, w)), NoBranching)
|
||||||
if (subtract) {
|
if (subtract) {
|
||||||
ErrorReporting.warn("Subtracting a stack-based value", ctx.options)
|
ErrorReporting.warn("Subtracting a stack-based value", ctx.options)
|
||||||
if (isRhsComplex(base)) {
|
if (isRhsComplex(base)) {
|
||||||
@@ -932,7 +932,7 @@ object BuiltIns {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (lhsIsStack) {
|
if (lhsIsStack) {
|
||||||
val fixedBase = ExpressionCompiler.compile(ctx, addend, Some(ExpressionCompiler.getExpressionType(ctx, addend) -> RegisterVariable(Register.AY, w)), NoBranching)
|
val fixedBase = MosExpressionCompiler.compile(ctx, addend, Some(MosExpressionCompiler.getExpressionType(ctx, addend) -> RegisterVariable(MosRegister.AY, w)), NoBranching)
|
||||||
fixedBase -> List(Nil, List(AssemblyLine.implied(TYA)))
|
fixedBase -> List(Nil, List(AssemblyLine.implied(TYA)))
|
||||||
} else {
|
} else {
|
||||||
base -> List(Nil, List(AssemblyLine.implied(TXA)))
|
base -> List(Nil, List(AssemblyLine.implied(TXA)))
|
||||||
@@ -1009,7 +1009,7 @@ object BuiltIns {
|
|||||||
} else {
|
} else {
|
||||||
if (i >= addendSize) {
|
if (i >= addendSize) {
|
||||||
if (addendType.isSigned) {
|
if (addendType.isSigned) {
|
||||||
val label = MfCompiler.nextLabel("sx")
|
val label = MosCompiler.nextLabel("sx")
|
||||||
buffer += AssemblyLine.implied(TXA)
|
buffer += AssemblyLine.implied(TXA)
|
||||||
if (i == addendSize) {
|
if (i == addendSize) {
|
||||||
buffer += AssemblyLine.immediate(ORA, 0x7f)
|
buffer += AssemblyLine.immediate(ORA, 0x7f)
|
||||||
@@ -1048,14 +1048,14 @@ object BuiltIns {
|
|||||||
Nil
|
Nil
|
||||||
case _ =>
|
case _ =>
|
||||||
if (simplicity(env, v) > simplicity(env, param)) {
|
if (simplicity(env, v) > simplicity(env, param)) {
|
||||||
val loadRhs = ExpressionCompiler.compile(ctx, param, Some(b -> RegisterVariable(Register.A, b)), NoBranching)
|
val loadRhs = MosExpressionCompiler.compile(ctx, param, Some(b -> RegisterVariable(MosRegister.A, b)), NoBranching)
|
||||||
val modifyAcc = simpleOperation(operation, ctx, v, IndexChoice.PreferY, preserveA = true, commutative = true)
|
val modifyAcc = simpleOperation(operation, ctx, v, IndexChoice.PreferY, preserveA = true, commutative = true)
|
||||||
val storeLhs = ExpressionCompiler.compileByteStorage(ctx, Register.A, v)
|
val storeLhs = MosExpressionCompiler.compileByteStorage(ctx, MosRegister.A, v)
|
||||||
loadRhs ++ modifyAcc ++ storeLhs
|
loadRhs ++ modifyAcc ++ storeLhs
|
||||||
} else {
|
} else {
|
||||||
val loadLhs = ExpressionCompiler.compile(ctx, v, Some(b -> RegisterVariable(Register.A, b)), NoBranching)
|
val loadLhs = MosExpressionCompiler.compile(ctx, v, Some(b -> RegisterVariable(MosRegister.A, b)), NoBranching)
|
||||||
val modifyLhs = simpleOperation(operation, ctx, param, IndexChoice.PreferY, preserveA = true, commutative = true)
|
val modifyLhs = simpleOperation(operation, ctx, param, IndexChoice.PreferY, preserveA = true, commutative = true)
|
||||||
val storeLhs = ExpressionCompiler.compileByteStorage(ctx, Register.A, v)
|
val storeLhs = MosExpressionCompiler.compileByteStorage(ctx, MosRegister.A, v)
|
||||||
loadLhs ++ modifyLhs ++ storeLhs
|
loadLhs ++ modifyLhs ++ storeLhs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1069,7 +1069,7 @@ object BuiltIns {
|
|||||||
val targetBytes: List[List[AssemblyLine]] = getStorageForEachByte(ctx, lhs)
|
val targetBytes: List[List[AssemblyLine]] = getStorageForEachByte(ctx, lhs)
|
||||||
val lo = targetBytes.head
|
val lo = targetBytes.head
|
||||||
val targetSize = targetBytes.size
|
val targetSize = targetBytes.size
|
||||||
val paramType = ExpressionCompiler.getExpressionType(ctx, param)
|
val paramType = MosExpressionCompiler.getExpressionType(ctx, param)
|
||||||
var paramSize = paramType.size
|
var paramSize = paramType.size
|
||||||
val extendMultipleBytes = targetSize > paramSize + 1
|
val extendMultipleBytes = targetSize > paramSize + 1
|
||||||
val extendAtLeastOneByte = targetSize > paramSize
|
val extendAtLeastOneByte = targetSize > paramSize
|
||||||
@@ -1080,10 +1080,10 @@ object BuiltIns {
|
|||||||
case None =>
|
case None =>
|
||||||
paramSize match {
|
paramSize match {
|
||||||
case 1 =>
|
case 1 =>
|
||||||
val base = ExpressionCompiler.compile(ctx, param, Some(b -> RegisterVariable(Register.A, b)), NoBranching)
|
val base = MosExpressionCompiler.compile(ctx, param, Some(b -> RegisterVariable(MosRegister.A, b)), NoBranching)
|
||||||
base -> List(Nil)
|
base -> List(Nil)
|
||||||
case 2 =>
|
case 2 =>
|
||||||
val base = ExpressionCompiler.compile(ctx, param, Some(ExpressionCompiler.getExpressionType(ctx, param) -> RegisterVariable(Register.AX, w)), NoBranching)
|
val base = MosExpressionCompiler.compile(ctx, param, Some(MosExpressionCompiler.getExpressionType(ctx, param) -> RegisterVariable(MosRegister.AX, w)), NoBranching)
|
||||||
base -> List(Nil, List(AssemblyLine.implied(TXA)))
|
base -> List(Nil, List(AssemblyLine.implied(TXA)))
|
||||||
case _ => Nil -> (param match {
|
case _ => Nil -> (param match {
|
||||||
case vv: VariableExpression =>
|
case vv: VariableExpression =>
|
||||||
@@ -1120,7 +1120,7 @@ object BuiltIns {
|
|||||||
case (EOR, Some(NumericConstant(0, _)))
|
case (EOR, Some(NumericConstant(0, _)))
|
||||||
| (ORA, Some(NumericConstant(0, _)))
|
| (ORA, Some(NumericConstant(0, _)))
|
||||||
| (AND, Some(NumericConstant(AllOnes, _))) =>
|
| (AND, Some(NumericConstant(AllOnes, _))) =>
|
||||||
ExpressionCompiler.compile(ctx, lhs, None, NoBranching)
|
MosExpressionCompiler.compile(ctx, lhs, None, NoBranching)
|
||||||
case _ =>
|
case _ =>
|
||||||
val buffer = mutable.ListBuffer[AssemblyLine]()
|
val buffer = mutable.ListBuffer[AssemblyLine]()
|
||||||
buffer ++= calculateRhs
|
buffer ++= calculateRhs
|
||||||
@@ -1132,7 +1132,7 @@ object BuiltIns {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (paramType.isSigned) {
|
if (paramType.isSigned) {
|
||||||
val label = MfCompiler.nextLabel("sx")
|
val label = MosCompiler.nextLabel("sx")
|
||||||
buffer += AssemblyLine.implied(TXA)
|
buffer += AssemblyLine.implied(TXA)
|
||||||
if (i == paramSize) {
|
if (i == paramSize) {
|
||||||
buffer += AssemblyLine.immediate(ORA, 0x7f)
|
buffer += AssemblyLine.immediate(ORA, 0x7f)
|
||||||
@@ -1163,7 +1163,7 @@ object BuiltIns {
|
|||||||
val variable = env.get[Variable](v.name)
|
val variable = env.get[Variable](v.name)
|
||||||
List.tabulate(variable.typ.size) { i => AssemblyLine.variable(ctx, STA, variable, i) }
|
List.tabulate(variable.typ.size) { i => AssemblyLine.variable(ctx, STA, variable, i) }
|
||||||
case IndexedExpression(variable, index) =>
|
case IndexedExpression(variable, index) =>
|
||||||
List(ExpressionCompiler.compileByteStorage(ctx, Register.A, lhs))
|
List(MosExpressionCompiler.compileByteStorage(ctx, MosRegister.A, lhs))
|
||||||
case SeparateBytesExpression(h: LhsExpression, l: LhsExpression) =>
|
case SeparateBytesExpression(h: LhsExpression, l: LhsExpression) =>
|
||||||
if (simplicity(ctx.env, h) < 'J' || simplicity(ctx.env, l) < 'J') {
|
if (simplicity(ctx.env, h) < 'J' || simplicity(ctx.env, l) < 'J') {
|
||||||
// a[b]:c[d] is the most complex expression that doesn't cause the following warning
|
// a[b]:c[d] is the most complex expression that doesn't cause the following warning
|
||||||
@@ -1171,7 +1171,7 @@ object BuiltIns {
|
|||||||
}
|
}
|
||||||
List(
|
List(
|
||||||
getStorageForEachByte(ctx, l).head,
|
getStorageForEachByte(ctx, l).head,
|
||||||
ExpressionCompiler.preserveRegisterIfNeeded(ctx, Register.A, getStorageForEachByte(ctx, h).head))
|
MosExpressionCompiler.preserveRegisterIfNeeded(ctx, MosRegister.A, getStorageForEachByte(ctx, h).head))
|
||||||
case _ =>
|
case _ =>
|
||||||
???
|
???
|
||||||
}
|
}
|
||||||
@@ -1189,7 +1189,7 @@ object BuiltIns {
|
|||||||
if (i < variable.typ.size) {
|
if (i < variable.typ.size) {
|
||||||
AssemblyLine.variable(ctx, STA, variable, i)
|
AssemblyLine.variable(ctx, STA, variable, i)
|
||||||
} else if (variable.typ.isSigned) {
|
} else if (variable.typ.isSigned) {
|
||||||
val label = MfCompiler.nextLabel("sx")
|
val label = MosCompiler.nextLabel("sx")
|
||||||
AssemblyLine.variable(ctx, STA, variable, variable.typ.size - 1) ++ List(
|
AssemblyLine.variable(ctx, STA, variable, variable.typ.size - 1) ++ List(
|
||||||
AssemblyLine.immediate(ORA, 0x7F),
|
AssemblyLine.immediate(ORA, 0x7F),
|
||||||
AssemblyLine.relative(BMI, label),
|
AssemblyLine.relative(BMI, label),
|
||||||
@@ -1199,7 +1199,7 @@ object BuiltIns {
|
|||||||
}
|
}
|
||||||
case expr@IndexedExpression(variable, index) =>
|
case expr@IndexedExpression(variable, index) =>
|
||||||
List.tabulate(size) { i =>
|
List.tabulate(size) { i =>
|
||||||
if (i == 0) ExpressionCompiler.compileByteStorage(ctx, Register.A, expr)
|
if (i == 0) MosExpressionCompiler.compileByteStorage(ctx, MosRegister.A, expr)
|
||||||
else List(AssemblyLine.immediate(STA, 0))
|
else List(AssemblyLine.immediate(STA, 0))
|
||||||
}
|
}
|
||||||
case SeparateBytesExpression(h: LhsExpression, l: LhsExpression) =>
|
case SeparateBytesExpression(h: LhsExpression, l: LhsExpression) =>
|
||||||
@@ -1209,7 +1209,7 @@ object BuiltIns {
|
|||||||
}
|
}
|
||||||
List.tabulate(size) { i =>
|
List.tabulate(size) { i =>
|
||||||
if (i == 0) getStorageForEachByte(ctx, l).head
|
if (i == 0) getStorageForEachByte(ctx, l).head
|
||||||
else if (i == 1) ExpressionCompiler.preserveRegisterIfNeeded(ctx, Register.A, getStorageForEachByte(ctx, h).head)
|
else if (i == 1) MosExpressionCompiler.preserveRegisterIfNeeded(ctx, MosRegister.A, getStorageForEachByte(ctx, h).head)
|
||||||
else List(AssemblyLine.immediate(STA, 0))
|
else List(AssemblyLine.immediate(STA, 0))
|
||||||
}
|
}
|
||||||
case _ =>
|
case _ =>
|
@@ -1,4 +1,4 @@
|
|||||||
package millfork.compiler
|
package millfork.compiler.mos
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Karol Stasiak
|
* @author Karol Stasiak
|
@@ -1,7 +1,7 @@
|
|||||||
package millfork.compiler
|
package millfork.compiler.mos
|
||||||
|
|
||||||
import millfork.{CompilationFlag, CompilationOptions}
|
|
||||||
import millfork.env.{Environment, Label, NormalFunction}
|
import millfork.env.{Environment, Label, NormalFunction}
|
||||||
|
import millfork.{CompilationFlag, CompilationOptions}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Karol Stasiak
|
* @author Karol Stasiak
|
||||||
@@ -13,7 +13,7 @@ case class CompilationContext(env: Environment,
|
|||||||
breakLabels: Map[String, Label] = Map(),
|
breakLabels: Map[String, Label] = Map(),
|
||||||
continueLabels: Map[String, Label] = Map()){
|
continueLabels: Map[String, Label] = Map()){
|
||||||
def withInlinedEnv(environment: Environment): CompilationContext = {
|
def withInlinedEnv(environment: Environment): CompilationContext = {
|
||||||
val newEnv = new Environment(Some(env), MfCompiler.nextLabel("en"))
|
val newEnv = new Environment(Some(env), MosCompiler.nextLabel("en"))
|
||||||
newEnv.things ++= environment.things
|
newEnv.things ++= environment.things
|
||||||
copy(env = newEnv)
|
copy(env = newEnv)
|
||||||
}
|
}
|
@@ -1,19 +1,13 @@
|
|||||||
package millfork.compiler
|
package millfork.compiler.mos
|
||||||
|
|
||||||
import millfork.{CompilationFlag, CompilationOptions}
|
import millfork.CompilationFlag
|
||||||
import millfork.assembly._
|
|
||||||
import millfork.env._
|
|
||||||
import millfork.node._
|
|
||||||
import millfork.assembly.Opcode._
|
|
||||||
import millfork.assembly.AddrMode._
|
import millfork.assembly.AddrMode._
|
||||||
|
import millfork.assembly.mos.Opcode._
|
||||||
|
import millfork.assembly.mos._
|
||||||
|
import millfork.assembly._
|
||||||
|
import millfork.env.{NumericConstant, RegisterVariable, Type, _}
|
||||||
import millfork.error.ErrorReporting
|
import millfork.error.ErrorReporting
|
||||||
|
import millfork.node.{Expression, MosRegister, _}
|
||||||
import scala.collection.mutable
|
|
||||||
import scala.collection.mutable.ListBuffer
|
|
||||||
import millfork.assembly.AssemblyLine
|
|
||||||
import millfork.env.{NumericConstant, RegisterVariable, Type}
|
|
||||||
import millfork.error.ErrorReporting
|
|
||||||
import millfork.node.{Expression, Register}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Karol Stasiak
|
* @author Karol Stasiak
|
||||||
@@ -34,7 +28,7 @@ object DecimalBuiltIns {
|
|||||||
|
|
||||||
def compileByteShiftRight(ctx: CompilationContext, l: Expression, r: Expression, rotate: Boolean): List[AssemblyLine] = {
|
def compileByteShiftRight(ctx: CompilationContext, l: Expression, r: Expression, rotate: Boolean): List[AssemblyLine] = {
|
||||||
val b = ctx.env.get[Type]("byte")
|
val b = ctx.env.get[Type]("byte")
|
||||||
ExpressionCompiler.compile(ctx, l, Some((b, RegisterVariable(Register.A, b))), BranchSpec.None) ++ (ctx.env.eval(r) match {
|
MosExpressionCompiler.compile(ctx, l, Some((b, RegisterVariable(MosRegister.A, b))), BranchSpec.None) ++ (ctx.env.eval(r) match {
|
||||||
case Some(NumericConstant(0, _)) =>
|
case Some(NumericConstant(0, _)) =>
|
||||||
Nil
|
Nil
|
||||||
case Some(NumericConstant(v, _)) =>
|
case Some(NumericConstant(v, _)) =>
|
||||||
@@ -48,11 +42,11 @@ object DecimalBuiltIns {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private def shiftOrRotateAccumulatorRight(ctx: CompilationContext, rotate: Boolean, preserveCarry: Boolean) = {
|
private def shiftOrRotateAccumulatorRight(ctx: CompilationContext, rotate: Boolean, preserveCarry: Boolean) = {
|
||||||
val skipHiDigit = MfCompiler.nextLabel("ds")
|
val skipHiDigit = MosCompiler.nextLabel("ds")
|
||||||
val skipLoDigit = MfCompiler.nextLabel("ds")
|
val skipLoDigit = MosCompiler.nextLabel("ds")
|
||||||
val cmos = ctx.options.flags(CompilationFlag.EmitCmosOpcodes)
|
val cmos = ctx.options.flags(CompilationFlag.EmitCmosOpcodes)
|
||||||
if (preserveCarry) {
|
if (preserveCarry) {
|
||||||
val constantLabel = MfCompiler.nextLabel("c8")
|
val constantLabel = MosCompiler.nextLabel("c8")
|
||||||
val bit = if (cmos) {
|
val bit = if (cmos) {
|
||||||
AssemblyLine.immediate(BIT, 8)
|
AssemblyLine.immediate(BIT, 8)
|
||||||
} else {
|
} else {
|
||||||
@@ -142,7 +136,7 @@ object DecimalBuiltIns {
|
|||||||
ErrorReporting.error("Cannot multiply by a non-constant amount", r.position)
|
ErrorReporting.error("Cannot multiply by a non-constant amount", r.position)
|
||||||
return Nil
|
return Nil
|
||||||
}
|
}
|
||||||
val fullStorage = ExpressionCompiler.compileByteStorage(ctx, Register.A, l)
|
val fullStorage = MosExpressionCompiler.compileByteStorage(ctx, MosRegister.A, l)
|
||||||
val sta = fullStorage.last
|
val sta = fullStorage.last
|
||||||
if (sta.opcode != STA) ???
|
if (sta.opcode != STA) ???
|
||||||
val fullLoad = fullStorage.init :+ sta.copy(opcode = LDA)
|
val fullLoad = fullStorage.init :+ sta.copy(opcode = LDA)
|
@@ -1,16 +1,10 @@
|
|||||||
package millfork.compiler
|
package millfork.compiler.mos
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicLong
|
import millfork.assembly.mos.Opcode._
|
||||||
|
import millfork.assembly.mos._
|
||||||
import millfork.{CompilationFlag, CompilationOptions}
|
|
||||||
import millfork.assembly._
|
|
||||||
import millfork.env._
|
import millfork.env._
|
||||||
import millfork.node.{Register, _}
|
|
||||||
import millfork.assembly.AddrMode._
|
|
||||||
import millfork.assembly.Opcode._
|
|
||||||
import millfork.error.ErrorReporting
|
import millfork.error.ErrorReporting
|
||||||
|
import millfork.node.{MosRegister, _}
|
||||||
import scala.collection.JavaConverters._
|
|
||||||
/**
|
/**
|
||||||
* @author Karol Stasiak
|
* @author Karol Stasiak
|
||||||
*/
|
*/
|
||||||
@@ -34,7 +28,7 @@ object MacroExpander {
|
|||||||
case DoWhileStatement(b, i, c, n) => DoWhileStatement(b.map(gx), i.map(gx), f(c), n)
|
case DoWhileStatement(b, i, c, n) => DoWhileStatement(b.map(gx), i.map(gx), f(c), n)
|
||||||
case ForStatement(v, start, end, dir, body) => ForStatement(h(v), f(start), f(end), dir, body.map(gx))
|
case ForStatement(v, start, end, dir, body) => ForStatement(h(v), f(start), f(end), dir, body.map(gx))
|
||||||
case IfStatement(c, t, e) => IfStatement(f(c), t.map(gx), e.map(gx))
|
case IfStatement(c, t, e) => IfStatement(f(c), t.map(gx), e.map(gx))
|
||||||
case s:AssemblyStatement => s.copy(expression = f(s.expression))
|
case s:MosAssemblyStatement => s.copy(expression = f(s.expression))
|
||||||
case Assignment(d,s) => Assignment(fx(d), f(s))
|
case Assignment(d,s) => Assignment(fx(d), f(s))
|
||||||
case BreakStatement(s) => if (s == paramName) BreakStatement(target.toString) else stmt
|
case BreakStatement(s) => if (s == paramName) BreakStatement(target.toString) else stmt
|
||||||
case ContinueStatement(s) => if (s == paramName) ContinueStatement(target.toString) else stmt
|
case ContinueStatement(s) => if (s == paramName) ContinueStatement(target.toString) else stmt
|
||||||
@@ -57,19 +51,19 @@ object MacroExpander {
|
|||||||
ctx.env.get[ThingInMemory](vname)
|
ctx.env.get[ThingInMemory](vname)
|
||||||
case l: LhsExpression =>
|
case l: LhsExpression =>
|
||||||
// TODO: ??
|
// TODO: ??
|
||||||
ExpressionCompiler.compileByteStorage(ctx, Register.A, l)
|
MosExpressionCompiler.compileByteStorage(ctx, MosRegister.A, l)
|
||||||
case _ =>
|
case _ =>
|
||||||
ErrorReporting.error("A non-assignable expression was passed to an inlineable function as a `ref` parameter", actualParam.position)
|
ErrorReporting.error("A non-assignable expression was passed to an inlineable function as a `ref` parameter", actualParam.position)
|
||||||
}
|
}
|
||||||
actualCode = actualCode.map {
|
actualCode = actualCode.map {
|
||||||
case a@AssemblyStatement(_, _, expr, _) =>
|
case a@MosAssemblyStatement(_, _, expr, _) =>
|
||||||
a.copy(expression = expr.replaceVariable(ph, actualParam))
|
a.copy(expression = expr.replaceVariable(ph, actualParam))
|
||||||
case x => x
|
case x => x
|
||||||
}
|
}
|
||||||
case (AssemblyParam(typ, Placeholder(ph, phType), AssemblyParameterPassingBehaviour.ByConstant), actualParam) =>
|
case (AssemblyParam(typ, Placeholder(ph, phType), AssemblyParameterPassingBehaviour.ByConstant), actualParam) =>
|
||||||
ctx.env.eval(actualParam).getOrElse(Constant.error("Non-constant expression was passed to an inlineable function as a `const` parameter", actualParam.position))
|
ctx.env.eval(actualParam).getOrElse(Constant.error("Non-constant expression was passed to an inlineable function as a `const` parameter", actualParam.position))
|
||||||
actualCode = actualCode.map {
|
actualCode = actualCode.map {
|
||||||
case a@AssemblyStatement(_, _, expr, _) =>
|
case a@MosAssemblyStatement(_, _, expr, _) =>
|
||||||
a.copy(expression = expr.replaceVariable(ph, actualParam))
|
a.copy(expression = expr.replaceVariable(ph, actualParam))
|
||||||
case x => x
|
case x => x
|
||||||
}
|
}
|
||||||
@@ -78,7 +72,7 @@ object MacroExpander {
|
|||||||
ErrorReporting.error("Only one macro assembly function parameter can be passed via a register", position)
|
ErrorReporting.error("Only one macro assembly function parameter can be passed via a register", position)
|
||||||
}
|
}
|
||||||
hadRegisterParam = true
|
hadRegisterParam = true
|
||||||
paramPreparation = ExpressionCompiler.compile(ctx, actualParam, Some(typ, v), BranchSpec.None)
|
paramPreparation = MosExpressionCompiler.compile(ctx, actualParam, Some(typ, v), BranchSpec.None)
|
||||||
case (AssemblyParam(_, _, AssemblyParameterPassingBehaviour.Copy), actualParam) =>
|
case (AssemblyParam(_, _, AssemblyParameterPassingBehaviour.Copy), actualParam) =>
|
||||||
???
|
???
|
||||||
case (_, actualParam) =>
|
case (_, actualParam) =>
|
||||||
@@ -101,12 +95,12 @@ object MacroExpander {
|
|||||||
// fix local labels:
|
// fix local labels:
|
||||||
// TODO: do it even if the labels are in an inline assembly block inside a Millfork function
|
// TODO: do it even if the labels are in an inline assembly block inside a Millfork function
|
||||||
val localLabels = actualCode.flatMap{
|
val localLabels = actualCode.flatMap{
|
||||||
case AssemblyStatement(LABEL, _, VariableExpression(l), _) => Some(l)
|
case MosAssemblyStatement(LABEL, _, VariableExpression(l), _) => Some(l)
|
||||||
case _ => None
|
case _ => None
|
||||||
}.toSet
|
}.toSet
|
||||||
val labelPrefix = MfCompiler.nextLabel("il")
|
val labelPrefix = MosCompiler.nextLabel("il")
|
||||||
paramPreparation -> actualCode.map{
|
paramPreparation -> actualCode.map{
|
||||||
case s@AssemblyStatement(_, _, VariableExpression(v), _) if localLabels(v) =>
|
case s@MosAssemblyStatement(_, _, VariableExpression(v), _) if localLabels(v) =>
|
||||||
s.copy(expression = VariableExpression(labelPrefix + v))
|
s.copy(expression = VariableExpression(labelPrefix + v))
|
||||||
case s => s
|
case s => s
|
||||||
}
|
}
|
@@ -1,31 +1,27 @@
|
|||||||
package millfork.compiler
|
package millfork.compiler.mos
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicLong
|
import java.util.concurrent.atomic.AtomicLong
|
||||||
|
|
||||||
import millfork.{CompilationFlag, CompilationOptions}
|
import millfork.CompilationFlag
|
||||||
import millfork.assembly._
|
import millfork.assembly.mos.Opcode._
|
||||||
|
import millfork.assembly.mos._
|
||||||
|
import millfork.compiler.AbstractCompiler
|
||||||
import millfork.env._
|
import millfork.env._
|
||||||
import millfork.node.{Register, _}
|
|
||||||
import millfork.assembly.AddrMode._
|
|
||||||
import millfork.assembly.Opcode._
|
|
||||||
import millfork.error.ErrorReporting
|
|
||||||
|
|
||||||
import scala.collection.JavaConverters._
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Karol Stasiak
|
* @author Karol Stasiak
|
||||||
*/
|
*/
|
||||||
//noinspection NotImplementedCode,ScalaUnusedSymbol
|
//noinspection NotImplementedCode,ScalaUnusedSymbol
|
||||||
object MfCompiler {
|
object MosCompiler extends AbstractCompiler[AssemblyLine] {
|
||||||
|
|
||||||
|
|
||||||
private val labelCounter = new AtomicLong
|
private val labelCounter = new AtomicLong
|
||||||
|
|
||||||
def nextLabel(prefix: String): String = "." + prefix + "__" + labelCounter.incrementAndGet().formatted("%05d")
|
def nextLabel(prefix: String): String = "." + prefix + "__" + labelCounter.incrementAndGet().formatted("%05d")
|
||||||
|
|
||||||
def compile(ctx: CompilationContext): List[AssemblyLine] = {
|
override def compile(ctx: CompilationContext): List[AssemblyLine] = {
|
||||||
ctx.env.nameCheck(ctx.function.code)
|
ctx.env.nameCheck(ctx.function.code)
|
||||||
val chunk = StatementCompiler.compile(ctx, ctx.function.code)
|
val chunk = MosStatementCompiler.compile(ctx, ctx.function.code)
|
||||||
|
|
||||||
val phReg =
|
val phReg =
|
||||||
if (ctx.options.flag(CompilationFlag.ZeropagePseudoregister)) {
|
if (ctx.options.flag(CompilationFlag.ZeropagePseudoregister)) {
|
@@ -1,119 +1,38 @@
|
|||||||
package millfork.compiler
|
package millfork.compiler.mos
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicLong
|
import millfork.CompilationFlag
|
||||||
|
|
||||||
import millfork.{CompilationFlag, CompilationOptions}
|
|
||||||
import millfork.assembly._
|
|
||||||
import millfork.env._
|
|
||||||
import millfork.node.{Register, _}
|
|
||||||
import millfork.assembly.AddrMode._
|
import millfork.assembly.AddrMode._
|
||||||
import millfork.assembly.Opcode._
|
import millfork.assembly.mos.Opcode._
|
||||||
|
import millfork.assembly.mos._
|
||||||
|
import millfork.compiler.AbstractExpressionCompiler
|
||||||
|
import millfork.env._
|
||||||
import millfork.error.ErrorReporting
|
import millfork.error.ErrorReporting
|
||||||
|
import millfork.node.{MosRegister, _}
|
||||||
/**
|
/**
|
||||||
* @author Karol Stasiak
|
* @author Karol Stasiak
|
||||||
*/
|
*/
|
||||||
object ExpressionCompiler {
|
object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
||||||
|
|
||||||
def getExpressionType(ctx: CompilationContext, expr: Expression): Type = {
|
|
||||||
val env = ctx.env
|
|
||||||
val b = env.get[Type]("byte")
|
|
||||||
val bool = env.get[Type]("bool$")
|
|
||||||
val v = env.get[Type]("void")
|
|
||||||
val w = env.get[Type]("word")
|
|
||||||
expr match {
|
|
||||||
case LiteralExpression(value, size) =>
|
|
||||||
size match {
|
|
||||||
case 1 => b
|
|
||||||
case 2 => w
|
|
||||||
case 3 => env.get[Type]("farword")
|
|
||||||
case 4 => env.get[Type]("long")
|
|
||||||
}
|
|
||||||
case VariableExpression(name) =>
|
|
||||||
env.get[TypedThing](name, expr.position).typ
|
|
||||||
case HalfWordExpression(param, _) =>
|
|
||||||
getExpressionType(ctx, param)
|
|
||||||
b
|
|
||||||
case IndexedExpression(_, _) => b
|
|
||||||
case SeparateBytesExpression(hi, lo) =>
|
|
||||||
if (getExpressionType(ctx, hi).size > 1) ErrorReporting.error("Hi byte too large", hi.position)
|
|
||||||
if (getExpressionType(ctx, lo).size > 1) ErrorReporting.error("Lo byte too large", lo.position)
|
|
||||||
w
|
|
||||||
case SumExpression(params, _) => params.map { case (_, e) => getExpressionType(ctx, e).size }.max match {
|
|
||||||
case 1 => b
|
|
||||||
case 2 => w
|
|
||||||
case _ => ErrorReporting.error("Adding values bigger than words", expr.position); w
|
|
||||||
}
|
|
||||||
case FunctionCallExpression("nonet", params) => w
|
|
||||||
case FunctionCallExpression("not", params) => bool
|
|
||||||
case FunctionCallExpression("hi", params) => b
|
|
||||||
case FunctionCallExpression("lo", params) => b
|
|
||||||
case FunctionCallExpression("*", params) => b
|
|
||||||
case FunctionCallExpression("|" | "&" | "^", params) => params.map { e => getExpressionType(ctx, e).size }.max match {
|
|
||||||
case 1 => b
|
|
||||||
case 2 => w
|
|
||||||
case _ => ErrorReporting.error("Adding values bigger than words", expr.position); w
|
|
||||||
}
|
|
||||||
case FunctionCallExpression("<<", List(a1, a2)) =>
|
|
||||||
if (getExpressionType(ctx, a2).size > 1) ErrorReporting.error("Shift amount too large", a2.position)
|
|
||||||
getExpressionType(ctx, a1)
|
|
||||||
case FunctionCallExpression(">>", List(a1, a2)) =>
|
|
||||||
if (getExpressionType(ctx, a2).size > 1) ErrorReporting.error("Shift amount too large", a2.position)
|
|
||||||
getExpressionType(ctx, a1)
|
|
||||||
case FunctionCallExpression("<<'", params) => b
|
|
||||||
case FunctionCallExpression(">>'", params) => b
|
|
||||||
case FunctionCallExpression(">>>>", params) => b
|
|
||||||
case FunctionCallExpression("&&", params) => bool
|
|
||||||
case FunctionCallExpression("||", params) => bool
|
|
||||||
case FunctionCallExpression("^^", params) => bool
|
|
||||||
case FunctionCallExpression("==", params) => bool
|
|
||||||
case FunctionCallExpression("!=", params) => bool
|
|
||||||
case FunctionCallExpression("<", params) => bool
|
|
||||||
case FunctionCallExpression(">", params) => bool
|
|
||||||
case FunctionCallExpression("<=", params) => bool
|
|
||||||
case FunctionCallExpression(">=", params) => bool
|
|
||||||
case FunctionCallExpression("+=", params) => v
|
|
||||||
case FunctionCallExpression("-=", params) => v
|
|
||||||
case FunctionCallExpression("*=", params) => v
|
|
||||||
case FunctionCallExpression("+'=", params) => v
|
|
||||||
case FunctionCallExpression("-'=", params) => v
|
|
||||||
case FunctionCallExpression("*'=", params) => v
|
|
||||||
case FunctionCallExpression("|=", params) => v
|
|
||||||
case FunctionCallExpression("&=", params) => v
|
|
||||||
case FunctionCallExpression("^=", params) => v
|
|
||||||
case FunctionCallExpression("<<=", params) => v
|
|
||||||
case FunctionCallExpression(">>=", params) => v
|
|
||||||
case FunctionCallExpression("<<'=", params) => v
|
|
||||||
case FunctionCallExpression(">>'=", params) => v
|
|
||||||
case f@FunctionCallExpression(name, params) =>
|
|
||||||
ctx.env.maybeGet[Type](name) match {
|
|
||||||
case Some(typ) =>
|
|
||||||
typ
|
|
||||||
case None =>
|
|
||||||
lookupFunction(ctx, f).returnType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def compileConstant(ctx: CompilationContext, expr: Constant, target: Variable): List[AssemblyLine] = {
|
def compileConstant(ctx: CompilationContext, expr: Constant, target: Variable): List[AssemblyLine] = {
|
||||||
target match {
|
target match {
|
||||||
case RegisterVariable(Register.A, _) => List(AssemblyLine(LDA, Immediate, expr))
|
case RegisterVariable(MosRegister.A, _) => List(AssemblyLine(LDA, Immediate, expr))
|
||||||
case RegisterVariable(Register.AW, _) =>
|
case RegisterVariable(MosRegister.AW, _) =>
|
||||||
List(
|
List(
|
||||||
AssemblyLine.accu16,
|
AssemblyLine.accu16,
|
||||||
AssemblyLine(LDA_W, WordImmediate, expr),
|
AssemblyLine(LDA_W, WordImmediate, expr),
|
||||||
AssemblyLine.accu8)
|
AssemblyLine.accu8)
|
||||||
case RegisterVariable(Register.X, _) => List(AssemblyLine(LDX, Immediate, expr))
|
case RegisterVariable(MosRegister.X, _) => List(AssemblyLine(LDX, Immediate, expr))
|
||||||
case RegisterVariable(Register.Y, _) => List(AssemblyLine(LDY, Immediate, expr))
|
case RegisterVariable(MosRegister.Y, _) => List(AssemblyLine(LDY, Immediate, expr))
|
||||||
case RegisterVariable(Register.AX, _) => List(
|
case RegisterVariable(MosRegister.AX, _) => List(
|
||||||
AssemblyLine(LDA, Immediate, expr.loByte),
|
AssemblyLine(LDA, Immediate, expr.loByte),
|
||||||
AssemblyLine(LDX, Immediate, expr.hiByte))
|
AssemblyLine(LDX, Immediate, expr.hiByte))
|
||||||
case RegisterVariable(Register.AY, _) => List(
|
case RegisterVariable(MosRegister.AY, _) => List(
|
||||||
AssemblyLine(LDA, Immediate, expr.loByte),
|
AssemblyLine(LDA, Immediate, expr.loByte),
|
||||||
AssemblyLine(LDY, Immediate, expr.hiByte))
|
AssemblyLine(LDY, Immediate, expr.hiByte))
|
||||||
case RegisterVariable(Register.XA, _) => List(
|
case RegisterVariable(MosRegister.XA, _) => List(
|
||||||
AssemblyLine(LDA, Immediate, expr.hiByte),
|
AssemblyLine(LDA, Immediate, expr.hiByte),
|
||||||
AssemblyLine(LDX, Immediate, expr.loByte))
|
AssemblyLine(LDX, Immediate, expr.loByte))
|
||||||
case RegisterVariable(Register.YA, _) => List(
|
case RegisterVariable(MosRegister.YA, _) => List(
|
||||||
AssemblyLine(LDA, Immediate, expr.hiByte),
|
AssemblyLine(LDA, Immediate, expr.hiByte),
|
||||||
AssemblyLine(LDY, Immediate, expr.loByte))
|
AssemblyLine(LDY, Immediate, expr.loByte))
|
||||||
case m: VariableInMemory =>
|
case m: VariableInMemory =>
|
||||||
@@ -160,18 +79,18 @@ object ExpressionCompiler {
|
|||||||
case Nil => Nil
|
case Nil => Nil
|
||||||
}
|
}
|
||||||
|
|
||||||
def preserveRegisterIfNeeded(ctx: CompilationContext, register: Register.Value, code: List[AssemblyLine]): List[AssemblyLine] = {
|
def preserveRegisterIfNeeded(ctx: CompilationContext, register: MosRegister.Value, code: List[AssemblyLine]): List[AssemblyLine] = {
|
||||||
val state = register match {
|
val state = register match {
|
||||||
case Register.A => State.A
|
case MosRegister.A => State.A
|
||||||
case Register.X => State.X
|
case MosRegister.X => State.X
|
||||||
case Register.Y => State.Y
|
case MosRegister.Y => State.Y
|
||||||
}
|
}
|
||||||
|
|
||||||
val cmos = ctx.options.flag(CompilationFlag.EmitCmosOpcodes)
|
val cmos = ctx.options.flag(CompilationFlag.EmitCmosOpcodes)
|
||||||
if (AssemblyLine.treatment(code, state) != Treatment.Unchanged) {
|
if (AssemblyLine.treatment(code, state) != Treatment.Unchanged) {
|
||||||
register match {
|
register match {
|
||||||
case Register.A => AssemblyLine.implied(PHA) +: fixTsx(code) :+ AssemblyLine.implied(PLA)
|
case MosRegister.A => AssemblyLine.implied(PHA) +: fixTsx(code) :+ AssemblyLine.implied(PLA)
|
||||||
case Register.X => if (cmos) {
|
case MosRegister.X => if (cmos) {
|
||||||
List(
|
List(
|
||||||
AssemblyLine.implied(PHA),
|
AssemblyLine.implied(PHA),
|
||||||
AssemblyLine.implied(PHX),
|
AssemblyLine.implied(PHX),
|
||||||
@@ -190,7 +109,7 @@ object ExpressionCompiler {
|
|||||||
AssemblyLine.implied(PLA),
|
AssemblyLine.implied(PLA),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
case Register.Y => if (cmos) {
|
case MosRegister.Y => if (cmos) {
|
||||||
List(
|
List(
|
||||||
AssemblyLine.implied(PHA),
|
AssemblyLine.implied(PHA),
|
||||||
AssemblyLine.implied(PHY),
|
AssemblyLine.implied(PHY),
|
||||||
@@ -222,7 +141,7 @@ object ExpressionCompiler {
|
|||||||
return Nil
|
return Nil
|
||||||
}
|
}
|
||||||
val reg = ctx.env.get[VariableInMemory]("__reg")
|
val reg = ctx.env.get[VariableInMemory]("__reg")
|
||||||
val compileIndex = compile(ctx, indexExpression, Some(ExpressionCompiler.getExpressionType(ctx, indexExpression) -> RegisterVariable(Register.YA, w)), BranchSpec.None)
|
val compileIndex = compile(ctx, indexExpression, Some(MosExpressionCompiler.getExpressionType(ctx, indexExpression) -> RegisterVariable(MosRegister.YA, w)), BranchSpec.None)
|
||||||
val prepareRegister = pointy match {
|
val prepareRegister = pointy match {
|
||||||
case ConstantPointy(addr, _) =>
|
case ConstantPointy(addr, _) =>
|
||||||
List(
|
List(
|
||||||
@@ -242,18 +161,18 @@ object ExpressionCompiler {
|
|||||||
compileIndex ++ prepareRegister
|
compileIndex ++ prepareRegister
|
||||||
}
|
}
|
||||||
|
|
||||||
def compileByteStorage(ctx: CompilationContext, register: Register.Value, target: LhsExpression): List[AssemblyLine] = {
|
def compileByteStorage(ctx: CompilationContext, register: MosRegister.Value, target: LhsExpression): List[AssemblyLine] = {
|
||||||
val env = ctx.env
|
val env = ctx.env
|
||||||
val b = env.get[Type]("byte")
|
val b = env.get[Type]("byte")
|
||||||
val store = register match {
|
val store = register match {
|
||||||
case Register.A => STA
|
case MosRegister.A => STA
|
||||||
case Register.X => STX
|
case MosRegister.X => STX
|
||||||
case Register.Y => STY
|
case MosRegister.Y => STY
|
||||||
}
|
}
|
||||||
val transferToA = register match {
|
val transferToA = register match {
|
||||||
case Register.A => NOP
|
case MosRegister.A => NOP
|
||||||
case Register.X => TXA
|
case MosRegister.X => TXA
|
||||||
case Register.Y => TYA
|
case MosRegister.Y => TYA
|
||||||
}
|
}
|
||||||
target match {
|
target match {
|
||||||
case VariableExpression(name) =>
|
case VariableExpression(name) =>
|
||||||
@@ -291,21 +210,21 @@ object ExpressionCompiler {
|
|||||||
|
|
||||||
def storeToArrayAtUnknownIndex(variableIndex: Expression, arrayAddr: Constant) = {
|
def storeToArrayAtUnknownIndex(variableIndex: Expression, arrayAddr: Constant) = {
|
||||||
// TODO check typ
|
// TODO check typ
|
||||||
val indexRegister = if (register == Register.Y) Register.X else Register.Y
|
val indexRegister = if (register == MosRegister.Y) MosRegister.X else MosRegister.Y
|
||||||
val calculatingIndex = preserveRegisterIfNeeded(ctx, register, compile(ctx, variableIndex, Some(b, RegisterVariable(indexRegister, b)), NoBranching))
|
val calculatingIndex = preserveRegisterIfNeeded(ctx, register, compile(ctx, variableIndex, Some(b, RegisterVariable(indexRegister, b)), NoBranching))
|
||||||
if (register == Register.A) {
|
if (register == MosRegister.A) {
|
||||||
indexRegister match {
|
indexRegister match {
|
||||||
case Register.Y =>
|
case MosRegister.Y =>
|
||||||
calculatingIndex ++ arrayBoundsCheck(ctx, pointy, Register.Y, indexExpr) ++ List(AssemblyLine.absoluteY(STA, arrayAddr + constIndex))
|
calculatingIndex ++ arrayBoundsCheck(ctx, pointy, MosRegister.Y, indexExpr) ++ List(AssemblyLine.absoluteY(STA, arrayAddr + constIndex))
|
||||||
case Register.X =>
|
case MosRegister.X =>
|
||||||
calculatingIndex ++ arrayBoundsCheck(ctx, pointy, Register.X, indexExpr) ++ List(AssemblyLine.absoluteX(STA, arrayAddr + constIndex))
|
calculatingIndex ++ arrayBoundsCheck(ctx, pointy, MosRegister.X, indexExpr) ++ List(AssemblyLine.absoluteX(STA, arrayAddr + constIndex))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
indexRegister match {
|
indexRegister match {
|
||||||
case Register.Y =>
|
case MosRegister.Y =>
|
||||||
calculatingIndex ++ arrayBoundsCheck(ctx, pointy, Register.Y, indexExpr) ++ List(AssemblyLine.implied(transferToA), AssemblyLine.absoluteY(STA, arrayAddr + constIndex))
|
calculatingIndex ++ arrayBoundsCheck(ctx, pointy, MosRegister.Y, indexExpr) ++ List(AssemblyLine.implied(transferToA), AssemblyLine.absoluteY(STA, arrayAddr + constIndex))
|
||||||
case Register.X =>
|
case MosRegister.X =>
|
||||||
calculatingIndex ++ arrayBoundsCheck(ctx, pointy, Register.X, indexExpr) ++ List(AssemblyLine.implied(transferToA), AssemblyLine.absoluteX(STA, arrayAddr + constIndex))
|
calculatingIndex ++ arrayBoundsCheck(ctx, pointy, MosRegister.X, indexExpr) ++ List(AssemblyLine.implied(transferToA), AssemblyLine.absoluteX(STA, arrayAddr + constIndex))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -313,9 +232,9 @@ object ExpressionCompiler {
|
|||||||
val reg = ctx.env.get[VariableInMemory]("__reg")
|
val reg = ctx.env.get[VariableInMemory]("__reg")
|
||||||
val cmos = ctx.options.flag(CompilationFlag.EmitCmosOpcodes)
|
val cmos = ctx.options.flag(CompilationFlag.EmitCmosOpcodes)
|
||||||
register match {
|
register match {
|
||||||
case Register.A =>
|
case MosRegister.A =>
|
||||||
List(AssemblyLine.implied(PHA)) ++ code ++ List(AssemblyLine.implied(PLA), AssemblyLine.indexedY(STA, reg))
|
List(AssemblyLine.implied(PHA)) ++ code ++ List(AssemblyLine.implied(PLA), AssemblyLine.indexedY(STA, reg))
|
||||||
case Register.X =>
|
case MosRegister.X =>
|
||||||
if (code.exists(l => OpcodeClasses.ChangesX(l.opcode))) {
|
if (code.exists(l => OpcodeClasses.ChangesX(l.opcode))) {
|
||||||
if (cmos)
|
if (cmos)
|
||||||
List(AssemblyLine.implied(PHX)) ++ code ++ List(AssemblyLine.implied(PLA), AssemblyLine.indexedY(STA, reg))
|
List(AssemblyLine.implied(PHX)) ++ code ++ List(AssemblyLine.implied(PLA), AssemblyLine.indexedY(STA, reg))
|
||||||
@@ -324,7 +243,7 @@ object ExpressionCompiler {
|
|||||||
} else {
|
} else {
|
||||||
code ++ List(AssemblyLine.implied(TXA), AssemblyLine.indexedY(STA, reg))
|
code ++ List(AssemblyLine.implied(TXA), AssemblyLine.indexedY(STA, reg))
|
||||||
}
|
}
|
||||||
case Register.Y =>
|
case MosRegister.Y =>
|
||||||
if (cmos)
|
if (cmos)
|
||||||
List(AssemblyLine.implied(PHY)) ++ code ++ List(AssemblyLine.implied(PLA), AssemblyLine.indexedY(STA, reg))
|
List(AssemblyLine.implied(PHY)) ++ code ++ List(AssemblyLine.implied(PLA), AssemblyLine.indexedY(STA, reg))
|
||||||
else
|
else
|
||||||
@@ -344,25 +263,25 @@ object ExpressionCompiler {
|
|||||||
//TODO: should there be a type check or a zeropage check?
|
//TODO: should there be a type check or a zeropage check?
|
||||||
case (pointerVariable:VariablePointy, None, _, 0 | 1) =>
|
case (pointerVariable:VariablePointy, None, _, 0 | 1) =>
|
||||||
register match {
|
register match {
|
||||||
case Register.A =>
|
case MosRegister.A =>
|
||||||
List(AssemblyLine.immediate(LDY, constIndex), AssemblyLine.indexedY(STA, pointerVariable.addr))
|
List(AssemblyLine.immediate(LDY, constIndex), AssemblyLine.indexedY(STA, pointerVariable.addr))
|
||||||
case Register.Y =>
|
case MosRegister.Y =>
|
||||||
List(AssemblyLine.implied(TYA), AssemblyLine.immediate(LDY, constIndex), AssemblyLine.indexedY(STA, pointerVariable.addr), AssemblyLine.implied(TAY))
|
List(AssemblyLine.implied(TYA), AssemblyLine.immediate(LDY, constIndex), AssemblyLine.indexedY(STA, pointerVariable.addr), AssemblyLine.implied(TAY))
|
||||||
case Register.X =>
|
case MosRegister.X =>
|
||||||
List(AssemblyLine.immediate(LDY, constIndex), AssemblyLine.implied(TXA), AssemblyLine.indexedY(STA, pointerVariable.addr))
|
List(AssemblyLine.immediate(LDY, constIndex), AssemblyLine.implied(TXA), AssemblyLine.indexedY(STA, pointerVariable.addr))
|
||||||
case _ =>
|
case _ =>
|
||||||
ErrorReporting.error("Cannot store a word in an array", target.position)
|
ErrorReporting.error("Cannot store a word in an array", target.position)
|
||||||
Nil
|
Nil
|
||||||
}
|
}
|
||||||
case (pointerVariable:VariablePointy, Some(_), _, 0 | 1) =>
|
case (pointerVariable:VariablePointy, Some(_), _, 0 | 1) =>
|
||||||
val calculatingIndex = compile(ctx, indexExpr, Some(b, RegisterVariable(Register.Y, b)), NoBranching)
|
val calculatingIndex = compile(ctx, indexExpr, Some(b, RegisterVariable(MosRegister.Y, b)), NoBranching)
|
||||||
register match {
|
register match {
|
||||||
case Register.A =>
|
case MosRegister.A =>
|
||||||
preserveRegisterIfNeeded(ctx, Register.A, calculatingIndex) :+ AssemblyLine.indexedY(STA, pointerVariable.addr)
|
preserveRegisterIfNeeded(ctx, MosRegister.A, calculatingIndex) :+ AssemblyLine.indexedY(STA, pointerVariable.addr)
|
||||||
case Register.X =>
|
case MosRegister.X =>
|
||||||
preserveRegisterIfNeeded(ctx, Register.X, calculatingIndex) ++ List(AssemblyLine.implied(TXA), AssemblyLine.indexedY(STA, pointerVariable.addr))
|
preserveRegisterIfNeeded(ctx, MosRegister.X, calculatingIndex) ++ List(AssemblyLine.implied(TXA), AssemblyLine.indexedY(STA, pointerVariable.addr))
|
||||||
case Register.Y =>
|
case MosRegister.Y =>
|
||||||
AssemblyLine.implied(TYA) :: preserveRegisterIfNeeded(ctx, Register.A, calculatingIndex) ++ List(
|
AssemblyLine.implied(TYA) :: preserveRegisterIfNeeded(ctx, MosRegister.A, calculatingIndex) ++ List(
|
||||||
AssemblyLine.indexedY(STA, pointerVariable.addr), AssemblyLine.implied(TAY)
|
AssemblyLine.indexedY(STA, pointerVariable.addr), AssemblyLine.implied(TAY)
|
||||||
)
|
)
|
||||||
case _ =>
|
case _ =>
|
||||||
@@ -462,8 +381,8 @@ object ExpressionCompiler {
|
|||||||
env.get[TypedThing](name) match {
|
env.get[TypedThing](name) match {
|
||||||
case source: VariableInMemory =>
|
case source: VariableInMemory =>
|
||||||
target match {
|
target match {
|
||||||
case RegisterVariable(Register.A, _) => AssemblyLine.variable(ctx, LDA, source)
|
case RegisterVariable(MosRegister.A, _) => AssemblyLine.variable(ctx, LDA, source)
|
||||||
case RegisterVariable(Register.AW, _) =>
|
case RegisterVariable(MosRegister.AW, _) =>
|
||||||
exprType.size match {
|
exprType.size match {
|
||||||
case 1 => if (exprType.isSigned) {
|
case 1 => if (exprType.isSigned) {
|
||||||
AssemblyLine.variable(ctx, LDA, source) ++ List(
|
AssemblyLine.variable(ctx, LDA, source) ++ List(
|
||||||
@@ -475,9 +394,9 @@ object ExpressionCompiler {
|
|||||||
// TODO: use LDA_W
|
// TODO: use LDA_W
|
||||||
AssemblyLine.variable(ctx, LDA, source, 1) ++ List(AssemblyLine.implied(XBA)) ++ AssemblyLine.variable(ctx, LDA, source)
|
AssemblyLine.variable(ctx, LDA, source, 1) ++ List(AssemblyLine.implied(XBA)) ++ AssemblyLine.variable(ctx, LDA, source)
|
||||||
}
|
}
|
||||||
case RegisterVariable(Register.X, _) => AssemblyLine.variable(ctx, LDX, source)
|
case RegisterVariable(MosRegister.X, _) => AssemblyLine.variable(ctx, LDX, source)
|
||||||
case RegisterVariable(Register.Y, _) => AssemblyLine.variable(ctx, LDY, source)
|
case RegisterVariable(MosRegister.Y, _) => AssemblyLine.variable(ctx, LDY, source)
|
||||||
case RegisterVariable(Register.AX, _) =>
|
case RegisterVariable(MosRegister.AX, _) =>
|
||||||
exprType.size match {
|
exprType.size match {
|
||||||
case 1 => if (exprType.isSigned) {
|
case 1 => if (exprType.isSigned) {
|
||||||
AssemblyLine.variable(ctx, LDA, source) ++ List(
|
AssemblyLine.variable(ctx, LDA, source) ++ List(
|
||||||
@@ -488,7 +407,7 @@ object ExpressionCompiler {
|
|||||||
case 2 =>
|
case 2 =>
|
||||||
AssemblyLine.variable(ctx, LDA, source) ++ AssemblyLine.variable(ctx, LDX, source, 1)
|
AssemblyLine.variable(ctx, LDA, source) ++ AssemblyLine.variable(ctx, LDX, source, 1)
|
||||||
}
|
}
|
||||||
case RegisterVariable(Register.AY, _) =>
|
case RegisterVariable(MosRegister.AY, _) =>
|
||||||
exprType.size match {
|
exprType.size match {
|
||||||
case 1 => if (exprType.isSigned) {
|
case 1 => if (exprType.isSigned) {
|
||||||
AssemblyLine.variable(ctx, LDA, source) ++ List(
|
AssemblyLine.variable(ctx, LDA, source) ++ List(
|
||||||
@@ -501,7 +420,7 @@ object ExpressionCompiler {
|
|||||||
case 2 =>
|
case 2 =>
|
||||||
AssemblyLine.variable(ctx, LDA, source) ++ AssemblyLine.variable(ctx, LDY, source, 1)
|
AssemblyLine.variable(ctx, LDA, source) ++ AssemblyLine.variable(ctx, LDY, source, 1)
|
||||||
}
|
}
|
||||||
case RegisterVariable(Register.XA, _) =>
|
case RegisterVariable(MosRegister.XA, _) =>
|
||||||
exprType.size match {
|
exprType.size match {
|
||||||
case 1 => if (exprType.isSigned) {
|
case 1 => if (exprType.isSigned) {
|
||||||
AssemblyLine.variable(ctx, LDX, source) ++ List(AssemblyLine.implied(TXA)) ++ signExtendA()
|
AssemblyLine.variable(ctx, LDX, source) ++ List(AssemblyLine.implied(TXA)) ++ signExtendA()
|
||||||
@@ -510,7 +429,7 @@ object ExpressionCompiler {
|
|||||||
case 2 =>
|
case 2 =>
|
||||||
AssemblyLine.variable(ctx, LDX, source) ++ AssemblyLine.variable(ctx,LDA, source, 1)
|
AssemblyLine.variable(ctx, LDX, source) ++ AssemblyLine.variable(ctx,LDA, source, 1)
|
||||||
}
|
}
|
||||||
case RegisterVariable(Register.YA, _) =>
|
case RegisterVariable(MosRegister.YA, _) =>
|
||||||
exprType.size match {
|
exprType.size match {
|
||||||
case 1 => if (exprType.isSigned) {
|
case 1 => if (exprType.isSigned) {
|
||||||
AssemblyLine.variable(ctx, LDY, source) ++ List(AssemblyLine.implied(TYA)) ++ signExtendA()
|
AssemblyLine.variable(ctx, LDY, source) ++ List(AssemblyLine.implied(TYA)) ++ signExtendA()
|
||||||
@@ -551,10 +470,10 @@ object ExpressionCompiler {
|
|||||||
}
|
}
|
||||||
case source@StackVariable(_, sourceType, offset) =>
|
case source@StackVariable(_, sourceType, offset) =>
|
||||||
target match {
|
target match {
|
||||||
case RegisterVariable(Register.A, _) => List(AssemblyLine.implied(TSX), AssemblyLine.absoluteX(LDA, offset + ctx.extraStackOffset))
|
case RegisterVariable(MosRegister.A, _) => List(AssemblyLine.implied(TSX), AssemblyLine.absoluteX(LDA, offset + ctx.extraStackOffset))
|
||||||
case RegisterVariable(Register.X, _) => List(AssemblyLine.implied(TSX), AssemblyLine.absoluteX(LDA, offset + ctx.extraStackOffset), AssemblyLine.implied(TAX))
|
case RegisterVariable(MosRegister.X, _) => List(AssemblyLine.implied(TSX), AssemblyLine.absoluteX(LDA, offset + ctx.extraStackOffset), AssemblyLine.implied(TAX))
|
||||||
case RegisterVariable(Register.Y, _) => List(AssemblyLine.implied(TSX), AssemblyLine.absoluteX(LDY, offset + ctx.extraStackOffset))
|
case RegisterVariable(MosRegister.Y, _) => List(AssemblyLine.implied(TSX), AssemblyLine.absoluteX(LDY, offset + ctx.extraStackOffset))
|
||||||
case RegisterVariable(Register.AX, _) =>
|
case RegisterVariable(MosRegister.AX, _) =>
|
||||||
exprType.size match {
|
exprType.size match {
|
||||||
case 1 => if (exprType.isSigned) {
|
case 1 => if (exprType.isSigned) {
|
||||||
List(
|
List(
|
||||||
@@ -575,10 +494,10 @@ object ExpressionCompiler {
|
|||||||
AssemblyLine.implied(TAX),
|
AssemblyLine.implied(TAX),
|
||||||
AssemblyLine.implied(PLA))
|
AssemblyLine.implied(PLA))
|
||||||
}
|
}
|
||||||
case RegisterVariable(Register.AY, _) =>
|
case RegisterVariable(MosRegister.AY, _) =>
|
||||||
exprType.size match {
|
exprType.size match {
|
||||||
case 1 => if (exprType.isSigned) {
|
case 1 => if (exprType.isSigned) {
|
||||||
val label = MfCompiler.nextLabel("sx")
|
val label = MosCompiler.nextLabel("sx")
|
||||||
??? // TODO
|
??? // TODO
|
||||||
} else {
|
} else {
|
||||||
List(
|
List(
|
||||||
@@ -591,12 +510,12 @@ object ExpressionCompiler {
|
|||||||
AssemblyLine.absoluteX(LDA, offset + ctx.extraStackOffset),
|
AssemblyLine.absoluteX(LDA, offset + ctx.extraStackOffset),
|
||||||
AssemblyLine.absoluteX(LDY, offset + ctx.extraStackOffset + 1))
|
AssemblyLine.absoluteX(LDY, offset + ctx.extraStackOffset + 1))
|
||||||
}
|
}
|
||||||
case RegisterVariable(Register.XA, _) =>
|
case RegisterVariable(MosRegister.XA, _) =>
|
||||||
??? // TODO
|
??? // TODO
|
||||||
case RegisterVariable(Register.YA, _) =>
|
case RegisterVariable(MosRegister.YA, _) =>
|
||||||
exprType.size match {
|
exprType.size match {
|
||||||
case 1 => if (exprType.isSigned) {
|
case 1 => if (exprType.isSigned) {
|
||||||
val label = MfCompiler.nextLabel("sx")
|
val label = MosCompiler.nextLabel("sx")
|
||||||
??? // TODO
|
??? // TODO
|
||||||
} else {
|
} else {
|
||||||
List(
|
List(
|
||||||
@@ -654,7 +573,7 @@ object ExpressionCompiler {
|
|||||||
|
|
||||||
val register = target match {
|
val register = target match {
|
||||||
case RegisterVariable(r, _) => r
|
case RegisterVariable(r, _) => r
|
||||||
case _ => Register.A
|
case _ => MosRegister.A
|
||||||
}
|
}
|
||||||
val suffix = target match {
|
val suffix = target match {
|
||||||
case RegisterVariable(_, _) => Nil
|
case RegisterVariable(_, _) => Nil
|
||||||
@@ -672,31 +591,31 @@ object ExpressionCompiler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
val load = register match {
|
val load = register match {
|
||||||
case Register.A | Register.AX | Register.AY => LDA
|
case MosRegister.A | MosRegister.AX | MosRegister.AY => LDA
|
||||||
case Register.X => LDX
|
case MosRegister.X => LDX
|
||||||
case Register.Y => LDY
|
case MosRegister.Y => LDY
|
||||||
}
|
}
|
||||||
|
|
||||||
def loadFromArrayAtUnknownIndex(variableIndex: Expression, arrayAddr: Constant) = {
|
def loadFromArrayAtUnknownIndex(variableIndex: Expression, arrayAddr: Constant) = {
|
||||||
// TODO check typ
|
// TODO check typ
|
||||||
val indexRegister = if (register == Register.Y) Register.X else Register.Y
|
val indexRegister = if (register == MosRegister.Y) MosRegister.X else MosRegister.Y
|
||||||
val calculatingIndex = compile(ctx, variableIndex, Some(b, RegisterVariable(indexRegister, b)), NoBranching)
|
val calculatingIndex = compile(ctx, variableIndex, Some(b, RegisterVariable(indexRegister, b)), NoBranching)
|
||||||
indexRegister match {
|
indexRegister match {
|
||||||
case Register.Y =>
|
case MosRegister.Y =>
|
||||||
calculatingIndex ++ arrayBoundsCheck(ctx, pointy, Register.Y, indexExpr) ++ List(AssemblyLine.absoluteY(load, arrayAddr + constantIndex))
|
calculatingIndex ++ arrayBoundsCheck(ctx, pointy, MosRegister.Y, indexExpr) ++ List(AssemblyLine.absoluteY(load, arrayAddr + constantIndex))
|
||||||
case Register.X =>
|
case MosRegister.X =>
|
||||||
calculatingIndex ++ arrayBoundsCheck(ctx, pointy, Register.X, indexExpr) ++ List(AssemblyLine.absoluteX(load, arrayAddr + constantIndex))
|
calculatingIndex ++ arrayBoundsCheck(ctx, pointy, MosRegister.X, indexExpr) ++ List(AssemblyLine.absoluteX(load, arrayAddr + constantIndex))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def loadFromReg() = {
|
def loadFromReg() = {
|
||||||
val reg = ctx.env.get[VariableInMemory]("__reg")
|
val reg = ctx.env.get[VariableInMemory]("__reg")
|
||||||
register match {
|
register match {
|
||||||
case Register.A =>
|
case MosRegister.A =>
|
||||||
List(AssemblyLine.indexedY(LDA, reg))
|
List(AssemblyLine.indexedY(LDA, reg))
|
||||||
case Register.X =>
|
case MosRegister.X =>
|
||||||
List(AssemblyLine.indexedY(LDA, reg), AssemblyLine.implied(TAX))
|
List(AssemblyLine.indexedY(LDA, reg), AssemblyLine.implied(TAX))
|
||||||
case Register.Y =>
|
case MosRegister.Y =>
|
||||||
List(AssemblyLine.indexedY(LDA, reg), AssemblyLine.implied(TAY))
|
List(AssemblyLine.indexedY(LDA, reg), AssemblyLine.implied(TAY))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -711,21 +630,21 @@ object ExpressionCompiler {
|
|||||||
prepareWordIndexing(ctx, a, indexExpr) ++ loadFromReg()
|
prepareWordIndexing(ctx, a, indexExpr) ++ loadFromReg()
|
||||||
case (p:VariablePointy, None, 0 | 1, _) =>
|
case (p:VariablePointy, None, 0 | 1, _) =>
|
||||||
register match {
|
register match {
|
||||||
case Register.A =>
|
case MosRegister.A =>
|
||||||
List(AssemblyLine.immediate(LDY, constantIndex), AssemblyLine.indexedY(LDA, p.addr))
|
List(AssemblyLine.immediate(LDY, constantIndex), AssemblyLine.indexedY(LDA, p.addr))
|
||||||
case Register.Y =>
|
case MosRegister.Y =>
|
||||||
List(AssemblyLine.immediate(LDY, constantIndex), AssemblyLine.indexedY(LDA, p.addr), AssemblyLine.implied(TAY))
|
List(AssemblyLine.immediate(LDY, constantIndex), AssemblyLine.indexedY(LDA, p.addr), AssemblyLine.implied(TAY))
|
||||||
case Register.X =>
|
case MosRegister.X =>
|
||||||
List(AssemblyLine.immediate(LDY, constantIndex), AssemblyLine.indexedY(LDA, p.addr), AssemblyLine.implied(TAX))
|
List(AssemblyLine.immediate(LDY, constantIndex), AssemblyLine.indexedY(LDA, p.addr), AssemblyLine.implied(TAX))
|
||||||
}
|
}
|
||||||
case (p:VariablePointy, Some(_), 0 | 1, _) =>
|
case (p:VariablePointy, Some(_), 0 | 1, _) =>
|
||||||
val calculatingIndex = compile(ctx, indexExpr, Some(b, RegisterVariable(Register.Y, b)), NoBranching)
|
val calculatingIndex = compile(ctx, indexExpr, Some(b, RegisterVariable(MosRegister.Y, b)), NoBranching)
|
||||||
register match {
|
register match {
|
||||||
case Register.A =>
|
case MosRegister.A =>
|
||||||
calculatingIndex :+ AssemblyLine.indexedY(LDA, p.addr)
|
calculatingIndex :+ AssemblyLine.indexedY(LDA, p.addr)
|
||||||
case Register.X =>
|
case MosRegister.X =>
|
||||||
calculatingIndex ++ List(AssemblyLine.indexedY(LDA, p.addr), AssemblyLine.implied(TAX))
|
calculatingIndex ++ List(AssemblyLine.indexedY(LDA, p.addr), AssemblyLine.implied(TAX))
|
||||||
case Register.Y =>
|
case MosRegister.Y =>
|
||||||
calculatingIndex ++ List(AssemblyLine.indexedY(LDA, p.addr), AssemblyLine.implied(TAY))
|
calculatingIndex ++ List(AssemblyLine.indexedY(LDA, p.addr), AssemblyLine.implied(TAY))
|
||||||
}
|
}
|
||||||
case _ =>
|
case _ =>
|
||||||
@@ -733,9 +652,9 @@ object ExpressionCompiler {
|
|||||||
Nil
|
Nil
|
||||||
}
|
}
|
||||||
register match {
|
register match {
|
||||||
case Register.A | Register.X | Register.Y => result ++ suffix
|
case MosRegister.A | MosRegister.X | MosRegister.Y => result ++ suffix
|
||||||
case Register.AX => result :+ AssemblyLine.immediate(LDX, 0)
|
case MosRegister.AX => result :+ AssemblyLine.immediate(LDX, 0)
|
||||||
case Register.AY => result :+ AssemblyLine.immediate(LDY, 0)
|
case MosRegister.AY => result :+ AssemblyLine.immediate(LDY, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case SumExpression(params, decimal) =>
|
case SumExpression(params, decimal) =>
|
||||||
@@ -774,19 +693,19 @@ object ExpressionCompiler {
|
|||||||
assertCompatible(exprType, target.typ)
|
assertCompatible(exprType, target.typ)
|
||||||
target match {
|
target match {
|
||||||
// TODO: some more complex ones may not work correctly
|
// TODO: some more complex ones may not work correctly
|
||||||
case RegisterVariable(Register.A | Register.X | Register.Y, _) => compile(ctx, l, exprTypeAndVariable, branches)
|
case RegisterVariable(MosRegister.A | MosRegister.X | MosRegister.Y, _) => compile(ctx, l, exprTypeAndVariable, branches)
|
||||||
case RegisterVariable(Register.AX, _) =>
|
case RegisterVariable(MosRegister.AX, _) =>
|
||||||
compile(ctx, l, Some(b -> RegisterVariable(Register.A, b)), branches) ++
|
compile(ctx, l, Some(b -> RegisterVariable(MosRegister.A, b)), branches) ++
|
||||||
preserveRegisterIfNeeded(ctx, Register.A, compile(ctx, h, Some(b -> RegisterVariable(Register.X, b)), branches))
|
preserveRegisterIfNeeded(ctx, MosRegister.A, compile(ctx, h, Some(b -> RegisterVariable(MosRegister.X, b)), branches))
|
||||||
case RegisterVariable(Register.AY, _) =>
|
case RegisterVariable(MosRegister.AY, _) =>
|
||||||
compile(ctx, l, Some(b -> RegisterVariable(Register.A, b)), branches) ++
|
compile(ctx, l, Some(b -> RegisterVariable(MosRegister.A, b)), branches) ++
|
||||||
preserveRegisterIfNeeded(ctx, Register.A, compile(ctx, h, Some(b -> RegisterVariable(Register.Y, b)), branches))
|
preserveRegisterIfNeeded(ctx, MosRegister.A, compile(ctx, h, Some(b -> RegisterVariable(MosRegister.Y, b)), branches))
|
||||||
case RegisterVariable(Register.XA, _) =>
|
case RegisterVariable(MosRegister.XA, _) =>
|
||||||
compile(ctx, l, Some(b -> RegisterVariable(Register.X, b)), branches) ++
|
compile(ctx, l, Some(b -> RegisterVariable(MosRegister.X, b)), branches) ++
|
||||||
compile(ctx, h, Some(b -> RegisterVariable(Register.A, b)), branches)
|
compile(ctx, h, Some(b -> RegisterVariable(MosRegister.A, b)), branches)
|
||||||
case RegisterVariable(Register.YA, _) =>
|
case RegisterVariable(MosRegister.YA, _) =>
|
||||||
compile(ctx, l, Some(b -> RegisterVariable(Register.Y, b)), branches) ++
|
compile(ctx, l, Some(b -> RegisterVariable(MosRegister.Y, b)), branches) ++
|
||||||
compile(ctx, h, Some(b -> RegisterVariable(Register.A, b)), branches)
|
compile(ctx, h, Some(b -> RegisterVariable(MosRegister.A, b)), branches)
|
||||||
case target: VariableInMemory =>
|
case target: VariableInMemory =>
|
||||||
target.typ.size match {
|
target.typ.size match {
|
||||||
case 1 =>
|
case 1 =>
|
||||||
@@ -827,7 +746,7 @@ object ExpressionCompiler {
|
|||||||
ErrorReporting.error("Invalid parameter type for hi/lo", param.position)
|
ErrorReporting.error("Invalid parameter type for hi/lo", param.position)
|
||||||
compile(ctx, param, None, BranchSpec.None)
|
compile(ctx, param, None, BranchSpec.None)
|
||||||
} else {
|
} else {
|
||||||
val compilation = compile(ctx, param, Some(ExpressionCompiler.getExpressionType(ctx, param) -> RegisterVariable(Register.AX, w)), BranchSpec.None)
|
val compilation = compile(ctx, param, Some(MosExpressionCompiler.getExpressionType(ctx, param) -> RegisterVariable(MosRegister.AX, w)), BranchSpec.None)
|
||||||
if (hi) {
|
if (hi) {
|
||||||
if (typ.size == 2) compilation :+ AssemblyLine.implied(TXA)
|
if (typ.size == 2) compilation :+ AssemblyLine.implied(TXA)
|
||||||
else if (typ.isSigned) compilation ++ signExtendA()
|
else if (typ.isSigned) compilation ++ signExtendA()
|
||||||
@@ -853,8 +772,8 @@ object ExpressionCompiler {
|
|||||||
case _ =>
|
case _ =>
|
||||||
ErrorReporting.warn("Unspecified nonet operation, results might be unpredictable", ctx.options, expr.position)
|
ErrorReporting.warn("Unspecified nonet operation, results might be unpredictable", ctx.options, expr.position)
|
||||||
}
|
}
|
||||||
val label = MfCompiler.nextLabel("no")
|
val label = MosCompiler.nextLabel("no")
|
||||||
compile(ctx, params.head, Some(b -> RegisterVariable(Register.A, b)), BranchSpec.None) ++ List(
|
compile(ctx, params.head, Some(b -> RegisterVariable(MosRegister.A, b)), BranchSpec.None) ++ List(
|
||||||
AssemblyLine.immediate(LDX, 0),
|
AssemblyLine.immediate(LDX, 0),
|
||||||
AssemblyLine.relative(BCC, label),
|
AssemblyLine.relative(BCC, label),
|
||||||
AssemblyLine.implied(INX),
|
AssemblyLine.implied(INX),
|
||||||
@@ -867,7 +786,7 @@ object ExpressionCompiler {
|
|||||||
case BranchIfFalse(_) =>
|
case BranchIfFalse(_) =>
|
||||||
params.flatMap(compile(ctx, _, exprTypeAndVariable, branches))
|
params.flatMap(compile(ctx, _, exprTypeAndVariable, branches))
|
||||||
case _ =>
|
case _ =>
|
||||||
val skip = MfCompiler.nextLabel("an")
|
val skip = MosCompiler.nextLabel("an")
|
||||||
params.init.flatMap(compile(ctx, _, exprTypeAndVariable, BranchIfFalse(skip))) ++
|
params.init.flatMap(compile(ctx, _, exprTypeAndVariable, BranchIfFalse(skip))) ++
|
||||||
compile(ctx, params.last, exprTypeAndVariable, branches) ++
|
compile(ctx, params.last, exprTypeAndVariable, branches) ++
|
||||||
List(AssemblyLine.label(skip))
|
List(AssemblyLine.label(skip))
|
||||||
@@ -878,7 +797,7 @@ object ExpressionCompiler {
|
|||||||
case BranchIfTrue(_) =>
|
case BranchIfTrue(_) =>
|
||||||
params.flatMap(compile(ctx, _, exprTypeAndVariable, branches))
|
params.flatMap(compile(ctx, _, exprTypeAndVariable, branches))
|
||||||
case _ =>
|
case _ =>
|
||||||
val skip = MfCompiler.nextLabel("or")
|
val skip = MosCompiler.nextLabel("or")
|
||||||
params.init.flatMap(compile(ctx, _, exprTypeAndVariable, BranchIfTrue(skip))) ++
|
params.init.flatMap(compile(ctx, _, exprTypeAndVariable, BranchIfTrue(skip))) ++
|
||||||
compile(ctx, params.last, exprTypeAndVariable, branches) ++
|
compile(ctx, params.last, exprTypeAndVariable, branches) ++
|
||||||
List(AssemblyLine.label(skip))
|
List(AssemblyLine.label(skip))
|
||||||
@@ -1096,7 +1015,7 @@ object ExpressionCompiler {
|
|||||||
val (l, r, size) = assertAssignmentLike(ctx, params)
|
val (l, r, size) = assertAssignmentLike(ctx, params)
|
||||||
size match {
|
size match {
|
||||||
case 1 =>
|
case 1 =>
|
||||||
DecimalBuiltIns.compileByteShiftLeft(ctx, l, r, rotate = false) ++ compileByteStorage(ctx, Register.A, l)
|
DecimalBuiltIns.compileByteShiftLeft(ctx, l, r, rotate = false) ++ compileByteStorage(ctx, MosRegister.A, l)
|
||||||
case i if i >= 2 =>
|
case i if i >= 2 =>
|
||||||
l match {
|
l match {
|
||||||
case v: LhsExpression =>
|
case v: LhsExpression =>
|
||||||
@@ -1107,7 +1026,7 @@ object ExpressionCompiler {
|
|||||||
val (l, r, size) = assertAssignmentLike(ctx, params)
|
val (l, r, size) = assertAssignmentLike(ctx, params)
|
||||||
size match {
|
size match {
|
||||||
case 1 =>
|
case 1 =>
|
||||||
DecimalBuiltIns.compileByteShiftRight(ctx, l, r, rotate = false) ++ compileByteStorage(ctx, Register.A, l)
|
DecimalBuiltIns.compileByteShiftRight(ctx, l, r, rotate = false) ++ compileByteStorage(ctx, MosRegister.A, l)
|
||||||
case i if i >= 2 =>
|
case i if i >= 2 =>
|
||||||
l match {
|
l match {
|
||||||
case v: LhsExpression =>
|
case v: LhsExpression =>
|
||||||
@@ -1181,7 +1100,7 @@ object ExpressionCompiler {
|
|||||||
case function: MacroFunction =>
|
case function: MacroFunction =>
|
||||||
val (paramPreparation, statements) = MacroExpander.inlineFunction(ctx, function, params, expr.position)
|
val (paramPreparation, statements) = MacroExpander.inlineFunction(ctx, function, params, expr.position)
|
||||||
paramPreparation ++ statements.map {
|
paramPreparation ++ statements.map {
|
||||||
case AssemblyStatement(opcode, addrMode, expression, elidable) =>
|
case MosAssemblyStatement(opcode, addrMode, expression, elidable) =>
|
||||||
val param = env.evalForAsm(expression).getOrElse {
|
val param = env.evalForAsm(expression).getOrElse {
|
||||||
ErrorReporting.error("Inlining failed due to non-constant things", expression.position)
|
ErrorReporting.error("Inlining failed due to non-constant things", expression.position)
|
||||||
Constant.Zero
|
Constant.Zero
|
||||||
@@ -1271,14 +1190,14 @@ object ExpressionCompiler {
|
|||||||
def expressionStorageFromAX(ctx: CompilationContext, exprTypeAndVariable: Option[(Type, Variable)], position: Option[Position]): List[AssemblyLine] = {
|
def expressionStorageFromAX(ctx: CompilationContext, exprTypeAndVariable: Option[(Type, Variable)], position: Option[Position]): List[AssemblyLine] = {
|
||||||
exprTypeAndVariable.fold(noop) {
|
exprTypeAndVariable.fold(noop) {
|
||||||
case (VoidType, _) => ErrorReporting.fatal("Cannot assign word to void", position)
|
case (VoidType, _) => ErrorReporting.fatal("Cannot assign word to void", position)
|
||||||
case (_, RegisterVariable(Register.A, _)) => noop
|
case (_, RegisterVariable(MosRegister.A, _)) => noop
|
||||||
case (_, RegisterVariable(Register.AW, _)) => List(AssemblyLine.implied(XBA), AssemblyLine.implied(TXA), AssemblyLine.implied(XBA))
|
case (_, RegisterVariable(MosRegister.AW, _)) => List(AssemblyLine.implied(XBA), AssemblyLine.implied(TXA), AssemblyLine.implied(XBA))
|
||||||
case (_, RegisterVariable(Register.X, _)) => List(AssemblyLine.implied(TAX))
|
case (_, RegisterVariable(MosRegister.X, _)) => List(AssemblyLine.implied(TAX))
|
||||||
case (_, RegisterVariable(Register.Y, _)) => List(AssemblyLine.implied(TAY))
|
case (_, RegisterVariable(MosRegister.Y, _)) => List(AssemblyLine.implied(TAY))
|
||||||
case (_, RegisterVariable(Register.AX, _)) =>
|
case (_, RegisterVariable(MosRegister.AX, _)) =>
|
||||||
// TODO: sign extension
|
// TODO: sign extension
|
||||||
noop
|
noop
|
||||||
case (_, RegisterVariable(Register.XA, _)) =>
|
case (_, RegisterVariable(MosRegister.XA, _)) =>
|
||||||
// TODO: sign extension
|
// TODO: sign extension
|
||||||
if (ctx.options.flag(CompilationFlag.EmitHudsonOpcodes)) {
|
if (ctx.options.flag(CompilationFlag.EmitHudsonOpcodes)) {
|
||||||
List(AssemblyLine.implied(HuSAX))
|
List(AssemblyLine.implied(HuSAX))
|
||||||
@@ -1297,12 +1216,12 @@ object ExpressionCompiler {
|
|||||||
AssemblyLine.implied(TAX),
|
AssemblyLine.implied(TAX),
|
||||||
AssemblyLine.implied(PLA)) // fuck this shit
|
AssemblyLine.implied(PLA)) // fuck this shit
|
||||||
}
|
}
|
||||||
case (_, RegisterVariable(Register.YA, _)) =>
|
case (_, RegisterVariable(MosRegister.YA, _)) =>
|
||||||
// TODO: sign extension
|
// TODO: sign extension
|
||||||
List(
|
List(
|
||||||
AssemblyLine.implied(TAY),
|
AssemblyLine.implied(TAY),
|
||||||
AssemblyLine.implied(TXA))
|
AssemblyLine.implied(TXA))
|
||||||
case (_, RegisterVariable(Register.AY, _)) =>
|
case (_, RegisterVariable(MosRegister.AY, _)) =>
|
||||||
// TODO: sign extension
|
// TODO: sign extension
|
||||||
if (ctx.options.flag(CompilationFlag.EmitHudsonOpcodes)) {
|
if (ctx.options.flag(CompilationFlag.EmitHudsonOpcodes)) {
|
||||||
List(AssemblyLine.implied(SXY))
|
List(AssemblyLine.implied(SXY))
|
||||||
@@ -1408,23 +1327,17 @@ object ExpressionCompiler {
|
|||||||
// TODO check v.typ
|
// TODO check v.typ
|
||||||
compile(ctx, source, Some((getExpressionType(ctx, source), v)), NoBranching)
|
compile(ctx, source, Some((getExpressionType(ctx, source), v)), NoBranching)
|
||||||
case SeparateBytesExpression(h: LhsExpression, l: LhsExpression) =>
|
case SeparateBytesExpression(h: LhsExpression, l: LhsExpression) =>
|
||||||
compile(ctx, source, Some(w, RegisterVariable(Register.AX, w)), NoBranching) ++
|
compile(ctx, source, Some(w, RegisterVariable(MosRegister.AX, w)), NoBranching) ++
|
||||||
compileByteStorage(ctx, Register.A, l) ++ compileByteStorage(ctx, Register.X, h)
|
compileByteStorage(ctx, MosRegister.A, l) ++ compileByteStorage(ctx, MosRegister.X, h)
|
||||||
case SeparateBytesExpression(_, _) =>
|
case SeparateBytesExpression(_, _) =>
|
||||||
ErrorReporting.error("Invalid left-hand-side use of `:`")
|
ErrorReporting.error("Invalid left-hand-side use of `:`")
|
||||||
Nil
|
Nil
|
||||||
case _ =>
|
case _ =>
|
||||||
compile(ctx, source, Some(b, RegisterVariable(Register.A, b)), NoBranching) ++ compileByteStorage(ctx, Register.A, target)
|
compile(ctx, source, Some(b, RegisterVariable(MosRegister.A, b)), NoBranching) ++ compileByteStorage(ctx, MosRegister.A, target)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def lookupFunction(ctx: CompilationContext, f: FunctionCallExpression): MangledFunction = {
|
def arrayBoundsCheck(ctx: CompilationContext, pointy: Pointy, register: MosRegister.Value, index: Expression): List[AssemblyLine] = {
|
||||||
val paramsWithTypes = f.expressions.map(x => getExpressionType(ctx, x) -> x)
|
|
||||||
ctx.env.lookupFunction(f.functionName, paramsWithTypes).getOrElse(
|
|
||||||
ErrorReporting.fatal(s"Cannot find function `${f.functionName}` with given params `${paramsWithTypes.map(_._1).mkString("(", ",", ")")}`", f.position))
|
|
||||||
}
|
|
||||||
|
|
||||||
def arrayBoundsCheck(ctx: CompilationContext, pointy: Pointy, register: Register.Value, index: Expression): List[AssemblyLine] = {
|
|
||||||
if (!ctx.options.flags(CompilationFlag.CheckIndexOutOfBounds)) return Nil
|
if (!ctx.options.flags(CompilationFlag.CheckIndexOutOfBounds)) return Nil
|
||||||
val arrayLength = pointy match {
|
val arrayLength = pointy match {
|
||||||
case _: VariablePointy => return Nil
|
case _: VariablePointy => return Nil
|
||||||
@@ -1442,11 +1355,11 @@ object ExpressionCompiler {
|
|||||||
case _ =>
|
case _ =>
|
||||||
}
|
}
|
||||||
if (arrayLength > 0 && arrayLength < 255) {
|
if (arrayLength > 0 && arrayLength < 255) {
|
||||||
val label = MfCompiler.nextLabel("bc")
|
val label = MosCompiler.nextLabel("bc")
|
||||||
val compare = register match {
|
val compare = register match {
|
||||||
case Register.A => CMP
|
case MosRegister.A => CMP
|
||||||
case Register.X => CPX
|
case MosRegister.X => CPX
|
||||||
case Register.Y => CPY
|
case MosRegister.Y => CPY
|
||||||
}
|
}
|
||||||
List(
|
List(
|
||||||
AssemblyLine.implied(PHP),
|
AssemblyLine.implied(PHP),
|
||||||
@@ -1461,7 +1374,7 @@ object ExpressionCompiler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private def signExtendA(): List[AssemblyLine] = {
|
private def signExtendA(): List[AssemblyLine] = {
|
||||||
val label = MfCompiler.nextLabel("sx")
|
val label = MosCompiler.nextLabel("sx")
|
||||||
List(
|
List(
|
||||||
AssemblyLine.immediate(ORA, 0x7F),
|
AssemblyLine.immediate(ORA, 0x7F),
|
||||||
AssemblyLine.relative(BMI, label),
|
AssemblyLine.relative(BMI, label),
|
@@ -1,19 +1,17 @@
|
|||||||
package millfork.compiler
|
package millfork.compiler.mos
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicLong
|
import millfork.CompilationFlag
|
||||||
|
|
||||||
import millfork.{CompilationFlag, CompilationOptions}
|
|
||||||
import millfork.assembly._
|
|
||||||
import millfork.env._
|
|
||||||
import millfork.node.{Register, _}
|
|
||||||
import millfork.assembly.AddrMode._
|
import millfork.assembly.AddrMode._
|
||||||
import millfork.assembly.Opcode._
|
import millfork.assembly.mos.Opcode._
|
||||||
|
import millfork.assembly.mos._
|
||||||
|
import millfork.env._
|
||||||
import millfork.error.ErrorReporting
|
import millfork.error.ErrorReporting
|
||||||
|
import millfork.node.{MosRegister, _}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Karol Stasiak
|
* @author Karol Stasiak
|
||||||
*/
|
*/
|
||||||
object StatementCompiler {
|
object MosStatementCompiler {
|
||||||
|
|
||||||
private def labelChunk(labelName: String) = List(AssemblyLine.label(Label(labelName)))
|
private def labelChunk(labelName: String) = List(AssemblyLine.label(Label(labelName)))
|
||||||
|
|
||||||
@@ -41,9 +39,9 @@ object StatementCompiler {
|
|||||||
AssemblyLine.zeropage(STA, reg)
|
AssemblyLine.zeropage(STA, reg)
|
||||||
)
|
)
|
||||||
} else Nil
|
} else Nil
|
||||||
val someRegisterA = Some(b, RegisterVariable(Register.A, b))
|
val someRegisterA = Some(b, RegisterVariable(MosRegister.A, b))
|
||||||
val someRegisterAX = Some(w, RegisterVariable(Register.AX, w))
|
val someRegisterAX = Some(w, RegisterVariable(MosRegister.AX, w))
|
||||||
val someRegisterYA = Some(w, RegisterVariable(Register.YA, w))
|
val someRegisterYA = Some(w, RegisterVariable(MosRegister.YA, w))
|
||||||
val returnInstructions = if (m.interrupt) {
|
val returnInstructions = if (m.interrupt) {
|
||||||
if (ctx.options.flag(CompilationFlag.EmitNative65816Opcodes)) {
|
if (ctx.options.flag(CompilationFlag.EmitNative65816Opcodes)) {
|
||||||
if (ctx.options.flag(CompilationFlag.ZeropagePseudoregister)) {
|
if (ctx.options.flag(CompilationFlag.ZeropagePseudoregister)) {
|
||||||
@@ -114,7 +112,7 @@ object StatementCompiler {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
statement match {
|
statement match {
|
||||||
case AssemblyStatement(o, a, x, e) =>
|
case MosAssemblyStatement(o, a, x, e) =>
|
||||||
val c: Constant = x match {
|
val c: Constant = x match {
|
||||||
// TODO: hmmm
|
// TODO: hmmm
|
||||||
case VariableExpression(name) =>
|
case VariableExpression(name) =>
|
||||||
@@ -143,14 +141,14 @@ object StatementCompiler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case Assignment(dest, source) =>
|
case Assignment(dest, source) =>
|
||||||
ExpressionCompiler.compileAssignment(ctx, source, dest)
|
MosExpressionCompiler.compileAssignment(ctx, source, dest)
|
||||||
case ExpressionStatement(e@FunctionCallExpression(name, params)) =>
|
case ExpressionStatement(e@FunctionCallExpression(name, params)) =>
|
||||||
env.lookupFunction(name, params.map(p => ExpressionCompiler.getExpressionType(ctx, p) -> p)) match {
|
env.lookupFunction(name, params.map(p => MosExpressionCompiler.getExpressionType(ctx, p) -> p)) match {
|
||||||
case Some(i: MacroFunction) =>
|
case Some(i: MacroFunction) =>
|
||||||
val (paramPreparation, inlinedStatements) = MacroExpander.inlineFunction(ctx, i, params, e.position)
|
val (paramPreparation, inlinedStatements) = MacroExpander.inlineFunction(ctx, i, params, e.position)
|
||||||
paramPreparation ++ compile(ctx.withInlinedEnv(i.environment), inlinedStatements)
|
paramPreparation ++ compile(ctx.withInlinedEnv(i.environment), inlinedStatements)
|
||||||
case _ =>
|
case _ =>
|
||||||
ExpressionCompiler.compile(ctx, e, None, NoBranching)
|
MosExpressionCompiler.compile(ctx, e, None, NoBranching)
|
||||||
}
|
}
|
||||||
case ExpressionStatement(e) =>
|
case ExpressionStatement(e) =>
|
||||||
e match {
|
e match {
|
||||||
@@ -158,7 +156,7 @@ object StatementCompiler {
|
|||||||
ErrorReporting.warn("Pointless expression statement", ctx.options, statement.position)
|
ErrorReporting.warn("Pointless expression statement", ctx.options, statement.position)
|
||||||
case _ =>
|
case _ =>
|
||||||
}
|
}
|
||||||
ExpressionCompiler.compile(ctx, e, None, NoBranching)
|
MosExpressionCompiler.compile(ctx, e, None, NoBranching)
|
||||||
case ReturnStatement(None) =>
|
case ReturnStatement(None) =>
|
||||||
// TODO: return type check
|
// TODO: return type check
|
||||||
// TODO: better stackpointer fix
|
// TODO: better stackpointer fix
|
||||||
@@ -187,9 +185,9 @@ object StatementCompiler {
|
|||||||
ErrorReporting.error("Cannot return anything from a void function", statement.position)
|
ErrorReporting.error("Cannot return anything from a void function", statement.position)
|
||||||
stackPointerFixBeforeReturn(ctx) ++ returnInstructions
|
stackPointerFixBeforeReturn(ctx) ++ returnInstructions
|
||||||
case 1 =>
|
case 1 =>
|
||||||
ExpressionCompiler.compile(ctx, e, someRegisterA, NoBranching) ++ stackPointerFixBeforeReturn(ctx) ++ returnInstructions
|
MosExpressionCompiler.compile(ctx, e, someRegisterA, NoBranching) ++ stackPointerFixBeforeReturn(ctx) ++ returnInstructions
|
||||||
case 2 =>
|
case 2 =>
|
||||||
ExpressionCompiler.compile(ctx, e, someRegisterAX, NoBranching) ++ stackPointerFixBeforeReturn(ctx) ++ returnInstructions
|
MosExpressionCompiler.compile(ctx, e, someRegisterAX, NoBranching) ++ stackPointerFixBeforeReturn(ctx) ++ returnInstructions
|
||||||
}
|
}
|
||||||
case _ =>
|
case _ =>
|
||||||
m.returnType.size match {
|
m.returnType.size match {
|
||||||
@@ -197,14 +195,14 @@ object StatementCompiler {
|
|||||||
ErrorReporting.error("Cannot return anything from a void function", statement.position)
|
ErrorReporting.error("Cannot return anything from a void function", statement.position)
|
||||||
stackPointerFixBeforeReturn(ctx) ++ List(AssemblyLine.discardAF(), AssemblyLine.discardXF(), AssemblyLine.discardYF()) ++ returnInstructions
|
stackPointerFixBeforeReturn(ctx) ++ List(AssemblyLine.discardAF(), AssemblyLine.discardXF(), AssemblyLine.discardYF()) ++ returnInstructions
|
||||||
case 1 =>
|
case 1 =>
|
||||||
ExpressionCompiler.compile(ctx, e, someRegisterA, NoBranching) ++ stackPointerFixBeforeReturn(ctx) ++ List(AssemblyLine.discardXF(), AssemblyLine.discardYF()) ++ returnInstructions
|
MosExpressionCompiler.compile(ctx, e, someRegisterA, NoBranching) ++ stackPointerFixBeforeReturn(ctx) ++ List(AssemblyLine.discardXF(), AssemblyLine.discardYF()) ++ returnInstructions
|
||||||
case 2 =>
|
case 2 =>
|
||||||
// TODO: ???
|
// TODO: ???
|
||||||
val stackPointerFix = stackPointerFixBeforeReturn(ctx)
|
val stackPointerFix = stackPointerFixBeforeReturn(ctx)
|
||||||
if (stackPointerFix.isEmpty) {
|
if (stackPointerFix.isEmpty) {
|
||||||
ExpressionCompiler.compile(ctx, e, someRegisterAX, NoBranching) ++ List(AssemblyLine.discardYF()) ++ returnInstructions
|
MosExpressionCompiler.compile(ctx, e, someRegisterAX, NoBranching) ++ List(AssemblyLine.discardYF()) ++ returnInstructions
|
||||||
} else {
|
} else {
|
||||||
ExpressionCompiler.compile(ctx, e, someRegisterYA, NoBranching) ++
|
MosExpressionCompiler.compile(ctx, e, someRegisterYA, NoBranching) ++
|
||||||
stackPointerFix ++
|
stackPointerFix ++
|
||||||
List(AssemblyLine.implied(TAX), AssemblyLine.implied(TYA), AssemblyLine.discardYF()) ++
|
List(AssemblyLine.implied(TAX), AssemblyLine.implied(TYA), AssemblyLine.discardYF()) ++
|
||||||
returnInstructions
|
returnInstructions
|
||||||
@@ -212,103 +210,103 @@ object StatementCompiler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case IfStatement(condition, thenPart, elsePart) =>
|
case IfStatement(condition, thenPart, elsePart) =>
|
||||||
val condType = ExpressionCompiler.getExpressionType(ctx, condition)
|
val condType = MosExpressionCompiler.getExpressionType(ctx, condition)
|
||||||
val thenBlock = compile(ctx, thenPart)
|
val thenBlock = compile(ctx, thenPart)
|
||||||
val elseBlock = compile(ctx, elsePart)
|
val elseBlock = compile(ctx, elsePart)
|
||||||
val largeThenBlock = thenBlock.map(_.sizeInBytes).sum > 100
|
val largeThenBlock = thenBlock.map(_.sizeInBytes).sum > 100
|
||||||
val largeElseBlock = elseBlock.map(_.sizeInBytes).sum > 100
|
val largeElseBlock = elseBlock.map(_.sizeInBytes).sum > 100
|
||||||
condType match {
|
condType match {
|
||||||
case ConstantBooleanType(_, true) =>
|
case ConstantBooleanType(_, true) =>
|
||||||
ExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching) ++ thenBlock
|
MosExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching) ++ thenBlock
|
||||||
case ConstantBooleanType(_, false) =>
|
case ConstantBooleanType(_, false) =>
|
||||||
ExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching) ++ elseBlock
|
MosExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching) ++ elseBlock
|
||||||
case FlagBooleanType(_, jumpIfTrue, jumpIfFalse) =>
|
case FlagBooleanType(_, jumpIfTrue, jumpIfFalse) =>
|
||||||
(thenPart, elsePart) match {
|
(thenPart, elsePart) match {
|
||||||
case (Nil, Nil) =>
|
case (Nil, Nil) =>
|
||||||
ExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching)
|
MosExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching)
|
||||||
case (Nil, _) =>
|
case (Nil, _) =>
|
||||||
val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching)
|
val conditionBlock = MosExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching)
|
||||||
if (largeElseBlock) {
|
if (largeElseBlock) {
|
||||||
val middle = MfCompiler.nextLabel("el")
|
val middle = MosCompiler.nextLabel("el")
|
||||||
val end = MfCompiler.nextLabel("fi")
|
val end = MosCompiler.nextLabel("fi")
|
||||||
List(conditionBlock, branchChunk(jumpIfFalse, middle), jmpChunk(end), labelChunk(middle), elseBlock, labelChunk(end)).flatten
|
List(conditionBlock, branchChunk(jumpIfFalse, middle), jmpChunk(end), labelChunk(middle), elseBlock, labelChunk(end)).flatten
|
||||||
} else {
|
} else {
|
||||||
val end = MfCompiler.nextLabel("fi")
|
val end = MosCompiler.nextLabel("fi")
|
||||||
List(conditionBlock, branchChunk(jumpIfTrue, end), elseBlock, labelChunk(end)).flatten
|
List(conditionBlock, branchChunk(jumpIfTrue, end), elseBlock, labelChunk(end)).flatten
|
||||||
}
|
}
|
||||||
case (_, Nil) =>
|
case (_, Nil) =>
|
||||||
val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching)
|
val conditionBlock = MosExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching)
|
||||||
if (largeThenBlock) {
|
if (largeThenBlock) {
|
||||||
val middle = MfCompiler.nextLabel("th")
|
val middle = MosCompiler.nextLabel("th")
|
||||||
val end = MfCompiler.nextLabel("fi")
|
val end = MosCompiler.nextLabel("fi")
|
||||||
List(conditionBlock, branchChunk(jumpIfTrue, middle), jmpChunk(end), labelChunk(middle), thenBlock, labelChunk(end)).flatten
|
List(conditionBlock, branchChunk(jumpIfTrue, middle), jmpChunk(end), labelChunk(middle), thenBlock, labelChunk(end)).flatten
|
||||||
} else {
|
} else {
|
||||||
val end = MfCompiler.nextLabel("fi")
|
val end = MosCompiler.nextLabel("fi")
|
||||||
List(conditionBlock, branchChunk(jumpIfFalse, end), thenBlock, labelChunk(end)).flatten
|
List(conditionBlock, branchChunk(jumpIfFalse, end), thenBlock, labelChunk(end)).flatten
|
||||||
}
|
}
|
||||||
case _ =>
|
case _ =>
|
||||||
val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching)
|
val conditionBlock = MosExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching)
|
||||||
if (largeThenBlock) {
|
if (largeThenBlock) {
|
||||||
if (largeElseBlock) {
|
if (largeElseBlock) {
|
||||||
val middleT = MfCompiler.nextLabel("th")
|
val middleT = MosCompiler.nextLabel("th")
|
||||||
val middleE = MfCompiler.nextLabel("el")
|
val middleE = MosCompiler.nextLabel("el")
|
||||||
val end = MfCompiler.nextLabel("fi")
|
val end = MosCompiler.nextLabel("fi")
|
||||||
List(conditionBlock, branchChunk(jumpIfTrue, middleT), jmpChunk(middleE), labelChunk(middleT), thenBlock, jmpChunk(end), labelChunk(middleE), elseBlock, labelChunk(end)).flatten
|
List(conditionBlock, branchChunk(jumpIfTrue, middleT), jmpChunk(middleE), labelChunk(middleT), thenBlock, jmpChunk(end), labelChunk(middleE), elseBlock, labelChunk(end)).flatten
|
||||||
} else {
|
} else {
|
||||||
val middle = MfCompiler.nextLabel("th")
|
val middle = MosCompiler.nextLabel("th")
|
||||||
val end = MfCompiler.nextLabel("fi")
|
val end = MosCompiler.nextLabel("fi")
|
||||||
List(conditionBlock, branchChunk(jumpIfTrue, middle), elseBlock, jmpChunk(end), labelChunk(middle), thenBlock, labelChunk(end)).flatten
|
List(conditionBlock, branchChunk(jumpIfTrue, middle), elseBlock, jmpChunk(end), labelChunk(middle), thenBlock, labelChunk(end)).flatten
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val middle = MfCompiler.nextLabel("el")
|
val middle = MosCompiler.nextLabel("el")
|
||||||
val end = MfCompiler.nextLabel("fi")
|
val end = MosCompiler.nextLabel("fi")
|
||||||
List(conditionBlock, branchChunk(jumpIfFalse, middle), thenBlock, jmpChunk(end), labelChunk(middle), elseBlock, labelChunk(end)).flatten
|
List(conditionBlock, branchChunk(jumpIfFalse, middle), thenBlock, jmpChunk(end), labelChunk(middle), elseBlock, labelChunk(end)).flatten
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case BuiltInBooleanType =>
|
case BuiltInBooleanType =>
|
||||||
(thenPart, elsePart) match {
|
(thenPart, elsePart) match {
|
||||||
case (Nil, Nil) =>
|
case (Nil, Nil) =>
|
||||||
ExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching)
|
MosExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching)
|
||||||
case (Nil, _) =>
|
case (Nil, _) =>
|
||||||
if (largeElseBlock) {
|
if (largeElseBlock) {
|
||||||
val middle = MfCompiler.nextLabel("el")
|
val middle = MosCompiler.nextLabel("el")
|
||||||
val end = MfCompiler.nextLabel("fi")
|
val end = MosCompiler.nextLabel("fi")
|
||||||
val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfFalse(middle))
|
val conditionBlock = MosExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfFalse(middle))
|
||||||
List(conditionBlock, jmpChunk(end), labelChunk(middle), elseBlock, labelChunk(end)).flatten
|
List(conditionBlock, jmpChunk(end), labelChunk(middle), elseBlock, labelChunk(end)).flatten
|
||||||
} else {
|
} else {
|
||||||
val end = MfCompiler.nextLabel("fi")
|
val end = MosCompiler.nextLabel("fi")
|
||||||
val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfTrue(end))
|
val conditionBlock = MosExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfTrue(end))
|
||||||
List(conditionBlock, elseBlock, labelChunk(end)).flatten
|
List(conditionBlock, elseBlock, labelChunk(end)).flatten
|
||||||
}
|
}
|
||||||
case (_, Nil) =>
|
case (_, Nil) =>
|
||||||
if (largeThenBlock) {
|
if (largeThenBlock) {
|
||||||
val middle = MfCompiler.nextLabel("th")
|
val middle = MosCompiler.nextLabel("th")
|
||||||
val end = MfCompiler.nextLabel("fi")
|
val end = MosCompiler.nextLabel("fi")
|
||||||
val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfTrue(middle))
|
val conditionBlock = MosExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfTrue(middle))
|
||||||
List(conditionBlock, jmpChunk(end), labelChunk(middle), thenBlock, labelChunk(end)).flatten
|
List(conditionBlock, jmpChunk(end), labelChunk(middle), thenBlock, labelChunk(end)).flatten
|
||||||
} else {
|
} else {
|
||||||
val end = MfCompiler.nextLabel("fi")
|
val end = MosCompiler.nextLabel("fi")
|
||||||
val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfFalse(end))
|
val conditionBlock = MosExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfFalse(end))
|
||||||
List(conditionBlock, thenBlock, labelChunk(end)).flatten
|
List(conditionBlock, thenBlock, labelChunk(end)).flatten
|
||||||
}
|
}
|
||||||
case _ =>
|
case _ =>
|
||||||
if (largeThenBlock) {
|
if (largeThenBlock) {
|
||||||
if (largeElseBlock) {
|
if (largeElseBlock) {
|
||||||
val middleT = MfCompiler.nextLabel("th")
|
val middleT = MosCompiler.nextLabel("th")
|
||||||
val middleE = MfCompiler.nextLabel("el")
|
val middleE = MosCompiler.nextLabel("el")
|
||||||
val end = MfCompiler.nextLabel("fi")
|
val end = MosCompiler.nextLabel("fi")
|
||||||
val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfTrue(middleT))
|
val conditionBlock = MosExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfTrue(middleT))
|
||||||
List(conditionBlock, jmpChunk(middleE), labelChunk(middleT), thenBlock, jmpChunk(end), labelChunk(middleE), elseBlock, labelChunk(end)).flatten
|
List(conditionBlock, jmpChunk(middleE), labelChunk(middleT), thenBlock, jmpChunk(end), labelChunk(middleE), elseBlock, labelChunk(end)).flatten
|
||||||
} else {
|
} else {
|
||||||
val middle = MfCompiler.nextLabel("th")
|
val middle = MosCompiler.nextLabel("th")
|
||||||
val end = MfCompiler.nextLabel("fi")
|
val end = MosCompiler.nextLabel("fi")
|
||||||
val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfTrue(middle))
|
val conditionBlock = MosExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfTrue(middle))
|
||||||
List(conditionBlock, elseBlock, jmpChunk(end), labelChunk(middle), thenBlock, labelChunk(end)).flatten
|
List(conditionBlock, elseBlock, jmpChunk(end), labelChunk(middle), thenBlock, labelChunk(end)).flatten
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val middle = MfCompiler.nextLabel("el")
|
val middle = MosCompiler.nextLabel("el")
|
||||||
val end = MfCompiler.nextLabel("fi")
|
val end = MosCompiler.nextLabel("fi")
|
||||||
val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfFalse(middle))
|
val conditionBlock = MosExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfFalse(middle))
|
||||||
List(conditionBlock, thenBlock, jmpChunk(end), labelChunk(middle), elseBlock, labelChunk(end)).flatten
|
List(conditionBlock, thenBlock, jmpChunk(end), labelChunk(middle), elseBlock, labelChunk(end)).flatten
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -317,11 +315,11 @@ object StatementCompiler {
|
|||||||
Nil
|
Nil
|
||||||
}
|
}
|
||||||
case WhileStatement(condition, bodyPart, incrementPart, labels) =>
|
case WhileStatement(condition, bodyPart, incrementPart, labels) =>
|
||||||
val start = MfCompiler.nextLabel("wh")
|
val start = MosCompiler.nextLabel("wh")
|
||||||
val middle = MfCompiler.nextLabel("he")
|
val middle = MosCompiler.nextLabel("he")
|
||||||
val inc = MfCompiler.nextLabel("fp")
|
val inc = MosCompiler.nextLabel("fp")
|
||||||
val end = MfCompiler.nextLabel("ew")
|
val end = MosCompiler.nextLabel("ew")
|
||||||
val condType = ExpressionCompiler.getExpressionType(ctx, condition)
|
val condType = MosExpressionCompiler.getExpressionType(ctx, condition)
|
||||||
val bodyBlock = compile(ctx.addLabels(labels, Label(end), Label(inc)), bodyPart)
|
val bodyBlock = compile(ctx.addLabels(labels, Label(end), Label(inc)), bodyPart)
|
||||||
val incrementBlock = compile(ctx.addLabels(labels, Label(end), Label(inc)), incrementPart)
|
val incrementBlock = compile(ctx.addLabels(labels, Label(end), Label(inc)), incrementPart)
|
||||||
val largeBodyBlock = bodyBlock.map(_.sizeInBytes).sum + incrementBlock.map(_.sizeInBytes).sum > 100
|
val largeBodyBlock = bodyBlock.map(_.sizeInBytes).sum + incrementBlock.map(_.sizeInBytes).sum > 100
|
||||||
@@ -331,19 +329,19 @@ object StatementCompiler {
|
|||||||
case ConstantBooleanType(_, false) => Nil
|
case ConstantBooleanType(_, false) => Nil
|
||||||
case FlagBooleanType(_, jumpIfTrue, jumpIfFalse) =>
|
case FlagBooleanType(_, jumpIfTrue, jumpIfFalse) =>
|
||||||
if (largeBodyBlock) {
|
if (largeBodyBlock) {
|
||||||
val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching)
|
val conditionBlock = MosExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching)
|
||||||
List(labelChunk(start), conditionBlock, branchChunk(jumpIfTrue, middle), jmpChunk(end), labelChunk(middle), bodyBlock, labelChunk(inc), incrementBlock, jmpChunk(start), labelChunk(end)).flatten
|
List(labelChunk(start), conditionBlock, branchChunk(jumpIfTrue, middle), jmpChunk(end), labelChunk(middle), bodyBlock, labelChunk(inc), incrementBlock, jmpChunk(start), labelChunk(end)).flatten
|
||||||
} else {
|
} else {
|
||||||
val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching)
|
val conditionBlock = MosExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching)
|
||||||
List(jmpChunk(middle), labelChunk(start), bodyBlock, labelChunk(inc), incrementBlock, labelChunk(middle), conditionBlock, branchChunk(jumpIfTrue, start), labelChunk(end)).flatten
|
List(jmpChunk(middle), labelChunk(start), bodyBlock, labelChunk(inc), incrementBlock, labelChunk(middle), conditionBlock, branchChunk(jumpIfTrue, start), labelChunk(end)).flatten
|
||||||
// List(labelChunk(start), conditionBlock, branchChunk(jumpIfFalse, end), bodyBlock, labelChunk(inc), incrementBlock, jmpChunk(start), labelChunk(end)).flatten
|
// List(labelChunk(start), conditionBlock, branchChunk(jumpIfFalse, end), bodyBlock, labelChunk(inc), incrementBlock, jmpChunk(start), labelChunk(end)).flatten
|
||||||
}
|
}
|
||||||
case BuiltInBooleanType =>
|
case BuiltInBooleanType =>
|
||||||
if (largeBodyBlock) {
|
if (largeBodyBlock) {
|
||||||
val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfTrue(middle))
|
val conditionBlock = MosExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfTrue(middle))
|
||||||
List(labelChunk(start), conditionBlock, jmpChunk(end), labelChunk(middle), bodyBlock, labelChunk(inc), incrementBlock, jmpChunk(start), labelChunk(end)).flatten
|
List(labelChunk(start), conditionBlock, jmpChunk(end), labelChunk(middle), bodyBlock, labelChunk(inc), incrementBlock, jmpChunk(start), labelChunk(end)).flatten
|
||||||
} else {
|
} else {
|
||||||
val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfTrue(start))
|
val conditionBlock = MosExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfTrue(start))
|
||||||
List(jmpChunk(middle), labelChunk(start), bodyBlock, labelChunk(inc), incrementBlock, labelChunk(middle), conditionBlock, labelChunk(end)).flatten
|
List(jmpChunk(middle), labelChunk(start), bodyBlock, labelChunk(inc), incrementBlock, labelChunk(middle), conditionBlock, labelChunk(end)).flatten
|
||||||
// List(labelChunk(start), conditionBlock, bodyBlock, labelChunk(inc), incrementBlock, jmpChunk(start), labelChunk(end)).flatten
|
// List(labelChunk(start), conditionBlock, bodyBlock, labelChunk(inc), incrementBlock, jmpChunk(start), labelChunk(end)).flatten
|
||||||
}
|
}
|
||||||
@@ -352,21 +350,21 @@ object StatementCompiler {
|
|||||||
Nil
|
Nil
|
||||||
}
|
}
|
||||||
case DoWhileStatement(bodyPart, incrementPart, condition, labels) =>
|
case DoWhileStatement(bodyPart, incrementPart, condition, labels) =>
|
||||||
val start = MfCompiler.nextLabel("do")
|
val start = MosCompiler.nextLabel("do")
|
||||||
val inc = MfCompiler.nextLabel("fp")
|
val inc = MosCompiler.nextLabel("fp")
|
||||||
val end = MfCompiler.nextLabel("od")
|
val end = MosCompiler.nextLabel("od")
|
||||||
val condType = ExpressionCompiler.getExpressionType(ctx, condition)
|
val condType = MosExpressionCompiler.getExpressionType(ctx, condition)
|
||||||
val bodyBlock = compile(ctx.addLabels(labels, Label(end), Label(inc)), bodyPart)
|
val bodyBlock = compile(ctx.addLabels(labels, Label(end), Label(inc)), bodyPart)
|
||||||
val incrementBlock = compile(ctx.addLabels(labels, Label(end), Label(inc)), incrementPart)
|
val incrementBlock = compile(ctx.addLabels(labels, Label(end), Label(inc)), incrementPart)
|
||||||
val largeBodyBlock = bodyBlock.map(_.sizeInBytes).sum + incrementBlock.map(_.sizeInBytes).sum > 100
|
val largeBodyBlock = bodyBlock.map(_.sizeInBytes).sum + incrementBlock.map(_.sizeInBytes).sum > 100
|
||||||
condType match {
|
condType match {
|
||||||
case ConstantBooleanType(_, true) =>
|
case ConstantBooleanType(_, true) =>
|
||||||
val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching)
|
val conditionBlock = MosExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching)
|
||||||
List(labelChunk(start),bodyBlock, labelChunk(inc), incrementBlock, jmpChunk(start), labelChunk(end)).flatten
|
List(labelChunk(start),bodyBlock, labelChunk(inc), incrementBlock, jmpChunk(start), labelChunk(end)).flatten
|
||||||
case ConstantBooleanType(_, false) =>
|
case ConstantBooleanType(_, false) =>
|
||||||
List(bodyBlock, labelChunk(inc), incrementBlock, labelChunk(end)).flatten
|
List(bodyBlock, labelChunk(inc), incrementBlock, labelChunk(end)).flatten
|
||||||
case FlagBooleanType(_, jumpIfTrue, jumpIfFalse) =>
|
case FlagBooleanType(_, jumpIfTrue, jumpIfFalse) =>
|
||||||
val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching)
|
val conditionBlock = MosExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching)
|
||||||
if (largeBodyBlock) {
|
if (largeBodyBlock) {
|
||||||
List(labelChunk(start), bodyBlock, labelChunk(inc), incrementBlock, conditionBlock, branchChunk(jumpIfFalse, end), jmpChunk(start), labelChunk(end)).flatten
|
List(labelChunk(start), bodyBlock, labelChunk(inc), incrementBlock, conditionBlock, branchChunk(jumpIfFalse, end), jmpChunk(start), labelChunk(end)).flatten
|
||||||
} else {
|
} else {
|
||||||
@@ -374,10 +372,10 @@ object StatementCompiler {
|
|||||||
}
|
}
|
||||||
case BuiltInBooleanType =>
|
case BuiltInBooleanType =>
|
||||||
if (largeBodyBlock) {
|
if (largeBodyBlock) {
|
||||||
val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfFalse(end))
|
val conditionBlock = MosExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfFalse(end))
|
||||||
List(labelChunk(start), bodyBlock, labelChunk(inc), incrementBlock, conditionBlock, jmpChunk(start), labelChunk(end)).flatten
|
List(labelChunk(start), bodyBlock, labelChunk(inc), incrementBlock, conditionBlock, jmpChunk(start), labelChunk(end)).flatten
|
||||||
} else {
|
} else {
|
||||||
val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfTrue(start))
|
val conditionBlock = MosExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfTrue(start))
|
||||||
List(labelChunk(start), bodyBlock, labelChunk(inc), incrementBlock, conditionBlock, labelChunk(end)).flatten
|
List(labelChunk(start), bodyBlock, labelChunk(inc), incrementBlock, conditionBlock, labelChunk(end)).flatten
|
||||||
}
|
}
|
||||||
case _ =>
|
case _ =>
|
||||||
@@ -395,13 +393,13 @@ object StatementCompiler {
|
|||||||
(direction, env.eval(start), env.eval(end)) match {
|
(direction, env.eval(start), env.eval(end)) match {
|
||||||
|
|
||||||
case (ForDirection.Until | ForDirection.ParallelUntil, Some(NumericConstant(s, ssize)), Some(NumericConstant(e, _))) if s == e - 1 =>
|
case (ForDirection.Until | ForDirection.ParallelUntil, Some(NumericConstant(s, ssize)), Some(NumericConstant(e, _))) if s == e - 1 =>
|
||||||
val end = MfCompiler.nextLabel("of")
|
val end = MosCompiler.nextLabel("of")
|
||||||
compile(ctx.addLabels(names, Label(end), Label(end)), Assignment(vex, f.start) :: f.body) ++ labelChunk(end)
|
compile(ctx.addLabels(names, Label(end), Label(end)), Assignment(vex, f.start) :: f.body) ++ labelChunk(end)
|
||||||
case (ForDirection.Until | ForDirection.ParallelUntil, Some(NumericConstant(s, ssize)), Some(NumericConstant(e, _))) if s >= e =>
|
case (ForDirection.Until | ForDirection.ParallelUntil, Some(NumericConstant(s, ssize)), Some(NumericConstant(e, _))) if s >= e =>
|
||||||
Nil
|
Nil
|
||||||
|
|
||||||
case (ForDirection.To | ForDirection.ParallelTo, Some(NumericConstant(s, ssize)), Some(NumericConstant(e, _))) if s == e =>
|
case (ForDirection.To | ForDirection.ParallelTo, Some(NumericConstant(s, ssize)), Some(NumericConstant(e, _))) if s == e =>
|
||||||
val end = MfCompiler.nextLabel("of")
|
val end = MosCompiler.nextLabel("of")
|
||||||
compile(ctx.addLabels(names, Label(end), Label(end)), Assignment(vex, f.start) :: f.body) ++ labelChunk(end)
|
compile(ctx.addLabels(names, Label(end), Label(end)), Assignment(vex, f.start) :: f.body) ++ labelChunk(end)
|
||||||
case (ForDirection.To | ForDirection.ParallelTo, Some(NumericConstant(s, ssize)), Some(NumericConstant(e, _))) if s > e =>
|
case (ForDirection.To | ForDirection.ParallelTo, Some(NumericConstant(s, ssize)), Some(NumericConstant(e, _))) if s > e =>
|
||||||
Nil
|
Nil
|
||||||
@@ -413,7 +411,7 @@ object StatementCompiler {
|
|||||||
))
|
))
|
||||||
|
|
||||||
case (ForDirection.DownTo, Some(NumericConstant(s, ssize)), Some(NumericConstant(e, esize))) if s == e =>
|
case (ForDirection.DownTo, Some(NumericConstant(s, ssize)), Some(NumericConstant(e, esize))) if s == e =>
|
||||||
val end = MfCompiler.nextLabel("of")
|
val end = MosCompiler.nextLabel("of")
|
||||||
compile(ctx.addLabels(names, Label(end), Label(end)), Assignment(vex, LiteralExpression(s, ssize)) :: f.body) ++ labelChunk(end)
|
compile(ctx.addLabels(names, Label(end), Label(end)), Assignment(vex, LiteralExpression(s, ssize)) :: f.body) ++ labelChunk(end)
|
||||||
case (ForDirection.DownTo, Some(NumericConstant(s, ssize)), Some(NumericConstant(e, esize))) if s < e =>
|
case (ForDirection.DownTo, Some(NumericConstant(s, ssize)), Some(NumericConstant(e, esize))) if s < e =>
|
||||||
Nil
|
Nil
|
@@ -1,13 +1,12 @@
|
|||||||
package millfork.compiler
|
package millfork.compiler.mos
|
||||||
|
|
||||||
import millfork.CompilationFlag
|
import millfork.CompilationFlag
|
||||||
import millfork.assembly.AssemblyLine
|
import millfork.assembly.AddrMode._
|
||||||
|
import millfork.assembly.mos.Opcode._
|
||||||
|
import millfork.assembly.mos._
|
||||||
import millfork.env._
|
import millfork.env._
|
||||||
import millfork.error.ErrorReporting
|
import millfork.error.ErrorReporting
|
||||||
import millfork.node._
|
import millfork.node._
|
||||||
import millfork.assembly.Opcode
|
|
||||||
import millfork.assembly.Opcode._
|
|
||||||
import millfork.assembly.AddrMode._
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Karol Stasiak
|
* @author Karol Stasiak
|
||||||
@@ -21,12 +20,12 @@ object PseudoregisterBuiltIns {
|
|||||||
val (variablePart, constPart) = ctx.env.evalVariableAndConstantSubParts(SumExpression(params, decimal = false))
|
val (variablePart, constPart) = ctx.env.evalVariableAndConstantSubParts(SumExpression(params, decimal = false))
|
||||||
variablePart match {
|
variablePart match {
|
||||||
case None =>
|
case None =>
|
||||||
return ExpressionCompiler.compileConstant(ctx, constPart, RegisterVariable(Register.AX, w))
|
return MosExpressionCompiler.compileConstant(ctx, constPart, RegisterVariable(MosRegister.AX, w))
|
||||||
case Some(v) =>
|
case Some(v) =>
|
||||||
val typ = ExpressionCompiler.getExpressionType(ctx, v)
|
val typ = MosExpressionCompiler.getExpressionType(ctx, v)
|
||||||
if (typ.size == 1 && !typ.isSigned) {
|
if (typ.size == 1 && !typ.isSigned) {
|
||||||
val bytePart = ExpressionCompiler.compile(ctx, v, Some(b -> RegisterVariable(Register.A, b)), BranchSpec.None)
|
val bytePart = MosExpressionCompiler.compile(ctx, v, Some(b -> RegisterVariable(MosRegister.A, b)), BranchSpec.None)
|
||||||
val label = MfCompiler.nextLabel("ah")
|
val label = MosCompiler.nextLabel("ah")
|
||||||
return bytePart ++ List(
|
return bytePart ++ List(
|
||||||
AssemblyLine.implied(CLC),
|
AssemblyLine.implied(CLC),
|
||||||
AssemblyLine.immediate(ADC, constPart.loByte),
|
AssemblyLine.immediate(ADC, constPart.loByte),
|
||||||
@@ -47,7 +46,7 @@ object PseudoregisterBuiltIns {
|
|||||||
}
|
}
|
||||||
val reg = ctx.env.get[VariableInMemory]("__reg")
|
val reg = ctx.env.get[VariableInMemory]("__reg")
|
||||||
val head = params.head match {
|
val head = params.head match {
|
||||||
case (false, e) => ExpressionCompiler.compile(ctx, e, Some(ExpressionCompiler.getExpressionType(ctx, e) -> reg), BranchSpec.None)
|
case (false, e) => MosExpressionCompiler.compile(ctx, e, Some(MosExpressionCompiler.getExpressionType(ctx, e) -> reg), BranchSpec.None)
|
||||||
case (true, e) => ???
|
case (true, e) => ???
|
||||||
}
|
}
|
||||||
params.tail.foldLeft[List[AssemblyLine]](head){case (code, (sub, param)) => code ++ addToReg(ctx, param, sub, decimal)} ++ List(
|
params.tail.foldLeft[List[AssemblyLine]](head){case (code, (sub, param)) => code ++ addToReg(ctx, param, sub, decimal)} ++ List(
|
||||||
@@ -65,7 +64,7 @@ object PseudoregisterBuiltIns {
|
|||||||
val w = ctx.env.get[Type]("word")
|
val w = ctx.env.get[Type]("word")
|
||||||
val reg = ctx.env.get[VariableInMemory]("__reg")
|
val reg = ctx.env.get[VariableInMemory]("__reg")
|
||||||
// TODO: smarter on 65816
|
// TODO: smarter on 65816
|
||||||
val compileRight = ExpressionCompiler.compile(ctx, r, Some(ExpressionCompiler.getExpressionType(ctx, r) -> reg), BranchSpec.None)
|
val compileRight = MosExpressionCompiler.compile(ctx, r, Some(MosExpressionCompiler.getExpressionType(ctx, r) -> reg), BranchSpec.None)
|
||||||
val op = if (subtract) SBC else ADC
|
val op = if (subtract) SBC else ADC
|
||||||
val prepareCarry = AssemblyLine.implied(if (subtract) SEC else CLC)
|
val prepareCarry = AssemblyLine.implied(if (subtract) SEC else CLC)
|
||||||
compileRight match {
|
compileRight match {
|
||||||
@@ -118,7 +117,7 @@ object PseudoregisterBuiltIns {
|
|||||||
val b = ctx.env.get[Type]("byte")
|
val b = ctx.env.get[Type]("byte")
|
||||||
val w = ctx.env.get[Type]("word")
|
val w = ctx.env.get[Type]("word")
|
||||||
val reg = ctx.env.get[VariableInMemory]("__reg")
|
val reg = ctx.env.get[VariableInMemory]("__reg")
|
||||||
val head = ExpressionCompiler.compile(ctx, params.head, Some(ExpressionCompiler.getExpressionType(ctx, params.head) -> reg), BranchSpec.None)
|
val head = MosExpressionCompiler.compile(ctx, params.head, Some(MosExpressionCompiler.getExpressionType(ctx, params.head) -> reg), BranchSpec.None)
|
||||||
params.tail.foldLeft[List[AssemblyLine]](head){case (code, param) => code ++ bitOpReg(ctx, param, op)} ++ List(
|
params.tail.foldLeft[List[AssemblyLine]](head){case (code, param) => code ++ bitOpReg(ctx, param, op)} ++ List(
|
||||||
AssemblyLine.zeropage(LDA, reg),
|
AssemblyLine.zeropage(LDA, reg),
|
||||||
AssemblyLine.zeropage(LDX, reg, 1),
|
AssemblyLine.zeropage(LDX, reg, 1),
|
||||||
@@ -134,7 +133,7 @@ object PseudoregisterBuiltIns {
|
|||||||
val w = ctx.env.get[Type]("word")
|
val w = ctx.env.get[Type]("word")
|
||||||
val reg = ctx.env.get[VariableInMemory]("__reg")
|
val reg = ctx.env.get[VariableInMemory]("__reg")
|
||||||
// TODO: smarter on 65816
|
// TODO: smarter on 65816
|
||||||
val compileRight = ExpressionCompiler.compile(ctx, r, Some(ExpressionCompiler.getExpressionType(ctx, r) -> reg), BranchSpec.None)
|
val compileRight = MosExpressionCompiler.compile(ctx, r, Some(MosExpressionCompiler.getExpressionType(ctx, r) -> reg), BranchSpec.None)
|
||||||
compileRight match {
|
compileRight match {
|
||||||
case List(
|
case List(
|
||||||
AssemblyLine(LDA, Immediate, NumericConstant(0, _), _),
|
AssemblyLine(LDA, Immediate, NumericConstant(0, _), _),
|
||||||
@@ -187,7 +186,7 @@ object PseudoregisterBuiltIns {
|
|||||||
val b = ctx.env.get[Type]("byte")
|
val b = ctx.env.get[Type]("byte")
|
||||||
val w = ctx.env.get[Type]("word")
|
val w = ctx.env.get[Type]("word")
|
||||||
val reg = ctx.env.get[VariableInMemory]("__reg")
|
val reg = ctx.env.get[VariableInMemory]("__reg")
|
||||||
val firstParamCompiled = ExpressionCompiler.compile(ctx, l, Some(ExpressionCompiler.getExpressionType(ctx, l) -> reg), NoBranching)
|
val firstParamCompiled = MosExpressionCompiler.compile(ctx, l, Some(MosExpressionCompiler.getExpressionType(ctx, l) -> reg), NoBranching)
|
||||||
ctx.env.eval(r) match {
|
ctx.env.eval(r) match {
|
||||||
case Some(NumericConstant(0, _)) =>
|
case Some(NumericConstant(0, _)) =>
|
||||||
Nil
|
Nil
|
||||||
@@ -204,20 +203,20 @@ object PseudoregisterBuiltIns {
|
|||||||
firstParamCompiled ++ List.fill(v.toInt)(cycle).flatten ++ List(AssemblyLine.zeropage(LDA, reg), AssemblyLine.zeropage(LDX, reg, 1))
|
firstParamCompiled ++ List.fill(v.toInt)(cycle).flatten ++ List(AssemblyLine.zeropage(LDA, reg), AssemblyLine.zeropage(LDX, reg, 1))
|
||||||
}
|
}
|
||||||
case _ =>
|
case _ =>
|
||||||
val compileCounter = ExpressionCompiler.compile(ctx, r, Some(b -> RegisterVariable(Register.X, b)), NoBranching)
|
val compileCounter = MosExpressionCompiler.compile(ctx, r, Some(b -> RegisterVariable(MosRegister.X, b)), NoBranching)
|
||||||
val compileCounterAndPrepareFirstParam = compileCounter match {
|
val compileCounterAndPrepareFirstParam = compileCounter match {
|
||||||
case List(AssemblyLine(LDX, _, _, _)) => firstParamCompiled ++ compileCounter
|
case List(AssemblyLine(LDX, _, _, _)) => firstParamCompiled ++ compileCounter
|
||||||
case List(AssemblyLine(LDY, _, _, _), AssemblyLine(LDX, _, _, _)) => firstParamCompiled ++ compileCounter
|
case List(AssemblyLine(LDY, _, _, _), AssemblyLine(LDX, _, _, _)) => firstParamCompiled ++ compileCounter
|
||||||
case _ =>
|
case _ =>
|
||||||
ExpressionCompiler.compile(ctx, r, Some(b -> RegisterVariable(Register.A, b)), NoBranching) ++
|
MosExpressionCompiler.compile(ctx, r, Some(b -> RegisterVariable(MosRegister.A, b)), NoBranching) ++
|
||||||
List(AssemblyLine.implied(PHA)) ++
|
List(AssemblyLine.implied(PHA)) ++
|
||||||
firstParamCompiled ++ (
|
firstParamCompiled ++ (
|
||||||
if (ctx.options.flag(CompilationFlag.EmitCmosOpcodes)) List(AssemblyLine.implied(PLX))
|
if (ctx.options.flag(CompilationFlag.EmitCmosOpcodes)) List(AssemblyLine.implied(PLX))
|
||||||
else List(AssemblyLine.implied(PLA), AssemblyLine.implied(TAX))
|
else List(AssemblyLine.implied(PLA), AssemblyLine.implied(TAX))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val labelRepeat = MfCompiler.nextLabel("sr")
|
val labelRepeat = MosCompiler.nextLabel("sr")
|
||||||
val labelSkip = MfCompiler.nextLabel("ss")
|
val labelSkip = MosCompiler.nextLabel("ss")
|
||||||
if (ctx.options.flag(CompilationFlag.EmitNative65816Opcodes)) {
|
if (ctx.options.flag(CompilationFlag.EmitNative65816Opcodes)) {
|
||||||
compileCounterAndPrepareFirstParam ++ List(
|
compileCounterAndPrepareFirstParam ++ List(
|
||||||
AssemblyLine.relative(BEQ, labelSkip),
|
AssemblyLine.relative(BEQ, labelSkip),
|
||||||
@@ -255,8 +254,8 @@ object PseudoregisterBuiltIns {
|
|||||||
val reg = ctx.env.get[VariableInMemory]("__reg")
|
val reg = ctx.env.get[VariableInMemory]("__reg")
|
||||||
val load: List[AssemblyLine] = param1OrRegister match {
|
val load: List[AssemblyLine] = param1OrRegister match {
|
||||||
case Some(param1) =>
|
case Some(param1) =>
|
||||||
val code1 = ExpressionCompiler.compile(ctx, param1, Some(b -> RegisterVariable(Register.A, b)), BranchSpec.None)
|
val code1 = MosExpressionCompiler.compile(ctx, param1, Some(b -> RegisterVariable(MosRegister.A, b)), BranchSpec.None)
|
||||||
val code2 = ExpressionCompiler.compile(ctx, param2, Some(b -> RegisterVariable(Register.A, b)), BranchSpec.None)
|
val code2 = MosExpressionCompiler.compile(ctx, param2, Some(b -> RegisterVariable(MosRegister.A, b)), BranchSpec.None)
|
||||||
if (!usesRegLo(code2)) {
|
if (!usesRegLo(code2)) {
|
||||||
code1 ++ List(AssemblyLine.zeropage(STA, reg)) ++ code2 ++ List(AssemblyLine.zeropage(STA, reg, 1))
|
code1 ++ List(AssemblyLine.zeropage(STA, reg)) ++ code2 ++ List(AssemblyLine.zeropage(STA, reg, 1))
|
||||||
} else if (!usesRegLo(code1)) {
|
} else if (!usesRegLo(code1)) {
|
||||||
@@ -269,7 +268,7 @@ object PseudoregisterBuiltIns {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
case None =>
|
case None =>
|
||||||
val code2 = ExpressionCompiler.compile(ctx, param2, Some(b -> RegisterVariable(Register.A, b)), BranchSpec.None)
|
val code2 = MosExpressionCompiler.compile(ctx, param2, Some(b -> RegisterVariable(MosRegister.A, b)), BranchSpec.None)
|
||||||
if (!usesRegLo(code2)) {
|
if (!usesRegLo(code2)) {
|
||||||
List(AssemblyLine.zeropage(STA, reg)) ++ code2 ++ List(AssemblyLine.zeropage(STA, reg, 1))
|
List(AssemblyLine.zeropage(STA, reg)) ++ code2 ++ List(AssemblyLine.zeropage(STA, reg, 1))
|
||||||
} else if (!usesRegHi(code2)) {
|
} else if (!usesRegHi(code2)) {
|
@@ -1,7 +1,8 @@
|
|||||||
package millfork.compiler
|
package millfork.compiler.mos
|
||||||
|
|
||||||
import millfork.CompilationFlag
|
import millfork.CompilationFlag
|
||||||
import millfork.assembly.{AssemblyLine, OpcodeClasses}
|
import millfork.assembly.mos.Opcode._
|
||||||
|
import millfork.assembly.mos._
|
||||||
import millfork.env._
|
import millfork.env._
|
||||||
import millfork.error.ErrorReporting
|
import millfork.error.ErrorReporting
|
||||||
import millfork.node._
|
import millfork.node._
|
||||||
@@ -37,7 +38,7 @@ object ReturnDispatch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val indexerType = ExpressionCompiler.getExpressionType(ctx, stmt.indexer)
|
val indexerType = MosExpressionCompiler.getExpressionType(ctx, stmt.indexer)
|
||||||
if (indexerType.size != 1) {
|
if (indexerType.size != 1) {
|
||||||
ErrorReporting.error("Return dispatch index expression type has to be a byte", stmt.indexer.position)
|
ErrorReporting.error("Return dispatch index expression type has to be a byte", stmt.indexer.position)
|
||||||
}
|
}
|
||||||
@@ -120,7 +121,7 @@ object ReturnDispatch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (env.parent.isDefined) env = env.parent.get
|
while (env.parent.isDefined) env = env.parent.get
|
||||||
val label = MfCompiler.nextLabel("di")
|
val label = MosCompiler.nextLabel("di")
|
||||||
val paramArrays = stmt.params.indices.map { ix =>
|
val paramArrays = stmt.params.indices.map { ix =>
|
||||||
val a = InitializedArray(label + "$" + ix + ".array", None, (paramMins(ix) to paramMaxes(ix)).map { key =>
|
val a = InitializedArray(label + "$" + ix + ".array", None, (paramMins(ix) to paramMaxes(ix)).map { key =>
|
||||||
map(key)._2.lift(ix).getOrElse(LiteralExpression(0, 1))
|
map(key)._2.lift(ix).getOrElse(LiteralExpression(0, 1))
|
||||||
@@ -134,11 +135,11 @@ object ReturnDispatch {
|
|||||||
val b = ctx.env.get[Type]("byte")
|
val b = ctx.env.get[Type]("byte")
|
||||||
|
|
||||||
import millfork.assembly.AddrMode._
|
import millfork.assembly.AddrMode._
|
||||||
import millfork.assembly.Opcode._
|
import millfork.assembly.mos.Opcode._
|
||||||
|
|
||||||
val ctxForStoringParams = ctx.neverCheckArrayBounds
|
val ctxForStoringParams = ctx.neverCheckArrayBounds
|
||||||
val copyParams = stmt.params.zipWithIndex.flatMap { case (paramVar, paramIndex) =>
|
val copyParams = stmt.params.zipWithIndex.flatMap { case (paramVar, paramIndex) =>
|
||||||
val storeParam = ExpressionCompiler.compileByteStorage(ctxForStoringParams, Register.A, paramVar)
|
val storeParam = MosExpressionCompiler.compileByteStorage(ctxForStoringParams, MosRegister.A, paramVar)
|
||||||
if (storeParam.exists(l => OpcodeClasses.ChangesX(l.opcode)))
|
if (storeParam.exists(l => OpcodeClasses.ChangesX(l.opcode)))
|
||||||
ErrorReporting.error("Invalid/too complex target parameter variable", paramVar.position)
|
ErrorReporting.error("Invalid/too complex target parameter variable", paramVar.position)
|
||||||
AssemblyLine.absoluteX(LDA, paramArrays(paramIndex), -paramMins(paramIndex)) :: storeParam
|
AssemblyLine.absoluteX(LDA, paramArrays(paramIndex), -paramMins(paramIndex)) :: storeParam
|
||||||
@@ -148,10 +149,10 @@ object ReturnDispatch {
|
|||||||
val jumpTable = InitializedArray(label + "$jt.array", None, (actualMin to actualMax).flatMap(i => List(lobyte0(map(i)._1), hibyte0(map(i)._1))).toList, ctx.function.declaredBank)
|
val jumpTable = InitializedArray(label + "$jt.array", None, (actualMin to actualMax).flatMap(i => List(lobyte0(map(i)._1), hibyte0(map(i)._1))).toList, ctx.function.declaredBank)
|
||||||
env.registerUnnamedArray(jumpTable)
|
env.registerUnnamedArray(jumpTable)
|
||||||
if (copyParams.isEmpty) {
|
if (copyParams.isEmpty) {
|
||||||
val loadIndex = ExpressionCompiler.compile(ctx, stmt.indexer, Some(b -> RegisterVariable(Register.A, b)), BranchSpec.None)
|
val loadIndex = MosExpressionCompiler.compile(ctx, stmt.indexer, Some(b -> RegisterVariable(MosRegister.A, b)), BranchSpec.None)
|
||||||
loadIndex ++ List(AssemblyLine.implied(ASL), AssemblyLine.implied(TAX)) ++ copyParams :+ AssemblyLine(JMP, AbsoluteIndexedX, jumpTable.toAddress - actualMin * 2)
|
loadIndex ++ List(AssemblyLine.implied(ASL), AssemblyLine.implied(TAX)) ++ copyParams :+ AssemblyLine(JMP, AbsoluteIndexedX, jumpTable.toAddress - actualMin * 2)
|
||||||
} else {
|
} else {
|
||||||
val loadIndex = ExpressionCompiler.compile(ctx, stmt.indexer, Some(b -> RegisterVariable(Register.X, b)), BranchSpec.None)
|
val loadIndex = MosExpressionCompiler.compile(ctx, stmt.indexer, Some(b -> RegisterVariable(MosRegister.X, b)), BranchSpec.None)
|
||||||
loadIndex ++ copyParams ++ List(
|
loadIndex ++ copyParams ++ List(
|
||||||
AssemblyLine.implied(TXA),
|
AssemblyLine.implied(TXA),
|
||||||
AssemblyLine.implied(ASL),
|
AssemblyLine.implied(ASL),
|
||||||
@@ -159,7 +160,7 @@ object ReturnDispatch {
|
|||||||
AssemblyLine(JMP, AbsoluteIndexedX, jumpTable.toAddress - actualMin * 2))
|
AssemblyLine(JMP, AbsoluteIndexedX, jumpTable.toAddress - actualMin * 2))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val loadIndex = ExpressionCompiler.compile(ctx, stmt.indexer, Some(b -> RegisterVariable(Register.X, b)), BranchSpec.None)
|
val loadIndex = MosExpressionCompiler.compile(ctx, stmt.indexer, Some(b -> RegisterVariable(MosRegister.X, b)), BranchSpec.None)
|
||||||
val jumpTableLo = InitializedArray(label + "$jl.array", None, (actualMin to actualMax).map(i => lobyte1(map(i)._1)).toList, ctx.function.declaredBank)
|
val jumpTableLo = InitializedArray(label + "$jl.array", None, (actualMin to actualMax).map(i => lobyte1(map(i)._1)).toList, ctx.function.declaredBank)
|
||||||
val jumpTableHi = InitializedArray(label + "$jh.array", None, (actualMin to actualMax).map(i => hibyte1(map(i)._1)).toList, ctx.function.declaredBank)
|
val jumpTableHi = InitializedArray(label + "$jh.array", None, (actualMin to actualMax).map(i => hibyte1(map(i)._1)).toList, ctx.function.declaredBank)
|
||||||
env.registerUnnamedArray(jumpTableLo)
|
env.registerUnnamedArray(jumpTableLo)
|
@@ -3,11 +3,10 @@ package millfork.env
|
|||||||
import java.util.concurrent.atomic.AtomicLong
|
import java.util.concurrent.atomic.AtomicLong
|
||||||
|
|
||||||
import millfork.{CompilationFlag, CompilationOptions}
|
import millfork.{CompilationFlag, CompilationOptions}
|
||||||
import millfork.assembly.{Opcode, OpcodeClasses}
|
import millfork.assembly.mos.Opcode
|
||||||
import millfork.compiler._
|
|
||||||
import millfork.error.ErrorReporting
|
import millfork.error.ErrorReporting
|
||||||
import millfork.node._
|
import millfork.node._
|
||||||
import millfork.output.{CompiledMemory, MemoryBank, VariableAllocator}
|
import millfork.output.{CompiledMemory, VariableAllocator}
|
||||||
|
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
|
|
||||||
@@ -576,7 +575,7 @@ class Environment(val parent: Option[Environment], val prefix: String) {
|
|||||||
resultType,
|
resultType,
|
||||||
params,
|
params,
|
||||||
env,
|
env,
|
||||||
executableStatements ++ (if (needsExtraRTS) List(AssemblyStatement.implied(Opcode.RTS, elidable = true)) else Nil)
|
executableStatements ++ (if (needsExtraRTS) List(MosAssemblyStatement.implied(Opcode.RTS, elidable = true)) else Nil)
|
||||||
)
|
)
|
||||||
addThing(mangled, stmt.position)
|
addThing(mangled, stmt.position)
|
||||||
} else {
|
} else {
|
||||||
@@ -1011,7 +1010,7 @@ class Environment(val parent: Option[Environment], val prefix: String) {
|
|||||||
def nameCheck(nodes: List[_ <:Node]): Unit = nodes.foreach(nameCheck)
|
def nameCheck(nodes: List[_ <:Node]): Unit = nodes.foreach(nameCheck)
|
||||||
|
|
||||||
def nameCheck(node: Node): Unit = node match {
|
def nameCheck(node: Node): Unit = node match {
|
||||||
case _:AssemblyStatement => ()
|
case _:MosAssemblyStatement => ()
|
||||||
case _:DeclarationStatement => ()
|
case _:DeclarationStatement => ()
|
||||||
case s:ForStatement =>
|
case s:ForStatement =>
|
||||||
checkName[Variable]("Variable", s.variable, s.position)
|
checkName[Variable]("Variable", s.variable, s.position)
|
||||||
|
6
src/main/scala/millfork/env/Thing.scala
vendored
6
src/main/scala/millfork/env/Thing.scala
vendored
@@ -1,7 +1,7 @@
|
|||||||
package millfork.env
|
package millfork.env
|
||||||
|
|
||||||
import millfork.{CompilationFlag, CompilationOptions}
|
import millfork.{CompilationFlag, CompilationOptions}
|
||||||
import millfork.assembly.Opcode
|
import millfork.assembly.mos.Opcode
|
||||||
import millfork.node._
|
import millfork.node._
|
||||||
|
|
||||||
sealed trait Thing {
|
sealed trait Thing {
|
||||||
@@ -122,7 +122,7 @@ sealed trait VariableInMemory extends Variable with ThingInMemory with Indexable
|
|||||||
declaredBank.getOrElse("default")
|
declaredBank.getOrElse("default")
|
||||||
}
|
}
|
||||||
|
|
||||||
case class RegisterVariable(register: Register.Value, typ: Type) extends Variable {
|
case class RegisterVariable(register: MosRegister.Value, typ: Type) extends Variable {
|
||||||
def name: String = register.toString
|
def name: String = register.toString
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,7 +294,7 @@ sealed trait ParamPassingConvention {
|
|||||||
def inNonInlinedOnly: Boolean
|
def inNonInlinedOnly: Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
case class ByRegister(register: Register.Value) extends ParamPassingConvention {
|
case class ByRegister(register: MosRegister.Value) extends ParamPassingConvention {
|
||||||
override def inInlinedOnly = false
|
override def inInlinedOnly = false
|
||||||
|
|
||||||
override def inNonInlinedOnly = false
|
override def inNonInlinedOnly = false
|
||||||
|
@@ -1,7 +1,8 @@
|
|||||||
package millfork.node
|
package millfork.node
|
||||||
|
|
||||||
import millfork.assembly.{AddrMode, Opcode}
|
import millfork.assembly.AddrMode
|
||||||
import millfork.env.{Constant, Label, ParamPassingConvention}
|
import millfork.assembly.mos.Opcode
|
||||||
|
import millfork.env.{Constant, ParamPassingConvention}
|
||||||
|
|
||||||
case class Position(filename: String, line: Int, column: Int, cursor: Int)
|
case class Position(filename: String, line: Int, column: Int, cursor: Int)
|
||||||
|
|
||||||
@@ -64,7 +65,7 @@ case class HalfWordExpression(expression: Expression, hiByte: Boolean) extends E
|
|||||||
HalfWordExpression(expression.replaceVariable(variable, actualParam), hiByte)
|
HalfWordExpression(expression.replaceVariable(variable, actualParam), hiByte)
|
||||||
}
|
}
|
||||||
|
|
||||||
object Register extends Enumeration {
|
object MosRegister extends Enumeration {
|
||||||
val A, X, Y, AX, AY, YA, XA, XY, YX, AW = Value
|
val A, X, Y, AX, AY, YA, XA, XY, YX, AW = Value
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,7 +212,7 @@ case class Assignment(destination: LhsExpression, source: Expression) extends Ex
|
|||||||
override def getAllExpressions: List[Expression] = List(destination, source)
|
override def getAllExpressions: List[Expression] = List(destination, source)
|
||||||
}
|
}
|
||||||
|
|
||||||
case class AssemblyStatement(opcode: Opcode.Value, addrMode: AddrMode.Value, expression: Expression, elidable: Boolean) extends ExecutableStatement {
|
case class MosAssemblyStatement(opcode: Opcode.Value, addrMode: AddrMode.Value, expression: Expression, elidable: Boolean) extends ExecutableStatement {
|
||||||
override def getAllExpressions: List[Expression] = List(expression)
|
override def getAllExpressions: List[Expression] = List(expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,8 +252,8 @@ case class ContinueStatement(label: String) extends ExecutableStatement {
|
|||||||
override def getAllExpressions: List[Expression] = Nil
|
override def getAllExpressions: List[Expression] = Nil
|
||||||
}
|
}
|
||||||
|
|
||||||
object AssemblyStatement {
|
object MosAssemblyStatement {
|
||||||
def implied(opcode: Opcode.Value, elidable: Boolean) = AssemblyStatement(opcode, AddrMode.Implied, LiteralExpression(0, 1), elidable)
|
def implied(opcode: Opcode.Value, elidable: Boolean) = MosAssemblyStatement(opcode, AddrMode.Implied, LiteralExpression(0, 1), elidable)
|
||||||
|
|
||||||
def nonexistent(opcode: Opcode.Value) = AssemblyStatement(opcode, AddrMode.DoesNotExist, LiteralExpression(0, 1), elidable = true)
|
def nonexistent(opcode: Opcode.Value) = MosAssemblyStatement(opcode, AddrMode.DoesNotExist, LiteralExpression(0, 1), elidable = true)
|
||||||
}
|
}
|
@@ -1,7 +1,6 @@
|
|||||||
package millfork.node.opt
|
package millfork.node.opt
|
||||||
|
|
||||||
import millfork.CompilationOptions
|
import millfork.CompilationOptions
|
||||||
import millfork.assembly.AssemblyLine
|
|
||||||
import millfork.env._
|
import millfork.env._
|
||||||
import millfork.error.ErrorReporting
|
import millfork.error.ErrorReporting
|
||||||
import millfork.node._
|
import millfork.node._
|
||||||
|
@@ -1,12 +1,12 @@
|
|||||||
package millfork.output
|
package millfork.output
|
||||||
|
|
||||||
import millfork.assembly.opt.{AssemblyOptimization, HudsonOptimizations, JumpFixing, JumpShortening}
|
import millfork.assembly._
|
||||||
import millfork.assembly.{AddrMode, AssemblyLine, Opcode}
|
import millfork.compiler.AbstractCompiler
|
||||||
import millfork.compiler.{CompilationContext, MfCompiler}
|
|
||||||
import millfork.env._
|
import millfork.env._
|
||||||
import millfork.error.ErrorReporting
|
import millfork.error.ErrorReporting
|
||||||
import millfork.node.{CallGraph, Program}
|
import millfork.node.{CallGraph, Program}
|
||||||
import millfork._
|
import millfork._
|
||||||
|
import millfork.compiler.mos.CompilationContext
|
||||||
|
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
|
|
||||||
@@ -16,7 +16,11 @@ import scala.collection.mutable
|
|||||||
|
|
||||||
case class AssemblerOutput(code: Map[String, Array[Byte]], asm: Array[String], labels: List[(String, Int)])
|
case class AssemblerOutput(code: Map[String, Array[Byte]], asm: Array[String], labels: List[(String, Int)])
|
||||||
|
|
||||||
class Assembler(private val program: Program, private val rootEnv: Environment, private val platform: Platform) {
|
abstract class AbstractAssembler[T <: AbstractCode](private val program: Program,
|
||||||
|
private val rootEnv: Environment,
|
||||||
|
private val platform: Platform,
|
||||||
|
private val inliningCalculator: AbstractInliningCalculator[T],
|
||||||
|
private val compiler: AbstractCompiler[T]) {
|
||||||
|
|
||||||
private var env = rootEnv.allThings
|
private var env = rootEnv.allThings
|
||||||
var unoptimizedCodeSize: Int = 0
|
var unoptimizedCodeSize: Int = 0
|
||||||
@@ -165,12 +169,12 @@ class Assembler(private val program: Program, private val rootEnv: Environment,
|
|||||||
private def asDecimal(a: Long, b: Long, f: (Long, Long) => Long): Long =
|
private def asDecimal(a: Long, b: Long, f: (Long, Long) => Long): Long =
|
||||||
storeDecimalValueInNormalRespresentation(f(parseNormalToDecimalValue(a), parseNormalToDecimalValue(b)))
|
storeDecimalValueInNormalRespresentation(f(parseNormalToDecimalValue(a), parseNormalToDecimalValue(b)))
|
||||||
|
|
||||||
def assemble(callGraph: CallGraph, optimizations: Seq[AssemblyOptimization], options: CompilationOptions): AssemblerOutput = {
|
def assemble(callGraph: CallGraph, optimizations: Seq[AssemblyOptimization[T]], options: CompilationOptions): AssemblerOutput = {
|
||||||
val platform = options.platform
|
val platform = options.platform
|
||||||
|
|
||||||
val assembly = mutable.ArrayBuffer[String]()
|
val assembly = mutable.ArrayBuffer[String]()
|
||||||
|
|
||||||
val inliningResult = InliningCalculator.calculate(
|
val inliningResult = MosInliningCalculator.calculate(
|
||||||
program,
|
program,
|
||||||
options.flags(CompilationFlag.InlineFunctions) || options.flags(CompilationFlag.OptimizeForSonicSpeed),
|
options.flags(CompilationFlag.InlineFunctions) || options.flags(CompilationFlag.OptimizeForSonicSpeed),
|
||||||
if (options.flags(CompilationFlag.OptimizeForSonicSpeed)) 4.0
|
if (options.flags(CompilationFlag.OptimizeForSonicSpeed)) 4.0
|
||||||
@@ -183,8 +187,8 @@ class Assembler(private val program: Program, private val rootEnv: Environment,
|
|||||||
val potentiallyInlineable: Map[String, Int] = inliningResult.potentiallyInlineableFunctions
|
val potentiallyInlineable: Map[String, Int] = inliningResult.potentiallyInlineableFunctions
|
||||||
var nonInlineableFunctions: Set[String] = inliningResult.nonInlineableFunctions
|
var nonInlineableFunctions: Set[String] = inliningResult.nonInlineableFunctions
|
||||||
|
|
||||||
var inlinedFunctions = Map[String, List[AssemblyLine]]()
|
var inlinedFunctions = Map[String, List[T]]()
|
||||||
val compiledFunctions = mutable.Map[String, List[AssemblyLine]]()
|
val compiledFunctions = mutable.Map[String, List[T]]()
|
||||||
val recommendedCompilationOrder = callGraph.recommendedCompilationOrder
|
val recommendedCompilationOrder = callGraph.recommendedCompilationOrder
|
||||||
recommendedCompilationOrder.foreach { f =>
|
recommendedCompilationOrder.foreach { f =>
|
||||||
env.maybeGet[NormalFunction](f).foreach { function =>
|
env.maybeGet[NormalFunction](f).foreach { function =>
|
||||||
@@ -192,7 +196,7 @@ class Assembler(private val program: Program, private val rootEnv: Environment,
|
|||||||
val strippedCodeForInlining = for {
|
val strippedCodeForInlining = for {
|
||||||
limit <- potentiallyInlineable.get(f)
|
limit <- potentiallyInlineable.get(f)
|
||||||
if code.map(_.sizeInBytes).sum <= limit
|
if code.map(_.sizeInBytes).sum <= limit
|
||||||
s <- InliningCalculator.codeForInlining(f, nonInlineableFunctions, code)
|
s <- inliningCalculator.codeForInlining(f, nonInlineableFunctions, code)
|
||||||
} yield s
|
} yield s
|
||||||
strippedCodeForInlining match {
|
strippedCodeForInlining match {
|
||||||
case Some(c) =>
|
case Some(c) =>
|
||||||
@@ -418,562 +422,33 @@ class Assembler(private val program: Program, private val rootEnv: Environment,
|
|||||||
AssemblerOutput(code, assembly.toArray, labelMap.toList)
|
AssemblerOutput(code, assembly.toArray, labelMap.toList)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def compileFunction(f: NormalFunction, optimizations: Seq[AssemblyOptimization], options: CompilationOptions, inlinedFunctions: Map[String, List[AssemblyLine]]): List[AssemblyLine] = {
|
private def compileFunction(f: NormalFunction, optimizations: Seq[AssemblyOptimization[T]], options: CompilationOptions, inlinedFunctions: Map[String, List[T]]): List[T] = {
|
||||||
ErrorReporting.debug("Compiling: " + f.name, f.position)
|
ErrorReporting.debug("Compiling: " + f.name, f.position)
|
||||||
val unoptimized =
|
val unoptimized: List[T] =
|
||||||
MfCompiler.compile(CompilationContext(env = f.environment, function = f, extraStackOffset = 0, options = options)).flatMap {
|
inliningCalculator.inline(
|
||||||
case AssemblyLine(Opcode.JSR, AddrMode.Absolute | AddrMode.LongAbsolute, p, true) if inlinedFunctions.contains(p.toString) =>
|
compiler.compile(CompilationContext(env = f.environment, function = f, extraStackOffset = 0, options = options)),
|
||||||
val labelPrefix = MfCompiler.nextLabel("ai")
|
inlinedFunctions,
|
||||||
inlinedFunctions(p.toString).map{
|
compiler)
|
||||||
case line@AssemblyLine(_, _, MemoryAddressConstant(Label(label)), _) =>
|
|
||||||
val newLabel = MemoryAddressConstant(Label(labelPrefix + label))
|
|
||||||
line.copy(parameter = newLabel)
|
|
||||||
case l => l
|
|
||||||
}
|
|
||||||
case AssemblyLine(Opcode.JMP, AddrMode.Absolute, p, true) if inlinedFunctions.contains(p.toString) =>
|
|
||||||
val labelPrefix = MfCompiler.nextLabel("ai")
|
|
||||||
inlinedFunctions(p.toString).map{
|
|
||||||
case line@AssemblyLine(_, _, MemoryAddressConstant(Label(label)), _) =>
|
|
||||||
val newLabel = MemoryAddressConstant(Label(labelPrefix + label))
|
|
||||||
line.copy(parameter = newLabel)
|
|
||||||
case l => l
|
|
||||||
} :+ AssemblyLine.implied(Opcode.RTS)
|
|
||||||
case x => List(x)
|
|
||||||
}
|
|
||||||
unoptimizedCodeSize += unoptimized.map(_.sizeInBytes).sum
|
unoptimizedCodeSize += unoptimized.map(_.sizeInBytes).sum
|
||||||
val code = optimizations.foldLeft(unoptimized) { (c, opt) =>
|
val code = optimizations.foldLeft(unoptimized) { (c, opt) =>
|
||||||
opt.optimize(f, c, options)
|
opt.optimize(f, c, options)
|
||||||
}
|
}
|
||||||
if (optimizations.nonEmpty) {
|
performFinalOptimizationPass(f, optimizations.nonEmpty, options, code)
|
||||||
val finalCode = if (options.flag(CompilationFlag.EmitHudsonOpcodes)) HudsonOptimizations.removeLoadZero(code) else code
|
|
||||||
JumpShortening(f, JumpShortening(f, JumpFixing(f, finalCode, options), options), options)
|
|
||||||
}
|
|
||||||
else JumpFixing(f, code, options)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private def outputFunction(bank: String, code: List[AssemblyLine], startFrom: Int, assOut: mutable.ArrayBuffer[String], options: CompilationOptions): Int = {
|
def performFinalOptimizationPass(f: NormalFunction, actuallyOptimize: Boolean, options: CompilationOptions, code: List[T]): List[T]
|
||||||
|
|
||||||
|
private def outputFunction(bank: String, code: List[T], startFrom: Int, assOut: mutable.ArrayBuffer[String], options: CompilationOptions): Int = {
|
||||||
var index = startFrom
|
var index = startFrom
|
||||||
assOut.append("* = $" + startFrom.toHexString)
|
assOut.append("* = $" + startFrom.toHexString)
|
||||||
import millfork.assembly.AddrMode._
|
|
||||||
import millfork.assembly.Opcode._
|
|
||||||
for (instr <- code) {
|
for (instr <- code) {
|
||||||
if (instr.isPrintable) {
|
if (instr.isPrintable) {
|
||||||
assOut.append(instr.toString)
|
assOut.append(instr.toString)
|
||||||
}
|
}
|
||||||
instr match {
|
index = emitInstruction(bank, options, index, instr)
|
||||||
case AssemblyLine(BYTE, RawByte, c, _) =>
|
|
||||||
writeByte(bank, index, c)
|
|
||||||
index += 1
|
|
||||||
case AssemblyLine(BYTE, _, _, _) => ???
|
|
||||||
case AssemblyLine(_, RawByte, _, _) => ???
|
|
||||||
case AssemblyLine(LABEL, _, MemoryAddressConstant(Label(labelName)), _) =>
|
|
||||||
labelMap(labelName) = index
|
|
||||||
case AssemblyLine(_, DoesNotExist, _, _) =>
|
|
||||||
()
|
|
||||||
case AssemblyLine(op, Implied, _, _) =>
|
|
||||||
writeByte(bank, index, Assembler.opcodeFor(op, Implied, options))
|
|
||||||
index += 1
|
|
||||||
case AssemblyLine(op, Relative, param, _) =>
|
|
||||||
writeByte(bank, index, Assembler.opcodeFor(op, Relative, options))
|
|
||||||
writeByte(bank, index + 1, AssertByte(param - (index + 2)))
|
|
||||||
index += 2
|
|
||||||
case AssemblyLine(op, am@(Immediate | ZeroPage | ZeroPageX | ZeroPageY | IndexedY | IndexedX | IndexedZ | LongIndexedY | LongIndexedZ | Stack), param, _) =>
|
|
||||||
writeByte(bank, index, Assembler.opcodeFor(op, am, options))
|
|
||||||
writeByte(bank, index + 1, param)
|
|
||||||
index += 2
|
|
||||||
case AssemblyLine(op, am@(WordImmediate | Absolute | AbsoluteY | AbsoluteX | Indirect | AbsoluteIndexedX), param, _) =>
|
|
||||||
writeByte(bank, index, Assembler.opcodeFor(op, am, options))
|
|
||||||
writeWord(bank, index + 1, param)
|
|
||||||
index += 3
|
|
||||||
case AssemblyLine(op, am@(LongAbsolute | LongAbsoluteX | LongIndirect), param, _) =>
|
|
||||||
writeByte(bank, index, Assembler.opcodeFor(op, am, options))
|
|
||||||
writeWord(bank, index + 1, param)
|
|
||||||
writeByte(bank, index + 3, extractBank(param, options))
|
|
||||||
index += 4
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
index
|
index
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
object Assembler {
|
def emitInstruction(bank: String, options: CompilationOptions, index: Int, instr: T): Int
|
||||||
val opcodes = mutable.Map[(Opcode.Value, AddrMode.Value), Byte]()
|
}
|
||||||
val illegalOpcodes = mutable.Map[(Opcode.Value, AddrMode.Value), Byte]()
|
|
||||||
val cmosOpcodes = mutable.Map[(Opcode.Value, AddrMode.Value), Byte]()
|
|
||||||
val cmosNopOpcodes = mutable.Map[(Opcode.Value, AddrMode.Value), Byte]()
|
|
||||||
val ce02Opcodes = mutable.Map[(Opcode.Value, AddrMode.Value), Byte]()
|
|
||||||
val hudsonOpcodes = mutable.Map[(Opcode.Value, AddrMode.Value), Byte]()
|
|
||||||
val emulation65816Opcodes = mutable.Map[(Opcode.Value, AddrMode.Value), Byte]()
|
|
||||||
val native65816Opcodes = mutable.Map[(Opcode.Value, AddrMode.Value), Byte]()
|
|
||||||
|
|
||||||
def opcodeFor(opcode: Opcode.Value, addrMode: AddrMode.Value, options: CompilationOptions): Byte = {
|
|
||||||
val key = opcode -> addrMode
|
|
||||||
opcodes.get(key).foreach(return _)
|
|
||||||
if (options.flag(CompilationFlag.EmitIllegals)) illegalOpcodes.get(key).foreach(return _)
|
|
||||||
if (options.flag(CompilationFlag.EmitCmosOpcodes)) cmosOpcodes.get(key).foreach(return _)
|
|
||||||
if (options.flag(CompilationFlag.EmitCmosNopOpcodes)) cmosNopOpcodes.get(key).foreach(return _)
|
|
||||||
if (options.flag(CompilationFlag.Emit65CE02Opcodes)) ce02Opcodes.get(key).foreach(return _)
|
|
||||||
if (options.flag(CompilationFlag.EmitHudsonOpcodes)) hudsonOpcodes.get(key).foreach(return _)
|
|
||||||
if (options.flag(CompilationFlag.EmitEmulation65816Opcodes)) emulation65816Opcodes.get(key).foreach(return _)
|
|
||||||
if (options.flag(CompilationFlag.EmitNative65816Opcodes)) native65816Opcodes.get(key).foreach(return _)
|
|
||||||
ErrorReporting.fatal("Cannot assemble an unknown opcode " + key)
|
|
||||||
}
|
|
||||||
|
|
||||||
private def op(op: Opcode.Value, am: AddrMode.Value, x: Int): Unit = {
|
|
||||||
if (x < 0 || x > 0xff) ErrorReporting.fatal("Invalid code for" + (op -> am))
|
|
||||||
opcodes(op -> am) = x.toByte
|
|
||||||
if (am == AddrMode.Relative) opcodes(op -> AddrMode.Immediate) = x.toByte
|
|
||||||
}
|
|
||||||
|
|
||||||
private def cm(op: Opcode.Value, am: AddrMode.Value, x: Int): Unit = {
|
|
||||||
if (x < 0 || x > 0xff) ErrorReporting.fatal("Invalid code for" + (op -> am))
|
|
||||||
cmosOpcodes(op -> am) = x.toByte
|
|
||||||
}
|
|
||||||
|
|
||||||
private def cn(op: Opcode.Value, am: AddrMode.Value, x: Int): Unit = {
|
|
||||||
if (x < 0 || x > 0xff) ErrorReporting.fatal("Invalid code for" + (op -> am))
|
|
||||||
cmosNopOpcodes(op -> am) = x.toByte
|
|
||||||
}
|
|
||||||
|
|
||||||
private def il(op: Opcode.Value, am: AddrMode.Value, x: Int): Unit = {
|
|
||||||
if (x < 0 || x > 0xff) ErrorReporting.fatal("Invalid code for" + (op -> am))
|
|
||||||
illegalOpcodes(op -> am) = x.toByte
|
|
||||||
}
|
|
||||||
|
|
||||||
private def hu(op: Opcode.Value, am: AddrMode.Value, x: Int): Unit = {
|
|
||||||
if (x < 0 || x > 0xff) ErrorReporting.fatal("Invalid code for" + (op -> am))
|
|
||||||
hudsonOpcodes(op -> am) = x.toByte
|
|
||||||
}
|
|
||||||
|
|
||||||
private def ce(op: Opcode.Value, am: AddrMode.Value, x: Int): Unit = {
|
|
||||||
if (x < 0 || x > 0xff) ErrorReporting.fatal("Invalid code for" + (op -> am))
|
|
||||||
ce02Opcodes(op -> am) = x.toByte
|
|
||||||
}
|
|
||||||
|
|
||||||
private def em(op: Opcode.Value, am: AddrMode.Value, x: Int): Unit = {
|
|
||||||
if (x < 0 || x > 0xff) ErrorReporting.fatal("Invalid code for" + (op -> am))
|
|
||||||
emulation65816Opcodes(op -> am) = x.toByte
|
|
||||||
}
|
|
||||||
|
|
||||||
private def na(op: Opcode.Value, am: AddrMode.Value, x: Int): Unit = {
|
|
||||||
if (x < 0 || x > 0xff) ErrorReporting.fatal("Invalid code for" + (op -> am))
|
|
||||||
native65816Opcodes(op -> am) = x.toByte
|
|
||||||
}
|
|
||||||
|
|
||||||
def getStandardLegalOpcodes: Set[Int] = opcodes.values.map(_ & 0xff).toSet
|
|
||||||
|
|
||||||
import AddrMode._
|
|
||||||
import Opcode._
|
|
||||||
|
|
||||||
op(ADC, Immediate, 0x69)
|
|
||||||
op(ADC, ZeroPage, 0x65)
|
|
||||||
op(ADC, ZeroPageX, 0x75)
|
|
||||||
op(ADC, Absolute, 0x6D)
|
|
||||||
op(ADC, AbsoluteX, 0x7D)
|
|
||||||
op(ADC, AbsoluteY, 0x79)
|
|
||||||
op(ADC, IndexedX, 0x61)
|
|
||||||
op(ADC, IndexedY, 0x71)
|
|
||||||
|
|
||||||
op(AND, Immediate, 0x29)
|
|
||||||
op(AND, ZeroPage, 0x25)
|
|
||||||
op(AND, ZeroPageX, 0x35)
|
|
||||||
op(AND, Absolute, 0x2D)
|
|
||||||
op(AND, AbsoluteX, 0x3D)
|
|
||||||
op(AND, AbsoluteY, 0x39)
|
|
||||||
op(AND, IndexedX, 0x21)
|
|
||||||
op(AND, IndexedY, 0x31)
|
|
||||||
|
|
||||||
op(ASL, Implied, 0x0A)
|
|
||||||
op(ASL, ZeroPage, 0x06)
|
|
||||||
op(ASL, ZeroPageX, 0x16)
|
|
||||||
op(ASL, Absolute, 0x0E)
|
|
||||||
op(ASL, AbsoluteX, 0x1E)
|
|
||||||
|
|
||||||
op(BIT, ZeroPage, 0x24)
|
|
||||||
op(BIT, Absolute, 0x2C)
|
|
||||||
|
|
||||||
op(BPL, Relative, 0x10)
|
|
||||||
op(BMI, Relative, 0x30)
|
|
||||||
op(BVC, Relative, 0x50)
|
|
||||||
op(BVS, Relative, 0x70)
|
|
||||||
op(BCC, Relative, 0x90)
|
|
||||||
op(BCS, Relative, 0xB0)
|
|
||||||
op(BNE, Relative, 0xD0)
|
|
||||||
op(BEQ, Relative, 0xF0)
|
|
||||||
|
|
||||||
op(BRK, Implied, 0)
|
|
||||||
|
|
||||||
op(CMP, Immediate, 0xC9)
|
|
||||||
op(CMP, ZeroPage, 0xC5)
|
|
||||||
op(CMP, ZeroPageX, 0xD5)
|
|
||||||
op(CMP, Absolute, 0xCD)
|
|
||||||
op(CMP, AbsoluteX, 0xDD)
|
|
||||||
op(CMP, AbsoluteY, 0xD9)
|
|
||||||
op(CMP, IndexedX, 0xC1)
|
|
||||||
op(CMP, IndexedY, 0xD1)
|
|
||||||
|
|
||||||
op(CPX, Immediate, 0xE0)
|
|
||||||
op(CPX, ZeroPage, 0xE4)
|
|
||||||
op(CPX, Absolute, 0xEC)
|
|
||||||
|
|
||||||
op(CPY, Immediate, 0xC0)
|
|
||||||
op(CPY, ZeroPage, 0xC4)
|
|
||||||
op(CPY, Absolute, 0xCC)
|
|
||||||
|
|
||||||
op(DEC, ZeroPage, 0xC6)
|
|
||||||
op(DEC, ZeroPageX, 0xD6)
|
|
||||||
op(DEC, Absolute, 0xCE)
|
|
||||||
op(DEC, AbsoluteX, 0xDE)
|
|
||||||
|
|
||||||
op(EOR, Immediate, 0x49)
|
|
||||||
op(EOR, ZeroPage, 0x45)
|
|
||||||
op(EOR, ZeroPageX, 0x55)
|
|
||||||
op(EOR, Absolute, 0x4D)
|
|
||||||
op(EOR, AbsoluteX, 0x5D)
|
|
||||||
op(EOR, AbsoluteY, 0x59)
|
|
||||||
op(EOR, IndexedX, 0x41)
|
|
||||||
op(EOR, IndexedY, 0x51)
|
|
||||||
|
|
||||||
op(INC, ZeroPage, 0xE6)
|
|
||||||
op(INC, ZeroPageX, 0xF6)
|
|
||||||
op(INC, Absolute, 0xEE)
|
|
||||||
op(INC, AbsoluteX, 0xFE)
|
|
||||||
|
|
||||||
op(CLC, Implied, 0x18)
|
|
||||||
op(SEC, Implied, 0x38)
|
|
||||||
op(CLI, Implied, 0x58)
|
|
||||||
op(SEI, Implied, 0x78)
|
|
||||||
op(CLV, Implied, 0xB8)
|
|
||||||
op(CLD, Implied, 0xD8)
|
|
||||||
op(SED, Implied, 0xF8)
|
|
||||||
|
|
||||||
op(JMP, Absolute, 0x4C)
|
|
||||||
op(JMP, Indirect, 0x6C)
|
|
||||||
|
|
||||||
op(JSR, Absolute, 0x20)
|
|
||||||
|
|
||||||
op(LDA, Immediate, 0xA9)
|
|
||||||
op(LDA, ZeroPage, 0xA5)
|
|
||||||
op(LDA, ZeroPageX, 0xB5)
|
|
||||||
op(LDA, Absolute, 0xAD)
|
|
||||||
op(LDA, AbsoluteX, 0xBD)
|
|
||||||
op(LDA, AbsoluteY, 0xB9)
|
|
||||||
op(LDA, IndexedX, 0xA1)
|
|
||||||
op(LDA, IndexedY, 0xB1)
|
|
||||||
|
|
||||||
op(LDX, Immediate, 0xA2)
|
|
||||||
op(LDX, ZeroPage, 0xA6)
|
|
||||||
op(LDX, ZeroPageY, 0xB6)
|
|
||||||
op(LDX, Absolute, 0xAE)
|
|
||||||
op(LDX, AbsoluteY, 0xBE)
|
|
||||||
|
|
||||||
op(LDY, Immediate, 0xA0)
|
|
||||||
op(LDY, ZeroPage, 0xA4)
|
|
||||||
op(LDY, ZeroPageX, 0xB4)
|
|
||||||
op(LDY, Absolute, 0xAC)
|
|
||||||
op(LDY, AbsoluteX, 0xBC)
|
|
||||||
|
|
||||||
op(LSR, Implied, 0x4A)
|
|
||||||
op(LSR, ZeroPage, 0x46)
|
|
||||||
op(LSR, ZeroPageX, 0x56)
|
|
||||||
op(LSR, Absolute, 0x4E)
|
|
||||||
op(LSR, AbsoluteX, 0x5E)
|
|
||||||
|
|
||||||
op(NOP, Implied, 0xEA)
|
|
||||||
|
|
||||||
op(ORA, Immediate, 0x09)
|
|
||||||
op(ORA, ZeroPage, 0x05)
|
|
||||||
op(ORA, ZeroPageX, 0x15)
|
|
||||||
op(ORA, Absolute, 0x0D)
|
|
||||||
op(ORA, AbsoluteX, 0x1D)
|
|
||||||
op(ORA, AbsoluteY, 0x19)
|
|
||||||
op(ORA, IndexedX, 0x01)
|
|
||||||
op(ORA, IndexedY, 0x11)
|
|
||||||
|
|
||||||
op(TAX, Implied, 0xAA)
|
|
||||||
op(TXA, Implied, 0x8A)
|
|
||||||
op(DEX, Implied, 0xCA)
|
|
||||||
op(INX, Implied, 0xE8)
|
|
||||||
op(TAY, Implied, 0xA8)
|
|
||||||
op(TYA, Implied, 0x98)
|
|
||||||
op(DEY, Implied, 0x88)
|
|
||||||
op(INY, Implied, 0xC8)
|
|
||||||
|
|
||||||
op(ROL, Implied, 0x2A)
|
|
||||||
op(ROL, ZeroPage, 0x26)
|
|
||||||
op(ROL, ZeroPageX, 0x36)
|
|
||||||
op(ROL, Absolute, 0x2E)
|
|
||||||
op(ROL, AbsoluteX, 0x3E)
|
|
||||||
|
|
||||||
op(ROR, Implied, 0x6A)
|
|
||||||
op(ROR, ZeroPage, 0x66)
|
|
||||||
op(ROR, ZeroPageX, 0x76)
|
|
||||||
op(ROR, Absolute, 0x6E)
|
|
||||||
op(ROR, AbsoluteX, 0x7E)
|
|
||||||
|
|
||||||
op(RTI, Implied, 0x40)
|
|
||||||
op(RTS, Implied, 0x60)
|
|
||||||
|
|
||||||
op(SBC, Immediate, 0xE9)
|
|
||||||
op(SBC, ZeroPage, 0xE5)
|
|
||||||
op(SBC, ZeroPageX, 0xF5)
|
|
||||||
op(SBC, Absolute, 0xED)
|
|
||||||
op(SBC, AbsoluteX, 0xFD)
|
|
||||||
op(SBC, AbsoluteY, 0xF9)
|
|
||||||
op(SBC, IndexedX, 0xE1)
|
|
||||||
op(SBC, IndexedY, 0xF1)
|
|
||||||
|
|
||||||
op(STA, ZeroPage, 0x85)
|
|
||||||
op(STA, ZeroPageX, 0x95)
|
|
||||||
op(STA, Absolute, 0x8D)
|
|
||||||
op(STA, AbsoluteX, 0x9D)
|
|
||||||
op(STA, AbsoluteY, 0x99)
|
|
||||||
op(STA, IndexedX, 0x81)
|
|
||||||
op(STA, IndexedY, 0x91)
|
|
||||||
|
|
||||||
op(TXS, Implied, 0x9A)
|
|
||||||
op(TSX, Implied, 0xBA)
|
|
||||||
op(PHA, Implied, 0x48)
|
|
||||||
op(PLA, Implied, 0x68)
|
|
||||||
op(PHP, Implied, 0x08)
|
|
||||||
op(PLP, Implied, 0x28)
|
|
||||||
|
|
||||||
op(STX, ZeroPage, 0x86)
|
|
||||||
op(STX, ZeroPageY, 0x96)
|
|
||||||
op(STX, Absolute, 0x8E)
|
|
||||||
|
|
||||||
op(STY, ZeroPage, 0x84)
|
|
||||||
op(STY, ZeroPageX, 0x94)
|
|
||||||
op(STY, Absolute, 0x8C)
|
|
||||||
|
|
||||||
il(LAX, ZeroPage, 0xA7)
|
|
||||||
il(LAX, ZeroPageY, 0xB7)
|
|
||||||
il(LAX, Absolute, 0xAF)
|
|
||||||
il(LAX, AbsoluteY, 0xBF)
|
|
||||||
il(LAX, IndexedX, 0xA3)
|
|
||||||
il(LAX, IndexedY, 0xB3)
|
|
||||||
|
|
||||||
il(SAX, ZeroPage, 0x87)
|
|
||||||
il(SAX, ZeroPageY, 0x97)
|
|
||||||
il(SAX, Absolute, 0x8F)
|
|
||||||
il(TAS, AbsoluteY, 0x9B)
|
|
||||||
il(AHX, AbsoluteY, 0x9F)
|
|
||||||
il(SAX, IndexedX, 0x83)
|
|
||||||
il(AHX, IndexedY, 0x93)
|
|
||||||
il(SHY, AbsoluteX, 0x9C)
|
|
||||||
|
|
||||||
il(ANC, Immediate, 0x0B)
|
|
||||||
il(ALR, Immediate, 0x4B)
|
|
||||||
il(ARR, Immediate, 0x6B)
|
|
||||||
il(XAA, Immediate, 0x8B)
|
|
||||||
il(LXA, Immediate, 0xAB)
|
|
||||||
il(SBX, Immediate, 0xCB)
|
|
||||||
|
|
||||||
il(SLO, ZeroPage, 0x07)
|
|
||||||
il(SLO, ZeroPageX, 0x17)
|
|
||||||
il(SLO, IndexedX, 0x03)
|
|
||||||
il(SLO, IndexedY, 0x13)
|
|
||||||
il(SLO, Absolute, 0x0F)
|
|
||||||
il(SLO, AbsoluteX, 0x1F)
|
|
||||||
il(SLO, AbsoluteY, 0x1B)
|
|
||||||
|
|
||||||
il(RLA, ZeroPage, 0x27)
|
|
||||||
il(RLA, ZeroPageX, 0x37)
|
|
||||||
il(RLA, IndexedX, 0x23)
|
|
||||||
il(RLA, IndexedY, 0x33)
|
|
||||||
il(RLA, Absolute, 0x2F)
|
|
||||||
il(RLA, AbsoluteX, 0x3F)
|
|
||||||
il(RLA, AbsoluteY, 0x3B)
|
|
||||||
|
|
||||||
il(SRE, ZeroPage, 0x47)
|
|
||||||
il(SRE, ZeroPageX, 0x57)
|
|
||||||
il(SRE, IndexedX, 0x43)
|
|
||||||
il(SRE, IndexedY, 0x53)
|
|
||||||
il(SRE, Absolute, 0x4F)
|
|
||||||
il(SRE, AbsoluteX, 0x5F)
|
|
||||||
il(SRE, AbsoluteY, 0x5B)
|
|
||||||
|
|
||||||
il(RRA, ZeroPage, 0x67)
|
|
||||||
il(RRA, ZeroPageX, 0x77)
|
|
||||||
il(RRA, IndexedX, 0x63)
|
|
||||||
il(RRA, IndexedY, 0x73)
|
|
||||||
il(RRA, Absolute, 0x6F)
|
|
||||||
il(RRA, AbsoluteX, 0x7F)
|
|
||||||
il(RRA, AbsoluteY, 0x7B)
|
|
||||||
|
|
||||||
il(DCP, ZeroPage, 0xC7)
|
|
||||||
il(DCP, ZeroPageX, 0xD7)
|
|
||||||
il(DCP, IndexedX, 0xC3)
|
|
||||||
il(DCP, IndexedY, 0xD3)
|
|
||||||
il(DCP, Absolute, 0xCF)
|
|
||||||
il(DCP, AbsoluteX, 0xDF)
|
|
||||||
il(DCP, AbsoluteY, 0xDB)
|
|
||||||
|
|
||||||
il(ISC, ZeroPage, 0xE7)
|
|
||||||
il(ISC, ZeroPageX, 0xF7)
|
|
||||||
il(ISC, IndexedX, 0xE3)
|
|
||||||
il(ISC, IndexedY, 0xF3)
|
|
||||||
il(ISC, Absolute, 0xEF)
|
|
||||||
il(ISC, AbsoluteX, 0xFF)
|
|
||||||
il(ISC, AbsoluteY, 0xFB)
|
|
||||||
|
|
||||||
il(NOP, Immediate, 0x80)
|
|
||||||
il(NOP, ZeroPage, 0x44)
|
|
||||||
il(NOP, ZeroPageX, 0x54)
|
|
||||||
il(NOP, Absolute, 0x5C)
|
|
||||||
il(NOP, AbsoluteX, 0x1C)
|
|
||||||
|
|
||||||
cn(NOP, Immediate, 0x02)
|
|
||||||
cn(NOP, ZeroPage, 0x44)
|
|
||||||
cn(NOP, ZeroPageX, 0x54)
|
|
||||||
cn(NOP, Absolute, 0x5C)
|
|
||||||
|
|
||||||
cm(STZ, ZeroPage, 0x64)
|
|
||||||
cm(STZ, ZeroPageX, 0x74)
|
|
||||||
cm(STZ, Absolute, 0x9C)
|
|
||||||
cm(STZ, AbsoluteX, 0x9E)
|
|
||||||
|
|
||||||
cm(PHX, Implied, 0xDA)
|
|
||||||
cm(PHY, Implied, 0x5A)
|
|
||||||
cm(PLX, Implied, 0xFA)
|
|
||||||
cm(PLY, Implied, 0x7A)
|
|
||||||
|
|
||||||
cm(ORA, IndexedZ, 0x12)
|
|
||||||
cm(AND, IndexedZ, 0x32)
|
|
||||||
cm(EOR, IndexedZ, 0x52)
|
|
||||||
cm(ADC, IndexedZ, 0x72)
|
|
||||||
cm(STA, IndexedZ, 0x92)
|
|
||||||
cm(LDA, IndexedZ, 0xB2)
|
|
||||||
cm(CMP, IndexedZ, 0xD2)
|
|
||||||
cm(SBC, IndexedZ, 0xF2)
|
|
||||||
|
|
||||||
cm(TSB, ZeroPage, 0x04)
|
|
||||||
cm(TSB, Absolute, 0x0C)
|
|
||||||
cm(TRB, ZeroPage, 0x14)
|
|
||||||
cm(TRB, Absolute, 0x1C)
|
|
||||||
|
|
||||||
cm(BRA, Relative, 0x80)
|
|
||||||
cm(BIT, ZeroPageX, 0x34)
|
|
||||||
cm(BIT, AbsoluteX, 0x3C)
|
|
||||||
cm(INC, Implied, 0x1A)
|
|
||||||
cm(DEC, Implied, 0x3A)
|
|
||||||
cm(JMP, AbsoluteIndexedX, 0x7C)
|
|
||||||
cm(WAI, Implied, 0xCB)
|
|
||||||
cm(STP, Implied, 0xDB)
|
|
||||||
|
|
||||||
ce(CPZ, Immediate, 0xC2)
|
|
||||||
ce(CPZ, ZeroPage, 0xD4)
|
|
||||||
ce(CPZ, Absolute, 0xDC)
|
|
||||||
ce(DEZ, Implied, 0x3B)
|
|
||||||
ce(INZ, Implied,0x1B )
|
|
||||||
ce(DEC_W, ZeroPage, 0xC3)
|
|
||||||
ce(INC_W, ZeroPage, 0xE3)
|
|
||||||
ce(ASL_W, Absolute, 0xCB)
|
|
||||||
// TODO: or is it ROL_W?
|
|
||||||
ce(ROR_W, Absolute, 0xEB)
|
|
||||||
ce(ASR, Implied, 0x43)
|
|
||||||
ce(ASR, ZeroPage, 0x44)
|
|
||||||
ce(ASR, ZeroPageX, 0x54)
|
|
||||||
ce(LDZ, Immediate, 0xA3)
|
|
||||||
ce(LDZ, Absolute, 0xAB)
|
|
||||||
ce(LDZ, AbsoluteX, 0xBB)
|
|
||||||
ce(TAB, Implied, 0x5B)
|
|
||||||
ce(TBA, Implied, 0x7B)
|
|
||||||
ce(TAZ, Implied, 0x4B)
|
|
||||||
ce(TZA, Implied, 0x6B)
|
|
||||||
ce(TSY, Implied, 0x0B)
|
|
||||||
ce(TYS, Implied, 0x2B)
|
|
||||||
ce(PHW, WordImmediate, 0xF4)
|
|
||||||
ce(PHW, Absolute, 0xFC)
|
|
||||||
ce(PHZ, Implied, 0xDB)
|
|
||||||
ce(PLZ, Implied, 0xFB)
|
|
||||||
// ce(CLE, Implied, )
|
|
||||||
// ce(SEE, Implied, )
|
|
||||||
// ce(BSR, , )
|
|
||||||
|
|
||||||
hu(CLY, Implied, 0xC2)
|
|
||||||
hu(CLX, Implied, 0x82)
|
|
||||||
hu(CLA, Implied, 0x62)
|
|
||||||
hu(CSH, Implied, 0xD4)
|
|
||||||
hu(CSL, Implied, 0x54)
|
|
||||||
hu(HuSAX, Implied, 0x22)
|
|
||||||
hu(SAY, Implied, 0x42)
|
|
||||||
hu(SXY, Implied, 0x02)
|
|
||||||
hu(TAM, Immediate, 0x53)
|
|
||||||
hu(TMA, Immediate, 0x43)
|
|
||||||
|
|
||||||
em(ORA, Stack, 0x03)
|
|
||||||
em(ORA, IndexedSY, 0x13)
|
|
||||||
na(ORA, LongIndexedZ, 0x07)
|
|
||||||
na(ORA, LongIndexedY, 0x17)
|
|
||||||
na(ORA, LongAbsolute, 0x0F)
|
|
||||||
na(ORA, LongAbsoluteX, 0x1F)
|
|
||||||
em(AND, Stack, 0x23)
|
|
||||||
em(AND, IndexedSY, 0x33)
|
|
||||||
na(AND, LongIndexedZ, 0x27)
|
|
||||||
na(AND, LongIndexedY, 0x37)
|
|
||||||
na(AND, LongAbsolute, 0x2F)
|
|
||||||
na(AND, LongAbsoluteX, 0x3F)
|
|
||||||
em(EOR, Stack, 0x43)
|
|
||||||
em(EOR, IndexedSY, 0x53)
|
|
||||||
na(EOR, LongIndexedZ, 0x47)
|
|
||||||
na(EOR, LongIndexedY, 0x57)
|
|
||||||
na(EOR, LongAbsolute, 0x4F)
|
|
||||||
na(EOR, LongAbsoluteX, 0x5F)
|
|
||||||
em(ADC, Stack, 0x63)
|
|
||||||
em(ADC, IndexedSY, 0x73)
|
|
||||||
na(ADC, LongIndexedZ, 0x67)
|
|
||||||
na(ADC, LongIndexedY, 0x77)
|
|
||||||
na(ADC, LongAbsolute, 0x6F)
|
|
||||||
na(ADC, LongAbsoluteX, 0x7F)
|
|
||||||
em(STA, Stack, 0x83)
|
|
||||||
em(STA, IndexedSY, 0x93)
|
|
||||||
na(STA, LongIndexedZ, 0x87)
|
|
||||||
na(STA, LongIndexedY, 0x97)
|
|
||||||
na(STA, LongAbsolute, 0x8F)
|
|
||||||
na(STA, LongAbsoluteX, 0x9F)
|
|
||||||
em(LDA, Stack, 0xA3)
|
|
||||||
em(LDA, IndexedSY, 0xB3)
|
|
||||||
na(LDA, LongIndexedZ, 0xA7)
|
|
||||||
na(LDA, LongIndexedY, 0xB7)
|
|
||||||
na(LDA, LongAbsolute, 0xAF)
|
|
||||||
na(LDA, LongAbsoluteX, 0xBF)
|
|
||||||
em(CMP, Stack, 0xA3)
|
|
||||||
em(CMP, IndexedSY, 0xB3)
|
|
||||||
na(CMP, LongIndexedZ, 0xA7)
|
|
||||||
na(CMP, LongIndexedY, 0xB7)
|
|
||||||
na(CMP, LongAbsolute, 0xAF)
|
|
||||||
na(CMP, LongAbsoluteX, 0xBF)
|
|
||||||
|
|
||||||
em(COP, Immediate, 0x02)
|
|
||||||
em(XBA, Implied, 0xEB)
|
|
||||||
em(TXY, Implied, 0x9B)
|
|
||||||
em(TYX, Implied, 0xBB)
|
|
||||||
|
|
||||||
|
|
||||||
na(RTL, Implied, 0x6B)
|
|
||||||
na(JMP, LongAbsolute, 0x5C)
|
|
||||||
na(JMP, LongIndirect, 0x7C)
|
|
||||||
na(BRL, LongRelative, 0x82)
|
|
||||||
|
|
||||||
em(PHD, Implied, 0x0B)
|
|
||||||
em(PLD, Implied, 0x2B)
|
|
||||||
em(PHB, Implied, 0x8B)
|
|
||||||
em(PLB, Implied, 0xAB)
|
|
||||||
em(PHK, Implied, 0x4B)
|
|
||||||
|
|
||||||
na(REP, Immediate, 0xC2)
|
|
||||||
na(SEP, Immediate, 0xE2)
|
|
||||||
|
|
||||||
na(XCE, Implied, 0xFB)
|
|
||||||
na(TCD, Implied, 0x5B)
|
|
||||||
na(TDC, Implied, 0x7B)
|
|
||||||
na(TSC, Implied, 0x3B)
|
|
||||||
na(TCS, Implied, 0x1B)
|
|
||||||
|
|
||||||
for {
|
|
||||||
((narrow, am), code) <- emulation65816Opcodes ++ opcodes ++ cmosOpcodes ++ native65816Opcodes
|
|
||||||
wide <- Opcode.widen(narrow)
|
|
||||||
} na(wide, if (am == Immediate) WordImmediate else am, code & 0xff)
|
|
||||||
|
|
||||||
}
|
|
@@ -0,0 +1,12 @@
|
|||||||
|
package millfork.output
|
||||||
|
|
||||||
|
import millfork.assembly.AbstractCode
|
||||||
|
import millfork.compiler.AbstractCompiler
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Karol Stasiak
|
||||||
|
*/
|
||||||
|
abstract class AbstractInliningCalculator[T <: AbstractCode] {
|
||||||
|
def codeForInlining(fname: String, functionsAlreadyKnownToBeNonInlineable: Set[String], code: List[T]): Option[List[T]]
|
||||||
|
def inline(code: List[T], inlinedFunctions: Map[String, List[T]], compiler: AbstractCompiler[T]): List[T]
|
||||||
|
}
|
549
src/main/scala/millfork/output/MosAssembler.scala
Normal file
549
src/main/scala/millfork/output/MosAssembler.scala
Normal file
@@ -0,0 +1,549 @@
|
|||||||
|
package millfork.output
|
||||||
|
|
||||||
|
import millfork.assembly.mos.opt.{HudsonOptimizations, JumpFixing, JumpShortening}
|
||||||
|
import millfork.assembly._
|
||||||
|
import millfork.env._
|
||||||
|
import millfork.error.ErrorReporting
|
||||||
|
import millfork.node.Program
|
||||||
|
import millfork._
|
||||||
|
import millfork.assembly.mos.{AssemblyLine, Opcode}
|
||||||
|
import millfork.compiler.mos.MosCompiler
|
||||||
|
|
||||||
|
import scala.collection.mutable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Karol Stasiak
|
||||||
|
*/
|
||||||
|
class MosAssembler(program: Program,
|
||||||
|
rootEnv: Environment,
|
||||||
|
platform: Platform) extends AbstractAssembler[AssemblyLine](program, rootEnv, platform, MosInliningCalculator, MosCompiler) {
|
||||||
|
|
||||||
|
|
||||||
|
override def performFinalOptimizationPass(f: NormalFunction, actuallyOptimize: Boolean, options: CompilationOptions, code: List[AssemblyLine]):List[AssemblyLine] = {
|
||||||
|
if (actuallyOptimize) {
|
||||||
|
val finalCode = if (options.flag(CompilationFlag.EmitHudsonOpcodes)) HudsonOptimizations.removeLoadZero(code) else code
|
||||||
|
JumpShortening(f, JumpShortening(f, JumpFixing(f, finalCode, options), options), options)
|
||||||
|
}
|
||||||
|
else JumpFixing(f, code, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
override def emitInstruction(bank: String, options: CompilationOptions, index: Int, instr: AssemblyLine): Int = {
|
||||||
|
import millfork.assembly.AddrMode._
|
||||||
|
import millfork.assembly.mos.Opcode._
|
||||||
|
instr match {
|
||||||
|
case AssemblyLine(BYTE, RawByte, c, _) =>
|
||||||
|
writeByte(bank, index, c)
|
||||||
|
index + 1
|
||||||
|
case AssemblyLine(BYTE, _, _, _) => ???
|
||||||
|
case AssemblyLine(_, RawByte, _, _) => ???
|
||||||
|
case AssemblyLine(LABEL, _, MemoryAddressConstant(Label(labelName)), _) =>
|
||||||
|
labelMap(labelName) = index
|
||||||
|
index
|
||||||
|
case AssemblyLine(_, DoesNotExist, _, _) =>
|
||||||
|
index
|
||||||
|
case AssemblyLine(op, Implied, _, _) =>
|
||||||
|
writeByte(bank, index, MosAssembler.opcodeFor(op, Implied, options))
|
||||||
|
index + 1
|
||||||
|
case AssemblyLine(op, Relative, param, _) =>
|
||||||
|
writeByte(bank, index, MosAssembler.opcodeFor(op, Relative, options))
|
||||||
|
writeByte(bank, index + 1, AssertByte(param - (index + 2)))
|
||||||
|
index + 2
|
||||||
|
case AssemblyLine(op, am@(Immediate | ZeroPage | ZeroPageX | ZeroPageY | IndexedY | IndexedX | IndexedZ | LongIndexedY | LongIndexedZ | Stack), param, _) =>
|
||||||
|
writeByte(bank, index, MosAssembler.opcodeFor(op, am, options))
|
||||||
|
writeByte(bank, index + 1, param)
|
||||||
|
index + 2
|
||||||
|
case AssemblyLine(op, am@(WordImmediate | Absolute | AbsoluteY | AbsoluteX | Indirect | AbsoluteIndexedX), param, _) =>
|
||||||
|
writeByte(bank, index, MosAssembler.opcodeFor(op, am, options))
|
||||||
|
writeWord(bank, index + 1, param)
|
||||||
|
index + 3
|
||||||
|
case AssemblyLine(op, am@(LongAbsolute | LongAbsoluteX | LongIndirect), param, _) =>
|
||||||
|
writeByte(bank, index, MosAssembler.opcodeFor(op, am, options))
|
||||||
|
writeWord(bank, index + 1, param)
|
||||||
|
writeByte(bank, index + 3, extractBank(param, options))
|
||||||
|
index + 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
object MosAssembler {
|
||||||
|
val opcodes = mutable.Map[(Opcode.Value, AddrMode.Value), Byte]()
|
||||||
|
val illegalOpcodes = mutable.Map[(Opcode.Value, AddrMode.Value), Byte]()
|
||||||
|
val cmosOpcodes = mutable.Map[(Opcode.Value, AddrMode.Value), Byte]()
|
||||||
|
val cmosNopOpcodes = mutable.Map[(Opcode.Value, AddrMode.Value), Byte]()
|
||||||
|
val ce02Opcodes = mutable.Map[(Opcode.Value, AddrMode.Value), Byte]()
|
||||||
|
val hudsonOpcodes = mutable.Map[(Opcode.Value, AddrMode.Value), Byte]()
|
||||||
|
val emulation65816Opcodes = mutable.Map[(Opcode.Value, AddrMode.Value), Byte]()
|
||||||
|
val native65816Opcodes = mutable.Map[(Opcode.Value, AddrMode.Value), Byte]()
|
||||||
|
|
||||||
|
def opcodeFor(opcode: Opcode.Value, addrMode: AddrMode.Value, options: CompilationOptions): Byte = {
|
||||||
|
val key = opcode -> addrMode
|
||||||
|
opcodes.get(key).foreach(return _)
|
||||||
|
if (options.flag(CompilationFlag.EmitIllegals)) illegalOpcodes.get(key).foreach(return _)
|
||||||
|
if (options.flag(CompilationFlag.EmitCmosOpcodes)) cmosOpcodes.get(key).foreach(return _)
|
||||||
|
if (options.flag(CompilationFlag.EmitCmosNopOpcodes)) cmosNopOpcodes.get(key).foreach(return _)
|
||||||
|
if (options.flag(CompilationFlag.Emit65CE02Opcodes)) ce02Opcodes.get(key).foreach(return _)
|
||||||
|
if (options.flag(CompilationFlag.EmitHudsonOpcodes)) hudsonOpcodes.get(key).foreach(return _)
|
||||||
|
if (options.flag(CompilationFlag.EmitEmulation65816Opcodes)) emulation65816Opcodes.get(key).foreach(return _)
|
||||||
|
if (options.flag(CompilationFlag.EmitNative65816Opcodes)) native65816Opcodes.get(key).foreach(return _)
|
||||||
|
ErrorReporting.fatal("Cannot assemble an unknown opcode " + key)
|
||||||
|
}
|
||||||
|
|
||||||
|
private def op(op: Opcode.Value, am: AddrMode.Value, x: Int): Unit = {
|
||||||
|
if (x < 0 || x > 0xff) ErrorReporting.fatal("Invalid code for" + (op -> am))
|
||||||
|
opcodes(op -> am) = x.toByte
|
||||||
|
if (am == AddrMode.Relative) opcodes(op -> AddrMode.Immediate) = x.toByte
|
||||||
|
}
|
||||||
|
|
||||||
|
private def cm(op: Opcode.Value, am: AddrMode.Value, x: Int): Unit = {
|
||||||
|
if (x < 0 || x > 0xff) ErrorReporting.fatal("Invalid code for" + (op -> am))
|
||||||
|
cmosOpcodes(op -> am) = x.toByte
|
||||||
|
}
|
||||||
|
|
||||||
|
private def cn(op: Opcode.Value, am: AddrMode.Value, x: Int): Unit = {
|
||||||
|
if (x < 0 || x > 0xff) ErrorReporting.fatal("Invalid code for" + (op -> am))
|
||||||
|
cmosNopOpcodes(op -> am) = x.toByte
|
||||||
|
}
|
||||||
|
|
||||||
|
private def il(op: Opcode.Value, am: AddrMode.Value, x: Int): Unit = {
|
||||||
|
if (x < 0 || x > 0xff) ErrorReporting.fatal("Invalid code for" + (op -> am))
|
||||||
|
illegalOpcodes(op -> am) = x.toByte
|
||||||
|
}
|
||||||
|
|
||||||
|
private def hu(op: Opcode.Value, am: AddrMode.Value, x: Int): Unit = {
|
||||||
|
if (x < 0 || x > 0xff) ErrorReporting.fatal("Invalid code for" + (op -> am))
|
||||||
|
hudsonOpcodes(op -> am) = x.toByte
|
||||||
|
}
|
||||||
|
|
||||||
|
private def ce(op: Opcode.Value, am: AddrMode.Value, x: Int): Unit = {
|
||||||
|
if (x < 0 || x > 0xff) ErrorReporting.fatal("Invalid code for" + (op -> am))
|
||||||
|
ce02Opcodes(op -> am) = x.toByte
|
||||||
|
}
|
||||||
|
|
||||||
|
private def em(op: Opcode.Value, am: AddrMode.Value, x: Int): Unit = {
|
||||||
|
if (x < 0 || x > 0xff) ErrorReporting.fatal("Invalid code for" + (op -> am))
|
||||||
|
emulation65816Opcodes(op -> am) = x.toByte
|
||||||
|
}
|
||||||
|
|
||||||
|
private def na(op: Opcode.Value, am: AddrMode.Value, x: Int): Unit = {
|
||||||
|
if (x < 0 || x > 0xff) ErrorReporting.fatal("Invalid code for" + (op -> am))
|
||||||
|
native65816Opcodes(op -> am) = x.toByte
|
||||||
|
}
|
||||||
|
|
||||||
|
def getStandardLegalOpcodes: Set[Int] = opcodes.values.map(_ & 0xff).toSet
|
||||||
|
|
||||||
|
import AddrMode._
|
||||||
|
import Opcode._
|
||||||
|
|
||||||
|
op(ADC, Immediate, 0x69)
|
||||||
|
op(ADC, ZeroPage, 0x65)
|
||||||
|
op(ADC, ZeroPageX, 0x75)
|
||||||
|
op(ADC, Absolute, 0x6D)
|
||||||
|
op(ADC, AbsoluteX, 0x7D)
|
||||||
|
op(ADC, AbsoluteY, 0x79)
|
||||||
|
op(ADC, IndexedX, 0x61)
|
||||||
|
op(ADC, IndexedY, 0x71)
|
||||||
|
|
||||||
|
op(AND, Immediate, 0x29)
|
||||||
|
op(AND, ZeroPage, 0x25)
|
||||||
|
op(AND, ZeroPageX, 0x35)
|
||||||
|
op(AND, Absolute, 0x2D)
|
||||||
|
op(AND, AbsoluteX, 0x3D)
|
||||||
|
op(AND, AbsoluteY, 0x39)
|
||||||
|
op(AND, IndexedX, 0x21)
|
||||||
|
op(AND, IndexedY, 0x31)
|
||||||
|
|
||||||
|
op(ASL, Implied, 0x0A)
|
||||||
|
op(ASL, ZeroPage, 0x06)
|
||||||
|
op(ASL, ZeroPageX, 0x16)
|
||||||
|
op(ASL, Absolute, 0x0E)
|
||||||
|
op(ASL, AbsoluteX, 0x1E)
|
||||||
|
|
||||||
|
op(BIT, ZeroPage, 0x24)
|
||||||
|
op(BIT, Absolute, 0x2C)
|
||||||
|
|
||||||
|
op(BPL, Relative, 0x10)
|
||||||
|
op(BMI, Relative, 0x30)
|
||||||
|
op(BVC, Relative, 0x50)
|
||||||
|
op(BVS, Relative, 0x70)
|
||||||
|
op(BCC, Relative, 0x90)
|
||||||
|
op(BCS, Relative, 0xB0)
|
||||||
|
op(BNE, Relative, 0xD0)
|
||||||
|
op(BEQ, Relative, 0xF0)
|
||||||
|
|
||||||
|
op(BRK, Implied, 0)
|
||||||
|
|
||||||
|
op(CMP, Immediate, 0xC9)
|
||||||
|
op(CMP, ZeroPage, 0xC5)
|
||||||
|
op(CMP, ZeroPageX, 0xD5)
|
||||||
|
op(CMP, Absolute, 0xCD)
|
||||||
|
op(CMP, AbsoluteX, 0xDD)
|
||||||
|
op(CMP, AbsoluteY, 0xD9)
|
||||||
|
op(CMP, IndexedX, 0xC1)
|
||||||
|
op(CMP, IndexedY, 0xD1)
|
||||||
|
|
||||||
|
op(CPX, Immediate, 0xE0)
|
||||||
|
op(CPX, ZeroPage, 0xE4)
|
||||||
|
op(CPX, Absolute, 0xEC)
|
||||||
|
|
||||||
|
op(CPY, Immediate, 0xC0)
|
||||||
|
op(CPY, ZeroPage, 0xC4)
|
||||||
|
op(CPY, Absolute, 0xCC)
|
||||||
|
|
||||||
|
op(DEC, ZeroPage, 0xC6)
|
||||||
|
op(DEC, ZeroPageX, 0xD6)
|
||||||
|
op(DEC, Absolute, 0xCE)
|
||||||
|
op(DEC, AbsoluteX, 0xDE)
|
||||||
|
|
||||||
|
op(EOR, Immediate, 0x49)
|
||||||
|
op(EOR, ZeroPage, 0x45)
|
||||||
|
op(EOR, ZeroPageX, 0x55)
|
||||||
|
op(EOR, Absolute, 0x4D)
|
||||||
|
op(EOR, AbsoluteX, 0x5D)
|
||||||
|
op(EOR, AbsoluteY, 0x59)
|
||||||
|
op(EOR, IndexedX, 0x41)
|
||||||
|
op(EOR, IndexedY, 0x51)
|
||||||
|
|
||||||
|
op(INC, ZeroPage, 0xE6)
|
||||||
|
op(INC, ZeroPageX, 0xF6)
|
||||||
|
op(INC, Absolute, 0xEE)
|
||||||
|
op(INC, AbsoluteX, 0xFE)
|
||||||
|
|
||||||
|
op(CLC, Implied, 0x18)
|
||||||
|
op(SEC, Implied, 0x38)
|
||||||
|
op(CLI, Implied, 0x58)
|
||||||
|
op(SEI, Implied, 0x78)
|
||||||
|
op(CLV, Implied, 0xB8)
|
||||||
|
op(CLD, Implied, 0xD8)
|
||||||
|
op(SED, Implied, 0xF8)
|
||||||
|
|
||||||
|
op(JMP, Absolute, 0x4C)
|
||||||
|
op(JMP, Indirect, 0x6C)
|
||||||
|
|
||||||
|
op(JSR, Absolute, 0x20)
|
||||||
|
|
||||||
|
op(LDA, Immediate, 0xA9)
|
||||||
|
op(LDA, ZeroPage, 0xA5)
|
||||||
|
op(LDA, ZeroPageX, 0xB5)
|
||||||
|
op(LDA, Absolute, 0xAD)
|
||||||
|
op(LDA, AbsoluteX, 0xBD)
|
||||||
|
op(LDA, AbsoluteY, 0xB9)
|
||||||
|
op(LDA, IndexedX, 0xA1)
|
||||||
|
op(LDA, IndexedY, 0xB1)
|
||||||
|
|
||||||
|
op(LDX, Immediate, 0xA2)
|
||||||
|
op(LDX, ZeroPage, 0xA6)
|
||||||
|
op(LDX, ZeroPageY, 0xB6)
|
||||||
|
op(LDX, Absolute, 0xAE)
|
||||||
|
op(LDX, AbsoluteY, 0xBE)
|
||||||
|
|
||||||
|
op(LDY, Immediate, 0xA0)
|
||||||
|
op(LDY, ZeroPage, 0xA4)
|
||||||
|
op(LDY, ZeroPageX, 0xB4)
|
||||||
|
op(LDY, Absolute, 0xAC)
|
||||||
|
op(LDY, AbsoluteX, 0xBC)
|
||||||
|
|
||||||
|
op(LSR, Implied, 0x4A)
|
||||||
|
op(LSR, ZeroPage, 0x46)
|
||||||
|
op(LSR, ZeroPageX, 0x56)
|
||||||
|
op(LSR, Absolute, 0x4E)
|
||||||
|
op(LSR, AbsoluteX, 0x5E)
|
||||||
|
|
||||||
|
op(NOP, Implied, 0xEA)
|
||||||
|
|
||||||
|
op(ORA, Immediate, 0x09)
|
||||||
|
op(ORA, ZeroPage, 0x05)
|
||||||
|
op(ORA, ZeroPageX, 0x15)
|
||||||
|
op(ORA, Absolute, 0x0D)
|
||||||
|
op(ORA, AbsoluteX, 0x1D)
|
||||||
|
op(ORA, AbsoluteY, 0x19)
|
||||||
|
op(ORA, IndexedX, 0x01)
|
||||||
|
op(ORA, IndexedY, 0x11)
|
||||||
|
|
||||||
|
op(TAX, Implied, 0xAA)
|
||||||
|
op(TXA, Implied, 0x8A)
|
||||||
|
op(DEX, Implied, 0xCA)
|
||||||
|
op(INX, Implied, 0xE8)
|
||||||
|
op(TAY, Implied, 0xA8)
|
||||||
|
op(TYA, Implied, 0x98)
|
||||||
|
op(DEY, Implied, 0x88)
|
||||||
|
op(INY, Implied, 0xC8)
|
||||||
|
|
||||||
|
op(ROL, Implied, 0x2A)
|
||||||
|
op(ROL, ZeroPage, 0x26)
|
||||||
|
op(ROL, ZeroPageX, 0x36)
|
||||||
|
op(ROL, Absolute, 0x2E)
|
||||||
|
op(ROL, AbsoluteX, 0x3E)
|
||||||
|
|
||||||
|
op(ROR, Implied, 0x6A)
|
||||||
|
op(ROR, ZeroPage, 0x66)
|
||||||
|
op(ROR, ZeroPageX, 0x76)
|
||||||
|
op(ROR, Absolute, 0x6E)
|
||||||
|
op(ROR, AbsoluteX, 0x7E)
|
||||||
|
|
||||||
|
op(RTI, Implied, 0x40)
|
||||||
|
op(RTS, Implied, 0x60)
|
||||||
|
|
||||||
|
op(SBC, Immediate, 0xE9)
|
||||||
|
op(SBC, ZeroPage, 0xE5)
|
||||||
|
op(SBC, ZeroPageX, 0xF5)
|
||||||
|
op(SBC, Absolute, 0xED)
|
||||||
|
op(SBC, AbsoluteX, 0xFD)
|
||||||
|
op(SBC, AbsoluteY, 0xF9)
|
||||||
|
op(SBC, IndexedX, 0xE1)
|
||||||
|
op(SBC, IndexedY, 0xF1)
|
||||||
|
|
||||||
|
op(STA, ZeroPage, 0x85)
|
||||||
|
op(STA, ZeroPageX, 0x95)
|
||||||
|
op(STA, Absolute, 0x8D)
|
||||||
|
op(STA, AbsoluteX, 0x9D)
|
||||||
|
op(STA, AbsoluteY, 0x99)
|
||||||
|
op(STA, IndexedX, 0x81)
|
||||||
|
op(STA, IndexedY, 0x91)
|
||||||
|
|
||||||
|
op(TXS, Implied, 0x9A)
|
||||||
|
op(TSX, Implied, 0xBA)
|
||||||
|
op(PHA, Implied, 0x48)
|
||||||
|
op(PLA, Implied, 0x68)
|
||||||
|
op(PHP, Implied, 0x08)
|
||||||
|
op(PLP, Implied, 0x28)
|
||||||
|
|
||||||
|
op(STX, ZeroPage, 0x86)
|
||||||
|
op(STX, ZeroPageY, 0x96)
|
||||||
|
op(STX, Absolute, 0x8E)
|
||||||
|
|
||||||
|
op(STY, ZeroPage, 0x84)
|
||||||
|
op(STY, ZeroPageX, 0x94)
|
||||||
|
op(STY, Absolute, 0x8C)
|
||||||
|
|
||||||
|
il(LAX, ZeroPage, 0xA7)
|
||||||
|
il(LAX, ZeroPageY, 0xB7)
|
||||||
|
il(LAX, Absolute, 0xAF)
|
||||||
|
il(LAX, AbsoluteY, 0xBF)
|
||||||
|
il(LAX, IndexedX, 0xA3)
|
||||||
|
il(LAX, IndexedY, 0xB3)
|
||||||
|
|
||||||
|
il(SAX, ZeroPage, 0x87)
|
||||||
|
il(SAX, ZeroPageY, 0x97)
|
||||||
|
il(SAX, Absolute, 0x8F)
|
||||||
|
il(TAS, AbsoluteY, 0x9B)
|
||||||
|
il(AHX, AbsoluteY, 0x9F)
|
||||||
|
il(SAX, IndexedX, 0x83)
|
||||||
|
il(AHX, IndexedY, 0x93)
|
||||||
|
il(SHY, AbsoluteX, 0x9C)
|
||||||
|
|
||||||
|
il(ANC, Immediate, 0x0B)
|
||||||
|
il(ALR, Immediate, 0x4B)
|
||||||
|
il(ARR, Immediate, 0x6B)
|
||||||
|
il(XAA, Immediate, 0x8B)
|
||||||
|
il(LXA, Immediate, 0xAB)
|
||||||
|
il(SBX, Immediate, 0xCB)
|
||||||
|
|
||||||
|
il(SLO, ZeroPage, 0x07)
|
||||||
|
il(SLO, ZeroPageX, 0x17)
|
||||||
|
il(SLO, IndexedX, 0x03)
|
||||||
|
il(SLO, IndexedY, 0x13)
|
||||||
|
il(SLO, Absolute, 0x0F)
|
||||||
|
il(SLO, AbsoluteX, 0x1F)
|
||||||
|
il(SLO, AbsoluteY, 0x1B)
|
||||||
|
|
||||||
|
il(RLA, ZeroPage, 0x27)
|
||||||
|
il(RLA, ZeroPageX, 0x37)
|
||||||
|
il(RLA, IndexedX, 0x23)
|
||||||
|
il(RLA, IndexedY, 0x33)
|
||||||
|
il(RLA, Absolute, 0x2F)
|
||||||
|
il(RLA, AbsoluteX, 0x3F)
|
||||||
|
il(RLA, AbsoluteY, 0x3B)
|
||||||
|
|
||||||
|
il(SRE, ZeroPage, 0x47)
|
||||||
|
il(SRE, ZeroPageX, 0x57)
|
||||||
|
il(SRE, IndexedX, 0x43)
|
||||||
|
il(SRE, IndexedY, 0x53)
|
||||||
|
il(SRE, Absolute, 0x4F)
|
||||||
|
il(SRE, AbsoluteX, 0x5F)
|
||||||
|
il(SRE, AbsoluteY, 0x5B)
|
||||||
|
|
||||||
|
il(RRA, ZeroPage, 0x67)
|
||||||
|
il(RRA, ZeroPageX, 0x77)
|
||||||
|
il(RRA, IndexedX, 0x63)
|
||||||
|
il(RRA, IndexedY, 0x73)
|
||||||
|
il(RRA, Absolute, 0x6F)
|
||||||
|
il(RRA, AbsoluteX, 0x7F)
|
||||||
|
il(RRA, AbsoluteY, 0x7B)
|
||||||
|
|
||||||
|
il(DCP, ZeroPage, 0xC7)
|
||||||
|
il(DCP, ZeroPageX, 0xD7)
|
||||||
|
il(DCP, IndexedX, 0xC3)
|
||||||
|
il(DCP, IndexedY, 0xD3)
|
||||||
|
il(DCP, Absolute, 0xCF)
|
||||||
|
il(DCP, AbsoluteX, 0xDF)
|
||||||
|
il(DCP, AbsoluteY, 0xDB)
|
||||||
|
|
||||||
|
il(ISC, ZeroPage, 0xE7)
|
||||||
|
il(ISC, ZeroPageX, 0xF7)
|
||||||
|
il(ISC, IndexedX, 0xE3)
|
||||||
|
il(ISC, IndexedY, 0xF3)
|
||||||
|
il(ISC, Absolute, 0xEF)
|
||||||
|
il(ISC, AbsoluteX, 0xFF)
|
||||||
|
il(ISC, AbsoluteY, 0xFB)
|
||||||
|
|
||||||
|
il(NOP, Immediate, 0x80)
|
||||||
|
il(NOP, ZeroPage, 0x44)
|
||||||
|
il(NOP, ZeroPageX, 0x54)
|
||||||
|
il(NOP, Absolute, 0x5C)
|
||||||
|
il(NOP, AbsoluteX, 0x1C)
|
||||||
|
|
||||||
|
cn(NOP, Immediate, 0x02)
|
||||||
|
cn(NOP, ZeroPage, 0x44)
|
||||||
|
cn(NOP, ZeroPageX, 0x54)
|
||||||
|
cn(NOP, Absolute, 0x5C)
|
||||||
|
|
||||||
|
cm(STZ, ZeroPage, 0x64)
|
||||||
|
cm(STZ, ZeroPageX, 0x74)
|
||||||
|
cm(STZ, Absolute, 0x9C)
|
||||||
|
cm(STZ, AbsoluteX, 0x9E)
|
||||||
|
|
||||||
|
cm(PHX, Implied, 0xDA)
|
||||||
|
cm(PHY, Implied, 0x5A)
|
||||||
|
cm(PLX, Implied, 0xFA)
|
||||||
|
cm(PLY, Implied, 0x7A)
|
||||||
|
|
||||||
|
cm(ORA, IndexedZ, 0x12)
|
||||||
|
cm(AND, IndexedZ, 0x32)
|
||||||
|
cm(EOR, IndexedZ, 0x52)
|
||||||
|
cm(ADC, IndexedZ, 0x72)
|
||||||
|
cm(STA, IndexedZ, 0x92)
|
||||||
|
cm(LDA, IndexedZ, 0xB2)
|
||||||
|
cm(CMP, IndexedZ, 0xD2)
|
||||||
|
cm(SBC, IndexedZ, 0xF2)
|
||||||
|
|
||||||
|
cm(TSB, ZeroPage, 0x04)
|
||||||
|
cm(TSB, Absolute, 0x0C)
|
||||||
|
cm(TRB, ZeroPage, 0x14)
|
||||||
|
cm(TRB, Absolute, 0x1C)
|
||||||
|
|
||||||
|
cm(BRA, Relative, 0x80)
|
||||||
|
cm(BIT, ZeroPageX, 0x34)
|
||||||
|
cm(BIT, AbsoluteX, 0x3C)
|
||||||
|
cm(INC, Implied, 0x1A)
|
||||||
|
cm(DEC, Implied, 0x3A)
|
||||||
|
cm(JMP, AbsoluteIndexedX, 0x7C)
|
||||||
|
cm(WAI, Implied, 0xCB)
|
||||||
|
cm(STP, Implied, 0xDB)
|
||||||
|
|
||||||
|
ce(CPZ, Immediate, 0xC2)
|
||||||
|
ce(CPZ, ZeroPage, 0xD4)
|
||||||
|
ce(CPZ, Absolute, 0xDC)
|
||||||
|
ce(DEZ, Implied, 0x3B)
|
||||||
|
ce(INZ, Implied,0x1B )
|
||||||
|
ce(DEC_W, ZeroPage, 0xC3)
|
||||||
|
ce(INC_W, ZeroPage, 0xE3)
|
||||||
|
ce(ASL_W, Absolute, 0xCB)
|
||||||
|
// TODO: or is it ROL_W?
|
||||||
|
ce(ROR_W, Absolute, 0xEB)
|
||||||
|
ce(ASR, Implied, 0x43)
|
||||||
|
ce(ASR, ZeroPage, 0x44)
|
||||||
|
ce(ASR, ZeroPageX, 0x54)
|
||||||
|
ce(LDZ, Immediate, 0xA3)
|
||||||
|
ce(LDZ, Absolute, 0xAB)
|
||||||
|
ce(LDZ, AbsoluteX, 0xBB)
|
||||||
|
ce(TAB, Implied, 0x5B)
|
||||||
|
ce(TBA, Implied, 0x7B)
|
||||||
|
ce(TAZ, Implied, 0x4B)
|
||||||
|
ce(TZA, Implied, 0x6B)
|
||||||
|
ce(TSY, Implied, 0x0B)
|
||||||
|
ce(TYS, Implied, 0x2B)
|
||||||
|
ce(PHW, WordImmediate, 0xF4)
|
||||||
|
ce(PHW, Absolute, 0xFC)
|
||||||
|
ce(PHZ, Implied, 0xDB)
|
||||||
|
ce(PLZ, Implied, 0xFB)
|
||||||
|
// ce(CLE, Implied, )
|
||||||
|
// ce(SEE, Implied, )
|
||||||
|
// ce(BSR, , )
|
||||||
|
|
||||||
|
hu(CLY, Implied, 0xC2)
|
||||||
|
hu(CLX, Implied, 0x82)
|
||||||
|
hu(CLA, Implied, 0x62)
|
||||||
|
hu(CSH, Implied, 0xD4)
|
||||||
|
hu(CSL, Implied, 0x54)
|
||||||
|
hu(HuSAX, Implied, 0x22)
|
||||||
|
hu(SAY, Implied, 0x42)
|
||||||
|
hu(SXY, Implied, 0x02)
|
||||||
|
hu(TAM, Immediate, 0x53)
|
||||||
|
hu(TMA, Immediate, 0x43)
|
||||||
|
|
||||||
|
em(ORA, Stack, 0x03)
|
||||||
|
em(ORA, IndexedSY, 0x13)
|
||||||
|
na(ORA, LongIndexedZ, 0x07)
|
||||||
|
na(ORA, LongIndexedY, 0x17)
|
||||||
|
na(ORA, LongAbsolute, 0x0F)
|
||||||
|
na(ORA, LongAbsoluteX, 0x1F)
|
||||||
|
em(AND, Stack, 0x23)
|
||||||
|
em(AND, IndexedSY, 0x33)
|
||||||
|
na(AND, LongIndexedZ, 0x27)
|
||||||
|
na(AND, LongIndexedY, 0x37)
|
||||||
|
na(AND, LongAbsolute, 0x2F)
|
||||||
|
na(AND, LongAbsoluteX, 0x3F)
|
||||||
|
em(EOR, Stack, 0x43)
|
||||||
|
em(EOR, IndexedSY, 0x53)
|
||||||
|
na(EOR, LongIndexedZ, 0x47)
|
||||||
|
na(EOR, LongIndexedY, 0x57)
|
||||||
|
na(EOR, LongAbsolute, 0x4F)
|
||||||
|
na(EOR, LongAbsoluteX, 0x5F)
|
||||||
|
em(ADC, Stack, 0x63)
|
||||||
|
em(ADC, IndexedSY, 0x73)
|
||||||
|
na(ADC, LongIndexedZ, 0x67)
|
||||||
|
na(ADC, LongIndexedY, 0x77)
|
||||||
|
na(ADC, LongAbsolute, 0x6F)
|
||||||
|
na(ADC, LongAbsoluteX, 0x7F)
|
||||||
|
em(STA, Stack, 0x83)
|
||||||
|
em(STA, IndexedSY, 0x93)
|
||||||
|
na(STA, LongIndexedZ, 0x87)
|
||||||
|
na(STA, LongIndexedY, 0x97)
|
||||||
|
na(STA, LongAbsolute, 0x8F)
|
||||||
|
na(STA, LongAbsoluteX, 0x9F)
|
||||||
|
em(LDA, Stack, 0xA3)
|
||||||
|
em(LDA, IndexedSY, 0xB3)
|
||||||
|
na(LDA, LongIndexedZ, 0xA7)
|
||||||
|
na(LDA, LongIndexedY, 0xB7)
|
||||||
|
na(LDA, LongAbsolute, 0xAF)
|
||||||
|
na(LDA, LongAbsoluteX, 0xBF)
|
||||||
|
em(CMP, Stack, 0xA3)
|
||||||
|
em(CMP, IndexedSY, 0xB3)
|
||||||
|
na(CMP, LongIndexedZ, 0xA7)
|
||||||
|
na(CMP, LongIndexedY, 0xB7)
|
||||||
|
na(CMP, LongAbsolute, 0xAF)
|
||||||
|
na(CMP, LongAbsoluteX, 0xBF)
|
||||||
|
|
||||||
|
em(COP, Immediate, 0x02)
|
||||||
|
em(XBA, Implied, 0xEB)
|
||||||
|
em(TXY, Implied, 0x9B)
|
||||||
|
em(TYX, Implied, 0xBB)
|
||||||
|
|
||||||
|
|
||||||
|
na(RTL, Implied, 0x6B)
|
||||||
|
na(JMP, LongAbsolute, 0x5C)
|
||||||
|
na(JMP, LongIndirect, 0x7C)
|
||||||
|
na(BRL, LongRelative, 0x82)
|
||||||
|
|
||||||
|
em(PHD, Implied, 0x0B)
|
||||||
|
em(PLD, Implied, 0x2B)
|
||||||
|
em(PHB, Implied, 0x8B)
|
||||||
|
em(PLB, Implied, 0xAB)
|
||||||
|
em(PHK, Implied, 0x4B)
|
||||||
|
|
||||||
|
na(REP, Immediate, 0xC2)
|
||||||
|
na(SEP, Immediate, 0xE2)
|
||||||
|
|
||||||
|
na(XCE, Implied, 0xFB)
|
||||||
|
na(TCD, Implied, 0x5B)
|
||||||
|
na(TDC, Implied, 0x7B)
|
||||||
|
na(TSC, Implied, 0x3B)
|
||||||
|
na(TCS, Implied, 0x1B)
|
||||||
|
|
||||||
|
for {
|
||||||
|
((narrow, am), code) <- emulation65816Opcodes ++ opcodes ++ cmosOpcodes ++ native65816Opcodes
|
||||||
|
wide <- Opcode.widen(narrow)
|
||||||
|
} na(wide, if (am == Immediate) WordImmediate else am, code & 0xff)
|
||||||
|
|
||||||
|
}
|
@@ -1,8 +1,9 @@
|
|||||||
package millfork.output
|
package millfork.output
|
||||||
|
|
||||||
import millfork.assembly.{AddrMode, AssemblyLine, Opcode, OpcodeClasses}
|
import millfork.assembly.AddrMode
|
||||||
import millfork.assembly.Opcode._
|
import millfork.assembly.mos.Opcode._
|
||||||
import millfork.compiler.{ExpressionCompiler, MfCompiler}
|
import millfork.assembly.mos._
|
||||||
|
import millfork.compiler.AbstractCompiler
|
||||||
import millfork.env._
|
import millfork.env._
|
||||||
import millfork.node._
|
import millfork.node._
|
||||||
|
|
||||||
@@ -14,7 +15,7 @@ import scala.collection.mutable
|
|||||||
|
|
||||||
case class InliningResult(potentiallyInlineableFunctions: Map[String, Int], nonInlineableFunctions: Set[String])
|
case class InliningResult(potentiallyInlineableFunctions: Map[String, Int], nonInlineableFunctions: Set[String])
|
||||||
|
|
||||||
object InliningCalculator {
|
object MosInliningCalculator extends AbstractInliningCalculator[AssemblyLine] {
|
||||||
|
|
||||||
private val sizes = Seq(64, 64, 8, 6, 5, 5, 4)
|
private val sizes = Seq(64, 64, 8, 6, 5, 5, 4)
|
||||||
|
|
||||||
@@ -69,7 +70,7 @@ object InliningCalculator {
|
|||||||
case s: ArrayContents => getAllCalledFunctions(s.getAllExpressions)
|
case s: ArrayContents => getAllCalledFunctions(s.getAllExpressions)
|
||||||
case s: FunctionDeclarationStatement => getAllCalledFunctions(s.address.toList) ++ getAllCalledFunctions(s.statements.getOrElse(Nil))
|
case s: FunctionDeclarationStatement => getAllCalledFunctions(s.address.toList) ++ getAllCalledFunctions(s.statements.getOrElse(Nil))
|
||||||
case Assignment(VariableExpression(_), expr) => getAllCalledFunctions(expr :: Nil)
|
case Assignment(VariableExpression(_), expr) => getAllCalledFunctions(expr :: Nil)
|
||||||
case AssemblyStatement(JSR, _, VariableExpression(name), true) => (name -> false) :: Nil
|
case MosAssemblyStatement(JSR, _, VariableExpression(name), true) => (name -> false) :: Nil
|
||||||
case s: Statement => getAllCalledFunctions(s.getAllExpressions)
|
case s: Statement => getAllCalledFunctions(s.getAllExpressions)
|
||||||
case s: VariableExpression => Set(
|
case s: VariableExpression => Set(
|
||||||
s.name,
|
s.name,
|
||||||
@@ -110,4 +111,26 @@ object InliningCalculator {
|
|||||||
}) return None
|
}) return None
|
||||||
Some(result)
|
Some(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def inline(code: List[AssemblyLine], inlinedFunctions: Map[String, List[AssemblyLine]], compiler: AbstractCompiler[AssemblyLine]): List[AssemblyLine] = {
|
||||||
|
code.flatMap {
|
||||||
|
case AssemblyLine(Opcode.JSR, AddrMode.Absolute | AddrMode.LongAbsolute, p, true) if inlinedFunctions.contains(p.toString) =>
|
||||||
|
val labelPrefix = compiler.nextLabel("ai")
|
||||||
|
inlinedFunctions(p.toString).map {
|
||||||
|
case line@AssemblyLine(_, _, MemoryAddressConstant(Label(label)), _) =>
|
||||||
|
val newLabel = MemoryAddressConstant(Label(labelPrefix + label))
|
||||||
|
line.copy(parameter = newLabel)
|
||||||
|
case l => l
|
||||||
|
}
|
||||||
|
case AssemblyLine(Opcode.JMP, AddrMode.Absolute, p, true) if inlinedFunctions.contains(p.toString) =>
|
||||||
|
val labelPrefix = compiler.nextLabel("ai")
|
||||||
|
inlinedFunctions(p.toString).map {
|
||||||
|
case line@AssemblyLine(_, _, MemoryAddressConstant(Label(label)), _) =>
|
||||||
|
val newLabel = MemoryAddressConstant(Label(labelPrefix + label))
|
||||||
|
line.copy(parameter = newLabel)
|
||||||
|
case l => l
|
||||||
|
} :+ AssemblyLine.implied(Opcode.RTS)
|
||||||
|
case x => List(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@@ -9,26 +9,24 @@ import millfork.node.{ImportStatement, Position, Program}
|
|||||||
|
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
|
|
||||||
/**
|
abstract class AbstractSourceLoadingQueue[T](val initialFilenames: List[String],
|
||||||
* @author Karol Stasiak
|
val includePath: List[String],
|
||||||
*/
|
val options: CompilationOptions) {
|
||||||
class SourceLoadingQueue(val initialFilenames: List[String], val includePath: List[String], val options: CompilationOptions) {
|
|
||||||
|
|
||||||
private val parsedModules = mutable.Map[String, Program]()
|
protected val parsedModules: mutable.Map[String, Program] = mutable.Map[String, Program]()
|
||||||
private val moduleQueue = mutable.Queue[() => Unit]()
|
protected val moduleQueue: mutable.Queue[() => Unit] = mutable.Queue[() => Unit]()
|
||||||
val extension: String = ".mfk"
|
val extension: String = ".mfk"
|
||||||
|
|
||||||
|
def enqueueStandardModules(): Unit
|
||||||
|
|
||||||
def run(): Program = {
|
def run(): Program = {
|
||||||
initialFilenames.foreach { i =>
|
initialFilenames.foreach { i =>
|
||||||
parseModule(extractName(i), includePath, Right(i), options)
|
parseModule(extractName(i), includePath, Right(i))
|
||||||
}
|
}
|
||||||
options.platform.startingModules.foreach {m =>
|
options.platform.startingModules.foreach {m =>
|
||||||
moduleQueue.enqueue(() => parseModule(m, includePath, Left(None), options))
|
moduleQueue.enqueue(() => parseModule(m, includePath, Left(None)))
|
||||||
}
|
|
||||||
if (options.flag(CompilationFlag.ZeropagePseudoregister)) {
|
|
||||||
moduleQueue.enqueue(() => parseModule("zp_reg", includePath, Left(None), options))
|
|
||||||
}
|
}
|
||||||
|
enqueueStandardModules()
|
||||||
while (moduleQueue.nonEmpty) {
|
while (moduleQueue.nonEmpty) {
|
||||||
if (options.flag(CompilationFlag.SingleThreaded)) {
|
if (options.flag(CompilationFlag.SingleThreaded)) {
|
||||||
moduleQueue.dequeueAll(_ => true).foreach(_())
|
moduleQueue.dequeueAll(_ => true).foreach(_())
|
||||||
@@ -51,13 +49,15 @@ class SourceLoadingQueue(val initialFilenames: List[String], val includePath: Li
|
|||||||
ErrorReporting.fatal(s"Module `$moduleName` not found", position)
|
ErrorReporting.fatal(s"Module `$moduleName` not found", position)
|
||||||
}
|
}
|
||||||
|
|
||||||
def parseModule(moduleName: String, includePath: List[String], why: Either[Option[Position], String], options: CompilationOptions): Unit = {
|
def createParser(filename: String, src: String, parentDir: String) : MfParser[T]
|
||||||
|
|
||||||
|
def parseModule(moduleName: String, includePath: List[String], why: Either[Option[Position], String]): Unit = {
|
||||||
val filename: String = why.fold(p => lookupModuleFile(includePath, moduleName, p), s => s)
|
val filename: String = why.fold(p => lookupModuleFile(includePath, moduleName, p), s => s)
|
||||||
ErrorReporting.debug(s"Parsing $filename")
|
ErrorReporting.debug(s"Parsing $filename")
|
||||||
val path = Paths.get(filename)
|
val path = Paths.get(filename)
|
||||||
val parentDir = path.toFile.getAbsoluteFile.getParent
|
val parentDir = path.toFile.getAbsoluteFile.getParent
|
||||||
val src = new String(Files.readAllBytes(path))
|
val src = new String(Files.readAllBytes(path))
|
||||||
val parser = MfParser(filename, src, parentDir, options)
|
val parser = createParser(filename, src, parentDir)
|
||||||
parser.toAst match {
|
parser.toAst match {
|
||||||
case Success(prog, _) =>
|
case Success(prog, _) =>
|
||||||
parsedModules.synchronized {
|
parsedModules.synchronized {
|
||||||
@@ -65,7 +65,7 @@ class SourceLoadingQueue(val initialFilenames: List[String], val includePath: Li
|
|||||||
prog.declarations.foreach {
|
prog.declarations.foreach {
|
||||||
case s@ImportStatement(m) =>
|
case s@ImportStatement(m) =>
|
||||||
if (!parsedModules.contains(m)) {
|
if (!parsedModules.contains(m)) {
|
||||||
moduleQueue.enqueue(() => parseModule(m, parentDir :: includePath, Left(s.position), options))
|
moduleQueue.enqueue(() => parseModule(m, parentDir :: includePath, Left(s.position)))
|
||||||
}
|
}
|
||||||
case _ => ()
|
case _ => ()
|
||||||
}
|
}
|
@@ -3,7 +3,7 @@ package millfork.parser
|
|||||||
import java.nio.file.{Files, Paths}
|
import java.nio.file.{Files, Paths}
|
||||||
|
|
||||||
import fastparse.all._
|
import fastparse.all._
|
||||||
import millfork.assembly.{AddrMode, Opcode}
|
import millfork.assembly.mos.Opcode
|
||||||
import millfork.env._
|
import millfork.env._
|
||||||
import millfork.error.ErrorReporting
|
import millfork.error.ErrorReporting
|
||||||
import millfork.node._
|
import millfork.node._
|
||||||
@@ -12,7 +12,7 @@ import millfork.{CompilationOptions, SeparatedList}
|
|||||||
/**
|
/**
|
||||||
* @author Karol Stasiak
|
* @author Karol Stasiak
|
||||||
*/
|
*/
|
||||||
case class MfParser(filename: String, input: String, currentDirectory: String, options: CompilationOptions) {
|
abstract class MfParser[T](filename: String, input: String, currentDirectory: String, options: CompilationOptions) {
|
||||||
|
|
||||||
var lastPosition = Position(filename, 1, 1, 0)
|
var lastPosition = Position(filename, 1, 1, 0)
|
||||||
var lastLabel = ""
|
var lastLabel = ""
|
||||||
@@ -147,7 +147,7 @@ case class MfParser(filename: String, input: String, currentDirectory: String, o
|
|||||||
|
|
||||||
val atom: P[Expression] = P(literalAtom | (position() ~ identifier).map { case (p, i) => VariableExpression(i).pos(p) })
|
val atom: P[Expression] = P(literalAtom | (position() ~ identifier).map { case (p, i) => VariableExpression(i).pos(p) })
|
||||||
|
|
||||||
val mlOperators = List(
|
val mfOperators = List(
|
||||||
List("+=", "-=", "+'=", "-'=", "^=", "&=", "|=", "*=", "*'=", "<<=", ">>=", "<<'=", ">>'="),
|
List("+=", "-=", "+'=", "-'=", "^=", "&=", "|=", "*=", "*'=", "<<=", ">>=", "<<'=", ">>'="),
|
||||||
List("||", "^^"),
|
List("||", "^^"),
|
||||||
List("&&"),
|
List("&&"),
|
||||||
@@ -167,8 +167,8 @@ case class MfParser(filename: String, input: String, currentDirectory: String, o
|
|||||||
flags <- flags("const", "static", "volatile", "stack", "register") ~ HWS
|
flags <- flags("const", "static", "volatile", "stack", "register") ~ HWS
|
||||||
typ <- identifier ~ SWS
|
typ <- identifier ~ SWS
|
||||||
name <- identifier ~/ HWS ~/ Pass
|
name <- identifier ~/ HWS ~/ Pass
|
||||||
addr <- ("@" ~/ HWS ~/ mlExpression(1)).?.opaque("<address>") ~ HWS
|
addr <- ("@" ~/ HWS ~/ mfExpression(1)).?.opaque("<address>") ~ HWS
|
||||||
initialValue <- ("=" ~/ HWS ~/ mlExpression(1)).? ~ HWS
|
initialValue <- ("=" ~/ HWS ~/ mfExpression(1)).? ~ HWS
|
||||||
_ <- &(EOL) ~/ ""
|
_ <- &(EOL) ~/ ""
|
||||||
} yield {
|
} yield {
|
||||||
Seq(VariableDeclarationStatement(name, typ,
|
Seq(VariableDeclarationStatement(name, typ,
|
||||||
@@ -191,33 +191,9 @@ case class MfParser(filename: String, input: String, currentDirectory: String, o
|
|||||||
ParameterDeclaration(typ, ByVariable(name)).pos(p)
|
ParameterDeclaration(typ, ByVariable(name)).pos(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
val appcSimple: P[ParamPassingConvention] = P("xy" | "yx" | "ax" | "ay" | "xa" | "ya" | "stack" | "a" | "x" | "y").!.map {
|
def asmParamDefinition: P[ParameterDeclaration]
|
||||||
case "xy" => ByRegister(Register.XY)
|
|
||||||
case "yx" => ByRegister(Register.YX)
|
|
||||||
case "ax" => ByRegister(Register.AX)
|
|
||||||
case "ay" => ByRegister(Register.AY)
|
|
||||||
case "xa" => ByRegister(Register.XA)
|
|
||||||
case "ya" => ByRegister(Register.YA)
|
|
||||||
case "a" => ByRegister(Register.A)
|
|
||||||
case "x" => ByRegister(Register.X)
|
|
||||||
case "y" => ByRegister(Register.Y)
|
|
||||||
case x => ErrorReporting.fatal(s"Unknown assembly parameter passing convention: `$x`")
|
|
||||||
}
|
|
||||||
|
|
||||||
val appcComplex: P[ParamPassingConvention] = P((("const" | "ref").! ~/ AWS).? ~ AWS ~ identifier) map {
|
def arrayListElement: P[ArrayContents] = arrayStringContents | arrayLoopContents | mfExpression(nonStatementLevel).map(e => LiteralContents(List(e)))
|
||||||
case (None, name) => ByVariable(name)
|
|
||||||
case (Some("const"), name) => ByConstant(name)
|
|
||||||
case (Some("ref"), name) => ByReference(name)
|
|
||||||
case x => ErrorReporting.fatal(s"Unknown assembly parameter passing convention: `$x`")
|
|
||||||
}
|
|
||||||
|
|
||||||
val asmParamDefinition: P[ParameterDeclaration] = for {
|
|
||||||
p <- position()
|
|
||||||
typ <- identifier ~ SWS
|
|
||||||
appc <- appcSimple | appcComplex
|
|
||||||
} yield ParameterDeclaration(typ, appc).pos(p)
|
|
||||||
|
|
||||||
def arrayListElement: P[ArrayContents] = arrayStringContents | arrayLoopContents | mlExpression(nonStatementLevel).map(e => LiteralContents(List(e)))
|
|
||||||
|
|
||||||
def arrayListContents: P[ArrayContents] = ("[" ~/ AWS ~/ arrayListElement.rep(sep = AWS ~ "," ~/ AWS) ~ AWS ~ "]" ~/ Pass).map(c => CombinedContents(c.toList))
|
def arrayListContents: P[ArrayContents] = ("[" ~/ AWS ~/ arrayListElement.rep(sep = AWS ~ "," ~/ AWS) ~ AWS ~ "]" ~/ Pass).map(c => CombinedContents(c.toList))
|
||||||
|
|
||||||
@@ -265,10 +241,10 @@ case class MfParser(filename: String, input: String, currentDirectory: String, o
|
|||||||
|
|
||||||
def arrayLoopContents: P[ArrayContents] = for {
|
def arrayLoopContents: P[ArrayContents] = for {
|
||||||
identifier <- "for" ~ SWS ~/ identifier ~/ HWS ~ "," ~/ HWS ~ Pass
|
identifier <- "for" ~ SWS ~/ identifier ~/ HWS ~ "," ~/ HWS ~ Pass
|
||||||
start <- mlExpression(nonStatementLevel) ~ HWS ~ "," ~/ HWS ~/ Pass
|
start <- mfExpression(nonStatementLevel) ~ HWS ~ "," ~/ HWS ~/ Pass
|
||||||
pos <- position()
|
pos <- position()
|
||||||
direction <- forDirection ~/ HWS ~/ "," ~/ HWS ~/ Pass
|
direction <- forDirection ~/ HWS ~/ "," ~/ HWS ~/ Pass
|
||||||
end <- mlExpression(nonStatementLevel)
|
end <- mfExpression(nonStatementLevel)
|
||||||
body <- AWS ~ arrayContents
|
body <- AWS ~ arrayContents
|
||||||
} yield {
|
} yield {
|
||||||
val fixedDirection = direction match {
|
val fixedDirection = direction match {
|
||||||
@@ -291,21 +267,21 @@ case class MfParser(filename: String, input: String, currentDirectory: String, o
|
|||||||
p <- position()
|
p <- position()
|
||||||
bank <- bankDeclaration
|
bank <- bankDeclaration
|
||||||
name <- "array" ~ !letterOrDigit ~/ SWS ~ identifier ~ HWS
|
name <- "array" ~ !letterOrDigit ~/ SWS ~ identifier ~ HWS
|
||||||
length <- ("[" ~/ AWS ~/ mlExpression(nonStatementLevel) ~ AWS ~ "]").? ~ HWS
|
length <- ("[" ~/ AWS ~/ mfExpression(nonStatementLevel) ~ AWS ~ "]").? ~ HWS
|
||||||
addr <- ("@" ~/ HWS ~/ mlExpression(1)).? ~/ HWS
|
addr <- ("@" ~/ HWS ~/ mfExpression(1)).? ~/ HWS
|
||||||
contents <- ("=" ~/ HWS ~/ arrayContents).? ~/ HWS
|
contents <- ("=" ~/ HWS ~/ arrayContents).? ~/ HWS
|
||||||
} yield Seq(ArrayDeclarationStatement(name, bank, length, addr, contents).pos(p))
|
} yield Seq(ArrayDeclarationStatement(name, bank, length, addr, contents).pos(p))
|
||||||
|
|
||||||
def tightMlExpression: P[Expression] = P(mlParenExpr | functionCall | mlIndexedExpression | atom) // TODO
|
def tightMfExpression: P[Expression] = P(mfParenExpr | functionCall | mfIndexedExpression | atom) // TODO
|
||||||
|
|
||||||
def tightMlExpressionButNotCall: P[Expression] = P(mlParenExpr | mlIndexedExpression | atom) // TODO
|
def tightMfExpressionButNotCall: P[Expression] = P(mfParenExpr | mfIndexedExpression | atom) // TODO
|
||||||
|
|
||||||
def mlExpression(level: Int): P[Expression] = {
|
def mfExpression(level: Int): P[Expression] = {
|
||||||
val allowedOperators = mlOperators.drop(level).flatten
|
val allowedOperators = mfOperators.drop(level).flatten
|
||||||
|
|
||||||
def inner: P[SeparatedList[Expression, String]] = {
|
def inner: P[SeparatedList[Expression, String]] = {
|
||||||
for {
|
for {
|
||||||
head <- tightMlExpression ~/ HWS
|
head <- tightMfExpression ~/ HWS
|
||||||
maybeOperator <- StringIn(allowedOperators: _*).!.?
|
maybeOperator <- StringIn(allowedOperators: _*).!.?
|
||||||
maybeTail <- maybeOperator.fold[P[Option[List[(String, Expression)]]]](Pass.map(_ => None))(o => (HWS ~/ inner ~/ HWS).map(x2 => Some((o -> x2.head) :: x2.tail)))
|
maybeTail <- maybeOperator.fold[P[Option[List[(String, Expression)]]]](Pass.map(_ => None))(o => (HWS ~/ inner ~/ HWS).map(x2 => Some((o -> x2.head) :: x2.tail)))
|
||||||
} yield {
|
} yield {
|
||||||
@@ -314,9 +290,9 @@ case class MfParser(filename: String, input: String, currentDirectory: String, o
|
|||||||
}
|
}
|
||||||
|
|
||||||
def p(list: SeparatedList[Expression, String], level: Int): Expression =
|
def p(list: SeparatedList[Expression, String], level: Int): Expression =
|
||||||
if (level == mlOperators.length) list.head
|
if (level == mfOperators.length) list.head
|
||||||
else {
|
else {
|
||||||
val xs = list.split(mlOperators(level).toSet(_))
|
val xs = list.split(mfOperators(level).toSet(_))
|
||||||
xs.separators.distinct match {
|
xs.separators.distinct match {
|
||||||
case Nil =>
|
case Nil =>
|
||||||
if (xs.tail.nonEmpty)
|
if (xs.tail.nonEmpty)
|
||||||
@@ -344,32 +320,32 @@ case class MfParser(filename: String, input: String, currentDirectory: String, o
|
|||||||
inner.map(x => p(x, 0))
|
inner.map(x => p(x, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
def mlLhsExpressionSimple: P[LhsExpression] = mlIndexedExpression | (position() ~ identifier).map { case (p, n) => VariableExpression(n).pos(p) }
|
def mfLhsExpressionSimple: P[LhsExpression] = mfIndexedExpression | (position() ~ identifier).map { case (p, n) => VariableExpression(n).pos(p) }
|
||||||
|
|
||||||
def mlLhsExpression: P[LhsExpression] = for {
|
def mfLhsExpression: P[LhsExpression] = for {
|
||||||
(p, left) <- position() ~ mlLhsExpressionSimple
|
(p, left) <- position() ~ mfLhsExpressionSimple
|
||||||
rightOpt <- (HWS ~ ":" ~/ HWS ~ mlLhsExpressionSimple).?
|
rightOpt <- (HWS ~ ":" ~/ HWS ~ mfLhsExpressionSimple).?
|
||||||
} yield rightOpt.fold(left)(right => SeparateBytesExpression(left, right).pos(p))
|
} yield rightOpt.fold(left)(right => SeparateBytesExpression(left, right).pos(p))
|
||||||
|
|
||||||
|
|
||||||
def mlParenExpr: P[Expression] = P("(" ~/ AWS ~/ mlExpression(nonStatementLevel) ~ AWS ~/ ")")
|
def mfParenExpr: P[Expression] = P("(" ~/ AWS ~/ mfExpression(nonStatementLevel) ~ AWS ~/ ")")
|
||||||
|
|
||||||
def mlIndexedExpression: P[IndexedExpression] = for {
|
def mfIndexedExpression: P[IndexedExpression] = for {
|
||||||
p <- position()
|
p <- position()
|
||||||
array <- identifier
|
array <- identifier
|
||||||
index <- HWS ~ "[" ~/ AWS ~/ mlExpression(nonStatementLevel) ~ AWS ~/ "]"
|
index <- HWS ~ "[" ~/ AWS ~/ mfExpression(nonStatementLevel) ~ AWS ~/ "]"
|
||||||
} yield IndexedExpression(array, index).pos(p)
|
} yield IndexedExpression(array, index).pos(p)
|
||||||
|
|
||||||
def functionCall: P[FunctionCallExpression] = for {
|
def functionCall: P[FunctionCallExpression] = for {
|
||||||
p <- position()
|
p <- position()
|
||||||
name <- identifier
|
name <- identifier
|
||||||
params <- HWS ~ "(" ~/ AWS ~/ mlExpression(nonStatementLevel).rep(min = 0, sep = AWS ~ "," ~/ AWS) ~ AWS ~/ ")" ~/ ""
|
params <- HWS ~ "(" ~/ AWS ~/ mfExpression(nonStatementLevel).rep(min = 0, sep = AWS ~ "," ~/ AWS) ~ AWS ~/ ")" ~/ ""
|
||||||
} yield FunctionCallExpression(name, params.toList).pos(p)
|
} yield FunctionCallExpression(name, params.toList).pos(p)
|
||||||
|
|
||||||
val expressionStatement: P[Seq[ExecutableStatement]] = mlExpression(0).map(x => Seq(ExpressionStatement(x)))
|
val expressionStatement: P[Seq[ExecutableStatement]] = mfExpression(0).map(x => Seq(ExpressionStatement(x)))
|
||||||
|
|
||||||
val assignmentStatement: P[Seq[ExecutableStatement]] =
|
val assignmentStatement: P[Seq[ExecutableStatement]] =
|
||||||
(position() ~ mlLhsExpression ~ HWS ~ "=" ~/ HWS ~ mlExpression(1)).map {
|
(position() ~ mfLhsExpression ~ HWS ~ "=" ~/ HWS ~ mfExpression(1)).map {
|
||||||
case (p, l, r) => Seq(Assignment(l, r).pos(p))
|
case (p, l, r) => Seq(Assignment(l, r).pos(p))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -386,65 +362,7 @@ case class MfParser(filename: String, input: String, currentDirectory: String, o
|
|||||||
|
|
||||||
def executableStatement: P[Seq[ExecutableStatement]] = (position() ~ P(keywordStatement | expressionStatement)).map { case (p, s) => s.map(_.pos(p)) }
|
def executableStatement: P[Seq[ExecutableStatement]] = (position() ~ P(keywordStatement | expressionStatement)).map { case (p, s) => s.map(_.pos(p)) }
|
||||||
|
|
||||||
// TODO: label and instruction in one line
|
def asmStatement: P[ExecutableStatement]
|
||||||
def asmLabel: P[ExecutableStatement] = (identifier ~ HWS ~ ":" ~/ HWS).map(l => AssemblyStatement(Opcode.LABEL, AddrMode.DoesNotExist, VariableExpression(l), elidable = true))
|
|
||||||
|
|
||||||
// def zeropageAddrModeHint: P[Option[Boolean]] = Pass
|
|
||||||
|
|
||||||
def asmOpcode: P[Opcode.Value] = (position() ~ letter.rep(exactly = 3).! ~ ("_W" | "_w").?.!).map { case (p, suffix, o) => Opcode.lookup(o + suffix, Some(p)) }
|
|
||||||
|
|
||||||
def asmExpression: P[Expression] = (position() ~ NoCut(
|
|
||||||
("<" ~/ HWS ~ mlExpression(mathLevel)).map(e => HalfWordExpression(e, hiByte = false)) |
|
|
||||||
(">" ~/ HWS ~ mlExpression(mathLevel)).map(e => HalfWordExpression(e, hiByte = true)) |
|
|
||||||
mlExpression(mathLevel)
|
|
||||||
)).map { case (p, e) => e.pos(p) }
|
|
||||||
|
|
||||||
private val commaX = HWS ~ "," ~ HWS ~ ("X" | "x") ~ HWS
|
|
||||||
private val commaY = HWS ~ "," ~ HWS ~ ("Y" | "y") ~ HWS
|
|
||||||
private val commaZ = HWS ~ "," ~ HWS ~ ("Z" | "z") ~ HWS
|
|
||||||
private val commaS = HWS ~ "," ~ HWS ~ ("S" | "s") ~ HWS
|
|
||||||
|
|
||||||
val farKeyword: P[Unit] = P(("f" | "F") ~ ("a" | "A") ~ ("r" | "R"))
|
|
||||||
|
|
||||||
def asmParameter: P[(AddrMode.Value, Expression)] = {
|
|
||||||
(SWS ~ (
|
|
||||||
("##" ~ asmExpression).map(AddrMode.WordImmediate -> _) |
|
|
||||||
("#" ~ asmExpression).map(AddrMode.Immediate -> _) |
|
|
||||||
("(" ~ HWS ~ asmExpression ~ HWS ~ ")" ~ commaY).map(AddrMode.IndexedY -> _) |
|
|
||||||
(farKeyword ~ HWS ~ "(" ~ HWS ~ asmExpression ~ HWS ~ ")" ~ commaY).map(AddrMode.LongIndexedY -> _) |
|
|
||||||
("(" ~ HWS ~ asmExpression ~ commaS ~ ")" ~ commaY).map(AddrMode.IndexedSY -> _) |
|
|
||||||
("(" ~ HWS ~ asmExpression ~ HWS ~ ")" ~ commaZ).map(AddrMode.IndexedZ -> _) |
|
|
||||||
("(" ~ HWS ~ asmExpression ~ commaX ~ ")").map(AddrMode.IndexedX -> _) |
|
|
||||||
("(" ~ HWS ~ asmExpression ~ HWS ~ ")").map(AddrMode.Indirect -> _) |
|
|
||||||
(farKeyword ~ HWS ~ "(" ~ HWS ~ asmExpression ~ HWS ~ ")").map(AddrMode.LongIndexedZ -> _) |
|
|
||||||
(farKeyword ~ HWS ~ asmExpression ~ commaX).map(AddrMode.LongAbsoluteX -> _) |
|
|
||||||
(farKeyword ~ HWS ~ asmExpression).map(AddrMode.LongAbsolute -> _) |
|
|
||||||
(asmExpression ~ commaS).map(AddrMode.Stack -> _) |
|
|
||||||
(asmExpression ~ commaX).map(AddrMode.AbsoluteX -> _) |
|
|
||||||
(asmExpression ~ commaY).map(AddrMode.AbsoluteY -> _) |
|
|
||||||
asmExpression.map(AddrMode.Absolute -> _)
|
|
||||||
)).?.map(_.getOrElse(AddrMode.Implied -> LiteralExpression(0, 1)))
|
|
||||||
}
|
|
||||||
|
|
||||||
def elidable: P[Boolean] = ("?".! ~/ HWS).?.map(_.isDefined)
|
|
||||||
|
|
||||||
def asmInstruction: P[ExecutableStatement] = {
|
|
||||||
val lineParser: P[(Boolean, Opcode.Value, (AddrMode.Value, Expression))] = !"}" ~ elidable ~/ asmOpcode ~/ asmParameter
|
|
||||||
lineParser.map { case (elid, op, param) =>
|
|
||||||
(op, param._1) match {
|
|
||||||
case (Opcode.SAX, AddrMode.Implied) => AssemblyStatement(Opcode.HuSAX, param._1, param._2, elid)
|
|
||||||
case (Opcode.SBX, AddrMode.Immediate) => AssemblyStatement(Opcode.SBX, param._1, param._2, elid)
|
|
||||||
case (Opcode.SAY, AddrMode.AbsoluteX) => AssemblyStatement(Opcode.SHY, param._1, param._2, elid)
|
|
||||||
case (Opcode.SBX, _) => AssemblyStatement(Opcode.SAX, param._1, param._2, elid)
|
|
||||||
case (_, AddrMode.Indirect) if op != Opcode.JMP && op != Opcode.JSR => AssemblyStatement(op, AddrMode.IndexedZ, param._2, elid)
|
|
||||||
case _ => AssemblyStatement(op, param._1, param._2, elid)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def asmMacro: P[ExecutableStatement] = ("+" ~/ HWS ~/ functionCall).map(ExpressionStatement)
|
|
||||||
|
|
||||||
def asmStatement: P[ExecutableStatement] = (position("assembly statement") ~ P(asmLabel | asmMacro | arrayContentsForAsm | asmInstruction)).map { case (p, s) => s.pos(p) } // TODO: macros
|
|
||||||
|
|
||||||
def statement: P[Seq[Statement]] = (position() ~ P(keywordStatement | variableDefinition(false) | expressionStatement)).map { case (p, s) => s.map(_.pos(p)) }
|
def statement: P[Seq[Statement]] = (position() ~ P(keywordStatement | variableDefinition(false) | expressionStatement)).map { case (p, s) => s.map(_.pos(p)) }
|
||||||
|
|
||||||
@@ -455,7 +373,7 @@ case class MfParser(filename: String, input: String, currentDirectory: String, o
|
|||||||
def executableStatements: P[Seq[ExecutableStatement]] = ("{" ~/ AWS ~/ executableStatement.rep(sep = NoCut(EOL) ~ !"}" ~/ Pass) ~/ AWS ~ "}").map(_.flatten)
|
def executableStatements: P[Seq[ExecutableStatement]] = ("{" ~/ AWS ~/ executableStatement.rep(sep = NoCut(EOL) ~ !"}" ~/ Pass) ~/ AWS ~ "}").map(_.flatten)
|
||||||
|
|
||||||
def dispatchLabel: P[ReturnDispatchLabel] =
|
def dispatchLabel: P[ReturnDispatchLabel] =
|
||||||
("default" ~ !letterOrDigit ~/ AWS ~/ ("(" ~/ position("default branch range") ~ AWS ~/ mlExpression(nonStatementLevel).rep(min = 0, sep = AWS ~ "," ~/ AWS) ~ AWS ~/ ")" ~/ "").?).map{
|
("default" ~ !letterOrDigit ~/ AWS ~/ ("(" ~/ position("default branch range") ~ AWS ~/ mfExpression(nonStatementLevel).rep(min = 0, sep = AWS ~ "," ~/ AWS) ~ AWS ~/ ")" ~/ "").?).map{
|
||||||
case None => DefaultReturnDispatchLabel(None, None)
|
case None => DefaultReturnDispatchLabel(None, None)
|
||||||
case Some((_, Seq())) => DefaultReturnDispatchLabel(None, None)
|
case Some((_, Seq())) => DefaultReturnDispatchLabel(None, None)
|
||||||
case Some((_, Seq(e))) => DefaultReturnDispatchLabel(None, Some(e))
|
case Some((_, Seq(e))) => DefaultReturnDispatchLabel(None, Some(e))
|
||||||
@@ -463,38 +381,38 @@ case class MfParser(filename: String, input: String, currentDirectory: String, o
|
|||||||
case Some((pos, _)) =>
|
case Some((pos, _)) =>
|
||||||
ErrorReporting.error("Invalid default branch declaration", Some(pos))
|
ErrorReporting.error("Invalid default branch declaration", Some(pos))
|
||||||
DefaultReturnDispatchLabel(None, None)
|
DefaultReturnDispatchLabel(None, None)
|
||||||
} | mlExpression(nonStatementLevel).rep(min = 0, sep = AWS ~ "," ~/ AWS).map(exprs => StandardReturnDispatchLabel(exprs.toList))
|
} | mfExpression(nonStatementLevel).rep(min = 0, sep = AWS ~ "," ~/ AWS).map(exprs => StandardReturnDispatchLabel(exprs.toList))
|
||||||
|
|
||||||
def dispatchBranch: P[ReturnDispatchBranch] = for {
|
def dispatchBranch: P[ReturnDispatchBranch] = for {
|
||||||
pos <- position()
|
pos <- position()
|
||||||
l <- dispatchLabel ~/ HWS ~/ "@" ~/ HWS
|
l <- dispatchLabel ~/ HWS ~/ "@" ~/ HWS
|
||||||
f <- tightMlExpressionButNotCall ~/ HWS
|
f <- tightMfExpressionButNotCall ~/ HWS
|
||||||
parameters <- ("(" ~/ position("dispatch actual parameters") ~ AWS ~/ mlExpression(nonStatementLevel).rep(min = 0, sep = AWS ~ "," ~/ AWS) ~ AWS ~/ ")" ~/ "").?
|
parameters <- ("(" ~/ position("dispatch actual parameters") ~ AWS ~/ mfExpression(nonStatementLevel).rep(min = 0, sep = AWS ~ "," ~/ AWS) ~ AWS ~/ ")" ~/ "").?
|
||||||
} yield ReturnDispatchBranch(l, f, parameters.map(_._2.toList).getOrElse(Nil)).pos(pos)
|
} yield ReturnDispatchBranch(l, f, parameters.map(_._2.toList).getOrElse(Nil)).pos(pos)
|
||||||
|
|
||||||
def dispatchStatementBody: P[Seq[ExecutableStatement]] = for {
|
def dispatchStatementBody: P[Seq[ExecutableStatement]] = for {
|
||||||
indexer <- "[" ~/ AWS ~/ mlExpression(nonStatementLevel) ~/ AWS ~/ "]" ~/ AWS
|
indexer <- "[" ~/ AWS ~/ mfExpression(nonStatementLevel) ~/ AWS ~/ "]" ~/ AWS
|
||||||
_ <- position("dispatch statement body")
|
_ <- position("dispatch statement body")
|
||||||
parameters <- ("(" ~/ position("dispatch parameters") ~ AWS ~/ mlLhsExpression.rep(min = 0, sep = AWS ~ "," ~/ AWS) ~ AWS ~/ ")" ~/ "").?
|
parameters <- ("(" ~/ position("dispatch parameters") ~ AWS ~/ mfLhsExpression.rep(min = 0, sep = AWS ~ "," ~/ AWS) ~ AWS ~/ ")" ~/ "").?
|
||||||
_ <- AWS ~/ position("dispatch statement body") ~/ "{" ~/ AWS
|
_ <- AWS ~/ position("dispatch statement body") ~/ "{" ~/ AWS
|
||||||
branches <- dispatchBranch.rep(sep = EOL ~ !"}" ~/ Pass)
|
branches <- dispatchBranch.rep(sep = EOL ~ !"}" ~/ Pass)
|
||||||
_ <- AWS ~/ "}"
|
_ <- AWS ~/ "}"
|
||||||
} yield Seq(ReturnDispatchStatement(indexer, parameters.map(_._2.toList).getOrElse(Nil), branches.toList))
|
} yield Seq(ReturnDispatchStatement(indexer, parameters.map(_._2.toList).getOrElse(Nil), branches.toList))
|
||||||
|
|
||||||
def returnOrDispatchStatement: P[Seq[ExecutableStatement]] = "return" ~ !letterOrDigit ~/ HWS ~ (dispatchStatementBody | mlExpression(nonStatementLevel).?.map(ReturnStatement).map(Seq(_)))
|
def returnOrDispatchStatement: P[Seq[ExecutableStatement]] = "return" ~ !letterOrDigit ~/ HWS ~ (dispatchStatementBody | mfExpression(nonStatementLevel).?.map(ReturnStatement).map(Seq(_)))
|
||||||
|
|
||||||
def breakStatement: P[Seq[ExecutableStatement]] = ("break" ~ !letterOrDigit ~/ HWS ~ identifier.?).map(l => Seq(BreakStatement(l.getOrElse(""))))
|
def breakStatement: P[Seq[ExecutableStatement]] = ("break" ~ !letterOrDigit ~/ HWS ~ identifier.?).map(l => Seq(BreakStatement(l.getOrElse(""))))
|
||||||
|
|
||||||
def continueStatement: P[Seq[ExecutableStatement]] = ("continue" ~ !letterOrDigit ~/ HWS ~ identifier.?).map(l => Seq(ContinueStatement(l.getOrElse(""))))
|
def continueStatement: P[Seq[ExecutableStatement]] = ("continue" ~ !letterOrDigit ~/ HWS ~ identifier.?).map(l => Seq(ContinueStatement(l.getOrElse(""))))
|
||||||
|
|
||||||
def ifStatement: P[Seq[ExecutableStatement]] = for {
|
def ifStatement: P[Seq[ExecutableStatement]] = for {
|
||||||
condition <- "if" ~ !letterOrDigit ~/ HWS ~/ mlExpression(nonStatementLevel)
|
condition <- "if" ~ !letterOrDigit ~/ HWS ~/ mfExpression(nonStatementLevel)
|
||||||
thenBranch <- AWS ~/ executableStatements
|
thenBranch <- AWS ~/ executableStatements
|
||||||
elseBranch <- (AWS ~ "else" ~/ AWS ~/ (ifStatement | executableStatements)).?
|
elseBranch <- (AWS ~ "else" ~/ AWS ~/ (ifStatement | executableStatements)).?
|
||||||
} yield Seq(IfStatement(condition, thenBranch.toList, elseBranch.getOrElse(Nil).toList))
|
} yield Seq(IfStatement(condition, thenBranch.toList, elseBranch.getOrElse(Nil).toList))
|
||||||
|
|
||||||
def whileStatement: P[Seq[ExecutableStatement]] = for {
|
def whileStatement: P[Seq[ExecutableStatement]] = for {
|
||||||
condition <- "while" ~ !letterOrDigit ~/ HWS ~/ mlExpression(nonStatementLevel)
|
condition <- "while" ~ !letterOrDigit ~/ HWS ~/ mfExpression(nonStatementLevel)
|
||||||
body <- AWS ~ executableStatements
|
body <- AWS ~ executableStatements
|
||||||
} yield Seq(WhileStatement(condition, body.toList, Nil))
|
} yield Seq(WhileStatement(condition, body.toList, Nil))
|
||||||
|
|
||||||
@@ -507,9 +425,9 @@ case class MfParser(filename: String, input: String, currentDirectory: String, o
|
|||||||
|
|
||||||
def forStatement: P[Seq[ExecutableStatement]] = for {
|
def forStatement: P[Seq[ExecutableStatement]] = for {
|
||||||
identifier <- "for" ~ SWS ~/ identifier ~/ HWS ~ "," ~/ HWS ~ Pass
|
identifier <- "for" ~ SWS ~/ identifier ~/ HWS ~ "," ~/ HWS ~ Pass
|
||||||
start <- mlExpression(nonStatementLevel) ~ HWS ~ "," ~/ HWS ~/ Pass
|
start <- mfExpression(nonStatementLevel) ~ HWS ~ "," ~/ HWS ~/ Pass
|
||||||
direction <- forDirection ~/ HWS ~/ "," ~/ HWS ~/ Pass
|
direction <- forDirection ~/ HWS ~/ "," ~/ HWS ~/ Pass
|
||||||
end <- mlExpression(nonStatementLevel)
|
end <- mfExpression(nonStatementLevel)
|
||||||
body <- AWS ~ executableStatements
|
body <- AWS ~ executableStatements
|
||||||
} yield Seq(ForStatement(identifier, start, end, direction, body.toList))
|
} yield Seq(ForStatement(identifier, start, end, direction, body.toList))
|
||||||
|
|
||||||
@@ -521,7 +439,7 @@ case class MfParser(filename: String, input: String, currentDirectory: String, o
|
|||||||
//noinspection MutatorLikeMethodIsParameterless
|
//noinspection MutatorLikeMethodIsParameterless
|
||||||
def doWhileStatement: P[Seq[ExecutableStatement]] = for {
|
def doWhileStatement: P[Seq[ExecutableStatement]] = for {
|
||||||
body <- "do" ~ !letterOrDigit ~/ AWS ~ executableStatements ~/ AWS
|
body <- "do" ~ !letterOrDigit ~/ AWS ~ executableStatements ~/ AWS
|
||||||
condition <- "while" ~ !letterOrDigit ~/ HWS ~/ mlExpression(nonStatementLevel)
|
condition <- "while" ~ !letterOrDigit ~/ HWS ~/ mfExpression(nonStatementLevel)
|
||||||
} yield Seq(DoWhileStatement(body.toList, Nil, condition))
|
} yield Seq(DoWhileStatement(body.toList, Nil, condition))
|
||||||
|
|
||||||
|
|
||||||
@@ -536,7 +454,7 @@ case class MfParser(filename: String, input: String, currentDirectory: String, o
|
|||||||
returnType <- identifier ~ SWS
|
returnType <- identifier ~ SWS
|
||||||
name <- identifier ~ HWS
|
name <- identifier ~ HWS
|
||||||
params <- "(" ~/ AWS ~/ (if (flags("asm")) asmParamDefinition else paramDefinition).rep(sep = AWS ~ "," ~/ AWS) ~ AWS ~ ")" ~/ AWS
|
params <- "(" ~/ AWS ~/ (if (flags("asm")) asmParamDefinition else paramDefinition).rep(sep = AWS ~ "," ~/ AWS) ~ AWS ~ ")" ~/ AWS
|
||||||
addr <- ("@" ~/ HWS ~/ mlExpression(1)).?.opaque("<address>") ~/ AWS
|
addr <- ("@" ~/ HWS ~/ mfExpression(1)).?.opaque("<address>") ~/ AWS
|
||||||
statements <- (externFunctionBody | (if (flags("asm")) asmStatements else statements).map(l => Some(l))) ~/ Pass
|
statements <- (externFunctionBody | (if (flags("asm")) asmStatements else statements).map(l => Some(l))) ~/ Pass
|
||||||
} yield {
|
} yield {
|
||||||
if (flags("interrupt") && flags("macro")) ErrorReporting.error(s"Interrupt function `$name` cannot be macros", Some(p))
|
if (flags("interrupt") && flags("macro")) ErrorReporting.error(s"Interrupt function `$name` cannot be macros", Some(p))
|
||||||
@@ -550,32 +468,7 @@ case class MfParser(filename: String, input: String, currentDirectory: String, o
|
|||||||
if (flags("interrupt") && returnType != "void") ErrorReporting.error("Interrupt function `$name` has to return void", Some(p))
|
if (flags("interrupt") && returnType != "void") ErrorReporting.error("Interrupt function `$name` has to return void", Some(p))
|
||||||
if (addr.isEmpty && statements.isEmpty) ErrorReporting.error("Extern function `$name` must have an address", Some(p))
|
if (addr.isEmpty && statements.isEmpty) ErrorReporting.error("Extern function `$name` must have an address", Some(p))
|
||||||
if (statements.isEmpty && !flags("asm") && params.nonEmpty) ErrorReporting.error("Extern non-asm function `$name` cannot have parameters", Some(p))
|
if (statements.isEmpty && !flags("asm") && params.nonEmpty) ErrorReporting.error("Extern non-asm function `$name` cannot have parameters", Some(p))
|
||||||
if (flags("asm")) statements match {
|
if (flags("asm")) validateAsmFunctionBody(p, flags, name, statements)
|
||||||
case Some(Nil) => ErrorReporting.warn("Assembly function `$name` is empty, did you mean RTS or RTI", options, Some(p))
|
|
||||||
case Some(xs) =>
|
|
||||||
if (flags("interrupt")) {
|
|
||||||
if (xs.exists {
|
|
||||||
case AssemblyStatement(Opcode.RTS, _, _, _) => true
|
|
||||||
case _ => false
|
|
||||||
}) ErrorReporting.warn("Assembly interrupt function `$name` contains RTS, did you mean RTI?", options, Some(p))
|
|
||||||
} else {
|
|
||||||
if (xs.exists {
|
|
||||||
case AssemblyStatement(Opcode.RTI, _, _, _) => true
|
|
||||||
case _ => false
|
|
||||||
}) ErrorReporting.warn("Assembly non-interrupt function `$name` contains RTI, did you mean RTS?", options, Some(p))
|
|
||||||
}
|
|
||||||
if (!name.startsWith("__") && !flags("macro")) {
|
|
||||||
xs.last match {
|
|
||||||
case AssemblyStatement(Opcode.RTS, _, _, _) => () // OK
|
|
||||||
case AssemblyStatement(Opcode.RTI, _, _, _) => () // OK
|
|
||||||
case AssemblyStatement(Opcode.JMP, _, _, _) => () // OK
|
|
||||||
case _ =>
|
|
||||||
val validReturn = if (flags("interrupt")) "RTI" else "RTS"
|
|
||||||
ErrorReporting.warn(s"Non-macro assembly function `$name` should end in " + validReturn, options, Some(p))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case None => ()
|
|
||||||
}
|
|
||||||
Seq(FunctionDeclarationStatement(name, returnType, params.toList,
|
Seq(FunctionDeclarationStatement(name, returnType, params.toList,
|
||||||
bank,
|
bank,
|
||||||
addr,
|
addr,
|
||||||
@@ -588,6 +481,8 @@ case class MfParser(filename: String, input: String, currentDirectory: String, o
|
|||||||
flags("reentrant")).pos(p))
|
flags("reentrant")).pos(p))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def validateAsmFunctionBody(p: Position, flags: Set[String], name: String, statements: Option[List[Statement]])
|
||||||
|
|
||||||
def importStatement: Parser[Seq[ImportStatement]] = ("import" ~ !letterOrDigit ~/ SWS ~/ identifier).map(x => Seq(ImportStatement(x)))
|
def importStatement: Parser[Seq[ImportStatement]] = ("import" ~ !letterOrDigit ~/ SWS ~/ identifier).map(x => Seq(ImportStatement(x)))
|
||||||
|
|
||||||
def program: Parser[Program] = for {
|
def program: Parser[Program] = for {
|
||||||
|
132
src/main/scala/millfork/parser/MosParser.scala
Normal file
132
src/main/scala/millfork/parser/MosParser.scala
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
package millfork.parser
|
||||||
|
|
||||||
|
import fastparse.all._
|
||||||
|
import millfork.assembly.AddrMode
|
||||||
|
import millfork.assembly.mos.Opcode
|
||||||
|
import millfork.assembly.mos.AssemblyLine
|
||||||
|
import millfork.env._
|
||||||
|
import millfork.error.ErrorReporting
|
||||||
|
import millfork.node._
|
||||||
|
import millfork.CompilationOptions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Karol Stasiak
|
||||||
|
*/
|
||||||
|
case class MosParser(filename: String, input: String, currentDirectory: String, options: CompilationOptions) extends MfParser[AssemblyLine](filename, input, currentDirectory, options) {
|
||||||
|
|
||||||
|
// TODO: label and instruction in one line
|
||||||
|
def asmLabel: P[ExecutableStatement] = (identifier ~ HWS ~ ":" ~/ HWS).map(l => MosAssemblyStatement(Opcode.LABEL, AddrMode.DoesNotExist, VariableExpression(l), elidable = true))
|
||||||
|
|
||||||
|
// def zeropageAddrModeHint: P[Option[Boolean]] = Pass
|
||||||
|
|
||||||
|
def asmOpcode: P[Opcode.Value] = (position() ~ letter.rep(exactly = 3).! ~ ("_W" | "_w").?.!).map { case (p, suffix, o) => Opcode.lookup(o + suffix, Some(p)) }
|
||||||
|
|
||||||
|
def asmExpression: P[Expression] = (position() ~ NoCut(
|
||||||
|
("<" ~/ HWS ~ mfExpression(mathLevel)).map(e => HalfWordExpression(e, hiByte = false)) |
|
||||||
|
(">" ~/ HWS ~ mfExpression(mathLevel)).map(e => HalfWordExpression(e, hiByte = true)) |
|
||||||
|
mfExpression(mathLevel)
|
||||||
|
)).map { case (p, e) => e.pos(p) }
|
||||||
|
|
||||||
|
private val commaX = HWS ~ "," ~ HWS ~ ("X" | "x") ~ HWS
|
||||||
|
private val commaY = HWS ~ "," ~ HWS ~ ("Y" | "y") ~ HWS
|
||||||
|
private val commaZ = HWS ~ "," ~ HWS ~ ("Z" | "z") ~ HWS
|
||||||
|
private val commaS = HWS ~ "," ~ HWS ~ ("S" | "s") ~ HWS
|
||||||
|
|
||||||
|
val farKeyword: P[Unit] = P(("f" | "F") ~ ("a" | "A") ~ ("r" | "R"))
|
||||||
|
|
||||||
|
def asmParameter: P[(AddrMode.Value, Expression)] = {
|
||||||
|
(SWS ~ (
|
||||||
|
("##" ~ asmExpression).map(AddrMode.WordImmediate -> _) |
|
||||||
|
("#" ~ asmExpression).map(AddrMode.Immediate -> _) |
|
||||||
|
("(" ~ HWS ~ asmExpression ~ HWS ~ ")" ~ commaY).map(AddrMode.IndexedY -> _) |
|
||||||
|
(farKeyword ~ HWS ~ "(" ~ HWS ~ asmExpression ~ HWS ~ ")" ~ commaY).map(AddrMode.LongIndexedY -> _) |
|
||||||
|
("(" ~ HWS ~ asmExpression ~ commaS ~ ")" ~ commaY).map(AddrMode.IndexedSY -> _) |
|
||||||
|
("(" ~ HWS ~ asmExpression ~ HWS ~ ")" ~ commaZ).map(AddrMode.IndexedZ -> _) |
|
||||||
|
("(" ~ HWS ~ asmExpression ~ commaX ~ ")").map(AddrMode.IndexedX -> _) |
|
||||||
|
("(" ~ HWS ~ asmExpression ~ HWS ~ ")").map(AddrMode.Indirect -> _) |
|
||||||
|
(farKeyword ~ HWS ~ "(" ~ HWS ~ asmExpression ~ HWS ~ ")").map(AddrMode.LongIndexedZ -> _) |
|
||||||
|
(farKeyword ~ HWS ~ asmExpression ~ commaX).map(AddrMode.LongAbsoluteX -> _) |
|
||||||
|
(farKeyword ~ HWS ~ asmExpression).map(AddrMode.LongAbsolute -> _) |
|
||||||
|
(asmExpression ~ commaS).map(AddrMode.Stack -> _) |
|
||||||
|
(asmExpression ~ commaX).map(AddrMode.AbsoluteX -> _) |
|
||||||
|
(asmExpression ~ commaY).map(AddrMode.AbsoluteY -> _) |
|
||||||
|
asmExpression.map(AddrMode.Absolute -> _)
|
||||||
|
)).?.map(_.getOrElse(AddrMode.Implied -> LiteralExpression(0, 1)))
|
||||||
|
}
|
||||||
|
|
||||||
|
def elidable: P[Boolean] = ("?".! ~/ HWS).?.map(_.isDefined)
|
||||||
|
|
||||||
|
def asmInstruction: P[ExecutableStatement] = {
|
||||||
|
val lineParser: P[(Boolean, Opcode.Value, (AddrMode.Value, Expression))] = !"}" ~ elidable ~/ asmOpcode ~/ asmParameter
|
||||||
|
lineParser.map { case (elid, op, param) =>
|
||||||
|
(op, param._1) match {
|
||||||
|
case (Opcode.SAX, AddrMode.Implied) => MosAssemblyStatement(Opcode.HuSAX, param._1, param._2, elid)
|
||||||
|
case (Opcode.SBX, AddrMode.Immediate) => MosAssemblyStatement(Opcode.SBX, param._1, param._2, elid)
|
||||||
|
case (Opcode.SAY, AddrMode.AbsoluteX) => MosAssemblyStatement(Opcode.SHY, param._1, param._2, elid)
|
||||||
|
case (Opcode.SBX, _) => MosAssemblyStatement(Opcode.SAX, param._1, param._2, elid)
|
||||||
|
case (_, AddrMode.Indirect) if op != Opcode.JMP && op != Opcode.JSR => MosAssemblyStatement(op, AddrMode.IndexedZ, param._2, elid)
|
||||||
|
case _ => MosAssemblyStatement(op, param._1, param._2, elid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def asmMacro: P[ExecutableStatement] = ("+" ~/ HWS ~/ functionCall).map(ExpressionStatement)
|
||||||
|
|
||||||
|
def asmStatement: P[ExecutableStatement] = (position("assembly statement") ~ P(asmLabel | asmMacro | arrayContentsForAsm | asmInstruction)).map { case (p, s) => s.pos(p) } // TODO: macros
|
||||||
|
|
||||||
|
|
||||||
|
val appcSimple: P[ParamPassingConvention] = P("xy" | "yx" | "ax" | "ay" | "xa" | "ya" | "stack" | "a" | "x" | "y").!.map {
|
||||||
|
case "xy" => ByRegister(MosRegister.XY)
|
||||||
|
case "yx" => ByRegister(MosRegister.YX)
|
||||||
|
case "ax" => ByRegister(MosRegister.AX)
|
||||||
|
case "ay" => ByRegister(MosRegister.AY)
|
||||||
|
case "xa" => ByRegister(MosRegister.XA)
|
||||||
|
case "ya" => ByRegister(MosRegister.YA)
|
||||||
|
case "a" => ByRegister(MosRegister.A)
|
||||||
|
case "x" => ByRegister(MosRegister.X)
|
||||||
|
case "y" => ByRegister(MosRegister.Y)
|
||||||
|
case x => ErrorReporting.fatal(s"Unknown assembly parameter passing convention: `$x`")
|
||||||
|
}
|
||||||
|
|
||||||
|
val appcComplex: P[ParamPassingConvention] = P((("const" | "ref").! ~/ AWS).? ~ AWS ~ identifier) map {
|
||||||
|
case (None, name) => ByVariable(name)
|
||||||
|
case (Some("const"), name) => ByConstant(name)
|
||||||
|
case (Some("ref"), name) => ByReference(name)
|
||||||
|
case x => ErrorReporting.fatal(s"Unknown assembly parameter passing convention: `$x`")
|
||||||
|
}
|
||||||
|
|
||||||
|
val asmParamDefinition: P[ParameterDeclaration] = for {
|
||||||
|
p <- position()
|
||||||
|
typ <- identifier ~ SWS
|
||||||
|
appc <- appcSimple | appcComplex
|
||||||
|
} yield ParameterDeclaration(typ, appc).pos(p)
|
||||||
|
|
||||||
|
def validateAsmFunctionBody(p: Position, flags: Set[String], name: String, statements: Option[List[Statement]]): Unit = {
|
||||||
|
statements match {
|
||||||
|
case Some(Nil) => ErrorReporting.warn("Assembly function `$name` is empty, did you mean RTS or RTI", options, Some(p))
|
||||||
|
case Some(xs) =>
|
||||||
|
if (flags("interrupt")) {
|
||||||
|
if (xs.exists {
|
||||||
|
case MosAssemblyStatement(Opcode.RTS, _, _, _) => true
|
||||||
|
case _ => false
|
||||||
|
}) ErrorReporting.warn("Assembly interrupt function `$name` contains RTS, did you mean RTI?", options, Some(p))
|
||||||
|
} else {
|
||||||
|
if (xs.exists {
|
||||||
|
case MosAssemblyStatement(Opcode.RTI, _, _, _) => true
|
||||||
|
case _ => false
|
||||||
|
}) ErrorReporting.warn("Assembly non-interrupt function `$name` contains RTI, did you mean RTS?", options, Some(p))
|
||||||
|
}
|
||||||
|
if (!name.startsWith("__") && !flags("macro")) {
|
||||||
|
xs.last match {
|
||||||
|
case MosAssemblyStatement(Opcode.RTS, _, _, _) => () // OK
|
||||||
|
case MosAssemblyStatement(Opcode.RTI, _, _, _) => () // OK
|
||||||
|
case MosAssemblyStatement(Opcode.JMP, _, _, _) => () // OK
|
||||||
|
case _ =>
|
||||||
|
val validReturn = if (flags("interrupt")) "RTI" else "RTS"
|
||||||
|
ErrorReporting.warn(s"Non-macro assembly function `$name` should end in " + validReturn, options, Some(p))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case None => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
src/main/scala/millfork/parser/MosSourceLoadingQueue.scala
Normal file
21
src/main/scala/millfork/parser/MosSourceLoadingQueue.scala
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package millfork.parser
|
||||||
|
|
||||||
|
import millfork.{CompilationFlag, CompilationOptions}
|
||||||
|
import millfork.assembly.mos.AssemblyLine
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Karol Stasiak
|
||||||
|
*/
|
||||||
|
class MosSourceLoadingQueue(initialFilenames: List[String],
|
||||||
|
includePath: List[String],
|
||||||
|
options: CompilationOptions) extends AbstractSourceLoadingQueue[AssemblyLine](initialFilenames, includePath, options) {
|
||||||
|
|
||||||
|
override def createParser(filename: String, src: String, parentDir: String): MfParser[AssemblyLine] = MosParser(filename, src, parentDir, options)
|
||||||
|
|
||||||
|
def enqueueStandardModules(): Unit = {
|
||||||
|
if (options.flag(CompilationFlag.ZeropagePseudoregister)) {
|
||||||
|
moduleQueue.enqueue(() => parseModule("zp_reg", includePath, Left(None)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -1,7 +1,7 @@
|
|||||||
package millfork.test
|
package millfork.test
|
||||||
|
|
||||||
import millfork.{Cpu, OptimizationPresets}
|
import millfork.{Cpu, OptimizationPresets}
|
||||||
import millfork.assembly.opt.{AlwaysGoodOptimizations, DangerousOptimizations}
|
import millfork.assembly.mos.opt.{AlwaysGoodOptimizations, DangerousOptimizations}
|
||||||
import millfork.test.emu._
|
import millfork.test.emu._
|
||||||
import org.scalatest.{FunSuite, Matchers}
|
import org.scalatest.{FunSuite, Matchers}
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
package millfork.test
|
package millfork.test
|
||||||
|
|
||||||
import millfork.assembly.opt.DangerousOptimizations
|
import millfork.assembly.mos.opt.DangerousOptimizations
|
||||||
import millfork.test.emu.EmuBenchmarkRun
|
import millfork.test.emu.EmuBenchmarkRun
|
||||||
import millfork.{Cpu, OptimizationPresets}
|
import millfork.{Cpu, OptimizationPresets}
|
||||||
import org.scalatest.{FunSuite, Matchers}
|
import org.scalatest.{FunSuite, Matchers}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
package millfork.test
|
package millfork.test
|
||||||
|
|
||||||
import millfork.{Cpu, OptimizationPresets}
|
import millfork.{Cpu, OptimizationPresets}
|
||||||
import millfork.assembly.opt.{AlwaysGoodOptimizations, LaterOptimizations, VariableToRegisterOptimization}
|
import millfork.assembly.mos.opt.{AlwaysGoodOptimizations, LaterOptimizations, VariableToRegisterOptimization}
|
||||||
import millfork.test.emu.{EmuBenchmarkRun, EmuRun, EmuSuperOptimizedRun, EmuUltraBenchmarkRun}
|
import millfork.test.emu.{EmuBenchmarkRun, EmuRun, EmuSuperOptimizedRun, EmuUltraBenchmarkRun}
|
||||||
import org.scalatest.{FunSuite, Matchers}
|
import org.scalatest.{FunSuite, Matchers}
|
||||||
|
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
package millfork.test
|
package millfork.test
|
||||||
|
|
||||||
import millfork.{Cpu, OptimizationPresets}
|
import millfork.{Cpu, OptimizationPresets}
|
||||||
import millfork.assembly.opt.{AlwaysGoodOptimizations, DangerousOptimizations}
|
import millfork.assembly.mos.opt.{AlwaysGoodOptimizations, DangerousOptimizations}
|
||||||
import millfork.test.emu._
|
import millfork.test.emu._
|
||||||
import org.scalatest.{FunSuite, Matchers}
|
import org.scalatest.{FunSuite, Matchers}
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
package millfork.test
|
package millfork.test
|
||||||
|
|
||||||
import millfork.assembly.opt.{AlwaysGoodOptimizations, LaterOptimizations, VariableToRegisterOptimization}
|
import millfork.assembly.mos.opt.{AlwaysGoodOptimizations, LaterOptimizations, VariableToRegisterOptimization}
|
||||||
import millfork.test.emu.{EmuBenchmarkRun, EmuRun, EmuUltraBenchmarkRun}
|
import millfork.test.emu.{EmuBenchmarkRun, EmuRun, EmuUltraBenchmarkRun}
|
||||||
import millfork.{Cpu, OptimizationPresets}
|
import millfork.{Cpu, OptimizationPresets}
|
||||||
import org.scalatest.{FunSuite, Matchers}
|
import org.scalatest.{FunSuite, Matchers}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
package millfork.test.emu
|
package millfork.test.emu
|
||||||
|
|
||||||
import millfork.assembly.opt.{CmosOptimizations, SixteenOptimizations}
|
import millfork.assembly.mos.opt.{CmosOptimizations, SixteenOptimizations}
|
||||||
import millfork.{Cpu, OptimizationPresets}
|
import millfork.{Cpu, OptimizationPresets}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
package millfork.test.emu
|
package millfork.test.emu
|
||||||
|
|
||||||
import millfork.assembly.opt.{CE02Optimizations, CmosOptimizations}
|
import millfork.assembly.mos.opt.{CE02Optimizations, CmosOptimizations}
|
||||||
import millfork.{Cpu, OptimizationPresets}
|
import millfork.{Cpu, OptimizationPresets}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
package millfork.test.emu
|
package millfork.test.emu
|
||||||
|
|
||||||
import millfork.assembly.opt.{CmosOptimizations, ZeropageRegisterOptimizations}
|
import millfork.assembly.mos.opt.{CmosOptimizations, ZeropageRegisterOptimizations}
|
||||||
import millfork.{Cpu, OptimizationPresets}
|
import millfork.{Cpu, OptimizationPresets}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
package millfork.test.emu
|
package millfork.test.emu
|
||||||
|
|
||||||
import millfork.assembly.opt.{CmosOptimizations, HudsonOptimizations}
|
import millfork.assembly.mos.opt.{CmosOptimizations, HudsonOptimizations}
|
||||||
import millfork.{Cpu, OptimizationPresets}
|
import millfork.{Cpu, OptimizationPresets}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
package millfork.test.emu
|
package millfork.test.emu
|
||||||
|
|
||||||
import millfork.assembly.opt.{LaterOptimizations, ZeropageRegisterOptimizations}
|
import millfork.assembly.mos.opt.{LaterOptimizations, ZeropageRegisterOptimizations}
|
||||||
import millfork.{Cpu, OptimizationPresets}
|
import millfork.{Cpu, OptimizationPresets}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
package millfork.test.emu
|
package millfork.test.emu
|
||||||
|
|
||||||
import millfork.assembly.opt.{LaterOptimizations, ZeropageRegisterOptimizations}
|
import millfork.assembly.mos.opt.{LaterOptimizations, ZeropageRegisterOptimizations}
|
||||||
import millfork.{Cpu, OptimizationPresets}
|
import millfork.{Cpu, OptimizationPresets}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -7,16 +7,18 @@ import com.grapeshot.halfnes.{CPU, CPURAM}
|
|||||||
import com.loomcom.symon.InstructionTable.CpuBehavior
|
import com.loomcom.symon.InstructionTable.CpuBehavior
|
||||||
import com.loomcom.symon.{Bus, Cpu, CpuState}
|
import com.loomcom.symon.{Bus, Cpu, CpuState}
|
||||||
import fastparse.core.Parsed.{Failure, Success}
|
import fastparse.core.Parsed.{Failure, Success}
|
||||||
import millfork.assembly.opt.AssemblyOptimization
|
import millfork.assembly.AssemblyOptimization
|
||||||
import millfork.compiler.{CompilationContext, MfCompiler}
|
import millfork.assembly.mos.AssemblyLine
|
||||||
|
import millfork.compiler.mos.{CompilationContext, MosCompiler}
|
||||||
import millfork.env.{Environment, InitializedArray, InitializedMemoryVariable, NormalFunction}
|
import millfork.env.{Environment, InitializedArray, InitializedMemoryVariable, NormalFunction}
|
||||||
import millfork.error.ErrorReporting
|
import millfork.error.ErrorReporting
|
||||||
import millfork.node.StandardCallGraph
|
import millfork.node.StandardCallGraph
|
||||||
import millfork.node.opt.NodeOptimization
|
import millfork.node.opt.NodeOptimization
|
||||||
import millfork.output.{Assembler, MemoryBank}
|
import millfork.output.{MemoryBank, MosAssembler}
|
||||||
import millfork.parser.MfParser
|
import millfork.parser.MosParser
|
||||||
import millfork.{CompilationFlag, CompilationOptions}
|
import millfork.{CompilationFlag, CompilationOptions}
|
||||||
import org.scalatest.Matchers
|
import org.scalatest.Matchers
|
||||||
|
|
||||||
import scala.collection.JavaConverters._
|
import scala.collection.JavaConverters._
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -24,7 +26,7 @@ import scala.collection.JavaConverters._
|
|||||||
*/
|
*/
|
||||||
case class Timings(nmos: Long, cmos: Long)
|
case class Timings(nmos: Long, cmos: Long)
|
||||||
|
|
||||||
class EmuRun(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimization], assemblyOptimizations: List[AssemblyOptimization]) extends Matchers {
|
class EmuRun(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimization], assemblyOptimizations: List[AssemblyOptimization[AssemblyLine]]) extends Matchers {
|
||||||
|
|
||||||
def apply(source: String): MemoryBank = {
|
def apply(source: String): MemoryBank = {
|
||||||
apply2(source)._2
|
apply2(source)._2
|
||||||
@@ -116,7 +118,7 @@ class EmuRun(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimization],
|
|||||||
if (!source.contains("__reg")) effectiveSource += "\n pointer __reg"
|
if (!source.contains("__reg")) effectiveSource += "\n pointer __reg"
|
||||||
if (source.contains("import zp_reg"))
|
if (source.contains("import zp_reg"))
|
||||||
effectiveSource += Files.readAllLines(Paths.get("include/zp_reg.mfk"), StandardCharsets.US_ASCII).asScala.mkString("\n", "\n", "")
|
effectiveSource += Files.readAllLines(Paths.get("include/zp_reg.mfk"), StandardCharsets.US_ASCII).asScala.mkString("\n", "\n", "")
|
||||||
val parserF = MfParser("", effectiveSource, "", options)
|
val parserF = MosParser("", effectiveSource, "", options)
|
||||||
parserF.toAst match {
|
parserF.toAst match {
|
||||||
case Success(unoptimized, _) =>
|
case Success(unoptimized, _) =>
|
||||||
ErrorReporting.assertNoErrors("Parse failed")
|
ErrorReporting.assertNoErrors("Parse failed")
|
||||||
@@ -133,7 +135,7 @@ class EmuRun(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimization],
|
|||||||
// print unoptimized asm
|
// print unoptimized asm
|
||||||
env.allPreallocatables.foreach {
|
env.allPreallocatables.foreach {
|
||||||
case f: NormalFunction =>
|
case f: NormalFunction =>
|
||||||
val unoptimized = MfCompiler.compile(CompilationContext(f.environment, f, 0, options))
|
val unoptimized = MosCompiler.compile(CompilationContext(f.environment, f, 0, options))
|
||||||
unoptimizedSize += unoptimized.map(_.sizeInBytes).sum
|
unoptimizedSize += unoptimized.map(_.sizeInBytes).sum
|
||||||
case d: InitializedArray =>
|
case d: InitializedArray =>
|
||||||
unoptimizedSize += d.contents.length
|
unoptimizedSize += d.contents.length
|
||||||
@@ -147,7 +149,7 @@ class EmuRun(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimization],
|
|||||||
// compile
|
// compile
|
||||||
val env2 = new Environment(None, "")
|
val env2 = new Environment(None, "")
|
||||||
env2.collectDeclarations(program, options)
|
env2.collectDeclarations(program, options)
|
||||||
val assembler = new Assembler(program, env2, platform)
|
val assembler = new MosAssembler(program, env2, platform)
|
||||||
val output = assembler.assemble(callGraph, assemblyOptimizations, options)
|
val output = assembler.assemble(callGraph, assemblyOptimizations, options)
|
||||||
println(";;; compiled: -----------------")
|
println(";;; compiled: -----------------")
|
||||||
output.asm.takeWhile(s => !(s.startsWith(".") && s.contains("= $"))).filterNot(_.contains("; DISCARD_")).foreach(println)
|
output.asm.takeWhile(s => !(s.startsWith(".") && s.contains("= $"))).filterNot(_.contains("; DISCARD_")).foreach(println)
|
||||||
@@ -222,7 +224,7 @@ class EmuRun(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimization],
|
|||||||
cpu.setBus(bus)
|
cpu.setBus(bus)
|
||||||
cpu.setProgramCounter(org)
|
cpu.setProgramCounter(org)
|
||||||
cpu.setStackPointer(0xff)
|
cpu.setStackPointer(0xff)
|
||||||
val legal = Assembler.getStandardLegalOpcodes
|
val legal = MosAssembler.getStandardLegalOpcodes
|
||||||
|
|
||||||
var countNmos = 0L
|
var countNmos = 0L
|
||||||
var countCmos = 0L
|
var countCmos = 0L
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
package millfork.test.emu
|
package millfork.test.emu
|
||||||
|
|
||||||
import millfork.assembly.opt.SuperOptimizer
|
import millfork.assembly.mos.opt.SuperOptimizer
|
||||||
import millfork.{Cpu, OptimizationPresets}
|
import millfork.{Cpu, OptimizationPresets}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
package millfork.test.emu
|
package millfork.test.emu
|
||||||
|
|
||||||
import millfork.assembly.opt.SuperOptimizer
|
import millfork.assembly.mos.opt.SuperOptimizer
|
||||||
import millfork.{Cpu, OptimizationPresets}
|
import millfork.{Cpu, OptimizationPresets}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
package millfork.test.emu
|
package millfork.test.emu
|
||||||
|
|
||||||
import millfork.assembly.opt.{LaterOptimizations, UndocumentedOptimizations}
|
import millfork.assembly.mos.opt.{LaterOptimizations, UndocumentedOptimizations}
|
||||||
import millfork.{Cpu, OptimizationPresets}
|
import millfork.{Cpu, OptimizationPresets}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user