mirror of
https://github.com/KarolS/millfork.git
synced 2024-12-24 15:29:23 +00:00
Refactoring for the upcoming Z80 support
This commit is contained in:
parent
70818cc3d2
commit
5281b5f527
@ -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 {
|
||||
|
||||
val Mos, StrictMos, Ricoh, StrictRicoh, Cmos, HuC6280, CE02, Sixteen = Value
|
||||
@ -76,27 +87,27 @@ object Cpu extends Enumeration {
|
||||
|
||||
import CompilationFlag._
|
||||
|
||||
private val alwaysDefaultFlags = Set(
|
||||
private val mosAlwaysDefaultFlags = Set(
|
||||
VariableOverlap, CompactReturnDispatchParams, ZeropagePseudoregister
|
||||
)
|
||||
|
||||
def defaultFlags(x: Cpu.Value): Set[CompilationFlag.Value] = x match {
|
||||
case StrictMos =>
|
||||
alwaysDefaultFlags ++ Set(DecimalMode, PreventJmpIndirectBug)
|
||||
mosAlwaysDefaultFlags ++ Set(DecimalMode, PreventJmpIndirectBug)
|
||||
case Mos =>
|
||||
alwaysDefaultFlags ++ Set(DecimalMode, PreventJmpIndirectBug)
|
||||
mosAlwaysDefaultFlags ++ Set(DecimalMode, PreventJmpIndirectBug)
|
||||
case Ricoh =>
|
||||
alwaysDefaultFlags ++ Set(PreventJmpIndirectBug)
|
||||
mosAlwaysDefaultFlags ++ Set(PreventJmpIndirectBug)
|
||||
case StrictRicoh =>
|
||||
alwaysDefaultFlags ++ Set(PreventJmpIndirectBug)
|
||||
mosAlwaysDefaultFlags ++ Set(PreventJmpIndirectBug)
|
||||
case Cmos =>
|
||||
alwaysDefaultFlags ++ Set(DecimalMode, EmitCmosOpcodes)
|
||||
mosAlwaysDefaultFlags ++ Set(DecimalMode, EmitCmosOpcodes)
|
||||
case HuC6280 =>
|
||||
alwaysDefaultFlags ++ Set(DecimalMode, EmitCmosOpcodes, EmitHudsonOpcodes)
|
||||
mosAlwaysDefaultFlags ++ Set(DecimalMode, EmitCmosOpcodes, EmitHudsonOpcodes)
|
||||
case CE02 =>
|
||||
alwaysDefaultFlags ++ Set(DecimalMode, EmitCmosOpcodes, Emit65CE02Opcodes)
|
||||
mosAlwaysDefaultFlags ++ Set(DecimalMode, EmitCmosOpcodes, Emit65CE02Opcodes)
|
||||
case Sixteen =>
|
||||
alwaysDefaultFlags ++ Set(DecimalMode, EmitCmosOpcodes, EmitEmulation65816Opcodes, EmitNative65816Opcodes, ReturnWordsViaAccumulator)
|
||||
mosAlwaysDefaultFlags ++ Set(DecimalMode, EmitCmosOpcodes, EmitEmulation65816Opcodes, EmitNative65816Opcodes, ReturnWordsViaAccumulator)
|
||||
}
|
||||
|
||||
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.util.Locale
|
||||
|
||||
import millfork.assembly.opt._
|
||||
import millfork.assembly.mos.AssemblyLine
|
||||
import millfork.assembly.mos.opt._
|
||||
import millfork.buildinfo.BuildInfo
|
||||
import millfork.cli.{CliParser, CliStatus}
|
||||
import millfork.compiler.mos.MosCompiler
|
||||
import millfork.env.Environment
|
||||
import millfork.error.ErrorReporting
|
||||
import millfork.node.StandardCallGraph
|
||||
import millfork.output.Assembler
|
||||
import millfork.parser.SourceLoadingQueue
|
||||
import millfork.output.{AbstractAssembler, AssemblerOutput, MosAssembler, MosInliningCalculator}
|
||||
import millfork.parser.MosSourceLoadingQueue
|
||||
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
@ -59,7 +61,6 @@ object Main {
|
||||
ErrorReporting.fatalQuit("No input files")
|
||||
}
|
||||
ErrorReporting.verbosity = c.verbosity.getOrElse(0)
|
||||
val optLevel = c.optimizationLevel.getOrElse(0)
|
||||
val platform = Platform.lookupPlatformFile(c.includePath, c.platform.getOrElse {
|
||||
ErrorReporting.info("No platform selected, defaulting to `c64`")
|
||||
"c64"
|
||||
@ -84,52 +85,9 @@ object Main {
|
||||
// }
|
||||
// }).toMap
|
||||
|
||||
val unoptimized = new SourceLoadingQueue(
|
||||
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 result: AssemblerOutput = CpuFamily.forType(platform.cpu) match {
|
||||
case CpuFamily.M6502 => assembleForMos(c, platform, options)
|
||||
}
|
||||
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) {
|
||||
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] {
|
||||
|
||||
fluff("Main options:", "")
|
||||
|
@ -1,6 +1,8 @@
|
||||
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}
|
||||
|
||||
/**
|
||||
@ -13,7 +15,7 @@ object OptimizationPresets {
|
||||
UnusedLocalVariables,
|
||||
UnusedGlobalVariables,
|
||||
)
|
||||
val AssOpt: List[AssemblyOptimization] = List[AssemblyOptimization](
|
||||
val AssOpt: List[AssemblyOptimization[AssemblyLine]] = List[AssemblyOptimization[AssemblyLine]](
|
||||
UnusedLabelRemoval,
|
||||
AlwaysGoodOptimizations.NonetAddition,
|
||||
AlwaysGoodOptimizations.NonetBitOp,
|
||||
@ -135,7 +137,7 @@ object OptimizationPresets {
|
||||
LaterOptimizations.UseBit,
|
||||
)
|
||||
|
||||
val Good: List[AssemblyOptimization] = List[AssemblyOptimization](
|
||||
val Good: List[AssemblyOptimization[AssemblyLine]] = List[AssemblyOptimization[AssemblyLine]](
|
||||
UnusedLabelRemoval,
|
||||
AlwaysGoodOptimizations.Adc0Optimization,
|
||||
AlwaysGoodOptimizations.BitPackingUnpacking,
|
||||
@ -204,7 +206,7 @@ object OptimizationPresets {
|
||||
VariableToRegisterOptimization,
|
||||
)
|
||||
|
||||
val QuickPreset: List[AssemblyOptimization] = List[AssemblyOptimization](
|
||||
val QuickPreset: List[AssemblyOptimization[AssemblyLine]] = List[AssemblyOptimization[AssemblyLine]](
|
||||
UnusedLabelRemoval,
|
||||
AlwaysGoodOptimizations.Adc0Optimization,
|
||||
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.Opcode._
|
||||
import millfork.compiler.{CompilationContext, MfCompiler}
|
||||
import millfork.assembly.{AbstractCode, AddrMode}
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.compiler.mos.{CompilationContext, MosCompiler}
|
||||
import millfork.env._
|
||||
import millfork.{CompilationFlag, CompilationOptions}
|
||||
|
||||
//noinspection TypeAnnotation
|
||||
object OpcodeClasses {
|
||||
@ -378,7 +379,7 @@ object AssemblyLine {
|
||||
List(AssemblyLine.immediate(opcode, 0))
|
||||
} else if (opcodesForZeroedOrSignExtendedVariableOperation(opcode)) {
|
||||
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.immediate(ORA, 0x7f),
|
||||
AssemblyLine.relative(BMI, label),
|
||||
@ -453,12 +454,12 @@ object AssemblyLine {
|
||||
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 State._
|
||||
import OpcodeClasses._
|
||||
import State._
|
||||
import Treatment._
|
||||
|
||||
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 Relative | ZeroPageX | ZeroPage | ZeroPageY | IndexedZ | IndexedX | IndexedY | IndexedSY | Stack | LongIndexedY | LongIndexedZ | Immediate => 2
|
||||
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 _ => 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
|
||||
|
||||
@ -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 millfork.assembly.AddrMode
|
||||
import millfork.assembly.AddrMode._
|
||||
import millfork.assembly.Opcode._
|
||||
import millfork.assembly.OpcodeClasses._
|
||||
import millfork.assembly.{opt, _}
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.assembly.mos.OpcodeClasses._
|
||||
import millfork.assembly.mos.{opt, _}
|
||||
import millfork.env._
|
||||
|
||||
/**
|
@ -1,9 +1,8 @@
|
||||
package millfork.assembly.opt
|
||||
package millfork.assembly.mos.opt
|
||||
|
||||
import millfork.assembly.AddrMode._
|
||||
import millfork.assembly.AssemblyLine
|
||||
import millfork.assembly.Opcode._
|
||||
import millfork.assembly.OpcodeClasses._
|
||||
import millfork.assembly.AssemblyOptimization
|
||||
import millfork.assembly.mos.AssemblyLine
|
||||
import millfork.assembly.mos.Opcode._
|
||||
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
@ -16,5 +15,5 @@ object CE02Optimizations {
|
||||
(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.assembly.{AssemblyLine, OpcodeClasses}
|
||||
import millfork.assembly.mos.{AssemblyLine, OpcodeClasses}
|
||||
import millfork.assembly.AssemblyOptimization
|
||||
import millfork.env.NormalFunction
|
||||
import millfork.error.ErrorReporting
|
||||
|
||||
@ -12,7 +13,7 @@ import millfork.error.ErrorReporting
|
||||
object ChangeIndexRegisterOptimizationPreferringX2Y extends ChangeIndexRegisterOptimization(true)
|
||||
object ChangeIndexRegisterOptimizationPreferringY2X extends ChangeIndexRegisterOptimization(false)
|
||||
|
||||
class ChangeIndexRegisterOptimization(preferX2Y: Boolean) extends AssemblyOptimization {
|
||||
class ChangeIndexRegisterOptimization(preferX2Y: Boolean) extends AssemblyOptimization[AssemblyLine] {
|
||||
|
||||
object IndexReg extends Enumeration {
|
||||
val X, Y = Value
|
||||
@ -25,7 +26,7 @@ class ChangeIndexRegisterOptimization(preferX2Y: Boolean) extends AssemblyOptimi
|
||||
import IndexReg._
|
||||
import IndexDirection._
|
||||
import millfork.assembly.AddrMode._
|
||||
import millfork.assembly.Opcode._
|
||||
import millfork.assembly.mos.Opcode._
|
||||
|
||||
type IndexReg = IndexReg.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.Opcode._
|
||||
import millfork.assembly.AssemblyOptimization
|
||||
import millfork.assembly.mos.{AssemblyLine, Opcode, State}
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.assembly.AddrMode._
|
||||
import millfork.assembly.OpcodeClasses._
|
||||
import millfork.assembly.mos.OpcodeClasses._
|
||||
import millfork.env._
|
||||
|
||||
/**
|
||||
@ -49,5 +50,5 @@ object CmosOptimizations {
|
||||
(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.assembly._
|
||||
import millfork.assembly.mos.AssemblyLine
|
||||
import millfork.assembly.mos.OpcodeClasses
|
||||
import millfork.env.{Label, MemoryAddressConstant, NormalFunction, NumericConstant}
|
||||
|
||||
/**
|
||||
@ -32,7 +33,7 @@ object CoarseFlowAnalyzer {
|
||||
changed = false
|
||||
var currentStatus: CpuStatus = functionStartStatus
|
||||
for (i <- codeArray.indices) {
|
||||
import millfork.assembly.Opcode._
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.assembly.AddrMode._
|
||||
if (flagArray(i) != currentStatus) {
|
||||
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
|
@ -1,7 +1,8 @@
|
||||
package millfork.assembly.opt
|
||||
package millfork.assembly.mos.opt
|
||||
|
||||
import millfork.assembly._
|
||||
import millfork.assembly.Opcode._
|
||||
import millfork.assembly.mos._
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.assembly.AddrMode._
|
||||
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.assembly.AssemblyLine
|
||||
import millfork.assembly.AssemblyOptimization
|
||||
import millfork.assembly.mos.AssemblyLine
|
||||
import millfork.env._
|
||||
import millfork.assembly.Opcode._
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.assembly.AddrMode._
|
||||
import millfork.error.ErrorReporting
|
||||
|
||||
@ -12,7 +13,7 @@ import scala.collection.{immutable, mutable}
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
*/
|
||||
object EmptyMemoryStoreRemoval extends AssemblyOptimization {
|
||||
object EmptyMemoryStoreRemoval extends AssemblyOptimization[AssemblyLine] {
|
||||
override def name = "Removing pointless stores to automatic variables"
|
||||
|
||||
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.assembly.{AssemblyLine, Opcode, State}
|
||||
import millfork.CompilationOptions
|
||||
import millfork.assembly.mos.{AssemblyLine, Opcode, State}
|
||||
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.Opcode._
|
||||
import millfork.assembly.mos.Opcode
|
||||
import millfork.assembly.mos.Opcode._
|
||||
|
||||
/**
|
||||
* @author Karol Stasiak
|
@ -1,7 +1,7 @@
|
||||
package millfork.assembly.opt
|
||||
package millfork.assembly.mos.opt
|
||||
|
||||
import millfork.assembly.Opcode
|
||||
import millfork.assembly.Opcode._
|
||||
import millfork.assembly.mos.Opcode
|
||||
import millfork.assembly.mos.Opcode._
|
||||
|
||||
/**
|
||||
* @author Karol Stasiak
|
@ -1,7 +1,7 @@
|
||||
package millfork.assembly.opt
|
||||
package millfork.assembly.mos.opt
|
||||
|
||||
import millfork.assembly.Opcode
|
||||
import millfork.assembly.Opcode._
|
||||
import millfork.assembly.mos.Opcode
|
||||
import millfork.assembly.mos.Opcode._
|
||||
|
||||
/**
|
||||
* @author Karol Stasiak
|
@ -1,7 +1,8 @@
|
||||
package millfork.assembly.opt
|
||||
package millfork.assembly.mos.opt
|
||||
|
||||
import millfork.assembly.AssemblyLine
|
||||
import millfork.assembly.Opcode._
|
||||
import millfork.assembly.AssemblyOptimization
|
||||
import millfork.assembly.mos.AssemblyLine
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.assembly.AddrMode._
|
||||
import millfork.env.NumericConstant
|
||||
|
||||
@ -10,7 +11,7 @@ import millfork.env.NumericConstant
|
||||
*/
|
||||
object HudsonOptimizations {
|
||||
|
||||
val All: List[AssemblyOptimization] = List()
|
||||
val All: List[AssemblyOptimization[AssemblyLine]] = List()
|
||||
|
||||
def removeLoadZero(code: List[AssemblyLine]): List[AssemblyLine] = code.map{
|
||||
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 millfork.assembly.Opcode._
|
||||
import millfork.assembly.{AddrMode, AssemblyLine, Opcode}
|
||||
import millfork.compiler.MfCompiler
|
||||
import millfork.assembly.mos.{AssemblyLine, Opcode}
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.assembly.AddrMode
|
||||
import millfork.env.{Label, MemoryAddressConstant, NormalFunction}
|
||||
import millfork.error.ErrorReporting
|
||||
import millfork.{CompilationFlag, CompilationOptions}
|
||||
import millfork.CompilationOptions
|
||||
|
||||
/**
|
||||
* @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.assembly.{AddrMode, AssemblyLine, Opcode}
|
||||
import millfork.assembly.Opcode._
|
||||
import millfork.assembly.AddrMode
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.env.{Label, MemoryAddressConstant, NormalFunction}
|
||||
import millfork.error.ErrorReporting
|
||||
|
@ -1,9 +1,10 @@
|
||||
package millfork.assembly.opt
|
||||
package millfork.assembly.mos.opt
|
||||
|
||||
import millfork.assembly._
|
||||
import millfork.assembly.Opcode._
|
||||
import millfork.assembly.mos._
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.assembly.AddrMode._
|
||||
import millfork.assembly.OpcodeClasses._
|
||||
import millfork.assembly.mos.OpcodeClasses._
|
||||
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.assembly.{AddrMode, AssemblyLine, OpcodeClasses}
|
||||
import millfork.assembly.Opcode._
|
||||
import millfork.CompilationOptions
|
||||
import millfork.assembly.AssemblyOptimization
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.assembly.AddrMode._
|
||||
import millfork.assembly.mos.{AssemblyLine, OpcodeClasses}
|
||||
import millfork.env._
|
||||
import millfork.error.ErrorReporting
|
||||
|
||||
import scala.annotation.tailrec
|
||||
import scala.collection.mutable.ListBuffer
|
||||
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
*/
|
||||
object LocalVariableReadOptimization extends AssemblyOptimization {
|
||||
object LocalVariableReadOptimization extends AssemblyOptimization[AssemblyLine] {
|
||||
|
||||
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 millfork.{CompilationFlag, CompilationOptions}
|
||||
import millfork.assembly.AssemblyLine
|
||||
import millfork.assembly.OpcodeClasses._
|
||||
import millfork.assembly.Opcode._
|
||||
import millfork.assembly.mos.AssemblyLine
|
||||
import millfork.assembly.mos.OpcodeClasses._
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.assembly.AddrMode._
|
||||
import millfork.env.{Constant, Label, MemoryAddressConstant}
|
||||
|
@ -1,10 +1,11 @@
|
||||
package millfork.assembly.opt
|
||||
package millfork.assembly.mos.opt
|
||||
|
||||
import millfork.CompilationOptions
|
||||
import millfork.assembly._
|
||||
import millfork.assembly.mos._
|
||||
import millfork.env._
|
||||
import millfork.error.ErrorReporting
|
||||
import millfork.node.Register
|
||||
import millfork.node.MosRegister
|
||||
|
||||
import scala.collection.immutable
|
||||
|
||||
@ -112,7 +113,7 @@ object ReverseFlowAnalyzer {
|
||||
changed = false
|
||||
var currentImportance: CpuImportance = finalImportance
|
||||
for (i <- codeArray.indices.reverse) {
|
||||
import millfork.assembly.Opcode._
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.assembly.AddrMode._
|
||||
if (importanceArray(i) != currentImportance) {
|
||||
changed = true
|
||||
@ -151,19 +152,19 @@ object ReverseFlowAnalyzer {
|
||||
fun.params match {
|
||||
case AssemblyParamSignature(params) =>
|
||||
params.foreach(_.variable match {
|
||||
case RegisterVariable(Register.A, _) =>
|
||||
case RegisterVariable(MosRegister.A, _) =>
|
||||
result = result.copy(a = Important)
|
||||
case RegisterVariable(Register.AW, _) =>
|
||||
case RegisterVariable(MosRegister.AW, _) =>
|
||||
result = result.copy(a = Important, ah = Important)
|
||||
case RegisterVariable(Register.X, _) =>
|
||||
case RegisterVariable(MosRegister.X, _) =>
|
||||
result = result.copy(x = Important)
|
||||
case RegisterVariable(Register.Y, _) =>
|
||||
case RegisterVariable(MosRegister.Y, _) =>
|
||||
result = result.copy(y = Important)
|
||||
case RegisterVariable(Register.AX | Register.XA, _) =>
|
||||
case RegisterVariable(MosRegister.AX | MosRegister.XA, _) =>
|
||||
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)
|
||||
case RegisterVariable(Register.XY | Register.YX, _) =>
|
||||
case RegisterVariable(MosRegister.XY | MosRegister.YX, _) =>
|
||||
result = result.copy(x = Important, y = Important)
|
||||
case _ =>
|
||||
})
|
@ -1,7 +1,7 @@
|
||||
package millfork.assembly.opt
|
||||
package millfork.assembly.mos.opt
|
||||
|
||||
import millfork.assembly.Opcode
|
||||
import millfork.assembly.Opcode._
|
||||
import millfork.assembly.mos.Opcode
|
||||
import millfork.assembly.mos.Opcode._
|
||||
|
||||
/**
|
||||
* @author Karol Stasiak
|
@ -1,7 +1,8 @@
|
||||
package millfork.assembly.opt
|
||||
package millfork.assembly.mos.opt
|
||||
|
||||
import millfork.{CompilationFlag, CompilationOptions}
|
||||
import millfork.assembly._
|
||||
import millfork.assembly.mos._
|
||||
import millfork.env._
|
||||
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))
|
||||
|
@ -1,9 +1,10 @@
|
||||
package millfork.assembly.opt
|
||||
package millfork.assembly.mos.opt
|
||||
|
||||
import millfork.{CompilationFlag, CompilationOptions, NonOverlappingIntervals}
|
||||
import millfork.assembly.{AddrMode, AssemblyLine, Opcode, OpcodeClasses}
|
||||
import millfork.assembly.Opcode._
|
||||
import millfork.assembly._
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.assembly.AddrMode._
|
||||
import millfork.assembly.mos.{AssemblyLine, Opcode}
|
||||
import millfork.env._
|
||||
import millfork.error.ErrorReporting
|
||||
|
||||
@ -13,7 +14,7 @@ import scala.collection.mutable.ListBuffer
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
*/
|
||||
object SingleAssignmentVariableOptimization extends AssemblyOptimization {
|
||||
object SingleAssignmentVariableOptimization extends AssemblyOptimization[AssemblyLine] {
|
||||
|
||||
private val BadOpcodes = Set(RTS, JSR, JMP, RTI)
|
||||
private val GoodOpcodes = Set(
|
@ -1,8 +1,10 @@
|
||||
package millfork.assembly.opt
|
||||
import millfork.assembly.Opcode._
|
||||
package millfork.assembly.mos.opt
|
||||
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.assembly.AddrMode._
|
||||
import millfork.assembly.OpcodeClasses._
|
||||
import millfork.assembly.{AssemblyLine, OpcodeClasses, State}
|
||||
import millfork.assembly.mos.OpcodeClasses._
|
||||
import millfork.assembly.AssemblyOptimization
|
||||
import millfork.assembly.mos.{AssemblyLine, OpcodeClasses, State}
|
||||
import millfork.env.{Constant, NumericConstant}
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
@ -216,7 +218,7 @@ object SixteenOptimizations {
|
||||
|
||||
// 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,
|
||||
OptimizeStackRelative,
|
||||
OptimizeZeroIndex,
|
||||
@ -224,9 +226,9 @@ object SixteenOptimizations {
|
||||
RepSepWeakening,
|
||||
)
|
||||
|
||||
val AllForNative: List[AssemblyOptimization] = List(
|
||||
val AllForNative: List[AssemblyOptimization[AssemblyLine]] = List(
|
||||
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
|
@ -1,7 +1,8 @@
|
||||
package millfork.assembly.opt
|
||||
package millfork.assembly.mos.opt
|
||||
|
||||
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.error.ErrorReporting
|
||||
|
||||
@ -10,7 +11,7 @@ import scala.collection.mutable
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
*/
|
||||
object SuperOptimizer extends AssemblyOptimization {
|
||||
object SuperOptimizer extends AssemblyOptimization[AssemblyLine] {
|
||||
|
||||
def optimize(m: NormalFunction, code: List[AssemblyLine], options: CompilationOptions): List[AssemblyLine] = {
|
||||
val oldVerbosity = ErrorReporting.verbosity
|
||||
@ -44,8 +45,8 @@ object SuperOptimizer extends AssemblyOptimization {
|
||||
ChangeIndexRegisterOptimizationPreferringX2Y,
|
||||
ChangeIndexRegisterOptimizationPreferringY2X)
|
||||
val seenSoFar = mutable.Set[CodeView]()
|
||||
val queue = mutable.Queue[(List[AssemblyOptimization], List[AssemblyLine])]()
|
||||
val leaves = mutable.ListBuffer[(List[AssemblyOptimization], List[AssemblyLine])]()
|
||||
val queue = mutable.Queue[(List[AssemblyOptimization[AssemblyLine]], List[AssemblyLine])]()
|
||||
val leaves = mutable.ListBuffer[(List[AssemblyOptimization[AssemblyLine]], List[AssemblyLine])]()
|
||||
|
||||
val quickScrub = List(
|
||||
UnusedLabelRemoval,
|
@ -1,11 +1,12 @@
|
||||
package millfork.assembly.opt
|
||||
package millfork.assembly.mos.opt
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
import millfork.assembly._
|
||||
import millfork.assembly.Opcode._
|
||||
import millfork.assembly.mos._
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.assembly.AddrMode._
|
||||
import millfork.assembly.OpcodeClasses._
|
||||
import millfork.assembly.mos.OpcodeClasses._
|
||||
import millfork.env.{Constant, NormalFunction, NumericConstant}
|
||||
|
||||
/**
|
||||
@ -515,7 +516,7 @@ object UndocumentedOptimizations {
|
||||
(Elidable & HasOpcode(ANC) & DoesntMatterWhatItDoesWith(State.C)) ~~> (_.map(_.copy(opcode = AND))),
|
||||
)
|
||||
|
||||
val All: List[AssemblyOptimization] = List(
|
||||
val All: List[AssemblyOptimization[AssemblyLine]] = List(
|
||||
UseLax,
|
||||
UseSax,
|
||||
UseSbx,
|
@ -1,16 +1,16 @@
|
||||
package millfork.assembly.opt
|
||||
package millfork.assembly.mos.opt
|
||||
|
||||
import millfork.CompilationOptions
|
||||
import millfork.assembly.AddrMode._
|
||||
import millfork.assembly.Opcode._
|
||||
import millfork.assembly.{AddrMode, AssemblyLine}
|
||||
import millfork.assembly.mos.AssemblyLine
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.assembly.AssemblyOptimization
|
||||
import millfork.env._
|
||||
import millfork.error.ErrorReporting
|
||||
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
*/
|
||||
object UnusedLabelRemoval extends AssemblyOptimization {
|
||||
object UnusedLabelRemoval extends AssemblyOptimization[AssemblyLine] {
|
||||
|
||||
override def optimize(f: NormalFunction, code: List[AssemblyLine], options: CompilationOptions): List[AssemblyLine] = {
|
||||
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.error.ErrorReporting
|
||||
|
@ -1,8 +1,9 @@
|
||||
package millfork.assembly.opt
|
||||
package millfork.assembly.mos.opt
|
||||
|
||||
import millfork.{CompilationFlag, CompilationOptions, NonOverlappingIntervals}
|
||||
import millfork.assembly.{AddrMode, AssemblyLine, OpcodeClasses}
|
||||
import millfork.assembly.Opcode._
|
||||
import millfork.assembly.{AddrMode, AssemblyOptimization}
|
||||
import millfork.assembly.mos._
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.assembly.AddrMode._
|
||||
import millfork.env._
|
||||
import millfork.error.ErrorReporting
|
||||
@ -12,7 +13,7 @@ import scala.collection.mutable.ListBuffer
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
*/
|
||||
object VariableToRegisterOptimization extends AssemblyOptimization {
|
||||
object VariableToRegisterOptimization extends AssemblyOptimization[AssemblyLine] {
|
||||
|
||||
object CyclesAndBytes {
|
||||
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.AssemblyLine
|
||||
import millfork.assembly.AssemblyOptimization
|
||||
import millfork.assembly.mos.AssemblyLine
|
||||
import millfork.env.{CompoundConstant, Constant, MathOperator}
|
||||
|
||||
/**
|
||||
@ -74,7 +75,7 @@ object ZeropageRegisterOptimizations {
|
||||
(Elidable & HasOpcode(STA) & RefersTo("__reg", 1) & DoesntMatterWhatItDoesWithReg(1)) ~~> (_.tail),
|
||||
)
|
||||
|
||||
val All: List[AssemblyOptimization] = List(
|
||||
val All: List[AssemblyOptimization[AssemblyLine]] = List(
|
||||
ConstantMultiplication,
|
||||
DeadRegStore,
|
||||
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
|
@ -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.env._
|
||||
import millfork.node._
|
||||
import millfork.assembly.Opcode._
|
||||
import millfork.assembly.AddrMode._
|
||||
import millfork.assembly.opt.ConcernsY
|
||||
import millfork.error.ErrorReporting
|
||||
import millfork.node._
|
||||
|
||||
import scala.collection.mutable
|
||||
import scala.collection.mutable.ListBuffer
|
||||
@ -55,15 +55,15 @@ object BuiltIns {
|
||||
case (p: ConstantPointy, _, _, _, None) =>
|
||||
Nil -> List(AssemblyLine.absolute(opcode, p.value + constantPart))
|
||||
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)) =>
|
||||
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, _) =>
|
||||
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)) =>
|
||||
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, _) =>
|
||||
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 _ =>
|
||||
ErrorReporting.error("Invalid index for simple operation argument", index.position)
|
||||
Nil -> Nil
|
||||
@ -73,11 +73,11 @@ object BuiltIns {
|
||||
case _: FunctionCallExpression | _:SumExpression if commutative =>
|
||||
// TODO: is it ok?
|
||||
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.implied(PHX)))
|
||||
} 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.absoluteX(opcode, 0x101),
|
||||
AssemblyLine.implied(INX),
|
||||
@ -130,7 +130,7 @@ object BuiltIns {
|
||||
val normalizedParams = sortedParams
|
||||
|
||||
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) {
|
||||
// TODO: check if decimal subtraction works correctly here
|
||||
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 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 =>
|
||||
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] = {
|
||||
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 {
|
||||
case Some(NumericConstant(0, _)) =>
|
||||
ExpressionCompiler.compile(ctx, l, None, NoBranching)
|
||||
MosExpressionCompiler.compile(ctx, l, None, NoBranching)
|
||||
case Some(NumericConstant(v, _)) if v > 0 =>
|
||||
firstParamCompiled ++ List.fill(v.toInt)(AssemblyLine.implied(opcode))
|
||||
case _ =>
|
||||
val compileCounter = ExpressionCompiler.preserveRegisterIfNeeded(ctx, Register.A,
|
||||
ExpressionCompiler.compile(ctx, r, Some(b -> RegisterVariable(Register.X, b)), NoBranching))
|
||||
val labelSkip = MfCompiler.nextLabel("ss")
|
||||
val labelRepeat = MfCompiler.nextLabel("sr")
|
||||
val compileCounter = MosExpressionCompiler.preserveRegisterIfNeeded(ctx, MosRegister.A,
|
||||
MosExpressionCompiler.compile(ctx, r, Some(b -> RegisterVariable(MosRegister.X, b)), NoBranching))
|
||||
val labelSkip = MosCompiler.nextLabel("ss")
|
||||
val labelRepeat = MosCompiler.nextLabel("sr")
|
||||
val loop = List(
|
||||
AssemblyLine.relative(BEQ, labelSkip),
|
||||
AssemblyLine.label(labelRepeat),
|
||||
@ -216,7 +216,7 @@ object BuiltIns {
|
||||
}
|
||||
env.eval(rhs) match {
|
||||
case Some(NumericConstant(0, _)) =>
|
||||
ExpressionCompiler.compile(ctx, lhs, None, NoBranching)
|
||||
MosExpressionCompiler.compile(ctx, lhs, None, NoBranching)
|
||||
case Some(NumericConstant(shift, _)) if shift > 0 =>
|
||||
if (ctx.options.flag(CompilationFlag.RorWarning))
|
||||
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] = {
|
||||
val env = ctx.env
|
||||
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 {
|
||||
case Some(NumericConstant(0, _)) =>
|
||||
ExpressionCompiler.compile(ctx, lhs, None, NoBranching)
|
||||
MosExpressionCompiler.compile(ctx, lhs, None, NoBranching)
|
||||
case Some(NumericConstant(v, _)) if v > 0 =>
|
||||
val result = simpleOperation(opcode, ctx, lhs, IndexChoice.RequireX, preserveA = true, commutative = false)
|
||||
result ++ List.fill(v.toInt - 1)(result.last)
|
||||
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
|
||||
env.eval(rhs) match {
|
||||
case Some(NumericConstant(0, _)) =>
|
||||
ExpressionCompiler.compile(ctx, lhs, None, NoBranching)
|
||||
MosExpressionCompiler.compile(ctx, lhs, None, NoBranching)
|
||||
case Some(NumericConstant(shift, _)) if shift > 0 =>
|
||||
if (ctx.options.flags(CompilationFlag.EmitNative65816Opcodes)) {
|
||||
targetBytes match {
|
||||
@ -273,16 +273,16 @@ object BuiltIns {
|
||||
val usesX = targetBytes.exists(_.exists(_.concernsX))
|
||||
val usesY = targetBytes.exists(_.exists(_.concernsY))
|
||||
val (register, decrease) = (usesX, usesY) match {
|
||||
case (true, false) => Register.Y -> DEY
|
||||
case (false, true) => Register.X -> DEX
|
||||
case (false, false) => Register.X -> DEX
|
||||
case (true, false) => MosRegister.Y -> DEY
|
||||
case (false, true) => MosRegister.X -> DEX
|
||||
case (false, false) => MosRegister.X -> DEX
|
||||
case (true, true) => ???
|
||||
}
|
||||
|
||||
val compileCounter = ExpressionCompiler.preserveRegisterIfNeeded(ctx, Register.A,
|
||||
ExpressionCompiler.compile(ctx, rhs, Some(b -> RegisterVariable(register, b)), NoBranching))
|
||||
val labelSkip = MfCompiler.nextLabel("ss")
|
||||
val labelRepeat = MfCompiler.nextLabel("sr")
|
||||
val compileCounter = MosExpressionCompiler.preserveRegisterIfNeeded(ctx, MosRegister.A,
|
||||
MosExpressionCompiler.compile(ctx, rhs, Some(b -> RegisterVariable(register, b)), NoBranching))
|
||||
val labelSkip = MosCompiler.nextLabel("ss")
|
||||
val labelRepeat = MosCompiler.nextLabel("sr")
|
||||
|
||||
if (ctx.options.flags(CompilationFlag.EmitNative65816Opcodes)) {
|
||||
targetBytes match {
|
||||
@ -323,7 +323,7 @@ object BuiltIns {
|
||||
if (simplicity(env, lhs) >= 'J' && simplicity(env, rhs) < 'J') {
|
||||
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)
|
||||
maybeConstant match {
|
||||
case Some(NumericConstant(0, _)) =>
|
||||
@ -395,7 +395,7 @@ object BuiltIns {
|
||||
case ComparisonType.LessOrEqualUnsigned =>
|
||||
List(AssemblyLine.relative(BCC, Label(label)), AssemblyLine.relative(BEQ, Label(label)))
|
||||
case ComparisonType.GreaterUnsigned =>
|
||||
val x = MfCompiler.nextLabel("co")
|
||||
val x = MosCompiler.nextLabel("co")
|
||||
List(
|
||||
AssemblyLine.relative(BEQ, x),
|
||||
AssemblyLine.relative(BCS, Label(label)),
|
||||
@ -408,7 +408,7 @@ object BuiltIns {
|
||||
case ComparisonType.LessOrEqualSigned =>
|
||||
List(AssemblyLine.relative(BMI, Label(label)), AssemblyLine.relative(BEQ, Label(label)))
|
||||
case ComparisonType.GreaterSigned =>
|
||||
val x = MfCompiler.nextLabel("co")
|
||||
val x = MosCompiler.nextLabel("co")
|
||||
List(
|
||||
AssemblyLine.relative(BEQ, x),
|
||||
AssemblyLine.relative(BPL, Label(label)),
|
||||
@ -479,8 +479,8 @@ object BuiltIns {
|
||||
ErrorReporting.error("Too complex expressions in comparison", lhs.position)
|
||||
(Nil, Nil, Nil, Nil)
|
||||
}
|
||||
val lType = ExpressionCompiler.getExpressionType(ctx, lhs)
|
||||
val rType = ExpressionCompiler.getExpressionType(ctx, rhs)
|
||||
val lType = MosExpressionCompiler.getExpressionType(ctx, lhs)
|
||||
val rType = MosExpressionCompiler.getExpressionType(ctx, rhs)
|
||||
val compactEqualityComparison = if (ctx.options.flag(CompilationFlag.OptimizeForSpeed)) {
|
||||
None
|
||||
} else if (lType.size == 1 && !lType.isSigned) {
|
||||
@ -495,7 +495,7 @@ object BuiltIns {
|
||||
compactEqualityComparison match {
|
||||
case Some(code) => code :+ AssemblyLine.relative(BEQ, Label(x))
|
||||
case None =>
|
||||
val innerLabel = MfCompiler.nextLabel("cp")
|
||||
val innerLabel = MosCompiler.nextLabel("cp")
|
||||
staTo(LDA, ll) ++
|
||||
staTo(CMP, rl) ++
|
||||
List(AssemblyLine.relative(BNE, innerLabel)) ++
|
||||
@ -519,7 +519,7 @@ object BuiltIns {
|
||||
}
|
||||
|
||||
case ComparisonType.LessUnsigned =>
|
||||
val innerLabel = MfCompiler.nextLabel("cp")
|
||||
val innerLabel = MosCompiler.nextLabel("cp")
|
||||
staTo(LDA, lh) ++
|
||||
staTo(CMP, rh) ++
|
||||
List(
|
||||
@ -532,7 +532,7 @@ object BuiltIns {
|
||||
AssemblyLine.label(innerLabel))
|
||||
|
||||
case ComparisonType.LessOrEqualUnsigned =>
|
||||
val innerLabel = MfCompiler.nextLabel("cp")
|
||||
val innerLabel = MosCompiler.nextLabel("cp")
|
||||
staTo(LDA, rh) ++
|
||||
staTo(CMP, lh) ++
|
||||
List(AssemblyLine.relative(BCC, innerLabel),
|
||||
@ -543,7 +543,7 @@ object BuiltIns {
|
||||
AssemblyLine.label(innerLabel))
|
||||
|
||||
case ComparisonType.GreaterUnsigned =>
|
||||
val innerLabel = MfCompiler.nextLabel("cp")
|
||||
val innerLabel = MosCompiler.nextLabel("cp")
|
||||
staTo(LDA, rh) ++
|
||||
staTo(CMP, lh) ++
|
||||
List(AssemblyLine.relative(BCC, Label(x)),
|
||||
@ -554,7 +554,7 @@ object BuiltIns {
|
||||
AssemblyLine.label(innerLabel))
|
||||
|
||||
case ComparisonType.GreaterOrEqualUnsigned =>
|
||||
val innerLabel = MfCompiler.nextLabel("cp")
|
||||
val innerLabel = MosCompiler.nextLabel("cp")
|
||||
staTo(LDA, lh) ++
|
||||
staTo(CMP, rh) ++
|
||||
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] = {
|
||||
val rType = ExpressionCompiler.getExpressionType(ctx, rhs)
|
||||
val rType = MosExpressionCompiler.getExpressionType(ctx, rhs)
|
||||
if (rType.size < size && rType.isSigned) {
|
||||
if (alreadyFlipped) ???
|
||||
else return compileLongComparison(ctx, ComparisonType.flip(compType), rhs, lhs, size, branches, alreadyFlipped = true)
|
||||
@ -617,7 +617,7 @@ object BuiltIns {
|
||||
case _ =>
|
||||
effectiveComparisonType match {
|
||||
case ComparisonType.Equal =>
|
||||
val innerLabel = MfCompiler.nextLabel("cp")
|
||||
val innerLabel = MosCompiler.nextLabel("cp")
|
||||
val bytewise = l.zip(r).map{
|
||||
case (staL, staR) => staTo(LDA, staL) ++ staTo(CMP, staR)
|
||||
}
|
||||
@ -658,13 +658,13 @@ object BuiltIns {
|
||||
val b = ctx.env.get[Type]("byte")
|
||||
ctx.env.eval(addend) match {
|
||||
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, _)) =>
|
||||
ExpressionCompiler.compile(ctx, v, None, NoBranching)
|
||||
MosExpressionCompiler.compile(ctx, v, None, NoBranching)
|
||||
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 _ =>
|
||||
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
|
||||
}
|
||||
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) {
|
||||
simpleOperation(DEC, ctx, v, IndexChoice.RequireX, preserveA = false, commutative = true)
|
||||
} else {
|
||||
@ -741,25 +741,25 @@ object BuiltIns {
|
||||
}
|
||||
case _ =>
|
||||
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 storeLhs = ExpressionCompiler.compileByteStorage(ctx, Register.A, v)
|
||||
val storeLhs = MosExpressionCompiler.compileByteStorage(ctx, MosRegister.A, v)
|
||||
loadRhs ++ modifyAcc ++ storeLhs
|
||||
} 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) {
|
||||
insertBeforeLast(AssemblyLine.implied(SEC), simpleOperation(SBC, ctx, addend, IndexChoice.PreferY, preserveA = true, commutative = false, decimal = decimal))
|
||||
} else {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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] = {
|
||||
@ -772,7 +772,7 @@ object BuiltIns {
|
||||
val targetBytes: List[List[AssemblyLine]] = getStorageForEachByte(ctx, lhs)
|
||||
val lhsIsStack = targetBytes.head.head.opcode == TSX
|
||||
val targetSize = targetBytes.size
|
||||
val addendType = ExpressionCompiler.getExpressionType(ctx, addend)
|
||||
val addendType = MosExpressionCompiler.getExpressionType(ctx, addend)
|
||||
var addendSize = addendType.size
|
||||
|
||||
def isRhsComplex(xs: List[AssemblyLine]): Boolean = xs match {
|
||||
@ -795,7 +795,7 @@ object BuiltIns {
|
||||
case Nil => Nil
|
||||
case x :: Nil => staTo(DEC, x)
|
||||
case x :: xs =>
|
||||
val label = MfCompiler.nextLabel("de")
|
||||
val label = MosCompiler.nextLabel("de")
|
||||
staTo(LDA, x) ++
|
||||
List(AssemblyLine.relative(BNE, label)) ++
|
||||
doDec(xs) ++
|
||||
@ -805,7 +805,7 @@ object BuiltIns {
|
||||
|
||||
val (calculateRhs, addendByteRead0): (List[AssemblyLine], List[List[AssemblyLine]]) = env.eval(addend) match {
|
||||
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 =>
|
||||
if (ctx.options.flags(CompilationFlag.Emit65CE02Opcodes)) {
|
||||
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)
|
||||
case Some(NumericConstant(-1, _)) if canUseIncDec && subtract =>
|
||||
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)
|
||||
case Some(NumericConstant(1, _)) if canUseIncDec && subtract =>
|
||||
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)
|
||||
case Some(NumericConstant(-1, _)) if canUseIncDec && !subtract =>
|
||||
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)
|
||||
case Some(constant) =>
|
||||
addendSize = targetSize
|
||||
@ -888,7 +888,7 @@ object BuiltIns {
|
||||
case None =>
|
||||
addendSize match {
|
||||
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 (isRhsComplex(base)) {
|
||||
if (isRhsStack(base)) {
|
||||
@ -903,9 +903,9 @@ object BuiltIns {
|
||||
base -> List(Nil)
|
||||
}
|
||||
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)) {
|
||||
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) {
|
||||
ErrorReporting.warn("Subtracting a stack-based value", ctx.options)
|
||||
if (isRhsComplex(base)) {
|
||||
@ -932,7 +932,7 @@ object BuiltIns {
|
||||
}
|
||||
} else {
|
||||
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)))
|
||||
} else {
|
||||
base -> List(Nil, List(AssemblyLine.implied(TXA)))
|
||||
@ -1009,7 +1009,7 @@ object BuiltIns {
|
||||
} else {
|
||||
if (i >= addendSize) {
|
||||
if (addendType.isSigned) {
|
||||
val label = MfCompiler.nextLabel("sx")
|
||||
val label = MosCompiler.nextLabel("sx")
|
||||
buffer += AssemblyLine.implied(TXA)
|
||||
if (i == addendSize) {
|
||||
buffer += AssemblyLine.immediate(ORA, 0x7f)
|
||||
@ -1048,14 +1048,14 @@ object BuiltIns {
|
||||
Nil
|
||||
case _ =>
|
||||
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 storeLhs = ExpressionCompiler.compileByteStorage(ctx, Register.A, v)
|
||||
val storeLhs = MosExpressionCompiler.compileByteStorage(ctx, MosRegister.A, v)
|
||||
loadRhs ++ modifyAcc ++ storeLhs
|
||||
} 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 storeLhs = ExpressionCompiler.compileByteStorage(ctx, Register.A, v)
|
||||
val storeLhs = MosExpressionCompiler.compileByteStorage(ctx, MosRegister.A, v)
|
||||
loadLhs ++ modifyLhs ++ storeLhs
|
||||
}
|
||||
}
|
||||
@ -1069,7 +1069,7 @@ object BuiltIns {
|
||||
val targetBytes: List[List[AssemblyLine]] = getStorageForEachByte(ctx, lhs)
|
||||
val lo = targetBytes.head
|
||||
val targetSize = targetBytes.size
|
||||
val paramType = ExpressionCompiler.getExpressionType(ctx, param)
|
||||
val paramType = MosExpressionCompiler.getExpressionType(ctx, param)
|
||||
var paramSize = paramType.size
|
||||
val extendMultipleBytes = targetSize > paramSize + 1
|
||||
val extendAtLeastOneByte = targetSize > paramSize
|
||||
@ -1080,10 +1080,10 @@ object BuiltIns {
|
||||
case None =>
|
||||
paramSize match {
|
||||
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)
|
||||
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)))
|
||||
case _ => Nil -> (param match {
|
||||
case vv: VariableExpression =>
|
||||
@ -1120,7 +1120,7 @@ object BuiltIns {
|
||||
case (EOR, Some(NumericConstant(0, _)))
|
||||
| (ORA, Some(NumericConstant(0, _)))
|
||||
| (AND, Some(NumericConstant(AllOnes, _))) =>
|
||||
ExpressionCompiler.compile(ctx, lhs, None, NoBranching)
|
||||
MosExpressionCompiler.compile(ctx, lhs, None, NoBranching)
|
||||
case _ =>
|
||||
val buffer = mutable.ListBuffer[AssemblyLine]()
|
||||
buffer ++= calculateRhs
|
||||
@ -1132,7 +1132,7 @@ object BuiltIns {
|
||||
}
|
||||
} else {
|
||||
if (paramType.isSigned) {
|
||||
val label = MfCompiler.nextLabel("sx")
|
||||
val label = MosCompiler.nextLabel("sx")
|
||||
buffer += AssemblyLine.implied(TXA)
|
||||
if (i == paramSize) {
|
||||
buffer += AssemblyLine.immediate(ORA, 0x7f)
|
||||
@ -1163,7 +1163,7 @@ object BuiltIns {
|
||||
val variable = env.get[Variable](v.name)
|
||||
List.tabulate(variable.typ.size) { i => AssemblyLine.variable(ctx, STA, variable, i) }
|
||||
case IndexedExpression(variable, index) =>
|
||||
List(ExpressionCompiler.compileByteStorage(ctx, Register.A, lhs))
|
||||
List(MosExpressionCompiler.compileByteStorage(ctx, MosRegister.A, lhs))
|
||||
case SeparateBytesExpression(h: LhsExpression, l: LhsExpression) =>
|
||||
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
|
||||
@ -1171,7 +1171,7 @@ object BuiltIns {
|
||||
}
|
||||
List(
|
||||
getStorageForEachByte(ctx, l).head,
|
||||
ExpressionCompiler.preserveRegisterIfNeeded(ctx, Register.A, getStorageForEachByte(ctx, h).head))
|
||||
MosExpressionCompiler.preserveRegisterIfNeeded(ctx, MosRegister.A, getStorageForEachByte(ctx, h).head))
|
||||
case _ =>
|
||||
???
|
||||
}
|
||||
@ -1189,7 +1189,7 @@ object BuiltIns {
|
||||
if (i < variable.typ.size) {
|
||||
AssemblyLine.variable(ctx, STA, variable, i)
|
||||
} 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.immediate(ORA, 0x7F),
|
||||
AssemblyLine.relative(BMI, label),
|
||||
@ -1199,7 +1199,7 @@ object BuiltIns {
|
||||
}
|
||||
case expr@IndexedExpression(variable, index) =>
|
||||
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))
|
||||
}
|
||||
case SeparateBytesExpression(h: LhsExpression, l: LhsExpression) =>
|
||||
@ -1209,7 +1209,7 @@ object BuiltIns {
|
||||
}
|
||||
List.tabulate(size) { i =>
|
||||
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))
|
||||
}
|
||||
case _ =>
|
@ -1,4 +1,4 @@
|
||||
package millfork.compiler
|
||||
package millfork.compiler.mos
|
||||
|
||||
/**
|
||||
* @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.{CompilationFlag, CompilationOptions}
|
||||
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
@ -13,7 +13,7 @@ case class CompilationContext(env: Environment,
|
||||
breakLabels: Map[String, Label] = Map(),
|
||||
continueLabels: Map[String, Label] = Map()){
|
||||
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
|
||||
copy(env = newEnv)
|
||||
}
|
@ -1,19 +1,13 @@
|
||||
package millfork.compiler
|
||||
package millfork.compiler.mos
|
||||
|
||||
import millfork.{CompilationFlag, CompilationOptions}
|
||||
import millfork.assembly._
|
||||
import millfork.env._
|
||||
import millfork.node._
|
||||
import millfork.assembly.Opcode._
|
||||
import millfork.CompilationFlag
|
||||
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 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}
|
||||
import millfork.node.{Expression, MosRegister, _}
|
||||
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
@ -34,7 +28,7 @@ object DecimalBuiltIns {
|
||||
|
||||
def compileByteShiftRight(ctx: CompilationContext, l: Expression, r: Expression, rotate: Boolean): List[AssemblyLine] = {
|
||||
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, _)) =>
|
||||
Nil
|
||||
case Some(NumericConstant(v, _)) =>
|
||||
@ -48,11 +42,11 @@ object DecimalBuiltIns {
|
||||
}
|
||||
|
||||
private def shiftOrRotateAccumulatorRight(ctx: CompilationContext, rotate: Boolean, preserveCarry: Boolean) = {
|
||||
val skipHiDigit = MfCompiler.nextLabel("ds")
|
||||
val skipLoDigit = MfCompiler.nextLabel("ds")
|
||||
val skipHiDigit = MosCompiler.nextLabel("ds")
|
||||
val skipLoDigit = MosCompiler.nextLabel("ds")
|
||||
val cmos = ctx.options.flags(CompilationFlag.EmitCmosOpcodes)
|
||||
if (preserveCarry) {
|
||||
val constantLabel = MfCompiler.nextLabel("c8")
|
||||
val constantLabel = MosCompiler.nextLabel("c8")
|
||||
val bit = if (cmos) {
|
||||
AssemblyLine.immediate(BIT, 8)
|
||||
} else {
|
||||
@ -142,7 +136,7 @@ object DecimalBuiltIns {
|
||||
ErrorReporting.error("Cannot multiply by a non-constant amount", r.position)
|
||||
return Nil
|
||||
}
|
||||
val fullStorage = ExpressionCompiler.compileByteStorage(ctx, Register.A, l)
|
||||
val fullStorage = MosExpressionCompiler.compileByteStorage(ctx, MosRegister.A, l)
|
||||
val sta = fullStorage.last
|
||||
if (sta.opcode != STA) ???
|
||||
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.{CompilationFlag, CompilationOptions}
|
||||
import millfork.assembly._
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.assembly.mos._
|
||||
import millfork.env._
|
||||
import millfork.node.{Register, _}
|
||||
import millfork.assembly.AddrMode._
|
||||
import millfork.assembly.Opcode._
|
||||
import millfork.error.ErrorReporting
|
||||
|
||||
import scala.collection.JavaConverters._
|
||||
import millfork.node.{MosRegister, _}
|
||||
/**
|
||||
* @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 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 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 BreakStatement(s) => if (s == paramName) BreakStatement(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)
|
||||
case l: LhsExpression =>
|
||||
// TODO: ??
|
||||
ExpressionCompiler.compileByteStorage(ctx, Register.A, l)
|
||||
MosExpressionCompiler.compileByteStorage(ctx, MosRegister.A, l)
|
||||
case _ =>
|
||||
ErrorReporting.error("A non-assignable expression was passed to an inlineable function as a `ref` parameter", actualParam.position)
|
||||
}
|
||||
actualCode = actualCode.map {
|
||||
case a@AssemblyStatement(_, _, expr, _) =>
|
||||
case a@MosAssemblyStatement(_, _, expr, _) =>
|
||||
a.copy(expression = expr.replaceVariable(ph, actualParam))
|
||||
case x => x
|
||||
}
|
||||
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))
|
||||
actualCode = actualCode.map {
|
||||
case a@AssemblyStatement(_, _, expr, _) =>
|
||||
case a@MosAssemblyStatement(_, _, expr, _) =>
|
||||
a.copy(expression = expr.replaceVariable(ph, actualParam))
|
||||
case x => x
|
||||
}
|
||||
@ -78,7 +72,7 @@ object MacroExpander {
|
||||
ErrorReporting.error("Only one macro assembly function parameter can be passed via a register", position)
|
||||
}
|
||||
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 (_, actualParam) =>
|
||||
@ -101,12 +95,12 @@ object MacroExpander {
|
||||
// fix local labels:
|
||||
// TODO: do it even if the labels are in an inline assembly block inside a Millfork function
|
||||
val localLabels = actualCode.flatMap{
|
||||
case AssemblyStatement(LABEL, _, VariableExpression(l), _) => Some(l)
|
||||
case MosAssemblyStatement(LABEL, _, VariableExpression(l), _) => Some(l)
|
||||
case _ => None
|
||||
}.toSet
|
||||
val labelPrefix = MfCompiler.nextLabel("il")
|
||||
val labelPrefix = MosCompiler.nextLabel("il")
|
||||
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))
|
||||
case s => s
|
||||
}
|
@ -1,31 +1,27 @@
|
||||
package millfork.compiler
|
||||
package millfork.compiler.mos
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
|
||||
import millfork.{CompilationFlag, CompilationOptions}
|
||||
import millfork.assembly._
|
||||
import millfork.CompilationFlag
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.assembly.mos._
|
||||
import millfork.compiler.AbstractCompiler
|
||||
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
|
||||
*/
|
||||
//noinspection NotImplementedCode,ScalaUnusedSymbol
|
||||
object MfCompiler {
|
||||
object MosCompiler extends AbstractCompiler[AssemblyLine] {
|
||||
|
||||
|
||||
private val labelCounter = new AtomicLong
|
||||
|
||||
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)
|
||||
val chunk = StatementCompiler.compile(ctx, ctx.function.code)
|
||||
val chunk = MosStatementCompiler.compile(ctx, ctx.function.code)
|
||||
|
||||
val phReg =
|
||||
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, CompilationOptions}
|
||||
import millfork.assembly._
|
||||
import millfork.env._
|
||||
import millfork.node.{Register, _}
|
||||
import millfork.CompilationFlag
|
||||
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.node.{MosRegister, _}
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
*/
|
||||
object ExpressionCompiler {
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
||||
|
||||
def compileConstant(ctx: CompilationContext, expr: Constant, target: Variable): List[AssemblyLine] = {
|
||||
target match {
|
||||
case RegisterVariable(Register.A, _) => List(AssemblyLine(LDA, Immediate, expr))
|
||||
case RegisterVariable(Register.AW, _) =>
|
||||
case RegisterVariable(MosRegister.A, _) => List(AssemblyLine(LDA, Immediate, expr))
|
||||
case RegisterVariable(MosRegister.AW, _) =>
|
||||
List(
|
||||
AssemblyLine.accu16,
|
||||
AssemblyLine(LDA_W, WordImmediate, expr),
|
||||
AssemblyLine.accu8)
|
||||
case RegisterVariable(Register.X, _) => List(AssemblyLine(LDX, Immediate, expr))
|
||||
case RegisterVariable(Register.Y, _) => List(AssemblyLine(LDY, Immediate, expr))
|
||||
case RegisterVariable(Register.AX, _) => List(
|
||||
case RegisterVariable(MosRegister.X, _) => List(AssemblyLine(LDX, Immediate, expr))
|
||||
case RegisterVariable(MosRegister.Y, _) => List(AssemblyLine(LDY, Immediate, expr))
|
||||
case RegisterVariable(MosRegister.AX, _) => List(
|
||||
AssemblyLine(LDA, Immediate, expr.loByte),
|
||||
AssemblyLine(LDX, Immediate, expr.hiByte))
|
||||
case RegisterVariable(Register.AY, _) => List(
|
||||
case RegisterVariable(MosRegister.AY, _) => List(
|
||||
AssemblyLine(LDA, Immediate, expr.loByte),
|
||||
AssemblyLine(LDY, Immediate, expr.hiByte))
|
||||
case RegisterVariable(Register.XA, _) => List(
|
||||
case RegisterVariable(MosRegister.XA, _) => List(
|
||||
AssemblyLine(LDA, Immediate, expr.hiByte),
|
||||
AssemblyLine(LDX, Immediate, expr.loByte))
|
||||
case RegisterVariable(Register.YA, _) => List(
|
||||
case RegisterVariable(MosRegister.YA, _) => List(
|
||||
AssemblyLine(LDA, Immediate, expr.hiByte),
|
||||
AssemblyLine(LDY, Immediate, expr.loByte))
|
||||
case m: VariableInMemory =>
|
||||
@ -160,18 +79,18 @@ object ExpressionCompiler {
|
||||
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 {
|
||||
case Register.A => State.A
|
||||
case Register.X => State.X
|
||||
case Register.Y => State.Y
|
||||
case MosRegister.A => State.A
|
||||
case MosRegister.X => State.X
|
||||
case MosRegister.Y => State.Y
|
||||
}
|
||||
|
||||
val cmos = ctx.options.flag(CompilationFlag.EmitCmosOpcodes)
|
||||
if (AssemblyLine.treatment(code, state) != Treatment.Unchanged) {
|
||||
register match {
|
||||
case Register.A => AssemblyLine.implied(PHA) +: fixTsx(code) :+ AssemblyLine.implied(PLA)
|
||||
case Register.X => if (cmos) {
|
||||
case MosRegister.A => AssemblyLine.implied(PHA) +: fixTsx(code) :+ AssemblyLine.implied(PLA)
|
||||
case MosRegister.X => if (cmos) {
|
||||
List(
|
||||
AssemblyLine.implied(PHA),
|
||||
AssemblyLine.implied(PHX),
|
||||
@ -190,7 +109,7 @@ object ExpressionCompiler {
|
||||
AssemblyLine.implied(PLA),
|
||||
)
|
||||
}
|
||||
case Register.Y => if (cmos) {
|
||||
case MosRegister.Y => if (cmos) {
|
||||
List(
|
||||
AssemblyLine.implied(PHA),
|
||||
AssemblyLine.implied(PHY),
|
||||
@ -222,7 +141,7 @@ object ExpressionCompiler {
|
||||
return Nil
|
||||
}
|
||||
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 {
|
||||
case ConstantPointy(addr, _) =>
|
||||
List(
|
||||
@ -242,18 +161,18 @@ object ExpressionCompiler {
|
||||
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 b = env.get[Type]("byte")
|
||||
val store = register match {
|
||||
case Register.A => STA
|
||||
case Register.X => STX
|
||||
case Register.Y => STY
|
||||
case MosRegister.A => STA
|
||||
case MosRegister.X => STX
|
||||
case MosRegister.Y => STY
|
||||
}
|
||||
val transferToA = register match {
|
||||
case Register.A => NOP
|
||||
case Register.X => TXA
|
||||
case Register.Y => TYA
|
||||
case MosRegister.A => NOP
|
||||
case MosRegister.X => TXA
|
||||
case MosRegister.Y => TYA
|
||||
}
|
||||
target match {
|
||||
case VariableExpression(name) =>
|
||||
@ -291,21 +210,21 @@ object ExpressionCompiler {
|
||||
|
||||
def storeToArrayAtUnknownIndex(variableIndex: Expression, arrayAddr: Constant) = {
|
||||
// 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))
|
||||
if (register == Register.A) {
|
||||
if (register == MosRegister.A) {
|
||||
indexRegister match {
|
||||
case Register.Y =>
|
||||
calculatingIndex ++ arrayBoundsCheck(ctx, pointy, Register.Y, indexExpr) ++ List(AssemblyLine.absoluteY(STA, arrayAddr + constIndex))
|
||||
case Register.X =>
|
||||
calculatingIndex ++ arrayBoundsCheck(ctx, pointy, Register.X, indexExpr) ++ List(AssemblyLine.absoluteX(STA, arrayAddr + constIndex))
|
||||
case MosRegister.Y =>
|
||||
calculatingIndex ++ arrayBoundsCheck(ctx, pointy, MosRegister.Y, indexExpr) ++ List(AssemblyLine.absoluteY(STA, arrayAddr + constIndex))
|
||||
case MosRegister.X =>
|
||||
calculatingIndex ++ arrayBoundsCheck(ctx, pointy, MosRegister.X, indexExpr) ++ List(AssemblyLine.absoluteX(STA, arrayAddr + constIndex))
|
||||
}
|
||||
} else {
|
||||
indexRegister match {
|
||||
case Register.Y =>
|
||||
calculatingIndex ++ arrayBoundsCheck(ctx, pointy, Register.Y, indexExpr) ++ List(AssemblyLine.implied(transferToA), AssemblyLine.absoluteY(STA, arrayAddr + constIndex))
|
||||
case Register.X =>
|
||||
calculatingIndex ++ arrayBoundsCheck(ctx, pointy, Register.X, indexExpr) ++ List(AssemblyLine.implied(transferToA), AssemblyLine.absoluteX(STA, arrayAddr + constIndex))
|
||||
case MosRegister.Y =>
|
||||
calculatingIndex ++ arrayBoundsCheck(ctx, pointy, MosRegister.Y, indexExpr) ++ List(AssemblyLine.implied(transferToA), AssemblyLine.absoluteY(STA, arrayAddr + constIndex))
|
||||
case MosRegister.X =>
|
||||
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 cmos = ctx.options.flag(CompilationFlag.EmitCmosOpcodes)
|
||||
register match {
|
||||
case Register.A =>
|
||||
case MosRegister.A =>
|
||||
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 (cmos)
|
||||
List(AssemblyLine.implied(PHX)) ++ code ++ List(AssemblyLine.implied(PLA), AssemblyLine.indexedY(STA, reg))
|
||||
@ -324,7 +243,7 @@ object ExpressionCompiler {
|
||||
} else {
|
||||
code ++ List(AssemblyLine.implied(TXA), AssemblyLine.indexedY(STA, reg))
|
||||
}
|
||||
case Register.Y =>
|
||||
case MosRegister.Y =>
|
||||
if (cmos)
|
||||
List(AssemblyLine.implied(PHY)) ++ code ++ List(AssemblyLine.implied(PLA), AssemblyLine.indexedY(STA, reg))
|
||||
else
|
||||
@ -344,25 +263,25 @@ object ExpressionCompiler {
|
||||
//TODO: should there be a type check or a zeropage check?
|
||||
case (pointerVariable:VariablePointy, None, _, 0 | 1) =>
|
||||
register match {
|
||||
case Register.A =>
|
||||
case MosRegister.A =>
|
||||
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))
|
||||
case Register.X =>
|
||||
case MosRegister.X =>
|
||||
List(AssemblyLine.immediate(LDY, constIndex), AssemblyLine.implied(TXA), AssemblyLine.indexedY(STA, pointerVariable.addr))
|
||||
case _ =>
|
||||
ErrorReporting.error("Cannot store a word in an array", target.position)
|
||||
Nil
|
||||
}
|
||||
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 {
|
||||
case Register.A =>
|
||||
preserveRegisterIfNeeded(ctx, Register.A, calculatingIndex) :+ AssemblyLine.indexedY(STA, pointerVariable.addr)
|
||||
case Register.X =>
|
||||
preserveRegisterIfNeeded(ctx, Register.X, calculatingIndex) ++ List(AssemblyLine.implied(TXA), AssemblyLine.indexedY(STA, pointerVariable.addr))
|
||||
case Register.Y =>
|
||||
AssemblyLine.implied(TYA) :: preserveRegisterIfNeeded(ctx, Register.A, calculatingIndex) ++ List(
|
||||
case MosRegister.A =>
|
||||
preserveRegisterIfNeeded(ctx, MosRegister.A, calculatingIndex) :+ AssemblyLine.indexedY(STA, pointerVariable.addr)
|
||||
case MosRegister.X =>
|
||||
preserveRegisterIfNeeded(ctx, MosRegister.X, calculatingIndex) ++ List(AssemblyLine.implied(TXA), AssemblyLine.indexedY(STA, pointerVariable.addr))
|
||||
case MosRegister.Y =>
|
||||
AssemblyLine.implied(TYA) :: preserveRegisterIfNeeded(ctx, MosRegister.A, calculatingIndex) ++ List(
|
||||
AssemblyLine.indexedY(STA, pointerVariable.addr), AssemblyLine.implied(TAY)
|
||||
)
|
||||
case _ =>
|
||||
@ -462,8 +381,8 @@ object ExpressionCompiler {
|
||||
env.get[TypedThing](name) match {
|
||||
case source: VariableInMemory =>
|
||||
target match {
|
||||
case RegisterVariable(Register.A, _) => AssemblyLine.variable(ctx, LDA, source)
|
||||
case RegisterVariable(Register.AW, _) =>
|
||||
case RegisterVariable(MosRegister.A, _) => AssemblyLine.variable(ctx, LDA, source)
|
||||
case RegisterVariable(MosRegister.AW, _) =>
|
||||
exprType.size match {
|
||||
case 1 => if (exprType.isSigned) {
|
||||
AssemblyLine.variable(ctx, LDA, source) ++ List(
|
||||
@ -475,9 +394,9 @@ object ExpressionCompiler {
|
||||
// TODO: use LDA_W
|
||||
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(Register.Y, _) => AssemblyLine.variable(ctx, LDY, source)
|
||||
case RegisterVariable(Register.AX, _) =>
|
||||
case RegisterVariable(MosRegister.X, _) => AssemblyLine.variable(ctx, LDX, source)
|
||||
case RegisterVariable(MosRegister.Y, _) => AssemblyLine.variable(ctx, LDY, source)
|
||||
case RegisterVariable(MosRegister.AX, _) =>
|
||||
exprType.size match {
|
||||
case 1 => if (exprType.isSigned) {
|
||||
AssemblyLine.variable(ctx, LDA, source) ++ List(
|
||||
@ -488,7 +407,7 @@ object ExpressionCompiler {
|
||||
case 2 =>
|
||||
AssemblyLine.variable(ctx, LDA, source) ++ AssemblyLine.variable(ctx, LDX, source, 1)
|
||||
}
|
||||
case RegisterVariable(Register.AY, _) =>
|
||||
case RegisterVariable(MosRegister.AY, _) =>
|
||||
exprType.size match {
|
||||
case 1 => if (exprType.isSigned) {
|
||||
AssemblyLine.variable(ctx, LDA, source) ++ List(
|
||||
@ -501,7 +420,7 @@ object ExpressionCompiler {
|
||||
case 2 =>
|
||||
AssemblyLine.variable(ctx, LDA, source) ++ AssemblyLine.variable(ctx, LDY, source, 1)
|
||||
}
|
||||
case RegisterVariable(Register.XA, _) =>
|
||||
case RegisterVariable(MosRegister.XA, _) =>
|
||||
exprType.size match {
|
||||
case 1 => if (exprType.isSigned) {
|
||||
AssemblyLine.variable(ctx, LDX, source) ++ List(AssemblyLine.implied(TXA)) ++ signExtendA()
|
||||
@ -510,7 +429,7 @@ object ExpressionCompiler {
|
||||
case 2 =>
|
||||
AssemblyLine.variable(ctx, LDX, source) ++ AssemblyLine.variable(ctx,LDA, source, 1)
|
||||
}
|
||||
case RegisterVariable(Register.YA, _) =>
|
||||
case RegisterVariable(MosRegister.YA, _) =>
|
||||
exprType.size match {
|
||||
case 1 => if (exprType.isSigned) {
|
||||
AssemblyLine.variable(ctx, LDY, source) ++ List(AssemblyLine.implied(TYA)) ++ signExtendA()
|
||||
@ -551,10 +470,10 @@ object ExpressionCompiler {
|
||||
}
|
||||
case source@StackVariable(_, sourceType, offset) =>
|
||||
target match {
|
||||
case RegisterVariable(Register.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(Register.Y, _) => List(AssemblyLine.implied(TSX), AssemblyLine.absoluteX(LDY, offset + ctx.extraStackOffset))
|
||||
case RegisterVariable(Register.AX, _) =>
|
||||
case RegisterVariable(MosRegister.A, _) => List(AssemblyLine.implied(TSX), AssemblyLine.absoluteX(LDA, offset + ctx.extraStackOffset))
|
||||
case RegisterVariable(MosRegister.X, _) => List(AssemblyLine.implied(TSX), AssemblyLine.absoluteX(LDA, offset + ctx.extraStackOffset), AssemblyLine.implied(TAX))
|
||||
case RegisterVariable(MosRegister.Y, _) => List(AssemblyLine.implied(TSX), AssemblyLine.absoluteX(LDY, offset + ctx.extraStackOffset))
|
||||
case RegisterVariable(MosRegister.AX, _) =>
|
||||
exprType.size match {
|
||||
case 1 => if (exprType.isSigned) {
|
||||
List(
|
||||
@ -575,10 +494,10 @@ object ExpressionCompiler {
|
||||
AssemblyLine.implied(TAX),
|
||||
AssemblyLine.implied(PLA))
|
||||
}
|
||||
case RegisterVariable(Register.AY, _) =>
|
||||
case RegisterVariable(MosRegister.AY, _) =>
|
||||
exprType.size match {
|
||||
case 1 => if (exprType.isSigned) {
|
||||
val label = MfCompiler.nextLabel("sx")
|
||||
val label = MosCompiler.nextLabel("sx")
|
||||
??? // TODO
|
||||
} else {
|
||||
List(
|
||||
@ -591,12 +510,12 @@ object ExpressionCompiler {
|
||||
AssemblyLine.absoluteX(LDA, offset + ctx.extraStackOffset),
|
||||
AssemblyLine.absoluteX(LDY, offset + ctx.extraStackOffset + 1))
|
||||
}
|
||||
case RegisterVariable(Register.XA, _) =>
|
||||
case RegisterVariable(MosRegister.XA, _) =>
|
||||
??? // TODO
|
||||
case RegisterVariable(Register.YA, _) =>
|
||||
case RegisterVariable(MosRegister.YA, _) =>
|
||||
exprType.size match {
|
||||
case 1 => if (exprType.isSigned) {
|
||||
val label = MfCompiler.nextLabel("sx")
|
||||
val label = MosCompiler.nextLabel("sx")
|
||||
??? // TODO
|
||||
} else {
|
||||
List(
|
||||
@ -654,7 +573,7 @@ object ExpressionCompiler {
|
||||
|
||||
val register = target match {
|
||||
case RegisterVariable(r, _) => r
|
||||
case _ => Register.A
|
||||
case _ => MosRegister.A
|
||||
}
|
||||
val suffix = target match {
|
||||
case RegisterVariable(_, _) => Nil
|
||||
@ -672,31 +591,31 @@ object ExpressionCompiler {
|
||||
}
|
||||
}
|
||||
val load = register match {
|
||||
case Register.A | Register.AX | Register.AY => LDA
|
||||
case Register.X => LDX
|
||||
case Register.Y => LDY
|
||||
case MosRegister.A | MosRegister.AX | MosRegister.AY => LDA
|
||||
case MosRegister.X => LDX
|
||||
case MosRegister.Y => LDY
|
||||
}
|
||||
|
||||
def loadFromArrayAtUnknownIndex(variableIndex: Expression, arrayAddr: Constant) = {
|
||||
// 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)
|
||||
indexRegister match {
|
||||
case Register.Y =>
|
||||
calculatingIndex ++ arrayBoundsCheck(ctx, pointy, Register.Y, indexExpr) ++ List(AssemblyLine.absoluteY(load, arrayAddr + constantIndex))
|
||||
case Register.X =>
|
||||
calculatingIndex ++ arrayBoundsCheck(ctx, pointy, Register.X, indexExpr) ++ List(AssemblyLine.absoluteX(load, arrayAddr + constantIndex))
|
||||
case MosRegister.Y =>
|
||||
calculatingIndex ++ arrayBoundsCheck(ctx, pointy, MosRegister.Y, indexExpr) ++ List(AssemblyLine.absoluteY(load, arrayAddr + constantIndex))
|
||||
case MosRegister.X =>
|
||||
calculatingIndex ++ arrayBoundsCheck(ctx, pointy, MosRegister.X, indexExpr) ++ List(AssemblyLine.absoluteX(load, arrayAddr + constantIndex))
|
||||
}
|
||||
}
|
||||
|
||||
def loadFromReg() = {
|
||||
val reg = ctx.env.get[VariableInMemory]("__reg")
|
||||
register match {
|
||||
case Register.A =>
|
||||
case MosRegister.A =>
|
||||
List(AssemblyLine.indexedY(LDA, reg))
|
||||
case Register.X =>
|
||||
case MosRegister.X =>
|
||||
List(AssemblyLine.indexedY(LDA, reg), AssemblyLine.implied(TAX))
|
||||
case Register.Y =>
|
||||
case MosRegister.Y =>
|
||||
List(AssemblyLine.indexedY(LDA, reg), AssemblyLine.implied(TAY))
|
||||
}
|
||||
}
|
||||
@ -711,21 +630,21 @@ object ExpressionCompiler {
|
||||
prepareWordIndexing(ctx, a, indexExpr) ++ loadFromReg()
|
||||
case (p:VariablePointy, None, 0 | 1, _) =>
|
||||
register match {
|
||||
case Register.A =>
|
||||
case MosRegister.A =>
|
||||
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))
|
||||
case Register.X =>
|
||||
case MosRegister.X =>
|
||||
List(AssemblyLine.immediate(LDY, constantIndex), AssemblyLine.indexedY(LDA, p.addr), AssemblyLine.implied(TAX))
|
||||
}
|
||||
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 {
|
||||
case Register.A =>
|
||||
case MosRegister.A =>
|
||||
calculatingIndex :+ AssemblyLine.indexedY(LDA, p.addr)
|
||||
case Register.X =>
|
||||
case MosRegister.X =>
|
||||
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))
|
||||
}
|
||||
case _ =>
|
||||
@ -733,9 +652,9 @@ object ExpressionCompiler {
|
||||
Nil
|
||||
}
|
||||
register match {
|
||||
case Register.A | Register.X | Register.Y => result ++ suffix
|
||||
case Register.AX => result :+ AssemblyLine.immediate(LDX, 0)
|
||||
case Register.AY => result :+ AssemblyLine.immediate(LDY, 0)
|
||||
case MosRegister.A | MosRegister.X | MosRegister.Y => result ++ suffix
|
||||
case MosRegister.AX => result :+ AssemblyLine.immediate(LDX, 0)
|
||||
case MosRegister.AY => result :+ AssemblyLine.immediate(LDY, 0)
|
||||
}
|
||||
}
|
||||
case SumExpression(params, decimal) =>
|
||||
@ -774,19 +693,19 @@ object ExpressionCompiler {
|
||||
assertCompatible(exprType, target.typ)
|
||||
target match {
|
||||
// TODO: some more complex ones may not work correctly
|
||||
case RegisterVariable(Register.A | Register.X | Register.Y, _) => compile(ctx, l, exprTypeAndVariable, branches)
|
||||
case RegisterVariable(Register.AX, _) =>
|
||||
compile(ctx, l, Some(b -> RegisterVariable(Register.A, b)), branches) ++
|
||||
preserveRegisterIfNeeded(ctx, Register.A, compile(ctx, h, Some(b -> RegisterVariable(Register.X, b)), branches))
|
||||
case RegisterVariable(Register.AY, _) =>
|
||||
compile(ctx, l, Some(b -> RegisterVariable(Register.A, b)), branches) ++
|
||||
preserveRegisterIfNeeded(ctx, Register.A, compile(ctx, h, Some(b -> RegisterVariable(Register.Y, b)), branches))
|
||||
case RegisterVariable(Register.XA, _) =>
|
||||
compile(ctx, l, Some(b -> RegisterVariable(Register.X, b)), branches) ++
|
||||
compile(ctx, h, Some(b -> RegisterVariable(Register.A, b)), branches)
|
||||
case RegisterVariable(Register.YA, _) =>
|
||||
compile(ctx, l, Some(b -> RegisterVariable(Register.Y, b)), branches) ++
|
||||
compile(ctx, h, Some(b -> RegisterVariable(Register.A, b)), branches)
|
||||
case RegisterVariable(MosRegister.A | MosRegister.X | MosRegister.Y, _) => compile(ctx, l, exprTypeAndVariable, branches)
|
||||
case RegisterVariable(MosRegister.AX, _) =>
|
||||
compile(ctx, l, Some(b -> RegisterVariable(MosRegister.A, b)), branches) ++
|
||||
preserveRegisterIfNeeded(ctx, MosRegister.A, compile(ctx, h, Some(b -> RegisterVariable(MosRegister.X, b)), branches))
|
||||
case RegisterVariable(MosRegister.AY, _) =>
|
||||
compile(ctx, l, Some(b -> RegisterVariable(MosRegister.A, b)), branches) ++
|
||||
preserveRegisterIfNeeded(ctx, MosRegister.A, compile(ctx, h, Some(b -> RegisterVariable(MosRegister.Y, b)), branches))
|
||||
case RegisterVariable(MosRegister.XA, _) =>
|
||||
compile(ctx, l, Some(b -> RegisterVariable(MosRegister.X, b)), branches) ++
|
||||
compile(ctx, h, Some(b -> RegisterVariable(MosRegister.A, b)), branches)
|
||||
case RegisterVariable(MosRegister.YA, _) =>
|
||||
compile(ctx, l, Some(b -> RegisterVariable(MosRegister.Y, b)), branches) ++
|
||||
compile(ctx, h, Some(b -> RegisterVariable(MosRegister.A, b)), branches)
|
||||
case target: VariableInMemory =>
|
||||
target.typ.size match {
|
||||
case 1 =>
|
||||
@ -827,7 +746,7 @@ object ExpressionCompiler {
|
||||
ErrorReporting.error("Invalid parameter type for hi/lo", param.position)
|
||||
compile(ctx, param, None, BranchSpec.None)
|
||||
} 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 (typ.size == 2) compilation :+ AssemblyLine.implied(TXA)
|
||||
else if (typ.isSigned) compilation ++ signExtendA()
|
||||
@ -853,8 +772,8 @@ object ExpressionCompiler {
|
||||
case _ =>
|
||||
ErrorReporting.warn("Unspecified nonet operation, results might be unpredictable", ctx.options, expr.position)
|
||||
}
|
||||
val label = MfCompiler.nextLabel("no")
|
||||
compile(ctx, params.head, Some(b -> RegisterVariable(Register.A, b)), BranchSpec.None) ++ List(
|
||||
val label = MosCompiler.nextLabel("no")
|
||||
compile(ctx, params.head, Some(b -> RegisterVariable(MosRegister.A, b)), BranchSpec.None) ++ List(
|
||||
AssemblyLine.immediate(LDX, 0),
|
||||
AssemblyLine.relative(BCC, label),
|
||||
AssemblyLine.implied(INX),
|
||||
@ -867,7 +786,7 @@ object ExpressionCompiler {
|
||||
case BranchIfFalse(_) =>
|
||||
params.flatMap(compile(ctx, _, exprTypeAndVariable, branches))
|
||||
case _ =>
|
||||
val skip = MfCompiler.nextLabel("an")
|
||||
val skip = MosCompiler.nextLabel("an")
|
||||
params.init.flatMap(compile(ctx, _, exprTypeAndVariable, BranchIfFalse(skip))) ++
|
||||
compile(ctx, params.last, exprTypeAndVariable, branches) ++
|
||||
List(AssemblyLine.label(skip))
|
||||
@ -878,7 +797,7 @@ object ExpressionCompiler {
|
||||
case BranchIfTrue(_) =>
|
||||
params.flatMap(compile(ctx, _, exprTypeAndVariable, branches))
|
||||
case _ =>
|
||||
val skip = MfCompiler.nextLabel("or")
|
||||
val skip = MosCompiler.nextLabel("or")
|
||||
params.init.flatMap(compile(ctx, _, exprTypeAndVariable, BranchIfTrue(skip))) ++
|
||||
compile(ctx, params.last, exprTypeAndVariable, branches) ++
|
||||
List(AssemblyLine.label(skip))
|
||||
@ -1096,7 +1015,7 @@ object ExpressionCompiler {
|
||||
val (l, r, size) = assertAssignmentLike(ctx, params)
|
||||
size match {
|
||||
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 =>
|
||||
l match {
|
||||
case v: LhsExpression =>
|
||||
@ -1107,7 +1026,7 @@ object ExpressionCompiler {
|
||||
val (l, r, size) = assertAssignmentLike(ctx, params)
|
||||
size match {
|
||||
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 =>
|
||||
l match {
|
||||
case v: LhsExpression =>
|
||||
@ -1181,7 +1100,7 @@ object ExpressionCompiler {
|
||||
case function: MacroFunction =>
|
||||
val (paramPreparation, statements) = MacroExpander.inlineFunction(ctx, function, params, expr.position)
|
||||
paramPreparation ++ statements.map {
|
||||
case AssemblyStatement(opcode, addrMode, expression, elidable) =>
|
||||
case MosAssemblyStatement(opcode, addrMode, expression, elidable) =>
|
||||
val param = env.evalForAsm(expression).getOrElse {
|
||||
ErrorReporting.error("Inlining failed due to non-constant things", expression.position)
|
||||
Constant.Zero
|
||||
@ -1271,14 +1190,14 @@ object ExpressionCompiler {
|
||||
def expressionStorageFromAX(ctx: CompilationContext, exprTypeAndVariable: Option[(Type, Variable)], position: Option[Position]): List[AssemblyLine] = {
|
||||
exprTypeAndVariable.fold(noop) {
|
||||
case (VoidType, _) => ErrorReporting.fatal("Cannot assign word to void", position)
|
||||
case (_, RegisterVariable(Register.A, _)) => noop
|
||||
case (_, RegisterVariable(Register.AW, _)) => List(AssemblyLine.implied(XBA), AssemblyLine.implied(TXA), AssemblyLine.implied(XBA))
|
||||
case (_, RegisterVariable(Register.X, _)) => List(AssemblyLine.implied(TAX))
|
||||
case (_, RegisterVariable(Register.Y, _)) => List(AssemblyLine.implied(TAY))
|
||||
case (_, RegisterVariable(Register.AX, _)) =>
|
||||
case (_, RegisterVariable(MosRegister.A, _)) => noop
|
||||
case (_, RegisterVariable(MosRegister.AW, _)) => List(AssemblyLine.implied(XBA), AssemblyLine.implied(TXA), AssemblyLine.implied(XBA))
|
||||
case (_, RegisterVariable(MosRegister.X, _)) => List(AssemblyLine.implied(TAX))
|
||||
case (_, RegisterVariable(MosRegister.Y, _)) => List(AssemblyLine.implied(TAY))
|
||||
case (_, RegisterVariable(MosRegister.AX, _)) =>
|
||||
// TODO: sign extension
|
||||
noop
|
||||
case (_, RegisterVariable(Register.XA, _)) =>
|
||||
case (_, RegisterVariable(MosRegister.XA, _)) =>
|
||||
// TODO: sign extension
|
||||
if (ctx.options.flag(CompilationFlag.EmitHudsonOpcodes)) {
|
||||
List(AssemblyLine.implied(HuSAX))
|
||||
@ -1297,12 +1216,12 @@ object ExpressionCompiler {
|
||||
AssemblyLine.implied(TAX),
|
||||
AssemblyLine.implied(PLA)) // fuck this shit
|
||||
}
|
||||
case (_, RegisterVariable(Register.YA, _)) =>
|
||||
case (_, RegisterVariable(MosRegister.YA, _)) =>
|
||||
// TODO: sign extension
|
||||
List(
|
||||
AssemblyLine.implied(TAY),
|
||||
AssemblyLine.implied(TXA))
|
||||
case (_, RegisterVariable(Register.AY, _)) =>
|
||||
case (_, RegisterVariable(MosRegister.AY, _)) =>
|
||||
// TODO: sign extension
|
||||
if (ctx.options.flag(CompilationFlag.EmitHudsonOpcodes)) {
|
||||
List(AssemblyLine.implied(SXY))
|
||||
@ -1408,23 +1327,17 @@ object ExpressionCompiler {
|
||||
// TODO check v.typ
|
||||
compile(ctx, source, Some((getExpressionType(ctx, source), v)), NoBranching)
|
||||
case SeparateBytesExpression(h: LhsExpression, l: LhsExpression) =>
|
||||
compile(ctx, source, Some(w, RegisterVariable(Register.AX, w)), NoBranching) ++
|
||||
compileByteStorage(ctx, Register.A, l) ++ compileByteStorage(ctx, Register.X, h)
|
||||
compile(ctx, source, Some(w, RegisterVariable(MosRegister.AX, w)), NoBranching) ++
|
||||
compileByteStorage(ctx, MosRegister.A, l) ++ compileByteStorage(ctx, MosRegister.X, h)
|
||||
case SeparateBytesExpression(_, _) =>
|
||||
ErrorReporting.error("Invalid left-hand-side use of `:`")
|
||||
Nil
|
||||
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 = {
|
||||
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] = {
|
||||
def arrayBoundsCheck(ctx: CompilationContext, pointy: Pointy, register: MosRegister.Value, index: Expression): List[AssemblyLine] = {
|
||||
if (!ctx.options.flags(CompilationFlag.CheckIndexOutOfBounds)) return Nil
|
||||
val arrayLength = pointy match {
|
||||
case _: VariablePointy => return Nil
|
||||
@ -1442,11 +1355,11 @@ object ExpressionCompiler {
|
||||
case _ =>
|
||||
}
|
||||
if (arrayLength > 0 && arrayLength < 255) {
|
||||
val label = MfCompiler.nextLabel("bc")
|
||||
val label = MosCompiler.nextLabel("bc")
|
||||
val compare = register match {
|
||||
case Register.A => CMP
|
||||
case Register.X => CPX
|
||||
case Register.Y => CPY
|
||||
case MosRegister.A => CMP
|
||||
case MosRegister.X => CPX
|
||||
case MosRegister.Y => CPY
|
||||
}
|
||||
List(
|
||||
AssemblyLine.implied(PHP),
|
||||
@ -1461,7 +1374,7 @@ object ExpressionCompiler {
|
||||
}
|
||||
|
||||
private def signExtendA(): List[AssemblyLine] = {
|
||||
val label = MfCompiler.nextLabel("sx")
|
||||
val label = MosCompiler.nextLabel("sx")
|
||||
List(
|
||||
AssemblyLine.immediate(ORA, 0x7F),
|
||||
AssemblyLine.relative(BMI, label),
|
@ -1,19 +1,17 @@
|
||||
package millfork.compiler
|
||||
package millfork.compiler.mos
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
|
||||
import millfork.{CompilationFlag, CompilationOptions}
|
||||
import millfork.assembly._
|
||||
import millfork.env._
|
||||
import millfork.node.{Register, _}
|
||||
import millfork.CompilationFlag
|
||||
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.node.{MosRegister, _}
|
||||
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
*/
|
||||
object StatementCompiler {
|
||||
object MosStatementCompiler {
|
||||
|
||||
private def labelChunk(labelName: String) = List(AssemblyLine.label(Label(labelName)))
|
||||
|
||||
@ -41,9 +39,9 @@ object StatementCompiler {
|
||||
AssemblyLine.zeropage(STA, reg)
|
||||
)
|
||||
} else Nil
|
||||
val someRegisterA = Some(b, RegisterVariable(Register.A, b))
|
||||
val someRegisterAX = Some(w, RegisterVariable(Register.AX, w))
|
||||
val someRegisterYA = Some(w, RegisterVariable(Register.YA, w))
|
||||
val someRegisterA = Some(b, RegisterVariable(MosRegister.A, b))
|
||||
val someRegisterAX = Some(w, RegisterVariable(MosRegister.AX, w))
|
||||
val someRegisterYA = Some(w, RegisterVariable(MosRegister.YA, w))
|
||||
val returnInstructions = if (m.interrupt) {
|
||||
if (ctx.options.flag(CompilationFlag.EmitNative65816Opcodes)) {
|
||||
if (ctx.options.flag(CompilationFlag.ZeropagePseudoregister)) {
|
||||
@ -114,7 +112,7 @@ object StatementCompiler {
|
||||
})
|
||||
}
|
||||
statement match {
|
||||
case AssemblyStatement(o, a, x, e) =>
|
||||
case MosAssemblyStatement(o, a, x, e) =>
|
||||
val c: Constant = x match {
|
||||
// TODO: hmmm
|
||||
case VariableExpression(name) =>
|
||||
@ -143,14 +141,14 @@ object StatementCompiler {
|
||||
}
|
||||
}
|
||||
case Assignment(dest, source) =>
|
||||
ExpressionCompiler.compileAssignment(ctx, source, dest)
|
||||
MosExpressionCompiler.compileAssignment(ctx, source, dest)
|
||||
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) =>
|
||||
val (paramPreparation, inlinedStatements) = MacroExpander.inlineFunction(ctx, i, params, e.position)
|
||||
paramPreparation ++ compile(ctx.withInlinedEnv(i.environment), inlinedStatements)
|
||||
case _ =>
|
||||
ExpressionCompiler.compile(ctx, e, None, NoBranching)
|
||||
MosExpressionCompiler.compile(ctx, e, None, NoBranching)
|
||||
}
|
||||
case ExpressionStatement(e) =>
|
||||
e match {
|
||||
@ -158,7 +156,7 @@ object StatementCompiler {
|
||||
ErrorReporting.warn("Pointless expression statement", ctx.options, statement.position)
|
||||
case _ =>
|
||||
}
|
||||
ExpressionCompiler.compile(ctx, e, None, NoBranching)
|
||||
MosExpressionCompiler.compile(ctx, e, None, NoBranching)
|
||||
case ReturnStatement(None) =>
|
||||
// TODO: return type check
|
||||
// TODO: better stackpointer fix
|
||||
@ -187,9 +185,9 @@ object StatementCompiler {
|
||||
ErrorReporting.error("Cannot return anything from a void function", statement.position)
|
||||
stackPointerFixBeforeReturn(ctx) ++ returnInstructions
|
||||
case 1 =>
|
||||
ExpressionCompiler.compile(ctx, e, someRegisterA, NoBranching) ++ stackPointerFixBeforeReturn(ctx) ++ returnInstructions
|
||||
MosExpressionCompiler.compile(ctx, e, someRegisterA, NoBranching) ++ stackPointerFixBeforeReturn(ctx) ++ returnInstructions
|
||||
case 2 =>
|
||||
ExpressionCompiler.compile(ctx, e, someRegisterAX, NoBranching) ++ stackPointerFixBeforeReturn(ctx) ++ returnInstructions
|
||||
MosExpressionCompiler.compile(ctx, e, someRegisterAX, NoBranching) ++ stackPointerFixBeforeReturn(ctx) ++ returnInstructions
|
||||
}
|
||||
case _ =>
|
||||
m.returnType.size match {
|
||||
@ -197,14 +195,14 @@ object StatementCompiler {
|
||||
ErrorReporting.error("Cannot return anything from a void function", statement.position)
|
||||
stackPointerFixBeforeReturn(ctx) ++ List(AssemblyLine.discardAF(), AssemblyLine.discardXF(), AssemblyLine.discardYF()) ++ returnInstructions
|
||||
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 =>
|
||||
// TODO: ???
|
||||
val stackPointerFix = stackPointerFixBeforeReturn(ctx)
|
||||
if (stackPointerFix.isEmpty) {
|
||||
ExpressionCompiler.compile(ctx, e, someRegisterAX, NoBranching) ++ List(AssemblyLine.discardYF()) ++ returnInstructions
|
||||
MosExpressionCompiler.compile(ctx, e, someRegisterAX, NoBranching) ++ List(AssemblyLine.discardYF()) ++ returnInstructions
|
||||
} else {
|
||||
ExpressionCompiler.compile(ctx, e, someRegisterYA, NoBranching) ++
|
||||
MosExpressionCompiler.compile(ctx, e, someRegisterYA, NoBranching) ++
|
||||
stackPointerFix ++
|
||||
List(AssemblyLine.implied(TAX), AssemblyLine.implied(TYA), AssemblyLine.discardYF()) ++
|
||||
returnInstructions
|
||||
@ -212,103 +210,103 @@ object StatementCompiler {
|
||||
}
|
||||
}
|
||||
case IfStatement(condition, thenPart, elsePart) =>
|
||||
val condType = ExpressionCompiler.getExpressionType(ctx, condition)
|
||||
val condType = MosExpressionCompiler.getExpressionType(ctx, condition)
|
||||
val thenBlock = compile(ctx, thenPart)
|
||||
val elseBlock = compile(ctx, elsePart)
|
||||
val largeThenBlock = thenBlock.map(_.sizeInBytes).sum > 100
|
||||
val largeElseBlock = elseBlock.map(_.sizeInBytes).sum > 100
|
||||
condType match {
|
||||
case ConstantBooleanType(_, true) =>
|
||||
ExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching) ++ thenBlock
|
||||
MosExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching) ++ thenBlock
|
||||
case ConstantBooleanType(_, false) =>
|
||||
ExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching) ++ elseBlock
|
||||
MosExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching) ++ elseBlock
|
||||
case FlagBooleanType(_, jumpIfTrue, jumpIfFalse) =>
|
||||
(thenPart, elsePart) match {
|
||||
case (Nil, Nil) =>
|
||||
ExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching)
|
||||
MosExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching)
|
||||
case (Nil, _) =>
|
||||
val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching)
|
||||
val conditionBlock = MosExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching)
|
||||
if (largeElseBlock) {
|
||||
val middle = MfCompiler.nextLabel("el")
|
||||
val end = MfCompiler.nextLabel("fi")
|
||||
val middle = MosCompiler.nextLabel("el")
|
||||
val end = MosCompiler.nextLabel("fi")
|
||||
List(conditionBlock, branchChunk(jumpIfFalse, middle), jmpChunk(end), labelChunk(middle), elseBlock, labelChunk(end)).flatten
|
||||
} else {
|
||||
val end = MfCompiler.nextLabel("fi")
|
||||
val end = MosCompiler.nextLabel("fi")
|
||||
List(conditionBlock, branchChunk(jumpIfTrue, end), elseBlock, labelChunk(end)).flatten
|
||||
}
|
||||
case (_, Nil) =>
|
||||
val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching)
|
||||
val conditionBlock = MosExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching)
|
||||
if (largeThenBlock) {
|
||||
val middle = MfCompiler.nextLabel("th")
|
||||
val end = MfCompiler.nextLabel("fi")
|
||||
val middle = MosCompiler.nextLabel("th")
|
||||
val end = MosCompiler.nextLabel("fi")
|
||||
List(conditionBlock, branchChunk(jumpIfTrue, middle), jmpChunk(end), labelChunk(middle), thenBlock, labelChunk(end)).flatten
|
||||
} else {
|
||||
val end = MfCompiler.nextLabel("fi")
|
||||
val end = MosCompiler.nextLabel("fi")
|
||||
List(conditionBlock, branchChunk(jumpIfFalse, end), thenBlock, labelChunk(end)).flatten
|
||||
}
|
||||
case _ =>
|
||||
val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching)
|
||||
val conditionBlock = MosExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching)
|
||||
if (largeThenBlock) {
|
||||
if (largeElseBlock) {
|
||||
val middleT = MfCompiler.nextLabel("th")
|
||||
val middleE = MfCompiler.nextLabel("el")
|
||||
val end = MfCompiler.nextLabel("fi")
|
||||
val middleT = MosCompiler.nextLabel("th")
|
||||
val middleE = MosCompiler.nextLabel("el")
|
||||
val end = MosCompiler.nextLabel("fi")
|
||||
List(conditionBlock, branchChunk(jumpIfTrue, middleT), jmpChunk(middleE), labelChunk(middleT), thenBlock, jmpChunk(end), labelChunk(middleE), elseBlock, labelChunk(end)).flatten
|
||||
} else {
|
||||
val middle = MfCompiler.nextLabel("th")
|
||||
val end = MfCompiler.nextLabel("fi")
|
||||
val middle = MosCompiler.nextLabel("th")
|
||||
val end = MosCompiler.nextLabel("fi")
|
||||
List(conditionBlock, branchChunk(jumpIfTrue, middle), elseBlock, jmpChunk(end), labelChunk(middle), thenBlock, labelChunk(end)).flatten
|
||||
}
|
||||
} else {
|
||||
val middle = MfCompiler.nextLabel("el")
|
||||
val end = MfCompiler.nextLabel("fi")
|
||||
val middle = MosCompiler.nextLabel("el")
|
||||
val end = MosCompiler.nextLabel("fi")
|
||||
List(conditionBlock, branchChunk(jumpIfFalse, middle), thenBlock, jmpChunk(end), labelChunk(middle), elseBlock, labelChunk(end)).flatten
|
||||
}
|
||||
}
|
||||
case BuiltInBooleanType =>
|
||||
(thenPart, elsePart) match {
|
||||
case (Nil, Nil) =>
|
||||
ExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching)
|
||||
MosExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching)
|
||||
case (Nil, _) =>
|
||||
if (largeElseBlock) {
|
||||
val middle = MfCompiler.nextLabel("el")
|
||||
val end = MfCompiler.nextLabel("fi")
|
||||
val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfFalse(middle))
|
||||
val middle = MosCompiler.nextLabel("el")
|
||||
val end = MosCompiler.nextLabel("fi")
|
||||
val conditionBlock = MosExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfFalse(middle))
|
||||
List(conditionBlock, jmpChunk(end), labelChunk(middle), elseBlock, labelChunk(end)).flatten
|
||||
} else {
|
||||
val end = MfCompiler.nextLabel("fi")
|
||||
val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfTrue(end))
|
||||
val end = MosCompiler.nextLabel("fi")
|
||||
val conditionBlock = MosExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfTrue(end))
|
||||
List(conditionBlock, elseBlock, labelChunk(end)).flatten
|
||||
}
|
||||
case (_, Nil) =>
|
||||
if (largeThenBlock) {
|
||||
val middle = MfCompiler.nextLabel("th")
|
||||
val end = MfCompiler.nextLabel("fi")
|
||||
val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfTrue(middle))
|
||||
val middle = MosCompiler.nextLabel("th")
|
||||
val end = MosCompiler.nextLabel("fi")
|
||||
val conditionBlock = MosExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfTrue(middle))
|
||||
List(conditionBlock, jmpChunk(end), labelChunk(middle), thenBlock, labelChunk(end)).flatten
|
||||
} else {
|
||||
val end = MfCompiler.nextLabel("fi")
|
||||
val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfFalse(end))
|
||||
val end = MosCompiler.nextLabel("fi")
|
||||
val conditionBlock = MosExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfFalse(end))
|
||||
List(conditionBlock, thenBlock, labelChunk(end)).flatten
|
||||
}
|
||||
case _ =>
|
||||
if (largeThenBlock) {
|
||||
if (largeElseBlock) {
|
||||
val middleT = MfCompiler.nextLabel("th")
|
||||
val middleE = MfCompiler.nextLabel("el")
|
||||
val end = MfCompiler.nextLabel("fi")
|
||||
val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfTrue(middleT))
|
||||
val middleT = MosCompiler.nextLabel("th")
|
||||
val middleE = MosCompiler.nextLabel("el")
|
||||
val end = MosCompiler.nextLabel("fi")
|
||||
val conditionBlock = MosExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfTrue(middleT))
|
||||
List(conditionBlock, jmpChunk(middleE), labelChunk(middleT), thenBlock, jmpChunk(end), labelChunk(middleE), elseBlock, labelChunk(end)).flatten
|
||||
} else {
|
||||
val middle = MfCompiler.nextLabel("th")
|
||||
val end = MfCompiler.nextLabel("fi")
|
||||
val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfTrue(middle))
|
||||
val middle = MosCompiler.nextLabel("th")
|
||||
val end = MosCompiler.nextLabel("fi")
|
||||
val conditionBlock = MosExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfTrue(middle))
|
||||
List(conditionBlock, elseBlock, jmpChunk(end), labelChunk(middle), thenBlock, labelChunk(end)).flatten
|
||||
}
|
||||
} else {
|
||||
val middle = MfCompiler.nextLabel("el")
|
||||
val end = MfCompiler.nextLabel("fi")
|
||||
val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfFalse(middle))
|
||||
val middle = MosCompiler.nextLabel("el")
|
||||
val end = MosCompiler.nextLabel("fi")
|
||||
val conditionBlock = MosExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfFalse(middle))
|
||||
List(conditionBlock, thenBlock, jmpChunk(end), labelChunk(middle), elseBlock, labelChunk(end)).flatten
|
||||
}
|
||||
}
|
||||
@ -317,11 +315,11 @@ object StatementCompiler {
|
||||
Nil
|
||||
}
|
||||
case WhileStatement(condition, bodyPart, incrementPart, labels) =>
|
||||
val start = MfCompiler.nextLabel("wh")
|
||||
val middle = MfCompiler.nextLabel("he")
|
||||
val inc = MfCompiler.nextLabel("fp")
|
||||
val end = MfCompiler.nextLabel("ew")
|
||||
val condType = ExpressionCompiler.getExpressionType(ctx, condition)
|
||||
val start = MosCompiler.nextLabel("wh")
|
||||
val middle = MosCompiler.nextLabel("he")
|
||||
val inc = MosCompiler.nextLabel("fp")
|
||||
val end = MosCompiler.nextLabel("ew")
|
||||
val condType = MosExpressionCompiler.getExpressionType(ctx, condition)
|
||||
val bodyBlock = compile(ctx.addLabels(labels, Label(end), Label(inc)), bodyPart)
|
||||
val incrementBlock = compile(ctx.addLabels(labels, Label(end), Label(inc)), incrementPart)
|
||||
val largeBodyBlock = bodyBlock.map(_.sizeInBytes).sum + incrementBlock.map(_.sizeInBytes).sum > 100
|
||||
@ -331,19 +329,19 @@ object StatementCompiler {
|
||||
case ConstantBooleanType(_, false) => Nil
|
||||
case FlagBooleanType(_, jumpIfTrue, jumpIfFalse) =>
|
||||
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
|
||||
} 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(labelChunk(start), conditionBlock, branchChunk(jumpIfFalse, end), bodyBlock, labelChunk(inc), incrementBlock, jmpChunk(start), labelChunk(end)).flatten
|
||||
}
|
||||
case BuiltInBooleanType =>
|
||||
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
|
||||
} 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(labelChunk(start), conditionBlock, bodyBlock, labelChunk(inc), incrementBlock, jmpChunk(start), labelChunk(end)).flatten
|
||||
}
|
||||
@ -352,21 +350,21 @@ object StatementCompiler {
|
||||
Nil
|
||||
}
|
||||
case DoWhileStatement(bodyPart, incrementPart, condition, labels) =>
|
||||
val start = MfCompiler.nextLabel("do")
|
||||
val inc = MfCompiler.nextLabel("fp")
|
||||
val end = MfCompiler.nextLabel("od")
|
||||
val condType = ExpressionCompiler.getExpressionType(ctx, condition)
|
||||
val start = MosCompiler.nextLabel("do")
|
||||
val inc = MosCompiler.nextLabel("fp")
|
||||
val end = MosCompiler.nextLabel("od")
|
||||
val condType = MosExpressionCompiler.getExpressionType(ctx, condition)
|
||||
val bodyBlock = compile(ctx.addLabels(labels, Label(end), Label(inc)), bodyPart)
|
||||
val incrementBlock = compile(ctx.addLabels(labels, Label(end), Label(inc)), incrementPart)
|
||||
val largeBodyBlock = bodyBlock.map(_.sizeInBytes).sum + incrementBlock.map(_.sizeInBytes).sum > 100
|
||||
condType match {
|
||||
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
|
||||
case ConstantBooleanType(_, false) =>
|
||||
List(bodyBlock, labelChunk(inc), incrementBlock, labelChunk(end)).flatten
|
||||
case FlagBooleanType(_, jumpIfTrue, jumpIfFalse) =>
|
||||
val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching)
|
||||
val conditionBlock = MosExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching)
|
||||
if (largeBodyBlock) {
|
||||
List(labelChunk(start), bodyBlock, labelChunk(inc), incrementBlock, conditionBlock, branchChunk(jumpIfFalse, end), jmpChunk(start), labelChunk(end)).flatten
|
||||
} else {
|
||||
@ -374,10 +372,10 @@ object StatementCompiler {
|
||||
}
|
||||
case BuiltInBooleanType =>
|
||||
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
|
||||
} 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
|
||||
}
|
||||
case _ =>
|
||||
@ -395,13 +393,13 @@ object StatementCompiler {
|
||||
(direction, env.eval(start), env.eval(end)) match {
|
||||
|
||||
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)
|
||||
case (ForDirection.Until | ForDirection.ParallelUntil, Some(NumericConstant(s, ssize)), Some(NumericConstant(e, _))) if s >= e =>
|
||||
Nil
|
||||
|
||||
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)
|
||||
case (ForDirection.To | ForDirection.ParallelTo, Some(NumericConstant(s, ssize)), Some(NumericConstant(e, _))) if s > e =>
|
||||
Nil
|
||||
@ -413,7 +411,7 @@ object StatementCompiler {
|
||||
))
|
||||
|
||||
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)
|
||||
case (ForDirection.DownTo, Some(NumericConstant(s, ssize)), Some(NumericConstant(e, esize))) if s < e =>
|
||||
Nil
|
@ -1,13 +1,12 @@
|
||||
package millfork.compiler
|
||||
package millfork.compiler.mos
|
||||
|
||||
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.error.ErrorReporting
|
||||
import millfork.node._
|
||||
import millfork.assembly.Opcode
|
||||
import millfork.assembly.Opcode._
|
||||
import millfork.assembly.AddrMode._
|
||||
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
@ -21,12 +20,12 @@ object PseudoregisterBuiltIns {
|
||||
val (variablePart, constPart) = ctx.env.evalVariableAndConstantSubParts(SumExpression(params, decimal = false))
|
||||
variablePart match {
|
||||
case None =>
|
||||
return ExpressionCompiler.compileConstant(ctx, constPart, RegisterVariable(Register.AX, w))
|
||||
return MosExpressionCompiler.compileConstant(ctx, constPart, RegisterVariable(MosRegister.AX, w))
|
||||
case Some(v) =>
|
||||
val typ = ExpressionCompiler.getExpressionType(ctx, v)
|
||||
val typ = MosExpressionCompiler.getExpressionType(ctx, v)
|
||||
if (typ.size == 1 && !typ.isSigned) {
|
||||
val bytePart = ExpressionCompiler.compile(ctx, v, Some(b -> RegisterVariable(Register.A, b)), BranchSpec.None)
|
||||
val label = MfCompiler.nextLabel("ah")
|
||||
val bytePart = MosExpressionCompiler.compile(ctx, v, Some(b -> RegisterVariable(MosRegister.A, b)), BranchSpec.None)
|
||||
val label = MosCompiler.nextLabel("ah")
|
||||
return bytePart ++ List(
|
||||
AssemblyLine.implied(CLC),
|
||||
AssemblyLine.immediate(ADC, constPart.loByte),
|
||||
@ -47,7 +46,7 @@ object PseudoregisterBuiltIns {
|
||||
}
|
||||
val reg = ctx.env.get[VariableInMemory]("__reg")
|
||||
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) => ???
|
||||
}
|
||||
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 reg = ctx.env.get[VariableInMemory]("__reg")
|
||||
// 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 prepareCarry = AssemblyLine.implied(if (subtract) SEC else CLC)
|
||||
compileRight match {
|
||||
@ -118,7 +117,7 @@ object PseudoregisterBuiltIns {
|
||||
val b = ctx.env.get[Type]("byte")
|
||||
val w = ctx.env.get[Type]("word")
|
||||
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(
|
||||
AssemblyLine.zeropage(LDA, reg),
|
||||
AssemblyLine.zeropage(LDX, reg, 1),
|
||||
@ -134,7 +133,7 @@ object PseudoregisterBuiltIns {
|
||||
val w = ctx.env.get[Type]("word")
|
||||
val reg = ctx.env.get[VariableInMemory]("__reg")
|
||||
// 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 {
|
||||
case List(
|
||||
AssemblyLine(LDA, Immediate, NumericConstant(0, _), _),
|
||||
@ -187,7 +186,7 @@ object PseudoregisterBuiltIns {
|
||||
val b = ctx.env.get[Type]("byte")
|
||||
val w = ctx.env.get[Type]("word")
|
||||
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 {
|
||||
case Some(NumericConstant(0, _)) =>
|
||||
Nil
|
||||
@ -204,20 +203,20 @@ object PseudoregisterBuiltIns {
|
||||
firstParamCompiled ++ List.fill(v.toInt)(cycle).flatten ++ List(AssemblyLine.zeropage(LDA, reg), AssemblyLine.zeropage(LDX, reg, 1))
|
||||
}
|
||||
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 {
|
||||
case List(AssemblyLine(LDX, _, _, _)) => firstParamCompiled ++ compileCounter
|
||||
case List(AssemblyLine(LDY, _, _, _), AssemblyLine(LDX, _, _, _)) => firstParamCompiled ++ compileCounter
|
||||
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)) ++
|
||||
firstParamCompiled ++ (
|
||||
if (ctx.options.flag(CompilationFlag.EmitCmosOpcodes)) List(AssemblyLine.implied(PLX))
|
||||
else List(AssemblyLine.implied(PLA), AssemblyLine.implied(TAX))
|
||||
)
|
||||
}
|
||||
val labelRepeat = MfCompiler.nextLabel("sr")
|
||||
val labelSkip = MfCompiler.nextLabel("ss")
|
||||
val labelRepeat = MosCompiler.nextLabel("sr")
|
||||
val labelSkip = MosCompiler.nextLabel("ss")
|
||||
if (ctx.options.flag(CompilationFlag.EmitNative65816Opcodes)) {
|
||||
compileCounterAndPrepareFirstParam ++ List(
|
||||
AssemblyLine.relative(BEQ, labelSkip),
|
||||
@ -255,8 +254,8 @@ object PseudoregisterBuiltIns {
|
||||
val reg = ctx.env.get[VariableInMemory]("__reg")
|
||||
val load: List[AssemblyLine] = param1OrRegister match {
|
||||
case Some(param1) =>
|
||||
val code1 = ExpressionCompiler.compile(ctx, param1, Some(b -> RegisterVariable(Register.A, b)), BranchSpec.None)
|
||||
val code2 = ExpressionCompiler.compile(ctx, param2, Some(b -> RegisterVariable(Register.A, b)), BranchSpec.None)
|
||||
val code1 = MosExpressionCompiler.compile(ctx, param1, Some(b -> RegisterVariable(MosRegister.A, b)), BranchSpec.None)
|
||||
val code2 = MosExpressionCompiler.compile(ctx, param2, Some(b -> RegisterVariable(MosRegister.A, b)), BranchSpec.None)
|
||||
if (!usesRegLo(code2)) {
|
||||
code1 ++ List(AssemblyLine.zeropage(STA, reg)) ++ code2 ++ List(AssemblyLine.zeropage(STA, reg, 1))
|
||||
} else if (!usesRegLo(code1)) {
|
||||
@ -269,7 +268,7 @@ object PseudoregisterBuiltIns {
|
||||
)
|
||||
}
|
||||
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)) {
|
||||
List(AssemblyLine.zeropage(STA, reg)) ++ code2 ++ List(AssemblyLine.zeropage(STA, reg, 1))
|
||||
} else if (!usesRegHi(code2)) {
|
@ -1,7 +1,8 @@
|
||||
package millfork.compiler
|
||||
package millfork.compiler.mos
|
||||
|
||||
import millfork.CompilationFlag
|
||||
import millfork.assembly.{AssemblyLine, OpcodeClasses}
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.assembly.mos._
|
||||
import millfork.env._
|
||||
import millfork.error.ErrorReporting
|
||||
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) {
|
||||
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
|
||||
val label = MfCompiler.nextLabel("di")
|
||||
val label = MosCompiler.nextLabel("di")
|
||||
val paramArrays = stmt.params.indices.map { ix =>
|
||||
val a = InitializedArray(label + "$" + ix + ".array", None, (paramMins(ix) to paramMaxes(ix)).map { key =>
|
||||
map(key)._2.lift(ix).getOrElse(LiteralExpression(0, 1))
|
||||
@ -134,11 +135,11 @@ object ReturnDispatch {
|
||||
val b = ctx.env.get[Type]("byte")
|
||||
|
||||
import millfork.assembly.AddrMode._
|
||||
import millfork.assembly.Opcode._
|
||||
import millfork.assembly.mos.Opcode._
|
||||
|
||||
val ctxForStoringParams = ctx.neverCheckArrayBounds
|
||||
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)))
|
||||
ErrorReporting.error("Invalid/too complex target parameter variable", paramVar.position)
|
||||
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)
|
||||
env.registerUnnamedArray(jumpTable)
|
||||
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)
|
||||
} 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(
|
||||
AssemblyLine.implied(TXA),
|
||||
AssemblyLine.implied(ASL),
|
||||
@ -159,7 +160,7 @@ object ReturnDispatch {
|
||||
AssemblyLine(JMP, AbsoluteIndexedX, jumpTable.toAddress - actualMin * 2))
|
||||
}
|
||||
} 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 jumpTableHi = InitializedArray(label + "$jh.array", None, (actualMin to actualMax).map(i => hibyte1(map(i)._1)).toList, ctx.function.declaredBank)
|
||||
env.registerUnnamedArray(jumpTableLo)
|
@ -3,11 +3,10 @@ package millfork.env
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
|
||||
import millfork.{CompilationFlag, CompilationOptions}
|
||||
import millfork.assembly.{Opcode, OpcodeClasses}
|
||||
import millfork.compiler._
|
||||
import millfork.assembly.mos.Opcode
|
||||
import millfork.error.ErrorReporting
|
||||
import millfork.node._
|
||||
import millfork.output.{CompiledMemory, MemoryBank, VariableAllocator}
|
||||
import millfork.output.{CompiledMemory, VariableAllocator}
|
||||
|
||||
import scala.collection.mutable
|
||||
|
||||
@ -576,7 +575,7 @@ class Environment(val parent: Option[Environment], val prefix: String) {
|
||||
resultType,
|
||||
params,
|
||||
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)
|
||||
} 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(node: Node): Unit = node match {
|
||||
case _:AssemblyStatement => ()
|
||||
case _:MosAssemblyStatement => ()
|
||||
case _:DeclarationStatement => ()
|
||||
case s:ForStatement =>
|
||||
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
|
||||
|
||||
import millfork.{CompilationFlag, CompilationOptions}
|
||||
import millfork.assembly.Opcode
|
||||
import millfork.assembly.mos.Opcode
|
||||
import millfork.node._
|
||||
|
||||
sealed trait Thing {
|
||||
@ -122,7 +122,7 @@ sealed trait VariableInMemory extends Variable with ThingInMemory with Indexable
|
||||
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
|
||||
}
|
||||
|
||||
@ -294,7 +294,7 @@ sealed trait ParamPassingConvention {
|
||||
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 inNonInlinedOnly = false
|
||||
|
@ -1,7 +1,8 @@
|
||||
package millfork.node
|
||||
|
||||
import millfork.assembly.{AddrMode, Opcode}
|
||||
import millfork.env.{Constant, Label, ParamPassingConvention}
|
||||
import millfork.assembly.AddrMode
|
||||
import millfork.assembly.mos.Opcode
|
||||
import millfork.env.{Constant, ParamPassingConvention}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
object Register extends Enumeration {
|
||||
object MosRegister extends Enumeration {
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
@ -251,8 +252,8 @@ case class ContinueStatement(label: String) extends ExecutableStatement {
|
||||
override def getAllExpressions: List[Expression] = Nil
|
||||
}
|
||||
|
||||
object AssemblyStatement {
|
||||
def implied(opcode: Opcode.Value, elidable: Boolean) = AssemblyStatement(opcode, AddrMode.Implied, LiteralExpression(0, 1), elidable)
|
||||
object MosAssemblyStatement {
|
||||
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
|
||||
|
||||
import millfork.CompilationOptions
|
||||
import millfork.assembly.AssemblyLine
|
||||
import millfork.env._
|
||||
import millfork.error.ErrorReporting
|
||||
import millfork.node._
|
||||
|
@ -1,12 +1,12 @@
|
||||
package millfork.output
|
||||
|
||||
import millfork.assembly.opt.{AssemblyOptimization, HudsonOptimizations, JumpFixing, JumpShortening}
|
||||
import millfork.assembly.{AddrMode, AssemblyLine, Opcode}
|
||||
import millfork.compiler.{CompilationContext, MfCompiler}
|
||||
import millfork.assembly._
|
||||
import millfork.compiler.AbstractCompiler
|
||||
import millfork.env._
|
||||
import millfork.error.ErrorReporting
|
||||
import millfork.node.{CallGraph, Program}
|
||||
import millfork._
|
||||
import millfork.compiler.mos.CompilationContext
|
||||
|
||||
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)])
|
||||
|
||||
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
|
||||
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 =
|
||||
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 assembly = mutable.ArrayBuffer[String]()
|
||||
|
||||
val inliningResult = InliningCalculator.calculate(
|
||||
val inliningResult = MosInliningCalculator.calculate(
|
||||
program,
|
||||
options.flags(CompilationFlag.InlineFunctions) || options.flags(CompilationFlag.OptimizeForSonicSpeed),
|
||||
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
|
||||
var nonInlineableFunctions: Set[String] = inliningResult.nonInlineableFunctions
|
||||
|
||||
var inlinedFunctions = Map[String, List[AssemblyLine]]()
|
||||
val compiledFunctions = mutable.Map[String, List[AssemblyLine]]()
|
||||
var inlinedFunctions = Map[String, List[T]]()
|
||||
val compiledFunctions = mutable.Map[String, List[T]]()
|
||||
val recommendedCompilationOrder = callGraph.recommendedCompilationOrder
|
||||
recommendedCompilationOrder.foreach { f =>
|
||||
env.maybeGet[NormalFunction](f).foreach { function =>
|
||||
@ -192,7 +196,7 @@ class Assembler(private val program: Program, private val rootEnv: Environment,
|
||||
val strippedCodeForInlining = for {
|
||||
limit <- potentiallyInlineable.get(f)
|
||||
if code.map(_.sizeInBytes).sum <= limit
|
||||
s <- InliningCalculator.codeForInlining(f, nonInlineableFunctions, code)
|
||||
s <- inliningCalculator.codeForInlining(f, nonInlineableFunctions, code)
|
||||
} yield s
|
||||
strippedCodeForInlining match {
|
||||
case Some(c) =>
|
||||
@ -418,562 +422,33 @@ class Assembler(private val program: Program, private val rootEnv: Environment,
|
||||
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)
|
||||
val unoptimized =
|
||||
MfCompiler.compile(CompilationContext(env = f.environment, function = f, extraStackOffset = 0, options = options)).flatMap {
|
||||
case AssemblyLine(Opcode.JSR, AddrMode.Absolute | AddrMode.LongAbsolute, 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
|
||||
}
|
||||
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)
|
||||
}
|
||||
val unoptimized: List[T] =
|
||||
inliningCalculator.inline(
|
||||
compiler.compile(CompilationContext(env = f.environment, function = f, extraStackOffset = 0, options = options)),
|
||||
inlinedFunctions,
|
||||
compiler)
|
||||
unoptimizedCodeSize += unoptimized.map(_.sizeInBytes).sum
|
||||
val code = optimizations.foldLeft(unoptimized) { (c, opt) =>
|
||||
opt.optimize(f, c, options)
|
||||
}
|
||||
if (optimizations.nonEmpty) {
|
||||
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)
|
||||
performFinalOptimizationPass(f, optimizations.nonEmpty, options, code)
|
||||
}
|
||||
|
||||
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
|
||||
assOut.append("* = $" + startFrom.toHexString)
|
||||
import millfork.assembly.AddrMode._
|
||||
import millfork.assembly.Opcode._
|
||||
for (instr <- code) {
|
||||
if (instr.isPrintable) {
|
||||
assOut.append(instr.toString)
|
||||
}
|
||||
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
|
||||
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 = emitInstruction(bank, options, index, instr)
|
||||
}
|
||||
index
|
||||
}
|
||||
}
|
||||
|
||||
object Assembler {
|
||||
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)
|
||||
|
||||
}
|
||||
def emitInstruction(bank: String, options: CompilationOptions, index: Int, instr: T): Int
|
||||
}
|
@ -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
|
||||
|
||||
import millfork.assembly.{AddrMode, AssemblyLine, Opcode, OpcodeClasses}
|
||||
import millfork.assembly.Opcode._
|
||||
import millfork.compiler.{ExpressionCompiler, MfCompiler}
|
||||
import millfork.assembly.AddrMode
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.assembly.mos._
|
||||
import millfork.compiler.AbstractCompiler
|
||||
import millfork.env._
|
||||
import millfork.node._
|
||||
|
||||
@ -14,7 +15,7 @@ import scala.collection.mutable
|
||||
|
||||
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)
|
||||
|
||||
@ -69,7 +70,7 @@ object InliningCalculator {
|
||||
case s: ArrayContents => getAllCalledFunctions(s.getAllExpressions)
|
||||
case s: FunctionDeclarationStatement => getAllCalledFunctions(s.address.toList) ++ getAllCalledFunctions(s.statements.getOrElse(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: VariableExpression => Set(
|
||||
s.name,
|
||||
@ -110,4 +111,26 @@ object InliningCalculator {
|
||||
}) return None
|
||||
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
|
||||
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
*/
|
||||
class SourceLoadingQueue(val initialFilenames: List[String], val includePath: List[String], val options: CompilationOptions) {
|
||||
abstract class AbstractSourceLoadingQueue[T](val initialFilenames: List[String],
|
||||
val includePath: List[String],
|
||||
val options: CompilationOptions) {
|
||||
|
||||
private val parsedModules = mutable.Map[String, Program]()
|
||||
private val moduleQueue = mutable.Queue[() => Unit]()
|
||||
protected val parsedModules: mutable.Map[String, Program] = mutable.Map[String, Program]()
|
||||
protected val moduleQueue: mutable.Queue[() => Unit] = mutable.Queue[() => Unit]()
|
||||
val extension: String = ".mfk"
|
||||
|
||||
def enqueueStandardModules(): Unit
|
||||
|
||||
def run(): Program = {
|
||||
initialFilenames.foreach { i =>
|
||||
parseModule(extractName(i), includePath, Right(i), options)
|
||||
parseModule(extractName(i), includePath, Right(i))
|
||||
}
|
||||
options.platform.startingModules.foreach {m =>
|
||||
moduleQueue.enqueue(() => parseModule(m, includePath, Left(None), options))
|
||||
}
|
||||
if (options.flag(CompilationFlag.ZeropagePseudoregister)) {
|
||||
moduleQueue.enqueue(() => parseModule("zp_reg", includePath, Left(None), options))
|
||||
moduleQueue.enqueue(() => parseModule(m, includePath, Left(None)))
|
||||
}
|
||||
enqueueStandardModules()
|
||||
while (moduleQueue.nonEmpty) {
|
||||
if (options.flag(CompilationFlag.SingleThreaded)) {
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
ErrorReporting.debug(s"Parsing $filename")
|
||||
val path = Paths.get(filename)
|
||||
val parentDir = path.toFile.getAbsoluteFile.getParent
|
||||
val src = new String(Files.readAllBytes(path))
|
||||
val parser = MfParser(filename, src, parentDir, options)
|
||||
val parser = createParser(filename, src, parentDir)
|
||||
parser.toAst match {
|
||||
case Success(prog, _) =>
|
||||
parsedModules.synchronized {
|
||||
@ -65,7 +65,7 @@ class SourceLoadingQueue(val initialFilenames: List[String], val includePath: Li
|
||||
prog.declarations.foreach {
|
||||
case s@ImportStatement(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 _ => ()
|
||||
}
|
@ -3,7 +3,7 @@ package millfork.parser
|
||||
import java.nio.file.{Files, Paths}
|
||||
|
||||
import fastparse.all._
|
||||
import millfork.assembly.{AddrMode, Opcode}
|
||||
import millfork.assembly.mos.Opcode
|
||||
import millfork.env._
|
||||
import millfork.error.ErrorReporting
|
||||
import millfork.node._
|
||||
@ -12,7 +12,7 @@ import millfork.{CompilationOptions, SeparatedList}
|
||||
/**
|
||||
* @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 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 mlOperators = List(
|
||||
val mfOperators = 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
|
||||
typ <- identifier ~ SWS
|
||||
name <- identifier ~/ HWS ~/ Pass
|
||||
addr <- ("@" ~/ HWS ~/ mlExpression(1)).?.opaque("<address>") ~ HWS
|
||||
initialValue <- ("=" ~/ HWS ~/ mlExpression(1)).? ~ HWS
|
||||
addr <- ("@" ~/ HWS ~/ mfExpression(1)).?.opaque("<address>") ~ HWS
|
||||
initialValue <- ("=" ~/ HWS ~/ mfExpression(1)).? ~ HWS
|
||||
_ <- &(EOL) ~/ ""
|
||||
} yield {
|
||||
Seq(VariableDeclarationStatement(name, typ,
|
||||
@ -191,33 +191,9 @@ case class MfParser(filename: String, input: String, currentDirectory: String, o
|
||||
ParameterDeclaration(typ, ByVariable(name)).pos(p)
|
||||
}
|
||||
|
||||
val appcSimple: P[ParamPassingConvention] = P("xy" | "yx" | "ax" | "ay" | "xa" | "ya" | "stack" | "a" | "x" | "y").!.map {
|
||||
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`")
|
||||
}
|
||||
def asmParamDefinition: P[ParameterDeclaration]
|
||||
|
||||
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 arrayListElement: P[ArrayContents] = arrayStringContents | arrayLoopContents | mlExpression(nonStatementLevel).map(e => LiteralContents(List(e)))
|
||||
def arrayListElement: P[ArrayContents] = arrayStringContents | arrayLoopContents | mfExpression(nonStatementLevel).map(e => LiteralContents(List(e)))
|
||||
|
||||
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 {
|
||||
identifier <- "for" ~ SWS ~/ identifier ~/ HWS ~ "," ~/ HWS ~ Pass
|
||||
start <- mlExpression(nonStatementLevel) ~ HWS ~ "," ~/ HWS ~/ Pass
|
||||
start <- mfExpression(nonStatementLevel) ~ HWS ~ "," ~/ HWS ~/ Pass
|
||||
pos <- position()
|
||||
direction <- forDirection ~/ HWS ~/ "," ~/ HWS ~/ Pass
|
||||
end <- mlExpression(nonStatementLevel)
|
||||
end <- mfExpression(nonStatementLevel)
|
||||
body <- AWS ~ arrayContents
|
||||
} yield {
|
||||
val fixedDirection = direction match {
|
||||
@ -291,21 +267,21 @@ case class MfParser(filename: String, input: String, currentDirectory: String, o
|
||||
p <- position()
|
||||
bank <- bankDeclaration
|
||||
name <- "array" ~ !letterOrDigit ~/ SWS ~ identifier ~ HWS
|
||||
length <- ("[" ~/ AWS ~/ mlExpression(nonStatementLevel) ~ AWS ~ "]").? ~ HWS
|
||||
addr <- ("@" ~/ HWS ~/ mlExpression(1)).? ~/ HWS
|
||||
length <- ("[" ~/ AWS ~/ mfExpression(nonStatementLevel) ~ AWS ~ "]").? ~ HWS
|
||||
addr <- ("@" ~/ HWS ~/ mfExpression(1)).? ~/ HWS
|
||||
contents <- ("=" ~/ HWS ~/ arrayContents).? ~/ HWS
|
||||
} 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] = {
|
||||
val allowedOperators = mlOperators.drop(level).flatten
|
||||
def mfExpression(level: Int): P[Expression] = {
|
||||
val allowedOperators = mfOperators.drop(level).flatten
|
||||
|
||||
def inner: P[SeparatedList[Expression, String]] = {
|
||||
for {
|
||||
head <- tightMlExpression ~/ HWS
|
||||
head <- tightMfExpression ~/ HWS
|
||||
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)))
|
||||
} yield {
|
||||
@ -314,9 +290,9 @@ case class MfParser(filename: String, input: String, currentDirectory: String, o
|
||||
}
|
||||
|
||||
def p(list: SeparatedList[Expression, String], level: Int): Expression =
|
||||
if (level == mlOperators.length) list.head
|
||||
if (level == mfOperators.length) list.head
|
||||
else {
|
||||
val xs = list.split(mlOperators(level).toSet(_))
|
||||
val xs = list.split(mfOperators(level).toSet(_))
|
||||
xs.separators.distinct match {
|
||||
case Nil =>
|
||||
if (xs.tail.nonEmpty)
|
||||
@ -344,32 +320,32 @@ case class MfParser(filename: String, input: String, currentDirectory: String, o
|
||||
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 {
|
||||
(p, left) <- position() ~ mlLhsExpressionSimple
|
||||
rightOpt <- (HWS ~ ":" ~/ HWS ~ mlLhsExpressionSimple).?
|
||||
def mfLhsExpression: P[LhsExpression] = for {
|
||||
(p, left) <- position() ~ mfLhsExpressionSimple
|
||||
rightOpt <- (HWS ~ ":" ~/ HWS ~ mfLhsExpressionSimple).?
|
||||
} 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()
|
||||
array <- identifier
|
||||
index <- HWS ~ "[" ~/ AWS ~/ mlExpression(nonStatementLevel) ~ AWS ~/ "]"
|
||||
index <- HWS ~ "[" ~/ AWS ~/ mfExpression(nonStatementLevel) ~ AWS ~/ "]"
|
||||
} yield IndexedExpression(array, index).pos(p)
|
||||
|
||||
def functionCall: P[FunctionCallExpression] = for {
|
||||
p <- position()
|
||||
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)
|
||||
|
||||
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]] =
|
||||
(position() ~ mlLhsExpression ~ HWS ~ "=" ~/ HWS ~ mlExpression(1)).map {
|
||||
(position() ~ mfLhsExpression ~ HWS ~ "=" ~/ HWS ~ mfExpression(1)).map {
|
||||
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)) }
|
||||
|
||||
// TODO: label and instruction in one line
|
||||
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 asmStatement: P[ExecutableStatement]
|
||||
|
||||
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 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 Some((_, Seq())) => DefaultReturnDispatchLabel(None, None)
|
||||
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, _)) =>
|
||||
ErrorReporting.error("Invalid default branch declaration", Some(pos))
|
||||
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 {
|
||||
pos <- position()
|
||||
l <- dispatchLabel ~/ HWS ~/ "@" ~/ HWS
|
||||
f <- tightMlExpressionButNotCall ~/ HWS
|
||||
parameters <- ("(" ~/ position("dispatch actual parameters") ~ AWS ~/ mlExpression(nonStatementLevel).rep(min = 0, sep = AWS ~ "," ~/ AWS) ~ AWS ~/ ")" ~/ "").?
|
||||
f <- tightMfExpressionButNotCall ~/ HWS
|
||||
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)
|
||||
|
||||
def dispatchStatementBody: P[Seq[ExecutableStatement]] = for {
|
||||
indexer <- "[" ~/ AWS ~/ mlExpression(nonStatementLevel) ~/ AWS ~/ "]" ~/ AWS
|
||||
indexer <- "[" ~/ AWS ~/ mfExpression(nonStatementLevel) ~/ AWS ~/ "]" ~/ AWS
|
||||
_ <- 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
|
||||
branches <- dispatchBranch.rep(sep = EOL ~ !"}" ~/ Pass)
|
||||
_ <- AWS ~/ "}"
|
||||
} 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 continueStatement: P[Seq[ExecutableStatement]] = ("continue" ~ !letterOrDigit ~/ HWS ~ identifier.?).map(l => Seq(ContinueStatement(l.getOrElse(""))))
|
||||
|
||||
def ifStatement: P[Seq[ExecutableStatement]] = for {
|
||||
condition <- "if" ~ !letterOrDigit ~/ HWS ~/ mlExpression(nonStatementLevel)
|
||||
condition <- "if" ~ !letterOrDigit ~/ HWS ~/ mfExpression(nonStatementLevel)
|
||||
thenBranch <- AWS ~/ executableStatements
|
||||
elseBranch <- (AWS ~ "else" ~/ AWS ~/ (ifStatement | executableStatements)).?
|
||||
} yield Seq(IfStatement(condition, thenBranch.toList, elseBranch.getOrElse(Nil).toList))
|
||||
|
||||
def whileStatement: P[Seq[ExecutableStatement]] = for {
|
||||
condition <- "while" ~ !letterOrDigit ~/ HWS ~/ mlExpression(nonStatementLevel)
|
||||
condition <- "while" ~ !letterOrDigit ~/ HWS ~/ mfExpression(nonStatementLevel)
|
||||
body <- AWS ~ executableStatements
|
||||
} 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 {
|
||||
identifier <- "for" ~ SWS ~/ identifier ~/ HWS ~ "," ~/ HWS ~ Pass
|
||||
start <- mlExpression(nonStatementLevel) ~ HWS ~ "," ~/ HWS ~/ Pass
|
||||
start <- mfExpression(nonStatementLevel) ~ HWS ~ "," ~/ HWS ~/ Pass
|
||||
direction <- forDirection ~/ HWS ~/ "," ~/ HWS ~/ Pass
|
||||
end <- mlExpression(nonStatementLevel)
|
||||
end <- mfExpression(nonStatementLevel)
|
||||
body <- AWS ~ executableStatements
|
||||
} 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
|
||||
def doWhileStatement: P[Seq[ExecutableStatement]] = for {
|
||||
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))
|
||||
|
||||
|
||||
@ -536,7 +454,7 @@ case class MfParser(filename: String, input: String, currentDirectory: String, o
|
||||
returnType <- identifier ~ SWS
|
||||
name <- identifier ~ HWS
|
||||
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
|
||||
} yield {
|
||||
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 (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 (flags("asm")) 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 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 => ()
|
||||
}
|
||||
if (flags("asm")) validateAsmFunctionBody(p, flags, name, statements)
|
||||
Seq(FunctionDeclarationStatement(name, returnType, params.toList,
|
||||
bank,
|
||||
addr,
|
||||
@ -588,6 +481,8 @@ case class MfParser(filename: String, input: String, currentDirectory: String, o
|
||||
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 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
|
||||
|
||||
import millfork.{Cpu, OptimizationPresets}
|
||||
import millfork.assembly.opt.{AlwaysGoodOptimizations, DangerousOptimizations}
|
||||
import millfork.assembly.mos.opt.{AlwaysGoodOptimizations, DangerousOptimizations}
|
||||
import millfork.test.emu._
|
||||
import org.scalatest.{FunSuite, Matchers}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
package millfork.test
|
||||
|
||||
import millfork.assembly.opt.DangerousOptimizations
|
||||
import millfork.assembly.mos.opt.DangerousOptimizations
|
||||
import millfork.test.emu.EmuBenchmarkRun
|
||||
import millfork.{Cpu, OptimizationPresets}
|
||||
import org.scalatest.{FunSuite, Matchers}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package millfork.test
|
||||
|
||||
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 org.scalatest.{FunSuite, Matchers}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
package millfork.test
|
||||
|
||||
import millfork.{Cpu, OptimizationPresets}
|
||||
import millfork.assembly.opt.{AlwaysGoodOptimizations, DangerousOptimizations}
|
||||
import millfork.assembly.mos.opt.{AlwaysGoodOptimizations, DangerousOptimizations}
|
||||
import millfork.test.emu._
|
||||
import org.scalatest.{FunSuite, Matchers}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
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.{Cpu, OptimizationPresets}
|
||||
import org.scalatest.{FunSuite, Matchers}
|
||||
|
@ -1,6 +1,6 @@
|
||||
package millfork.test.emu
|
||||
|
||||
import millfork.assembly.opt.{CmosOptimizations, SixteenOptimizations}
|
||||
import millfork.assembly.mos.opt.{CmosOptimizations, SixteenOptimizations}
|
||||
import millfork.{Cpu, OptimizationPresets}
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,6 @@
|
||||
package millfork.test.emu
|
||||
|
||||
import millfork.assembly.opt.{CE02Optimizations, CmosOptimizations}
|
||||
import millfork.assembly.mos.opt.{CE02Optimizations, CmosOptimizations}
|
||||
import millfork.{Cpu, OptimizationPresets}
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,6 @@
|
||||
package millfork.test.emu
|
||||
|
||||
import millfork.assembly.opt.{CmosOptimizations, ZeropageRegisterOptimizations}
|
||||
import millfork.assembly.mos.opt.{CmosOptimizations, ZeropageRegisterOptimizations}
|
||||
import millfork.{Cpu, OptimizationPresets}
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,6 @@
|
||||
package millfork.test.emu
|
||||
|
||||
import millfork.assembly.opt.{CmosOptimizations, HudsonOptimizations}
|
||||
import millfork.assembly.mos.opt.{CmosOptimizations, HudsonOptimizations}
|
||||
import millfork.{Cpu, OptimizationPresets}
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,6 @@
|
||||
package millfork.test.emu
|
||||
|
||||
import millfork.assembly.opt.{LaterOptimizations, ZeropageRegisterOptimizations}
|
||||
import millfork.assembly.mos.opt.{LaterOptimizations, ZeropageRegisterOptimizations}
|
||||
import millfork.{Cpu, OptimizationPresets}
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,6 @@
|
||||
package millfork.test.emu
|
||||
|
||||
import millfork.assembly.opt.{LaterOptimizations, ZeropageRegisterOptimizations}
|
||||
import millfork.assembly.mos.opt.{LaterOptimizations, ZeropageRegisterOptimizations}
|
||||
import millfork.{Cpu, OptimizationPresets}
|
||||
|
||||
/**
|
||||
|
@ -7,16 +7,18 @@ import com.grapeshot.halfnes.{CPU, CPURAM}
|
||||
import com.loomcom.symon.InstructionTable.CpuBehavior
|
||||
import com.loomcom.symon.{Bus, Cpu, CpuState}
|
||||
import fastparse.core.Parsed.{Failure, Success}
|
||||
import millfork.assembly.opt.AssemblyOptimization
|
||||
import millfork.compiler.{CompilationContext, MfCompiler}
|
||||
import millfork.assembly.AssemblyOptimization
|
||||
import millfork.assembly.mos.AssemblyLine
|
||||
import millfork.compiler.mos.{CompilationContext, MosCompiler}
|
||||
import millfork.env.{Environment, InitializedArray, InitializedMemoryVariable, NormalFunction}
|
||||
import millfork.error.ErrorReporting
|
||||
import millfork.node.StandardCallGraph
|
||||
import millfork.node.opt.NodeOptimization
|
||||
import millfork.output.{Assembler, MemoryBank}
|
||||
import millfork.parser.MfParser
|
||||
import millfork.output.{MemoryBank, MosAssembler}
|
||||
import millfork.parser.MosParser
|
||||
import millfork.{CompilationFlag, CompilationOptions}
|
||||
import org.scalatest.Matchers
|
||||
|
||||
import scala.collection.JavaConverters._
|
||||
|
||||
/**
|
||||
@ -24,7 +26,7 @@ import scala.collection.JavaConverters._
|
||||
*/
|
||||
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 = {
|
||||
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("import zp_reg"))
|
||||
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 {
|
||||
case Success(unoptimized, _) =>
|
||||
ErrorReporting.assertNoErrors("Parse failed")
|
||||
@ -133,7 +135,7 @@ class EmuRun(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimization],
|
||||
// print unoptimized asm
|
||||
env.allPreallocatables.foreach {
|
||||
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
|
||||
case d: InitializedArray =>
|
||||
unoptimizedSize += d.contents.length
|
||||
@ -147,7 +149,7 @@ class EmuRun(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimization],
|
||||
// compile
|
||||
val env2 = new Environment(None, "")
|
||||
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)
|
||||
println(";;; compiled: -----------------")
|
||||
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.setProgramCounter(org)
|
||||
cpu.setStackPointer(0xff)
|
||||
val legal = Assembler.getStandardLegalOpcodes
|
||||
val legal = MosAssembler.getStandardLegalOpcodes
|
||||
|
||||
var countNmos = 0L
|
||||
var countCmos = 0L
|
||||
|
@ -1,6 +1,6 @@
|
||||
package millfork.test.emu
|
||||
|
||||
import millfork.assembly.opt.SuperOptimizer
|
||||
import millfork.assembly.mos.opt.SuperOptimizer
|
||||
import millfork.{Cpu, OptimizationPresets}
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,6 @@
|
||||
package millfork.test.emu
|
||||
|
||||
import millfork.assembly.opt.SuperOptimizer
|
||||
import millfork.assembly.mos.opt.SuperOptimizer
|
||||
import millfork.{Cpu, OptimizationPresets}
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,6 @@
|
||||
package millfork.test.emu
|
||||
|
||||
import millfork.assembly.opt.{LaterOptimizations, UndocumentedOptimizations}
|
||||
import millfork.assembly.mos.opt.{LaterOptimizations, UndocumentedOptimizations}
|
||||
import millfork.{Cpu, OptimizationPresets}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user