From 5281b5f5276ad615cb429afd56495e24de74c040 Mon Sep 17 00:00:00 2001 From: Karol Stasiak Date: Tue, 12 Jun 2018 22:46:20 +0200 Subject: [PATCH] Refactoring for the upcoming Z80 support --- .../scala/millfork/CompilationOptions.scala | 29 +- src/main/scala/millfork/Main.scala | 107 ++-- .../scala/millfork/OptimizationPresets.scala | 10 +- .../millfork/assembly/AbstractCode.scala | 12 + .../scala/millfork/assembly/AddrMode.scala | 58 ++ .../assembly/AssemblyOptimization.scala | 13 + .../assembly/{ => mos}/AssemblyLine.scala | 19 +- .../millfork/assembly/{ => mos}/Opcode.scala | 55 +- .../opt/AlwaysGoodOptimizations.scala | 9 +- .../{ => mos}/opt/CE02Optimizations.scala | 11 +- .../opt/ChangeIndexRegisterOptimization.scala | 9 +- .../{ => mos}/opt/CmosOptimizations.scala | 11 +- .../{ => mos}/opt/CoarseFlowAnalyzer.scala | 7 +- .../assembly/{ => mos}/opt/CpuStatus.scala | 4 +- .../opt/DangerousOptimizations.scala | 7 +- .../opt/EmptyMemoryStoreRemoval.scala | 9 +- .../assembly/{ => mos}/opt/FlowAnalyzer.scala | 6 +- .../opt/FlowAnalyzerForImmediate.scala | 6 +- .../opt/FlowAnalyzerForImplied.scala | 6 +- .../opt/FlowAnalyzerForTheRest.scala | 6 +- .../{ => mos}/opt/HudsonOptimizations.scala | 9 +- .../assembly/{ => mos}/opt/JumpFixing.scala | 10 +- .../{ => mos}/opt/JumpShortening.scala | 7 +- .../{ => mos}/opt/LaterOptimizations.scala | 7 +- .../opt/LocalVariableReadOptimization.scala | 14 +- .../{ => mos}/opt/LoopUnrolling.scala | 8 +- .../{ => mos}/opt/ReverseFlowAnalyzer.scala | 21 +- .../opt/ReverseFlowAnalyzerPerOpcode.scala | 6 +- .../opt/RuleBasedAssemblyOptimization.scala | 5 +- ...SingleAssignmentVariableOptimization.scala | 9 +- .../{ => mos}/opt/SixteenOptimizations.scala | 16 +- .../{ => mos}/opt/SizeOptimizations.scala | 2 +- .../{ => mos}/opt/SuperOptimizer.scala | 11 +- .../opt/UndocumentedOptimizations.scala | 9 +- .../{ => mos}/opt/UnusedLabelRemoval.scala | 10 +- .../{ => mos}/opt/VariableLifetime.scala | 4 +- .../opt/VariableToRegisterOptimization.scala | 9 +- .../opt/ZeropageRegisterOptimizations.scala | 9 +- .../assembly/opt/AssemblyOptimization.scala | 14 - .../millfork/compiler/AbstractCompiler.scala | 12 + .../compiler/AbstractExpressionCompiler.scala | 99 +++ .../compiler/{ => mos}/BranchSpec.scala | 2 +- .../compiler/{ => mos}/BuiltIns.scala | 162 ++--- .../compiler/{ => mos}/ComparisonType.scala | 2 +- .../{ => mos}/CompilationContext.scala | 6 +- .../compiler/{ => mos}/DecimalBuiltIns.scala | 30 +- .../compiler/{ => mos}/MacroExpander.scala | 30 +- .../MosCompiler.scala} | 20 +- .../MosExpressionCompiler.scala} | 349 ++++------- .../MosStatementCompiler.scala} | 164 +++-- .../{ => mos}/PseudoregisterBuiltIns.scala | 41 +- .../compiler/{ => mos}/ReturnDispatch.scala | 19 +- src/main/scala/millfork/env/Environment.scala | 9 +- src/main/scala/millfork/env/Thing.scala | 6 +- src/main/scala/millfork/node/Node.scala | 15 +- .../node/opt/UnusedLocalVariables.scala | 1 - ...ssembler.scala => AbstractAssembler.scala} | 577 +----------------- .../output/AbstractInliningCalculator.scala | 12 + .../scala/millfork/output/MosAssembler.scala | 549 +++++++++++++++++ ...ator.scala => MosInliningCalculator.scala} | 33 +- ...scala => AbstractSourceLoadingQueue.scala} | 28 +- src/main/scala/millfork/parser/MfParser.scala | 195 ++---- .../scala/millfork/parser/MosParser.scala | 132 ++++ .../parser/MosSourceLoadingQueue.scala | 21 + src/test/scala/millfork/test/ArraySuite.scala | 2 +- .../millfork/test/AssemblyMacroSuite.scala | 2 +- .../test/AssemblyOptimizationSuite.scala | 2 +- .../scala/millfork/test/ForArraySuite.scala | 2 +- .../SecondAssemblyOptimizationSuite.scala | 2 +- .../test/emu/EmuOptimized65816Run.scala | 2 +- .../test/emu/EmuOptimized65CE02Run.scala | 2 +- .../test/emu/EmuOptimizedCmosRun.scala | 2 +- .../test/emu/EmuOptimizedHudsonRun.scala | 2 +- .../test/emu/EmuOptimizedInlinedRun.scala | 2 +- .../millfork/test/emu/EmuOptimizedRun.scala | 2 +- src/test/scala/millfork/test/emu/EmuRun.scala | 20 +- .../emu/EmuSuperOptimizedInliningRun.scala | 2 +- .../test/emu/EmuSuperoptimizedRun.scala | 2 +- .../test/emu/EmuUndocumentedRun.scala | 2 +- 79 files changed, 1652 insertions(+), 1484 deletions(-) create mode 100644 src/main/scala/millfork/assembly/AbstractCode.scala create mode 100644 src/main/scala/millfork/assembly/AddrMode.scala create mode 100644 src/main/scala/millfork/assembly/AssemblyOptimization.scala rename src/main/scala/millfork/assembly/{ => mos}/AssemblyLine.scala (97%) rename src/main/scala/millfork/assembly/{ => mos}/Opcode.scala (83%) rename src/main/scala/millfork/assembly/{ => mos}/opt/AlwaysGoodOptimizations.scala (99%) rename src/main/scala/millfork/assembly/{ => mos}/opt/CE02Optimizations.scala (59%) rename src/main/scala/millfork/assembly/{ => mos}/opt/ChangeIndexRegisterOptimization.scala (98%) rename src/main/scala/millfork/assembly/{ => mos}/opt/CmosOptimizations.scala (87%) rename src/main/scala/millfork/assembly/{ => mos}/opt/CoarseFlowAnalyzer.scala (95%) rename src/main/scala/millfork/assembly/{ => mos}/opt/CpuStatus.scala (99%) rename src/main/scala/millfork/assembly/{ => mos}/opt/DangerousOptimizations.scala (93%) rename src/main/scala/millfork/assembly/{ => mos}/opt/EmptyMemoryStoreRemoval.scala (94%) rename src/main/scala/millfork/assembly/{ => mos}/opt/FlowAnalyzer.scala (94%) rename src/main/scala/millfork/assembly/{ => mos}/opt/FlowAnalyzerForImmediate.scala (98%) rename src/main/scala/millfork/assembly/{ => mos}/opt/FlowAnalyzerForImplied.scala (98%) rename src/main/scala/millfork/assembly/{ => mos}/opt/FlowAnalyzerForTheRest.scala (98%) rename src/main/scala/millfork/assembly/{ => mos}/opt/HudsonOptimizations.scala (70%) rename src/main/scala/millfork/assembly/{ => mos}/opt/JumpFixing.scala (92%) rename src/main/scala/millfork/assembly/{ => mos}/opt/JumpShortening.scala (95%) rename src/main/scala/millfork/assembly/{ => mos}/opt/LaterOptimizations.scala (99%) rename src/main/scala/millfork/assembly/{ => mos}/opt/LocalVariableReadOptimization.scala (94%) rename src/main/scala/millfork/assembly/{ => mos}/opt/LoopUnrolling.scala (98%) rename src/main/scala/millfork/assembly/{ => mos}/opt/ReverseFlowAnalyzer.scala (95%) rename src/main/scala/millfork/assembly/{ => mos}/opt/ReverseFlowAnalyzerPerOpcode.scala (99%) rename src/main/scala/millfork/assembly/{ => mos}/opt/RuleBasedAssemblyOptimization.scala (99%) rename src/main/scala/millfork/assembly/{ => mos}/opt/SingleAssignmentVariableOptimization.scala (96%) rename src/main/scala/millfork/assembly/{ => mos}/opt/SixteenOptimizations.scala (96%) rename src/main/scala/millfork/assembly/{ => mos}/opt/SizeOptimizations.scala (66%) rename src/main/scala/millfork/assembly/{ => mos}/opt/SuperOptimizer.scala (90%) rename src/main/scala/millfork/assembly/{ => mos}/opt/UndocumentedOptimizations.scala (99%) rename src/main/scala/millfork/assembly/{ => mos}/opt/UnusedLabelRemoval.scala (81%) rename src/main/scala/millfork/assembly/{ => mos}/opt/VariableLifetime.scala (95%) rename src/main/scala/millfork/assembly/{ => mos}/opt/VariableToRegisterOptimization.scala (99%) rename src/main/scala/millfork/assembly/{ => mos}/opt/ZeropageRegisterOptimizations.scala (93%) delete mode 100644 src/main/scala/millfork/assembly/opt/AssemblyOptimization.scala create mode 100644 src/main/scala/millfork/compiler/AbstractCompiler.scala create mode 100644 src/main/scala/millfork/compiler/AbstractExpressionCompiler.scala rename src/main/scala/millfork/compiler/{ => mos}/BranchSpec.scala (94%) rename src/main/scala/millfork/compiler/{ => mos}/BuiltIns.scala (87%) rename src/main/scala/millfork/compiler/{ => mos}/ComparisonType.scala (97%) rename src/main/scala/millfork/compiler/{ => mos}/CompilationContext.scala (92%) rename src/main/scala/millfork/compiler/{ => mos}/DecimalBuiltIns.scala (94%) rename src/main/scala/millfork/compiler/{ => mos}/MacroExpander.scala (85%) rename src/main/scala/millfork/compiler/{MfCompiler.scala => mos/MosCompiler.scala} (89%) rename src/main/scala/millfork/compiler/{ExpressionCompiler.scala => mos/MosExpressionCompiler.scala} (83%) rename src/main/scala/millfork/compiler/{StatementCompiler.scala => mos/MosStatementCompiler.scala} (77%) rename src/main/scala/millfork/compiler/{ => mos}/PseudoregisterBuiltIns.scala (86%) rename src/main/scala/millfork/compiler/{ => mos}/ReturnDispatch.scala (91%) rename src/main/scala/millfork/output/{Assembler.scala => AbstractAssembler.scala} (50%) create mode 100644 src/main/scala/millfork/output/AbstractInliningCalculator.scala create mode 100644 src/main/scala/millfork/output/MosAssembler.scala rename src/main/scala/millfork/output/{InliningCalculator.scala => MosInliningCalculator.scala} (77%) rename src/main/scala/millfork/parser/{SourceLoadingQueue.scala => AbstractSourceLoadingQueue.scala} (77%) create mode 100644 src/main/scala/millfork/parser/MosParser.scala create mode 100644 src/main/scala/millfork/parser/MosSourceLoadingQueue.scala diff --git a/src/main/scala/millfork/CompilationOptions.scala b/src/main/scala/millfork/CompilationOptions.scala index e665cabc..2d244149 100644 --- a/src/main/scala/millfork/CompilationOptions.scala +++ b/src/main/scala/millfork/CompilationOptions.scala @@ -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 { diff --git a/src/main/scala/millfork/Main.scala b/src/main/scala/millfork/Main.scala index a0024964..3e11f188 100644 --- a/src/main/scala/millfork/Main.scala +++ b/src/main/scala/millfork/Main.scala @@ -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:", "") diff --git a/src/main/scala/millfork/OptimizationPresets.scala b/src/main/scala/millfork/OptimizationPresets.scala index 13492f09..41284733 100644 --- a/src/main/scala/millfork/OptimizationPresets.scala +++ b/src/main/scala/millfork/OptimizationPresets.scala @@ -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, diff --git a/src/main/scala/millfork/assembly/AbstractCode.scala b/src/main/scala/millfork/assembly/AbstractCode.scala new file mode 100644 index 00000000..f069bd61 --- /dev/null +++ b/src/main/scala/millfork/assembly/AbstractCode.scala @@ -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 +} diff --git a/src/main/scala/millfork/assembly/AddrMode.scala b/src/main/scala/millfork/assembly/AddrMode.scala new file mode 100644 index 00000000..91c53993 --- /dev/null +++ b/src/main/scala/millfork/assembly/AddrMode.scala @@ -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; + } + } +} diff --git a/src/main/scala/millfork/assembly/AssemblyOptimization.scala b/src/main/scala/millfork/assembly/AssemblyOptimization.scala new file mode 100644 index 00000000..894b6f93 --- /dev/null +++ b/src/main/scala/millfork/assembly/AssemblyOptimization.scala @@ -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] +} diff --git a/src/main/scala/millfork/assembly/AssemblyLine.scala b/src/main/scala/millfork/assembly/mos/AssemblyLine.scala similarity index 97% rename from src/main/scala/millfork/assembly/AssemblyLine.scala rename to src/main/scala/millfork/assembly/mos/AssemblyLine.scala index bb2606b2..bdff6716 100644 --- a/src/main/scala/millfork/assembly/AssemblyLine.scala +++ b/src/main/scala/millfork/assembly/mos/AssemblyLine.scala @@ -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)}" } } diff --git a/src/main/scala/millfork/assembly/Opcode.scala b/src/main/scala/millfork/assembly/mos/Opcode.scala similarity index 83% rename from src/main/scala/millfork/assembly/Opcode.scala rename to src/main/scala/millfork/assembly/mos/Opcode.scala index 2fc01412..a7d31063 100644 --- a/src/main/scala/millfork/assembly/Opcode.scala +++ b/src/main/scala/millfork/assembly/mos/Opcode.scala @@ -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; - } - } -} diff --git a/src/main/scala/millfork/assembly/opt/AlwaysGoodOptimizations.scala b/src/main/scala/millfork/assembly/mos/opt/AlwaysGoodOptimizations.scala similarity index 99% rename from src/main/scala/millfork/assembly/opt/AlwaysGoodOptimizations.scala rename to src/main/scala/millfork/assembly/mos/opt/AlwaysGoodOptimizations.scala index 31c6ca56..a66a1265 100644 --- a/src/main/scala/millfork/assembly/opt/AlwaysGoodOptimizations.scala +++ b/src/main/scala/millfork/assembly/mos/opt/AlwaysGoodOptimizations.scala @@ -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._ /** diff --git a/src/main/scala/millfork/assembly/opt/CE02Optimizations.scala b/src/main/scala/millfork/assembly/mos/opt/CE02Optimizations.scala similarity index 59% rename from src/main/scala/millfork/assembly/opt/CE02Optimizations.scala rename to src/main/scala/millfork/assembly/mos/opt/CE02Optimizations.scala index d8f9f02a..7466fc38 100644 --- a/src/main/scala/millfork/assembly/opt/CE02Optimizations.scala +++ b/src/main/scala/millfork/assembly/mos/opt/CE02Optimizations.scala @@ -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) } diff --git a/src/main/scala/millfork/assembly/opt/ChangeIndexRegisterOptimization.scala b/src/main/scala/millfork/assembly/mos/opt/ChangeIndexRegisterOptimization.scala similarity index 98% rename from src/main/scala/millfork/assembly/opt/ChangeIndexRegisterOptimization.scala rename to src/main/scala/millfork/assembly/mos/opt/ChangeIndexRegisterOptimization.scala index 464312ee..9c9e0e9e 100644 --- a/src/main/scala/millfork/assembly/opt/ChangeIndexRegisterOptimization.scala +++ b/src/main/scala/millfork/assembly/mos/opt/ChangeIndexRegisterOptimization.scala @@ -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 diff --git a/src/main/scala/millfork/assembly/opt/CmosOptimizations.scala b/src/main/scala/millfork/assembly/mos/opt/CmosOptimizations.scala similarity index 87% rename from src/main/scala/millfork/assembly/opt/CmosOptimizations.scala rename to src/main/scala/millfork/assembly/mos/opt/CmosOptimizations.scala index 3fdbdda6..73eecec5 100644 --- a/src/main/scala/millfork/assembly/opt/CmosOptimizations.scala +++ b/src/main/scala/millfork/assembly/mos/opt/CmosOptimizations.scala @@ -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) } diff --git a/src/main/scala/millfork/assembly/opt/CoarseFlowAnalyzer.scala b/src/main/scala/millfork/assembly/mos/opt/CoarseFlowAnalyzer.scala similarity index 95% rename from src/main/scala/millfork/assembly/opt/CoarseFlowAnalyzer.scala rename to src/main/scala/millfork/assembly/mos/opt/CoarseFlowAnalyzer.scala index 00dc1272..dcd5c376 100644 --- a/src/main/scala/millfork/assembly/opt/CoarseFlowAnalyzer.scala +++ b/src/main/scala/millfork/assembly/mos/opt/CoarseFlowAnalyzer.scala @@ -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 diff --git a/src/main/scala/millfork/assembly/opt/CpuStatus.scala b/src/main/scala/millfork/assembly/mos/opt/CpuStatus.scala similarity index 99% rename from src/main/scala/millfork/assembly/opt/CpuStatus.scala rename to src/main/scala/millfork/assembly/mos/opt/CpuStatus.scala index dca8c93a..2d30b7af 100644 --- a/src/main/scala/millfork/assembly/opt/CpuStatus.scala +++ b/src/main/scala/millfork/assembly/mos/opt/CpuStatus.scala @@ -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 diff --git a/src/main/scala/millfork/assembly/opt/DangerousOptimizations.scala b/src/main/scala/millfork/assembly/mos/opt/DangerousOptimizations.scala similarity index 93% rename from src/main/scala/millfork/assembly/opt/DangerousOptimizations.scala rename to src/main/scala/millfork/assembly/mos/opt/DangerousOptimizations.scala index 649bd4e1..e1e5af97 100644 --- a/src/main/scala/millfork/assembly/opt/DangerousOptimizations.scala +++ b/src/main/scala/millfork/assembly/mos/opt/DangerousOptimizations.scala @@ -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) } diff --git a/src/main/scala/millfork/assembly/opt/EmptyMemoryStoreRemoval.scala b/src/main/scala/millfork/assembly/mos/opt/EmptyMemoryStoreRemoval.scala similarity index 94% rename from src/main/scala/millfork/assembly/opt/EmptyMemoryStoreRemoval.scala rename to src/main/scala/millfork/assembly/mos/opt/EmptyMemoryStoreRemoval.scala index c46e2968..9c164ea2 100644 --- a/src/main/scala/millfork/assembly/opt/EmptyMemoryStoreRemoval.scala +++ b/src/main/scala/millfork/assembly/mos/opt/EmptyMemoryStoreRemoval.scala @@ -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) diff --git a/src/main/scala/millfork/assembly/opt/FlowAnalyzer.scala b/src/main/scala/millfork/assembly/mos/opt/FlowAnalyzer.scala similarity index 94% rename from src/main/scala/millfork/assembly/opt/FlowAnalyzer.scala rename to src/main/scala/millfork/assembly/mos/opt/FlowAnalyzer.scala index 8e308c0c..812421ae 100644 --- a/src/main/scala/millfork/assembly/opt/FlowAnalyzer.scala +++ b/src/main/scala/millfork/assembly/mos/opt/FlowAnalyzer.scala @@ -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} /** diff --git a/src/main/scala/millfork/assembly/opt/FlowAnalyzerForImmediate.scala b/src/main/scala/millfork/assembly/mos/opt/FlowAnalyzerForImmediate.scala similarity index 98% rename from src/main/scala/millfork/assembly/opt/FlowAnalyzerForImmediate.scala rename to src/main/scala/millfork/assembly/mos/opt/FlowAnalyzerForImmediate.scala index c3ac668c..a22b8615 100644 --- a/src/main/scala/millfork/assembly/opt/FlowAnalyzerForImmediate.scala +++ b/src/main/scala/millfork/assembly/mos/opt/FlowAnalyzerForImmediate.scala @@ -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 diff --git a/src/main/scala/millfork/assembly/opt/FlowAnalyzerForImplied.scala b/src/main/scala/millfork/assembly/mos/opt/FlowAnalyzerForImplied.scala similarity index 98% rename from src/main/scala/millfork/assembly/opt/FlowAnalyzerForImplied.scala rename to src/main/scala/millfork/assembly/mos/opt/FlowAnalyzerForImplied.scala index a91b7f81..e74f6975 100644 --- a/src/main/scala/millfork/assembly/opt/FlowAnalyzerForImplied.scala +++ b/src/main/scala/millfork/assembly/mos/opt/FlowAnalyzerForImplied.scala @@ -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 diff --git a/src/main/scala/millfork/assembly/opt/FlowAnalyzerForTheRest.scala b/src/main/scala/millfork/assembly/mos/opt/FlowAnalyzerForTheRest.scala similarity index 98% rename from src/main/scala/millfork/assembly/opt/FlowAnalyzerForTheRest.scala rename to src/main/scala/millfork/assembly/mos/opt/FlowAnalyzerForTheRest.scala index a0671f57..7c981321 100644 --- a/src/main/scala/millfork/assembly/opt/FlowAnalyzerForTheRest.scala +++ b/src/main/scala/millfork/assembly/mos/opt/FlowAnalyzerForTheRest.scala @@ -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 diff --git a/src/main/scala/millfork/assembly/opt/HudsonOptimizations.scala b/src/main/scala/millfork/assembly/mos/opt/HudsonOptimizations.scala similarity index 70% rename from src/main/scala/millfork/assembly/opt/HudsonOptimizations.scala rename to src/main/scala/millfork/assembly/mos/opt/HudsonOptimizations.scala index 38e90b43..b61b10c3 100644 --- a/src/main/scala/millfork/assembly/opt/HudsonOptimizations.scala +++ b/src/main/scala/millfork/assembly/mos/opt/HudsonOptimizations.scala @@ -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) diff --git a/src/main/scala/millfork/assembly/opt/JumpFixing.scala b/src/main/scala/millfork/assembly/mos/opt/JumpFixing.scala similarity index 92% rename from src/main/scala/millfork/assembly/opt/JumpFixing.scala rename to src/main/scala/millfork/assembly/mos/opt/JumpFixing.scala index 55fc4393..2c0378b0 100644 --- a/src/main/scala/millfork/assembly/opt/JumpFixing.scala +++ b/src/main/scala/millfork/assembly/mos/opt/JumpFixing.scala @@ -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 diff --git a/src/main/scala/millfork/assembly/opt/JumpShortening.scala b/src/main/scala/millfork/assembly/mos/opt/JumpShortening.scala similarity index 95% rename from src/main/scala/millfork/assembly/opt/JumpShortening.scala rename to src/main/scala/millfork/assembly/mos/opt/JumpShortening.scala index c095c8f0..78eadbb4 100644 --- a/src/main/scala/millfork/assembly/opt/JumpShortening.scala +++ b/src/main/scala/millfork/assembly/mos/opt/JumpShortening.scala @@ -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 diff --git a/src/main/scala/millfork/assembly/opt/LaterOptimizations.scala b/src/main/scala/millfork/assembly/mos/opt/LaterOptimizations.scala similarity index 99% rename from src/main/scala/millfork/assembly/opt/LaterOptimizations.scala rename to src/main/scala/millfork/assembly/mos/opt/LaterOptimizations.scala index e545a18d..e22f45d7 100644 --- a/src/main/scala/millfork/assembly/opt/LaterOptimizations.scala +++ b/src/main/scala/millfork/assembly/mos/opt/LaterOptimizations.scala @@ -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} /** diff --git a/src/main/scala/millfork/assembly/opt/LocalVariableReadOptimization.scala b/src/main/scala/millfork/assembly/mos/opt/LocalVariableReadOptimization.scala similarity index 94% rename from src/main/scala/millfork/assembly/opt/LocalVariableReadOptimization.scala rename to src/main/scala/millfork/assembly/mos/opt/LocalVariableReadOptimization.scala index df6fa4ce..130b5513 100644 --- a/src/main/scala/millfork/assembly/opt/LocalVariableReadOptimization.scala +++ b/src/main/scala/millfork/assembly/mos/opt/LocalVariableReadOptimization.scala @@ -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" diff --git a/src/main/scala/millfork/assembly/opt/LoopUnrolling.scala b/src/main/scala/millfork/assembly/mos/opt/LoopUnrolling.scala similarity index 98% rename from src/main/scala/millfork/assembly/opt/LoopUnrolling.scala rename to src/main/scala/millfork/assembly/mos/opt/LoopUnrolling.scala index 946569de..6f827378 100644 --- a/src/main/scala/millfork/assembly/opt/LoopUnrolling.scala +++ b/src/main/scala/millfork/assembly/mos/opt/LoopUnrolling.scala @@ -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} diff --git a/src/main/scala/millfork/assembly/opt/ReverseFlowAnalyzer.scala b/src/main/scala/millfork/assembly/mos/opt/ReverseFlowAnalyzer.scala similarity index 95% rename from src/main/scala/millfork/assembly/opt/ReverseFlowAnalyzer.scala rename to src/main/scala/millfork/assembly/mos/opt/ReverseFlowAnalyzer.scala index 65fa1716..56c2c030 100644 --- a/src/main/scala/millfork/assembly/opt/ReverseFlowAnalyzer.scala +++ b/src/main/scala/millfork/assembly/mos/opt/ReverseFlowAnalyzer.scala @@ -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 _ => }) diff --git a/src/main/scala/millfork/assembly/opt/ReverseFlowAnalyzerPerOpcode.scala b/src/main/scala/millfork/assembly/mos/opt/ReverseFlowAnalyzerPerOpcode.scala similarity index 99% rename from src/main/scala/millfork/assembly/opt/ReverseFlowAnalyzerPerOpcode.scala rename to src/main/scala/millfork/assembly/mos/opt/ReverseFlowAnalyzerPerOpcode.scala index a681e3ec..3928e883 100644 --- a/src/main/scala/millfork/assembly/opt/ReverseFlowAnalyzerPerOpcode.scala +++ b/src/main/scala/millfork/assembly/mos/opt/ReverseFlowAnalyzerPerOpcode.scala @@ -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 diff --git a/src/main/scala/millfork/assembly/opt/RuleBasedAssemblyOptimization.scala b/src/main/scala/millfork/assembly/mos/opt/RuleBasedAssemblyOptimization.scala similarity index 99% rename from src/main/scala/millfork/assembly/opt/RuleBasedAssemblyOptimization.scala rename to src/main/scala/millfork/assembly/mos/opt/RuleBasedAssemblyOptimization.scala index d939bc33..fa9d822a 100644 --- a/src/main/scala/millfork/assembly/opt/RuleBasedAssemblyOptimization.scala +++ b/src/main/scala/millfork/assembly/mos/opt/RuleBasedAssemblyOptimization.scala @@ -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)) diff --git a/src/main/scala/millfork/assembly/opt/SingleAssignmentVariableOptimization.scala b/src/main/scala/millfork/assembly/mos/opt/SingleAssignmentVariableOptimization.scala similarity index 96% rename from src/main/scala/millfork/assembly/opt/SingleAssignmentVariableOptimization.scala rename to src/main/scala/millfork/assembly/mos/opt/SingleAssignmentVariableOptimization.scala index 322d6412..bd9a2825 100644 --- a/src/main/scala/millfork/assembly/opt/SingleAssignmentVariableOptimization.scala +++ b/src/main/scala/millfork/assembly/mos/opt/SingleAssignmentVariableOptimization.scala @@ -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( diff --git a/src/main/scala/millfork/assembly/opt/SixteenOptimizations.scala b/src/main/scala/millfork/assembly/mos/opt/SixteenOptimizations.scala similarity index 96% rename from src/main/scala/millfork/assembly/opt/SixteenOptimizations.scala rename to src/main/scala/millfork/assembly/mos/opt/SixteenOptimizations.scala index 048288b0..33347db9 100644 --- a/src/main/scala/millfork/assembly/opt/SixteenOptimizations.scala +++ b/src/main/scala/millfork/assembly/mos/opt/SixteenOptimizations.scala @@ -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 } diff --git a/src/main/scala/millfork/assembly/opt/SizeOptimizations.scala b/src/main/scala/millfork/assembly/mos/opt/SizeOptimizations.scala similarity index 66% rename from src/main/scala/millfork/assembly/opt/SizeOptimizations.scala rename to src/main/scala/millfork/assembly/mos/opt/SizeOptimizations.scala index d76eefb5..b0e74067 100644 --- a/src/main/scala/millfork/assembly/opt/SizeOptimizations.scala +++ b/src/main/scala/millfork/assembly/mos/opt/SizeOptimizations.scala @@ -1,4 +1,4 @@ -package millfork.assembly.opt +package millfork.assembly.mos.opt /** * @author Karol Stasiak diff --git a/src/main/scala/millfork/assembly/opt/SuperOptimizer.scala b/src/main/scala/millfork/assembly/mos/opt/SuperOptimizer.scala similarity index 90% rename from src/main/scala/millfork/assembly/opt/SuperOptimizer.scala rename to src/main/scala/millfork/assembly/mos/opt/SuperOptimizer.scala index 098711c0..6cf9eb4d 100644 --- a/src/main/scala/millfork/assembly/opt/SuperOptimizer.scala +++ b/src/main/scala/millfork/assembly/mos/opt/SuperOptimizer.scala @@ -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, diff --git a/src/main/scala/millfork/assembly/opt/UndocumentedOptimizations.scala b/src/main/scala/millfork/assembly/mos/opt/UndocumentedOptimizations.scala similarity index 99% rename from src/main/scala/millfork/assembly/opt/UndocumentedOptimizations.scala rename to src/main/scala/millfork/assembly/mos/opt/UndocumentedOptimizations.scala index 343676eb..cd8fc50f 100644 --- a/src/main/scala/millfork/assembly/opt/UndocumentedOptimizations.scala +++ b/src/main/scala/millfork/assembly/mos/opt/UndocumentedOptimizations.scala @@ -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, diff --git a/src/main/scala/millfork/assembly/opt/UnusedLabelRemoval.scala b/src/main/scala/millfork/assembly/mos/opt/UnusedLabelRemoval.scala similarity index 81% rename from src/main/scala/millfork/assembly/opt/UnusedLabelRemoval.scala rename to src/main/scala/millfork/assembly/mos/opt/UnusedLabelRemoval.scala index dd919b48..ce554713 100644 --- a/src/main/scala/millfork/assembly/opt/UnusedLabelRemoval.scala +++ b/src/main/scala/millfork/assembly/mos/opt/UnusedLabelRemoval.scala @@ -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 { diff --git a/src/main/scala/millfork/assembly/opt/VariableLifetime.scala b/src/main/scala/millfork/assembly/mos/opt/VariableLifetime.scala similarity index 95% rename from src/main/scala/millfork/assembly/opt/VariableLifetime.scala rename to src/main/scala/millfork/assembly/mos/opt/VariableLifetime.scala index d7da9502..2c0cf2b9 100644 --- a/src/main/scala/millfork/assembly/opt/VariableLifetime.scala +++ b/src/main/scala/millfork/assembly/mos/opt/VariableLifetime.scala @@ -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 diff --git a/src/main/scala/millfork/assembly/opt/VariableToRegisterOptimization.scala b/src/main/scala/millfork/assembly/mos/opt/VariableToRegisterOptimization.scala similarity index 99% rename from src/main/scala/millfork/assembly/opt/VariableToRegisterOptimization.scala rename to src/main/scala/millfork/assembly/mos/opt/VariableToRegisterOptimization.scala index 11d9c198..56a2df52 100644 --- a/src/main/scala/millfork/assembly/opt/VariableToRegisterOptimization.scala +++ b/src/main/scala/millfork/assembly/mos/opt/VariableToRegisterOptimization.scala @@ -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) diff --git a/src/main/scala/millfork/assembly/opt/ZeropageRegisterOptimizations.scala b/src/main/scala/millfork/assembly/mos/opt/ZeropageRegisterOptimizations.scala similarity index 93% rename from src/main/scala/millfork/assembly/opt/ZeropageRegisterOptimizations.scala rename to src/main/scala/millfork/assembly/mos/opt/ZeropageRegisterOptimizations.scala index a1f2d031..fc0bec5f 100644 --- a/src/main/scala/millfork/assembly/opt/ZeropageRegisterOptimizations.scala +++ b/src/main/scala/millfork/assembly/mos/opt/ZeropageRegisterOptimizations.scala @@ -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, diff --git a/src/main/scala/millfork/assembly/opt/AssemblyOptimization.scala b/src/main/scala/millfork/assembly/opt/AssemblyOptimization.scala deleted file mode 100644 index 5ab931fd..00000000 --- a/src/main/scala/millfork/assembly/opt/AssemblyOptimization.scala +++ /dev/null @@ -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] -} diff --git a/src/main/scala/millfork/compiler/AbstractCompiler.scala b/src/main/scala/millfork/compiler/AbstractCompiler.scala new file mode 100644 index 00000000..c78d464c --- /dev/null +++ b/src/main/scala/millfork/compiler/AbstractCompiler.scala @@ -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] +} diff --git a/src/main/scala/millfork/compiler/AbstractExpressionCompiler.scala b/src/main/scala/millfork/compiler/AbstractExpressionCompiler.scala new file mode 100644 index 00000000..3c59f51e --- /dev/null +++ b/src/main/scala/millfork/compiler/AbstractExpressionCompiler.scala @@ -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)) + } +} diff --git a/src/main/scala/millfork/compiler/BranchSpec.scala b/src/main/scala/millfork/compiler/mos/BranchSpec.scala similarity index 94% rename from src/main/scala/millfork/compiler/BranchSpec.scala rename to src/main/scala/millfork/compiler/mos/BranchSpec.scala index 8763f6ab..0c0e16ab 100644 --- a/src/main/scala/millfork/compiler/BranchSpec.scala +++ b/src/main/scala/millfork/compiler/mos/BranchSpec.scala @@ -1,4 +1,4 @@ -package millfork.compiler +package millfork.compiler.mos /** * @author Karol Stasiak diff --git a/src/main/scala/millfork/compiler/BuiltIns.scala b/src/main/scala/millfork/compiler/mos/BuiltIns.scala similarity index 87% rename from src/main/scala/millfork/compiler/BuiltIns.scala rename to src/main/scala/millfork/compiler/mos/BuiltIns.scala index 0e5fa9e6..01b061bb 100644 --- a/src/main/scala/millfork/compiler/BuiltIns.scala +++ b/src/main/scala/millfork/compiler/mos/BuiltIns.scala @@ -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 _ => diff --git a/src/main/scala/millfork/compiler/ComparisonType.scala b/src/main/scala/millfork/compiler/mos/ComparisonType.scala similarity index 97% rename from src/main/scala/millfork/compiler/ComparisonType.scala rename to src/main/scala/millfork/compiler/mos/ComparisonType.scala index c2812177..ed894d9c 100644 --- a/src/main/scala/millfork/compiler/ComparisonType.scala +++ b/src/main/scala/millfork/compiler/mos/ComparisonType.scala @@ -1,4 +1,4 @@ -package millfork.compiler +package millfork.compiler.mos /** * @author Karol Stasiak diff --git a/src/main/scala/millfork/compiler/CompilationContext.scala b/src/main/scala/millfork/compiler/mos/CompilationContext.scala similarity index 92% rename from src/main/scala/millfork/compiler/CompilationContext.scala rename to src/main/scala/millfork/compiler/mos/CompilationContext.scala index 8b106ca3..592cb68a 100644 --- a/src/main/scala/millfork/compiler/CompilationContext.scala +++ b/src/main/scala/millfork/compiler/mos/CompilationContext.scala @@ -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) } diff --git a/src/main/scala/millfork/compiler/DecimalBuiltIns.scala b/src/main/scala/millfork/compiler/mos/DecimalBuiltIns.scala similarity index 94% rename from src/main/scala/millfork/compiler/DecimalBuiltIns.scala rename to src/main/scala/millfork/compiler/mos/DecimalBuiltIns.scala index 21af65ed..738b8c99 100644 --- a/src/main/scala/millfork/compiler/DecimalBuiltIns.scala +++ b/src/main/scala/millfork/compiler/mos/DecimalBuiltIns.scala @@ -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) diff --git a/src/main/scala/millfork/compiler/MacroExpander.scala b/src/main/scala/millfork/compiler/mos/MacroExpander.scala similarity index 85% rename from src/main/scala/millfork/compiler/MacroExpander.scala rename to src/main/scala/millfork/compiler/mos/MacroExpander.scala index 16a8a972..42d321f1 100644 --- a/src/main/scala/millfork/compiler/MacroExpander.scala +++ b/src/main/scala/millfork/compiler/mos/MacroExpander.scala @@ -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 } diff --git a/src/main/scala/millfork/compiler/MfCompiler.scala b/src/main/scala/millfork/compiler/mos/MosCompiler.scala similarity index 89% rename from src/main/scala/millfork/compiler/MfCompiler.scala rename to src/main/scala/millfork/compiler/mos/MosCompiler.scala index 8a0a4529..7fd7e38b 100644 --- a/src/main/scala/millfork/compiler/MfCompiler.scala +++ b/src/main/scala/millfork/compiler/mos/MosCompiler.scala @@ -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)) { diff --git a/src/main/scala/millfork/compiler/ExpressionCompiler.scala b/src/main/scala/millfork/compiler/mos/MosExpressionCompiler.scala similarity index 83% rename from src/main/scala/millfork/compiler/ExpressionCompiler.scala rename to src/main/scala/millfork/compiler/mos/MosExpressionCompiler.scala index ef58d9db..16c414ca 100644 --- a/src/main/scala/millfork/compiler/ExpressionCompiler.scala +++ b/src/main/scala/millfork/compiler/mos/MosExpressionCompiler.scala @@ -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), diff --git a/src/main/scala/millfork/compiler/StatementCompiler.scala b/src/main/scala/millfork/compiler/mos/MosStatementCompiler.scala similarity index 77% rename from src/main/scala/millfork/compiler/StatementCompiler.scala rename to src/main/scala/millfork/compiler/mos/MosStatementCompiler.scala index 0f4c1f4f..412441c2 100644 --- a/src/main/scala/millfork/compiler/StatementCompiler.scala +++ b/src/main/scala/millfork/compiler/mos/MosStatementCompiler.scala @@ -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 diff --git a/src/main/scala/millfork/compiler/PseudoregisterBuiltIns.scala b/src/main/scala/millfork/compiler/mos/PseudoregisterBuiltIns.scala similarity index 86% rename from src/main/scala/millfork/compiler/PseudoregisterBuiltIns.scala rename to src/main/scala/millfork/compiler/mos/PseudoregisterBuiltIns.scala index 431a44ef..62b9a873 100644 --- a/src/main/scala/millfork/compiler/PseudoregisterBuiltIns.scala +++ b/src/main/scala/millfork/compiler/mos/PseudoregisterBuiltIns.scala @@ -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)) { diff --git a/src/main/scala/millfork/compiler/ReturnDispatch.scala b/src/main/scala/millfork/compiler/mos/ReturnDispatch.scala similarity index 91% rename from src/main/scala/millfork/compiler/ReturnDispatch.scala rename to src/main/scala/millfork/compiler/mos/ReturnDispatch.scala index 0474946d..9f846c7a 100644 --- a/src/main/scala/millfork/compiler/ReturnDispatch.scala +++ b/src/main/scala/millfork/compiler/mos/ReturnDispatch.scala @@ -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) diff --git a/src/main/scala/millfork/env/Environment.scala b/src/main/scala/millfork/env/Environment.scala index 58906e76..71f49a3d 100644 --- a/src/main/scala/millfork/env/Environment.scala +++ b/src/main/scala/millfork/env/Environment.scala @@ -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) diff --git a/src/main/scala/millfork/env/Thing.scala b/src/main/scala/millfork/env/Thing.scala index 4fe10a01..5786c410 100644 --- a/src/main/scala/millfork/env/Thing.scala +++ b/src/main/scala/millfork/env/Thing.scala @@ -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 diff --git a/src/main/scala/millfork/node/Node.scala b/src/main/scala/millfork/node/Node.scala index d58fb639..99fcdfd9 100644 --- a/src/main/scala/millfork/node/Node.scala +++ b/src/main/scala/millfork/node/Node.scala @@ -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) } \ No newline at end of file diff --git a/src/main/scala/millfork/node/opt/UnusedLocalVariables.scala b/src/main/scala/millfork/node/opt/UnusedLocalVariables.scala index e6434476..e92ebd74 100644 --- a/src/main/scala/millfork/node/opt/UnusedLocalVariables.scala +++ b/src/main/scala/millfork/node/opt/UnusedLocalVariables.scala @@ -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._ diff --git a/src/main/scala/millfork/output/Assembler.scala b/src/main/scala/millfork/output/AbstractAssembler.scala similarity index 50% rename from src/main/scala/millfork/output/Assembler.scala rename to src/main/scala/millfork/output/AbstractAssembler.scala index 87a9c77d..9a844a3a 100644 --- a/src/main/scala/millfork/output/Assembler.scala +++ b/src/main/scala/millfork/output/AbstractAssembler.scala @@ -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 +} \ No newline at end of file diff --git a/src/main/scala/millfork/output/AbstractInliningCalculator.scala b/src/main/scala/millfork/output/AbstractInliningCalculator.scala new file mode 100644 index 00000000..3fb94d0b --- /dev/null +++ b/src/main/scala/millfork/output/AbstractInliningCalculator.scala @@ -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] +} diff --git a/src/main/scala/millfork/output/MosAssembler.scala b/src/main/scala/millfork/output/MosAssembler.scala new file mode 100644 index 00000000..8a60c8d3 --- /dev/null +++ b/src/main/scala/millfork/output/MosAssembler.scala @@ -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) + +} diff --git a/src/main/scala/millfork/output/InliningCalculator.scala b/src/main/scala/millfork/output/MosInliningCalculator.scala similarity index 77% rename from src/main/scala/millfork/output/InliningCalculator.scala rename to src/main/scala/millfork/output/MosInliningCalculator.scala index 0cf36717..aa283853 100644 --- a/src/main/scala/millfork/output/InliningCalculator.scala +++ b/src/main/scala/millfork/output/MosInliningCalculator.scala @@ -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) + } + } } diff --git a/src/main/scala/millfork/parser/SourceLoadingQueue.scala b/src/main/scala/millfork/parser/AbstractSourceLoadingQueue.scala similarity index 77% rename from src/main/scala/millfork/parser/SourceLoadingQueue.scala rename to src/main/scala/millfork/parser/AbstractSourceLoadingQueue.scala index 0b72b385..f0a043f3 100644 --- a/src/main/scala/millfork/parser/SourceLoadingQueue.scala +++ b/src/main/scala/millfork/parser/AbstractSourceLoadingQueue.scala @@ -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 _ => () } diff --git a/src/main/scala/millfork/parser/MfParser.scala b/src/main/scala/millfork/parser/MfParser.scala index eaeb22f9..267944fb 100644 --- a/src/main/scala/millfork/parser/MfParser.scala +++ b/src/main/scala/millfork/parser/MfParser.scala @@ -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("
") ~ HWS - initialValue <- ("=" ~/ HWS ~/ mlExpression(1)).? ~ HWS + addr <- ("@" ~/ HWS ~/ mfExpression(1)).?.opaque("
") ~ 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("
") ~/ AWS + addr <- ("@" ~/ HWS ~/ mfExpression(1)).?.opaque("
") ~/ 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 { diff --git a/src/main/scala/millfork/parser/MosParser.scala b/src/main/scala/millfork/parser/MosParser.scala new file mode 100644 index 00000000..858d1cd1 --- /dev/null +++ b/src/main/scala/millfork/parser/MosParser.scala @@ -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 => () + } + } +} diff --git a/src/main/scala/millfork/parser/MosSourceLoadingQueue.scala b/src/main/scala/millfork/parser/MosSourceLoadingQueue.scala new file mode 100644 index 00000000..22296d8f --- /dev/null +++ b/src/main/scala/millfork/parser/MosSourceLoadingQueue.scala @@ -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))) + } + } + +} diff --git a/src/test/scala/millfork/test/ArraySuite.scala b/src/test/scala/millfork/test/ArraySuite.scala index 289bad57..3f9e64c3 100644 --- a/src/test/scala/millfork/test/ArraySuite.scala +++ b/src/test/scala/millfork/test/ArraySuite.scala @@ -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} diff --git a/src/test/scala/millfork/test/AssemblyMacroSuite.scala b/src/test/scala/millfork/test/AssemblyMacroSuite.scala index f0be6db4..e034dc1c 100644 --- a/src/test/scala/millfork/test/AssemblyMacroSuite.scala +++ b/src/test/scala/millfork/test/AssemblyMacroSuite.scala @@ -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} diff --git a/src/test/scala/millfork/test/AssemblyOptimizationSuite.scala b/src/test/scala/millfork/test/AssemblyOptimizationSuite.scala index 1df9c4c6..03fee9ea 100644 --- a/src/test/scala/millfork/test/AssemblyOptimizationSuite.scala +++ b/src/test/scala/millfork/test/AssemblyOptimizationSuite.scala @@ -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} diff --git a/src/test/scala/millfork/test/ForArraySuite.scala b/src/test/scala/millfork/test/ForArraySuite.scala index 0198ad71..e290e7db 100644 --- a/src/test/scala/millfork/test/ForArraySuite.scala +++ b/src/test/scala/millfork/test/ForArraySuite.scala @@ -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} diff --git a/src/test/scala/millfork/test/SecondAssemblyOptimizationSuite.scala b/src/test/scala/millfork/test/SecondAssemblyOptimizationSuite.scala index f0caeede..3034b048 100644 --- a/src/test/scala/millfork/test/SecondAssemblyOptimizationSuite.scala +++ b/src/test/scala/millfork/test/SecondAssemblyOptimizationSuite.scala @@ -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} diff --git a/src/test/scala/millfork/test/emu/EmuOptimized65816Run.scala b/src/test/scala/millfork/test/emu/EmuOptimized65816Run.scala index e47e32d6..a550d51d 100644 --- a/src/test/scala/millfork/test/emu/EmuOptimized65816Run.scala +++ b/src/test/scala/millfork/test/emu/EmuOptimized65816Run.scala @@ -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} /** diff --git a/src/test/scala/millfork/test/emu/EmuOptimized65CE02Run.scala b/src/test/scala/millfork/test/emu/EmuOptimized65CE02Run.scala index 891f26b6..214c1fdd 100644 --- a/src/test/scala/millfork/test/emu/EmuOptimized65CE02Run.scala +++ b/src/test/scala/millfork/test/emu/EmuOptimized65CE02Run.scala @@ -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} /** diff --git a/src/test/scala/millfork/test/emu/EmuOptimizedCmosRun.scala b/src/test/scala/millfork/test/emu/EmuOptimizedCmosRun.scala index 9e841834..37b392a2 100644 --- a/src/test/scala/millfork/test/emu/EmuOptimizedCmosRun.scala +++ b/src/test/scala/millfork/test/emu/EmuOptimizedCmosRun.scala @@ -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} /** diff --git a/src/test/scala/millfork/test/emu/EmuOptimizedHudsonRun.scala b/src/test/scala/millfork/test/emu/EmuOptimizedHudsonRun.scala index f41d465c..4602e695 100644 --- a/src/test/scala/millfork/test/emu/EmuOptimizedHudsonRun.scala +++ b/src/test/scala/millfork/test/emu/EmuOptimizedHudsonRun.scala @@ -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} /** diff --git a/src/test/scala/millfork/test/emu/EmuOptimizedInlinedRun.scala b/src/test/scala/millfork/test/emu/EmuOptimizedInlinedRun.scala index e48b5a73..068e77f8 100644 --- a/src/test/scala/millfork/test/emu/EmuOptimizedInlinedRun.scala +++ b/src/test/scala/millfork/test/emu/EmuOptimizedInlinedRun.scala @@ -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} /** diff --git a/src/test/scala/millfork/test/emu/EmuOptimizedRun.scala b/src/test/scala/millfork/test/emu/EmuOptimizedRun.scala index 29e5bde9..2fd2394b 100644 --- a/src/test/scala/millfork/test/emu/EmuOptimizedRun.scala +++ b/src/test/scala/millfork/test/emu/EmuOptimizedRun.scala @@ -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} /** diff --git a/src/test/scala/millfork/test/emu/EmuRun.scala b/src/test/scala/millfork/test/emu/EmuRun.scala index ea115812..e42917d8 100644 --- a/src/test/scala/millfork/test/emu/EmuRun.scala +++ b/src/test/scala/millfork/test/emu/EmuRun.scala @@ -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 diff --git a/src/test/scala/millfork/test/emu/EmuSuperOptimizedInliningRun.scala b/src/test/scala/millfork/test/emu/EmuSuperOptimizedInliningRun.scala index 0b582694..432155c2 100644 --- a/src/test/scala/millfork/test/emu/EmuSuperOptimizedInliningRun.scala +++ b/src/test/scala/millfork/test/emu/EmuSuperOptimizedInliningRun.scala @@ -1,6 +1,6 @@ package millfork.test.emu -import millfork.assembly.opt.SuperOptimizer +import millfork.assembly.mos.opt.SuperOptimizer import millfork.{Cpu, OptimizationPresets} /** diff --git a/src/test/scala/millfork/test/emu/EmuSuperoptimizedRun.scala b/src/test/scala/millfork/test/emu/EmuSuperoptimizedRun.scala index df8baf65..48b64449 100644 --- a/src/test/scala/millfork/test/emu/EmuSuperoptimizedRun.scala +++ b/src/test/scala/millfork/test/emu/EmuSuperoptimizedRun.scala @@ -1,6 +1,6 @@ package millfork.test.emu -import millfork.assembly.opt.SuperOptimizer +import millfork.assembly.mos.opt.SuperOptimizer import millfork.{Cpu, OptimizationPresets} /** diff --git a/src/test/scala/millfork/test/emu/EmuUndocumentedRun.scala b/src/test/scala/millfork/test/emu/EmuUndocumentedRun.scala index fd222ae4..4559c7f8 100644 --- a/src/test/scala/millfork/test/emu/EmuUndocumentedRun.scala +++ b/src/test/scala/millfork/test/emu/EmuUndocumentedRun.scala @@ -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} /**