From 73a223b9b68e58750ac663e7a9f2656dd5414d4a Mon Sep 17 00:00:00 2001 From: Karol Stasiak Date: Wed, 3 Nov 2021 21:48:45 +0100 Subject: [PATCH] Add support for Mesen label file format by tracking file-relative positions of segments (#128) --- .gitignore | 1 + docs/api/command-line.md | 2 + docs/api/custom-platform.md | 2 + .../scala/millfork/DebugOutputFormat.scala | 88 ++++++++++++++---- src/main/scala/millfork/Main.scala | 16 ++-- src/main/scala/millfork/Platform.scala | 13 +++ .../assembly/AssemblyOptimization.scala | 2 +- .../opt/RuleBasedAssemblyOptimization.scala | 2 +- .../opt/RuleBasedAssemblyOptimization.scala | 2 +- src/main/scala/millfork/env/Environment.scala | 8 +- .../millfork/output/AbstractAssembler.scala | 90 +++++++++++-------- .../millfork/output/BankLayoutInFile.scala | 32 +++++++ .../millfork/output/CompiledMemory.scala | 2 +- .../scala/millfork/output/D88Output.scala | 2 +- .../millfork/output/FormattableLabel.scala | 14 +++ .../millfork/output/M6809Assembler.scala | 4 +- .../scala/millfork/output/MosAssembler.scala | 4 +- .../millfork/output/OutputPackager.scala | 79 +++++++++++----- .../scala/millfork/output/TapOutput.scala | 2 +- .../scala/millfork/output/TrsCmdOutput.scala | 2 +- .../scala/millfork/output/Z80Assembler.scala | 4 +- .../output/Z80ToX86Crossassembler.scala | 4 +- 22 files changed, 273 insertions(+), 102 deletions(-) create mode 100644 src/main/scala/millfork/output/BankLayoutInFile.scala create mode 100644 src/main/scala/millfork/output/FormattableLabel.scala diff --git a/.gitignore b/.gitignore index 7f8e668d..018de792 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,7 @@ issue*.mfk *.nl *.fns *.sym +*.mlb *.deb *.xex *.nes diff --git a/docs/api/command-line.md b/docs/api/command-line.md index 3e9ecdb2..75526096 100644 --- a/docs/api/command-line.md +++ b/docs/api/command-line.md @@ -48,6 +48,8 @@ The extension and the file format are platform-dependent. * `-G fceux` – multi-file format used by the FCEUX emulator. The extension is `.nl`. + * `-G mesen` – format used by the Mesen emulator. The extension is `.mlb`. + * `-G raw` – Millfork-specific format. The extension is '.labels'. Each row contains bank number, start address, end address (if known), object type, and Millfork-specific object identifier. * `-fbreakpoints`, `-fno-breakpoints` – diff --git a/docs/api/custom-platform.md b/docs/api/custom-platform.md index d451cc58..eb3344f5 100644 --- a/docs/api/custom-platform.md +++ b/docs/api/custom-platform.md @@ -267,3 +267,5 @@ Default: `main,*` * `sym` – format used by the WLA/DX assembler. The extension is `.sym`. * `fceux` – multi-file format used by the FCEUX emulator. The extension is `.nl`. + + * `mesen` – format used by the Mesen emulator. The extension is `.mlb`. diff --git a/src/main/scala/millfork/DebugOutputFormat.scala b/src/main/scala/millfork/DebugOutputFormat.scala index c1924ab7..8381f4cc 100644 --- a/src/main/scala/millfork/DebugOutputFormat.scala +++ b/src/main/scala/millfork/DebugOutputFormat.scala @@ -1,5 +1,10 @@ package millfork +import millfork.output.{BankLayoutInFile, FormattableLabel} + +import java.util.regex.Pattern +import scala.util.control.Breaks.{break, breakable} + /** * @author Karol Stasiak */ @@ -12,13 +17,16 @@ object DebugOutputFormat { "fns" -> NesasmDebugOutputFormat, "fceux" -> FceuxDebugOutputFormat, "nl" -> FceuxDebugOutputFormat, + "mlb" -> MesenOutputFormat, + "mesen" -> MesenOutputFormat, + "asm6f" -> MesenOutputFormat, "sym" -> SymDebugOutputFormat) } sealed trait DebugOutputFormat { - def formatAll(labels: Seq[(String, Int, Int, Char, Option[Int])], breakpoints: Seq[(Int, Int)]): String = { - val labelPart = labelsHeader + labels.map(formatLineTupled).mkString("\n") + "\n" + def formatAll(b: BankLayoutInFile, labels: Seq[FormattableLabel], breakpoints: Seq[(Int, Int)]): String = { + val labelPart = labelsHeader + labels.map(formatLine).mkString("\n") + "\n" if (breakpoints.isEmpty) { labelPart } else { @@ -26,10 +34,7 @@ sealed trait DebugOutputFormat { } } - final def formatLineTupled(labelAndValue: (String, Int, Int, Char, Option[Int])): String = - formatLine(labelAndValue._1, labelAndValue._2, labelAndValue._3, labelAndValue._4, labelAndValue._5) - - def formatLine(label: String, bank: Int, startValue: Int, category: Char, endValue: Option[Int]): String + def formatLine(label: FormattableLabel): String final def formatBreakpointTupled(value: (Int, Int)): Seq[String] = formatBreakpoint(value._1, value._2).toSeq @@ -48,8 +53,8 @@ sealed trait DebugOutputFormat { } object RawDebugOutputFormat extends DebugOutputFormat { - override def formatLine(label: String, bank: Int, startValue: Int, category: Char, endValue: Option[Int]): String = { - f"$bank%02X:$startValue%04X:${endValue.fold("")(_.formatted("%04X"))}%s:$category%s:$label%s" + override def formatLine(label: FormattableLabel): String = { + f"${label.bankNumber}%02X:${label.startValue}%04X:${label.endValue.fold("")(_.formatted("%04X"))}%s:${label.category}%s:$label%s" } override def fileExtension(bank: Int): String = ".labels" @@ -63,9 +68,9 @@ object RawDebugOutputFormat extends DebugOutputFormat { } object ViceDebugOutputFormat extends DebugOutputFormat { - override def formatLine(label: String, bank: Int, startValue: Int, category: Char, endValue: Option[Int]): String = { - val normalized = label.replace('$', '_').replace('.', '_') - s"al ${startValue.toHexString} .$normalized" + override def formatLine(label: FormattableLabel): String = { + val normalized = label.labelName.replace('$', '_').replace('.', '_') + s"al ${label.startValue.toHexString} .$normalized" } override def fileExtension(bank: Int): String = ".lbl" @@ -78,8 +83,8 @@ object ViceDebugOutputFormat extends DebugOutputFormat { } object NesasmDebugOutputFormat extends DebugOutputFormat { - override def formatLine(label: String, bank: Int, startValue: Int, category: Char, endValue: Option[Int]): String = { - label + " = $" + startValue.toHexString + override def formatLine(label: FormattableLabel): String = { + label.labelName + " = $" + label.startValue.toHexString } override def fileExtension(bank: Int): String = ".fns" @@ -92,8 +97,8 @@ object NesasmDebugOutputFormat extends DebugOutputFormat { } object SymDebugOutputFormat extends DebugOutputFormat { - override def formatLine(label: String, bank: Int, startValue: Int, category: Char, endValue:Option[Int]): String = { - f"$bank%02x:$startValue%04x $label%s" + override def formatLine(label: FormattableLabel): String = { + f"${label.bankNumber}%02x:${label.startValue}%04x ${label.labelName}%s" } override def fileExtension(bank: Int): String = ".sym" @@ -110,8 +115,8 @@ object SymDebugOutputFormat extends DebugOutputFormat { } object FceuxDebugOutputFormat extends DebugOutputFormat { - override def formatLine(label: String, bank: Int, startValue: Int, category: Char, endValue: Option[Int]): String = { - f"$$$startValue%04x#$label%s#" + override def formatLine(label: FormattableLabel): String = { + f"$$${label.startValue}%04x#${label.labelName}%s#" } override def fileExtension(bank: Int): String = if (bank == 0xff) ".ram.nl" else s".$bank.nl" @@ -122,3 +127,52 @@ object FceuxDebugOutputFormat extends DebugOutputFormat { override def formatBreakpoint(bank: Int, value: Int): Option[String] = None } + +object MesenOutputFormat extends DebugOutputFormat { + + override def formatAll(b: BankLayoutInFile, labels: Seq[FormattableLabel], breakpoints: Seq[(Int, Int)]): String = { + val allStarts = labels.groupBy(_.bankName).mapValues(_.map(_.startValue).toSet) + labels.flatMap{ l => + val mesenShift = b.getMesenShift(l.bankName) + val shiftedStart = l.startValue + mesenShift + var shiftedEnd = l.endValue.map(_ + mesenShift).filter(_ != shiftedStart) + l.endValue match { + case None => + case Some(e) => + // Mesen does not like labels of form XXX-XXX, where both ends are equal + breakable { + for (i <- l.startValue.+(1) to e) { + if (allStarts.getOrElse(l.bankName, Set.empty).contains(i)) { + shiftedEnd = None + break + } + } + } + } + if (shiftedStart >= 0 && shiftedEnd.forall(_ >= 0)) { + val normalized = l.labelName.replace('$', '_').replace('.', '_') + val comment = (l.category match { + case 'F' => "function " + case 'A' => "initialized array " + case 'V' => "initialized variable " + case 'a' => "array " + case 'v' => "variable " + case _ => "" + }) + l.labelName + Some(f"${l.mesenSymbol}%s:${shiftedStart}%04X${shiftedEnd.fold("")(e => f"-$e%04X")}%s:$normalized%s:$comment%s") + } else { + None + } + }.mkString("\n") + } + + override def formatLine(label: FormattableLabel): String = throw new UnsupportedOperationException() + + override def formatBreakpoint(bank: Int, value: Int): Option[String] = None + + override def fileExtension(bank: Int): String = ".mlb" + + override def filePerBank: Boolean = false + + override def addOutputExtension: Boolean = false +} \ No newline at end of file diff --git a/src/main/scala/millfork/Main.scala b/src/main/scala/millfork/Main.scala index f93d6166..d80d0bc9 100644 --- a/src/main/scala/millfork/Main.scala +++ b/src/main/scala/millfork/Main.scala @@ -119,33 +119,35 @@ object Main { else if (l.startsWith("__")) 7 else 0 } - val sortedLabels: Seq[(String, Int, Int, Char, Option[Int])] = + val sortedLabels: Seq[FormattableLabel] = result.labels.groupBy(_._2).values .map(_.minBy(a => labelUnimportance(a._1) -> a._1)).toSeq.sortBy(_._2) .map { case (l, (b, s)) => + val bankNumber = options.platform.bankNumbers.getOrElse(b, 0) + val mesenCategory = options.platform.getMesenLabelCategory(b, s) result.endLabels.get(l) match { - case Some((c, e)) => (l, b, s, c, Some(e)) - case _ => (l, b, s, 'x', None) + case Some((c, e)) => FormattableLabel(l, b, bankNumber, s, Some(e), c, mesenCategory) + case _ => FormattableLabel(l, b, bankNumber, s, None, 'x', mesenCategory) } } val sortedBreakpoints = result.breakpoints val format = c.outputLabelsFormatOverride.getOrElse(platform.outputLabelsFormat) val basename = if (format.addOutputExtension) output + platform.fileExtension else output if (format.filePerBank) { - val banks: Set[Int] = sortedLabels.map(_._2).toSet ++ sortedBreakpoints.map(_._1).toSet + val banks: Set[Int] = sortedLabels.map(_.bankNumber).toSet ++ sortedBreakpoints.map(_._1).toSet banks.foreach{ bank => - val labels = sortedLabels.filter(_._2.==(bank)) + val labels = sortedLabels.filter(_.bankNumber.==(bank)) val breakpoints = sortedBreakpoints.filter(_._1.==(bank)) val labelOutput = basename + format.fileExtension(bank) val path = Paths.get(labelOutput) errorReporting.debug("Writing labels to " + path.toAbsolutePath) - Files.write(path, format.formatAll(labels, breakpoints).getBytes(StandardCharsets.UTF_8)) + Files.write(path, format.formatAll(result.bankLayoutInFile, labels, breakpoints).getBytes(StandardCharsets.UTF_8)) } } else { val labelOutput = basename + format.fileExtension(0) val path = Paths.get(labelOutput) errorReporting.debug("Writing labels to " + path.toAbsolutePath) - Files.write(path, format.formatAll(sortedLabels, sortedBreakpoints).getBytes(StandardCharsets.UTF_8)) + Files.write(path, format.formatAll(result.bankLayoutInFile, sortedLabels, sortedBreakpoints).getBytes(StandardCharsets.UTF_8)) } } val defaultPrgOutput = if (output.endsWith(platform.fileExtension)) output else output + platform.fileExtension diff --git a/src/main/scala/millfork/Platform.scala b/src/main/scala/millfork/Platform.scala index b066eab6..a565dc55 100644 --- a/src/main/scala/millfork/Platform.scala +++ b/src/main/scala/millfork/Platform.scala @@ -42,6 +42,7 @@ class Platform( val outputLabelsFormat: DebugOutputFormat, val outputStyle: OutputStyle.Value ) { + def hasZeroPage: Boolean = cpuFamily == CpuFamily.M6502 def cpuFamily: CpuFamily.Value = CpuFamily.forType(this.cpu) @@ -60,6 +61,18 @@ class Platform( val e2 = bankEndBefore(bank2) e2 > s1 && s2 < e1 } + + lazy val banksExplicitlyWrittenToOutput: Set[String] = bankNumbers.keySet.filter(b => defaultOutputPackager.writes(b)).toSet + + def getMesenLabelCategory(bank: String, address: Int): Char = { + // see: https://www.mesen.ca/docs/debugging/debuggerintegration.html#mesen-label-files-mlb + val start = bankStart(bank) + val end = bankEndBefore(bank) + if (start > address || address >= end) 'G' + else if (banksExplicitlyWrittenToOutput(bank)) 'P' + else if (bank == "default") 'R' + else 'W' // TODO: distinguish between W and S + } } object Platform { diff --git a/src/main/scala/millfork/assembly/AssemblyOptimization.scala b/src/main/scala/millfork/assembly/AssemblyOptimization.scala index 36dc9916..6edc1e5a 100644 --- a/src/main/scala/millfork/assembly/AssemblyOptimization.scala +++ b/src/main/scala/millfork/assembly/AssemblyOptimization.scala @@ -10,7 +10,7 @@ import millfork.node.NiceFunctionProperty * @author Karol Stasiak */ case class OptimizationContext(options: CompilationOptions, - labelMap: Map[String, (Int, Int)], + labelMap: Map[String, (String, Int)], zreg: Option[ThingInMemory], niceFunctionProperties: Set[(NiceFunctionProperty, String)]) { @inline diff --git a/src/main/scala/millfork/assembly/m6809/opt/RuleBasedAssemblyOptimization.scala b/src/main/scala/millfork/assembly/m6809/opt/RuleBasedAssemblyOptimization.scala index 86eb6e35..8e4be81d 100644 --- a/src/main/scala/millfork/assembly/m6809/opt/RuleBasedAssemblyOptimization.scala +++ b/src/main/scala/millfork/assembly/m6809/opt/RuleBasedAssemblyOptimization.scala @@ -101,7 +101,7 @@ class RuleBasedAssemblyOptimization(val name: String, val needsFlowInfo: FlowInf } class AssemblyMatchingContext(val compilationOptions: CompilationOptions, - val labelMap: Map[String, (Int, Int)], + val labelMap: Map[String, (String, Int)], val niceFunctionProperties: Set[(NiceFunctionProperty, String)], val labelUseCount: String => Int) { @inline diff --git a/src/main/scala/millfork/assembly/mos/opt/RuleBasedAssemblyOptimization.scala b/src/main/scala/millfork/assembly/mos/opt/RuleBasedAssemblyOptimization.scala index 28336347..26836175 100644 --- a/src/main/scala/millfork/assembly/mos/opt/RuleBasedAssemblyOptimization.scala +++ b/src/main/scala/millfork/assembly/mos/opt/RuleBasedAssemblyOptimization.scala @@ -102,7 +102,7 @@ class RuleBasedAssemblyOptimization(val name: String, val needsFlowInfo: FlowInf } class AssemblyMatchingContext(val compilationOptions: CompilationOptions, - val labelMap: Map[String, (Int, Int)], + val labelMap: Map[String, (String, Int)], val zeropageRegister: Option[ThingInMemory], val niceFunctionProperties: Set[(NiceFunctionProperty, String)], val labelUseCount: String => Int) { diff --git a/src/main/scala/millfork/env/Environment.scala b/src/main/scala/millfork/env/Environment.scala index a5ddc457..02c433e9 100644 --- a/src/main/scala/millfork/env/Environment.scala +++ b/src/main/scala/millfork/env/Environment.scala @@ -117,7 +117,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa callGraph: CallGraph, allocators: Map[String, VariableAllocator], options: CompilationOptions, - onEachVariable: (String, (Int, Int)) => Unit, + onEachVariable: (String, (String, Int)) => Unit, onEachVariableEnd: (String, (Char, Int)) => Unit, pass: Int, forZpOnly: Boolean): Unit = { @@ -184,7 +184,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa val addr = allocators(bank).allocateBytes(bank0, callGraph, vertex, options, m.sizeInBytes, initialized = false, writeable = true, location = AllocationLocation.Zeropage, alignment = m.alignment) if (log.traceEnabled) log.trace("addr $" + addr.toHexString) - onEachVariable(m.name, bank0.index -> addr) + onEachVariable(m.name, bank -> addr) onEachVariableEnd(m.name, (if (m.isInstanceOf[MfArray])'a' else 'v') -> (addr + m.sizeInBytes - 1)) List( ConstantThing(m.name.stripPrefix(prefix) + "`", NumericConstant(addr, 2), p) @@ -208,7 +208,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa case None => Nil case Some(addr) => if (log.traceEnabled) log.trace("addr $" + addr.toHexString) - onEachVariable(m.name, bank0.index -> addr) + onEachVariable(m.name, bank -> addr) onEachVariableEnd(m.name, (if (m.isInstanceOf[MfArray])'a' else 'v') -> (addr + m.sizeInBytes - 1)) List( ConstantThing(m.name.stripPrefix(prefix) + "`", NumericConstant(addr, 2), p) @@ -220,7 +220,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa } else { val addr = allocators(bank).allocateBytes(bank0, callGraph, vertex, options, m.sizeInBytes, initialized = false, writeable = true, location = AllocationLocation.Either, alignment = m.alignment) if (log.traceEnabled) log.trace("addr $" + addr.toHexString) - onEachVariable(m.name, bank0.index -> addr) + onEachVariable(m.name, bank -> addr) onEachVariableEnd(m.name, (if (m.isInstanceOf[MfArray])'a' else 'v') -> (addr + m.sizeInBytes - 1)) List( ConstantThing(graveName, NumericConstant(addr, 2), p) diff --git a/src/main/scala/millfork/output/AbstractAssembler.scala b/src/main/scala/millfork/output/AbstractAssembler.scala index 21b308c0..70665d5d 100644 --- a/src/main/scala/millfork/output/AbstractAssembler.scala +++ b/src/main/scala/millfork/output/AbstractAssembler.scala @@ -19,7 +19,12 @@ import scala.collection.mutable.ArrayBuffer * @author Karol Stasiak */ -case class AssemblerOutput(code: Map[String, Array[Byte]], asm: Array[String], labels: List[(String, (Int, Int))], endLabels: Map[String, (Char, Int)], breakpoints: List[(Int, Int)]) +case class AssemblerOutput(code: Map[String, Array[Byte]], + bankLayoutInFile: BankLayoutInFile, + asm: Array[String], + labels: List[(String, (String, Int))], + endLabels: Map[String, (Char, Int)], + breakpoints: List[(Int, Int)]) abstract class AbstractAssembler[T <: AbstractCode](private val program: Program, private val rootEnv: Environment, @@ -33,9 +38,9 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program var initializedVariablesSize: Int = 0 protected val log: Logger = rootEnv.log - val labelMap: mutable.Map[String, (Int, Int)] = mutable.Map() + val labelMap: mutable.Map[String, (String, Int)] = mutable.Map() val endLabelMap: mutable.Map[String, (Char, Int)] = mutable.Map() - val unimportantLabelMap: mutable.Map[String, (Int, Int)] = mutable.Map() + val unimportantLabelMap: mutable.Map[String, (String, Int)] = mutable.Map() val mem = new CompiledMemory(platform.bankNumbers.toList, platform.bankFill, platform.isBigEndian, labelMap, log) val breakpointSet: mutable.Set[(Int, Int)] = mutable.Set() private val bytesToWriteLater = mutable.ListBuffer[(String, Int, Constant, Option[Position])]() @@ -116,7 +121,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program try { if (labelMap.contains(th.name)) return labelMap(th.name)._2 if (labelMap.contains(th.name + "`")) return labelMap(th.name)._2 - if (labelMap.contains(th.name + ".addr")) return labelMap.getOrElse[(Int, Int)](th.name, labelMap(th.name + ".array"))._2 + if (labelMap.contains(th.name + ".addr")) return labelMap.getOrElse[(String, Int)](th.name, labelMap(th.name + ".array"))._2 if (unimportantLabelMap.contains(th.name)) return labelMap(th.name)._2 val x1 = env.maybeGet[ConstantThing](th.name).map(_.value) val x2 = env.maybeGet[ConstantThing](th.name + "`").map(_.value) @@ -247,11 +252,12 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program case tim: VariableInMemory => tim.toAddress match { case NumericConstant(n, _) => - val m = mem.banks(tim.bank(options)) + val bank = tim.bank(options) + val m = mem.banks(bank) for (i <- 0 until tim.typ.size) { m.occupied(i + n.toInt) = true } - labelMap.put(tim.name, m.index -> n.toInt) + labelMap.put(tim.name, bank -> n.toInt) endLabelMap.put(tim.name, (if (tim.isInstanceOf[InitializedMemoryVariable]) 'V' else 'v') -> (n.toInt + tim.typ.size - 1)) @@ -260,11 +266,12 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program case arr: MfArray => arr.toAddress match { case NumericConstant(n, _) => - val m = mem.banks(arr.bank(options)) + val bank = arr.bank(options) + val m = mem.banks(bank) for (i <- 0 until arr.sizeInBytes) { m.occupied(i + n.toInt) = true } - labelMap.put(arr.name, m.index -> n.toInt) + labelMap.put(arr.name, bank -> n.toInt) endLabelMap.put(arr.name, (if (arr.isInstanceOf[InitializedArray]) 'A' else 'a') -> (n.toInt + arr.sizeInBytes - 1)) @@ -401,7 +408,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program val index = f.address.get.asInstanceOf[NumericConstant].value.toInt compiledFunctions(f.name) match { case NormalCompiledFunction(_, functionCode, _, _, _) => - labelMap(f.name) = bank0.index -> index + labelMap(f.name) = bank -> index val end = outputFunction(bank, functionCode, index, assembly, options) endLabelMap(f.name) = 'F' -> (end - 1) for (i <- index until end) { @@ -451,7 +458,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program val size = functionCode.map(_.sizeInBytes).sum val bank0 = mem.banks(bank) val index = codeAllocators(bank).allocateBytes(bank0, options, size, initialized = true, writeable = false, location = AllocationLocation.High, alignment = alignment) - labelMap(name) = bank0.index -> index + labelMap(name) = bank -> index endLabelMap(name) = 'F' -> (index + size - 1) justAfterCode += bank -> outputFunction(bank, functionCode, index, assembly, options) case _ => @@ -486,7 +493,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program if (bank != "default") ??? val bank0 = mem.banks(bank) var index = codeAllocators(bank).allocateBytes(bank0, options, typ.size + 1, initialized = true, writeable = false, location = AllocationLocation.High, alignment = m.alignment) - labelMap(name) = bank0.index -> (index + 1) + labelMap(name) = bank -> (index + 1) val altName = m.name.stripPrefix(env.prefix) + "`" val thing = if (name.endsWith(".addr")) env.get[ThingInMemory](name.stripSuffix(".addr")) else env.get[ThingInMemory](name + ".array") env.things += altName -> ConstantThing(altName, NumericConstant(index, 2), env.get[Type]("pointer")) @@ -537,7 +544,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program } val bank0 = mem.banks(bank) var index = codeAllocators(bank).allocateBytes(bank0, options, thing.sizeInBytes, initialized = true, writeable = true, location = AllocationLocation.High, alignment = alignment) - labelMap(name) = bank0.index -> index + labelMap(name) = bank -> index endLabelMap(name) = 'A' -> (index + thing.sizeInBytes - 1) if (!readOnlyPass) { rwDataStart = rwDataStart.min(index) @@ -568,7 +575,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program } val bank0 = mem.banks(bank) var index = codeAllocators(bank).allocateBytes(bank0, options, typ.alignedSize, initialized = true, writeable = true, location = AllocationLocation.High, alignment = alignment) - labelMap(name) = bank0.index -> index + labelMap(name) = bank -> index endLabelMap(name) = 'V' -> (index + typ.size - 1) if (!readOnlyPass) { rwDataStart = rwDataStart.min(index) @@ -610,9 +617,9 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program } if (size < 0) log.fatal("Negative writable memory size. It's a compiler bug.") val ivAddr = codeAllocators(ivBank).allocateBytes(ib, options, size, initialized = true, writeable = false, AllocationLocation.High, NoAlignment) - unimportantLabelMap += "__rwdata_init_start" -> (ib.index -> ivAddr) - unimportantLabelMap += "__rwdata_init_end" -> (ib.index -> (ivAddr + size)) - unimportantLabelMap += "__rwdata_size" -> (ib.index -> size) + unimportantLabelMap += "__rwdata_init_start" -> (ivBank -> ivAddr) + unimportantLabelMap += "__rwdata_init_end" -> (ivBank -> (ivAddr + size)) + unimportantLabelMap += "__rwdata_size" -> (ivBank -> size) for (i <- 0 until size) { ib.output(ivAddr + i) = db.output(rwDataStart + i) db.outputted(rwDataStart + i) = true @@ -650,30 +657,30 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program if (platform.freeZpBytes.nonEmpty) { val zpUsageOffset = platform.freeZpBytes.min val zeropageOccupation = zpOccupied.slice(zpUsageOffset, platform.freeZpBytes.max + 1) - unimportantLabelMap += "__zeropage_usage" -> (defaultBank, zeropageOccupation.lastIndexOf(true) - zeropageOccupation.indexOf(true) + 1) - unimportantLabelMap += "__zeropage_first" -> (defaultBank, zpUsageOffset + (zeropageOccupation.indexOf(true) max 0)) - unimportantLabelMap += "__zeropage_last" -> (defaultBank, zpUsageOffset + (zeropageOccupation.lastIndexOf(true) max 0)) - unimportantLabelMap += "__zeropage_end" -> (defaultBank, zpUsageOffset + zeropageOccupation.lastIndexOf(true) + 1) + unimportantLabelMap += "__zeropage_usage" -> ("default", zeropageOccupation.lastIndexOf(true) - zeropageOccupation.indexOf(true) + 1) + unimportantLabelMap += "__zeropage_first" -> ("default", zpUsageOffset + (zeropageOccupation.indexOf(true) max 0)) + unimportantLabelMap += "__zeropage_last" -> ("default", zpUsageOffset + (zeropageOccupation.lastIndexOf(true) max 0)) + unimportantLabelMap += "__zeropage_end" -> ("default", zpUsageOffset + zeropageOccupation.lastIndexOf(true) + 1) } else { - unimportantLabelMap += "__zeropage_usage" -> (defaultBank -> 0) - unimportantLabelMap += "__zeropage_first" -> (defaultBank -> 3) - unimportantLabelMap += "__zeropage_last" -> (defaultBank -> 2) - unimportantLabelMap += "__zeropage_end" -> (defaultBank -> 3) + unimportantLabelMap += "__zeropage_usage" -> ("default" -> 0) + unimportantLabelMap += "__zeropage_first" -> ("default" -> 3) + unimportantLabelMap += "__zeropage_last" -> ("default" -> 2) + unimportantLabelMap += "__zeropage_end" -> ("default" -> 3) } - unimportantLabelMap += "__rwdata_start" -> (defaultBank -> rwDataStart) - unimportantLabelMap += "__rwdata_end" -> (defaultBank -> rwDataEnd) - unimportantLabelMap += "__heap_start" -> (defaultBank -> variableAllocators("default").heapStart) + unimportantLabelMap += "__rwdata_start" -> ("default" -> rwDataStart) + unimportantLabelMap += "__rwdata_end" -> ("default" -> rwDataEnd) + unimportantLabelMap += "__heap_start" -> ("default" -> variableAllocators("default").heapStart) for (segment <- platform.bankNumbers.keys) { val variableAllocator = options.platform.variableAllocators(segment) val codeAllocator = options.platform.codeAllocators(segment) - unimportantLabelMap += s"segment.$segment.start" -> (defaultBank -> codeAllocator.startAt) - unimportantLabelMap += s"segment.$segment.codeend" -> (defaultBank -> (codeAllocator.endBefore - 1)) - unimportantLabelMap += s"segment.$segment.datastart" -> (defaultBank -> variableAllocator.startAt) - unimportantLabelMap += s"segment.$segment.heapstart" -> (defaultBank -> variableAllocator.heapStart) - unimportantLabelMap += s"segment.$segment.end" -> (defaultBank -> (variableAllocator.endBefore - 1)) - unimportantLabelMap += s"segment.$segment.length" -> (defaultBank -> (variableAllocator.endBefore - codeAllocator.startAt)) - unimportantLabelMap += s"segment.$segment.bank" -> (defaultBank -> platform.bankNumbers(segment)) - unimportantLabelMap += s"segment.$segment.fill" -> (defaultBank -> platform.bankFill(segment)) + unimportantLabelMap += s"segment.$segment.start" -> ("default" -> codeAllocator.startAt) + unimportantLabelMap += s"segment.$segment.codeend" -> ("default" -> (codeAllocator.endBefore - 1)) + unimportantLabelMap += s"segment.$segment.datastart" -> ("default" -> variableAllocator.startAt) + unimportantLabelMap += s"segment.$segment.heapstart" -> ("default" -> variableAllocator.heapStart) + unimportantLabelMap += s"segment.$segment.end" -> ("default" -> (variableAllocator.endBefore - 1)) + unimportantLabelMap += s"segment.$segment.length" -> ("default" -> (variableAllocator.endBefore - codeAllocator.startAt)) + unimportantLabelMap += s"segment.$segment.bank" -> ("default" -> platform.bankNumbers(segment)) + unimportantLabelMap += s"segment.$segment.fill" -> ("default" -> platform.bankFill(segment)) } env = rootEnv.allThings @@ -754,13 +761,18 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program assembly += f" ; $$$v%04X = $l%s" } + var bankLayoutInFile = BankLayoutInFile.empty // TODO: val code = (platform.outputStyle match { case OutputStyle.Single | OutputStyle.LUnix => List("default") case OutputStyle.PerBank => platform.bankNumbers.keys.toList }).map{b => val outputPackager = platform.outputPackagers.getOrElse(b, platform.defaultOutputPackager) - b -> outputPackager.packageOutput(mem, b) + val tuple = outputPackager.packageOutputAndLayout(mem, b) + if (b == "default") { + bankLayoutInFile = tuple._2 + } + b -> tuple._1 }.toMap if (options.flag(CompilationFlag.DataMissingInOutputWarning)) { for (bank <- mem.banks.keys.toSeq.sorted) { @@ -771,7 +783,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program } } } - AssemblerOutput(code, assembly.toArray, labelMap.toList, endLabelMap.toMap, breakpointSet.toList.sorted) + AssemblerOutput(code, bankLayoutInFile, assembly.toArray, labelMap.toList, endLabelMap.toMap, breakpointSet.toList.sorted) } private def printArrayToAssemblyOutput(assembly: ArrayBuffer[String], name: String, elementType: Type, items: Seq[Expression]): Unit = { @@ -804,13 +816,13 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program } } - def injectLabels(labelMap: Map[String, (Int, Int)], code: List[T]): List[T] + def injectLabels(labelMap: Map[String, (String, Int)], code: List[T]): List[T] private def compileFunction(f: NormalFunction, optimizations: Seq[AssemblyOptimization[T]], options: CompilationOptions, inlinedFunctions: Map[String, List[T]], - labelMap: Map[String, (Int, Int)], + labelMap: Map[String, (String, Int)], niceFunctionProperties: Set[(NiceFunctionProperty, String)]): List[T] = { log.debug("Compiling: " + f.name, f.position) val unoptimized: List[T] = diff --git a/src/main/scala/millfork/output/BankLayoutInFile.scala b/src/main/scala/millfork/output/BankLayoutInFile.scala new file mode 100644 index 00000000..8535ad3d --- /dev/null +++ b/src/main/scala/millfork/output/BankLayoutInFile.scala @@ -0,0 +1,32 @@ +package millfork.output + +/** + * @author Karol Stasiak + */ +object BankLayoutInFile{ + def empty: BankLayoutInFile = new BankLayoutInFile(Map.empty, Map.empty) +} + +class BankLayoutInFile(startInFile: Map[String, Int], firstAddress: Map[String, Int]) { + + val fileHeaderSize: Int = if (startInFile.isEmpty) 0 else startInFile.values.min + + // Mesen represents all label values as offsets from the start of ROM data in the .nes file, + // not as actual addresses + def getMesenShift(bank: String): Int = { + val s = startInFile.getOrElse(bank, 0) + val f = firstAddress.getOrElse(bank, 0) + // for example, a typical 32K NROM PRG has: + // s = 16 + // h = 16 + // f = 0x8000 + // addresses = 0x8000-0xffff + // Mesen Label values = 0x0000-0x7fff + // shift = -0x8000 + s - fileHeaderSize - f + } + + def wasWritten(bank: String): Boolean = startInFile.contains(bank) + + def Ld65Offset(bank: String): Int = startInFile(bank) +} diff --git a/src/main/scala/millfork/output/CompiledMemory.scala b/src/main/scala/millfork/output/CompiledMemory.scala index 982aa614..fef6fc1f 100644 --- a/src/main/scala/millfork/output/CompiledMemory.scala +++ b/src/main/scala/millfork/output/CompiledMemory.scala @@ -7,7 +7,7 @@ import scala.collection.mutable /** * @author Karol Stasiak */ -class CompiledMemory(bankNames: List[(String, Int)], bankFills: Map[String, Int], bigEndian: Boolean, labels: mutable.Map[String, (Int, Int)], log: Logger) { +class CompiledMemory(bankNames: List[(String, Int)], bankFills: Map[String, Int], bigEndian: Boolean, labels: mutable.Map[String, (String, Int)], log: Logger) { var programName = "MILLFORK" val banks: mutable.Map[String, MemoryBank] = mutable.Map(bankNames.map{p => val bank = new MemoryBank(p._2, bigEndian) diff --git a/src/main/scala/millfork/output/D88Output.scala b/src/main/scala/millfork/output/D88Output.scala index 5a595a45..c16c010b 100644 --- a/src/main/scala/millfork/output/D88Output.scala +++ b/src/main/scala/millfork/output/D88Output.scala @@ -23,7 +23,7 @@ object D88Output extends OutputPackager { ).map(_.toByte) - override def packageOutput(mem: CompiledMemory, bank: String): Array[Byte] = { + override def packageOutput(flc: FileLayoutCollector, mem: CompiledMemory, bank: String): Array[Byte] = { val b = mem.banks(bank) val start = b.start val header = new D88Header(mem.programName.take(16)) diff --git a/src/main/scala/millfork/output/FormattableLabel.scala b/src/main/scala/millfork/output/FormattableLabel.scala new file mode 100644 index 00000000..3d7f1c53 --- /dev/null +++ b/src/main/scala/millfork/output/FormattableLabel.scala @@ -0,0 +1,14 @@ +package millfork.output + +/** + * @author Karol Stasiak + */ +case class FormattableLabel( + labelName: String, + bankName: String, + bankNumber: Int, + startValue: Int, + endValue: Option[Int], + category: Char, + mesenSymbol: Char + ) diff --git a/src/main/scala/millfork/output/M6809Assembler.scala b/src/main/scala/millfork/output/M6809Assembler.scala index 7c57f8a0..73dae626 100644 --- a/src/main/scala/millfork/output/M6809Assembler.scala +++ b/src/main/scala/millfork/output/M6809Assembler.scala @@ -20,7 +20,7 @@ class M6809Assembler(program: Program, override def deduplicate(options: CompilationOptions, compiledFunctions: mutable.Map[String, CompiledFunction[MLine]]): Unit = () - override def injectLabels(labelMap: Map[String, (Int, Int)], code: List[MLine]): List[MLine] = code + override def injectLabels(labelMap: Map[String, (String, Int)], code: List[MLine]): List[MLine] = code override def quickSimplify(code: List[MLine]): List[MLine] = code @@ -105,7 +105,7 @@ class M6809Assembler(program: Program, case MLine0(_, RawByte, _) => log.fatal("BYTE opcode failure") case MLine0(LABEL, NonExistent, MemoryAddressConstant(Label(labelName))) => val bank0 = mem.banks(bank) - labelMap(labelName) = bank0.index -> index + labelMap(labelName) = bank -> index index case MLine0(op, NonExistent, _) if MOpcode.NoopDiscard(op) => index diff --git a/src/main/scala/millfork/output/MosAssembler.scala b/src/main/scala/millfork/output/MosAssembler.scala index b682bb13..5246b30f 100644 --- a/src/main/scala/millfork/output/MosAssembler.scala +++ b/src/main/scala/millfork/output/MosAssembler.scala @@ -42,7 +42,7 @@ class MosAssembler(program: Program, case AssemblyLine0(_, RawByte, _) => log.fatal("BYTE opcode failure") case AssemblyLine0(LABEL, _, MemoryAddressConstant(Label(labelName))) => val bank0 = mem.banks(bank) - labelMap(labelName) = bank0.index -> index + labelMap(labelName) = bank -> index index case AssemblyLine0(CHANGED_MEM, DoesNotExist, MemoryAddressConstant(Label(l))) if l.contains("..brk") => breakpointSet += mem.banks(bank).index -> index @@ -112,7 +112,7 @@ class MosAssembler(program: Program, } } - override def injectLabels(labelMap: Map[String, (Int, Int)], code: List[AssemblyLine]): List[AssemblyLine] = { + override def injectLabels(labelMap: Map[String, (String, Int)], code: List[AssemblyLine]): List[AssemblyLine] = { import Opcode._ code.map { case l@AssemblyLine(LDA | STA | CMP | diff --git a/src/main/scala/millfork/output/OutputPackager.scala b/src/main/scala/millfork/output/OutputPackager.scala index 3f4eb7a6..dc113a3f 100644 --- a/src/main/scala/millfork/output/OutputPackager.scala +++ b/src/main/scala/millfork/output/OutputPackager.scala @@ -3,60 +3,98 @@ package millfork.output import java.io.ByteArrayOutputStream import java.nio.charset.StandardCharsets import java.util.Locale +import scala.collection.mutable /** * @author Karol Stasiak */ trait OutputPackager { - def packageOutput(mem: CompiledMemory, bank: String): Array[Byte] + + def packageOutputAndLayout(mem: CompiledMemory, bank: String): (Array[Byte], BankLayoutInFile) = { + val startInFile = mutable.Map[String, Int]() + val firstAddress = mutable.Map[String, Int]() + val fileLayoutCollector = new FileLayoutCollector(startInFile, firstAddress) + val output = packageOutput(fileLayoutCollector, mem, bank) + output -> fileLayoutCollector.toBankLayoutInFile + } + + def packageOutput(flc: FileLayoutCollector, mem: CompiledMemory, bank: String): Array[Byte] + + def writes(b: String): Boolean = false +} + +class FileLayoutCollector(startInFile: mutable.Map[String, Int], + firstAddress: mutable.Map[String, Int], + offset: Int = 0) { + def reportBankChunk(bank: String, extraOffset: Int, addr: Int): Unit = { + if (!startInFile.contains(bank)) { + println(s"bank $bank starts at $offset + $extraOffset") + startInFile(bank) = offset + extraOffset + } + if (!firstAddress.contains(bank)) { + firstAddress(bank) = addr + } + } + + def +(deltaOffset: Int) = new FileLayoutCollector(startInFile, firstAddress, offset + deltaOffset) + + def toBankLayoutInFile = new BankLayoutInFile(startInFile.toMap, firstAddress.toMap) } case class SequenceOutput(children: List[OutputPackager]) extends OutputPackager { - def packageOutput(mem: CompiledMemory, bank: String): Array[Byte] = { + def packageOutput(flc: FileLayoutCollector, mem: CompiledMemory, bank: String): Array[Byte] = { val baos = new ByteArrayOutputStream - children.foreach { c => - val a = c.packageOutput(mem, bank) + var f = flc + for (c <- children) { + val a = c.packageOutput(f, mem, bank) baos.write(a, 0, a.length) + f += a.length } baos.toByteArray } + + override def writes(b: String): Boolean = children.exists(_.writes(b)) } case class ConstOutput(byte: Byte) extends OutputPackager { - def packageOutput(mem: CompiledMemory, bank: String): Array[Byte] = Array(byte) + def packageOutput(flc: FileLayoutCollector, mem: CompiledMemory, bank: String): Array[Byte] = Array(byte) } case class CurrentBankFragmentOutput(start: Int, end: Int) extends OutputPackager { - def packageOutput(mem: CompiledMemory, bank: String): Array[Byte] = { + def packageOutput(flc: FileLayoutCollector, mem: CompiledMemory, bank: String): Array[Byte] = { val b = mem.banks(bank) b.markAsOutputted(start, end + 1) + flc.reportBankChunk(bank, 0, start) b.output.slice(start, end + 1) } } case class BankFragmentOutput(alwaysBank: String, start: Int, end: Int) extends OutputPackager { - def packageOutput(mem: CompiledMemory, bank: String): Array[Byte] = { + def packageOutput(flc: FileLayoutCollector, mem: CompiledMemory, bank: String): Array[Byte] = { val b = mem.banks(alwaysBank) b.markAsOutputted(start, end + 1) + flc.reportBankChunk(alwaysBank, 0, start) b.output.slice(start, end + 1) } + + override def writes(b: String): Boolean = b == alwaysBank } case class ProgramNameOutput(length: Int) extends OutputPackager { def isAlphanum(c: Char): Boolean = (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') - def packageOutput(mem: CompiledMemory, bank: String): Array[Byte] = { + def packageOutput(flc: FileLayoutCollector, mem: CompiledMemory, bank: String): Array[Byte] = { mem.programName.toUpperCase(Locale.ROOT).filter(isAlphanum).take(length).padTo(length, ' ').getBytes(StandardCharsets.US_ASCII) } } case class StringOutput(string: String) extends OutputPackager { - def packageOutput(mem: CompiledMemory, bank: String): Array[Byte] = { + def packageOutput(flc: FileLayoutCollector, mem: CompiledMemory, bank: String): Array[Byte] = { string.getBytes(StandardCharsets.US_ASCII) } } case class StartAddressOutput(bonus: Int) extends OutputPackager { - def packageOutput(mem: CompiledMemory, bank: String): Array[Byte] = { + def packageOutput(flc: FileLayoutCollector, mem: CompiledMemory, bank: String): Array[Byte] = { val b = mem.banks(bank) val x = b.start + bonus Array(x.toByte, x.>>(8).toByte) @@ -64,7 +102,7 @@ case class StartAddressOutput(bonus: Int) extends OutputPackager { } case class StartAddressOutputBe(bonus: Int) extends OutputPackager { - def packageOutput(mem: CompiledMemory, bank: String): Array[Byte] = { + def packageOutput(flc: FileLayoutCollector, mem: CompiledMemory, bank: String): Array[Byte] = { val b = mem.banks(bank) val x = b.start + bonus Array(x.>>(8).toByte, x.toByte) @@ -72,14 +110,14 @@ case class StartAddressOutputBe(bonus: Int) extends OutputPackager { } object StartPageOutput extends OutputPackager { - def packageOutput(mem: CompiledMemory, bank: String): Array[Byte] = { + def packageOutput(flc: FileLayoutCollector, mem: CompiledMemory, bank: String): Array[Byte] = { val b = mem.banks(bank) Array(b.start.>>(8).toByte) } } case class EndAddressOutput(bonus: Int) extends OutputPackager { - def packageOutput(mem: CompiledMemory, bank: String): Array[Byte] = { + def packageOutput(flc: FileLayoutCollector, mem: CompiledMemory, bank: String): Array[Byte] = { val b = mem.banks(bank) val x = b.end + bonus Array(x.toByte, x.>>(8).toByte) @@ -87,7 +125,7 @@ case class EndAddressOutput(bonus: Int) extends OutputPackager { } case class EndAddressOutputBe(bonus: Int) extends OutputPackager { - def packageOutput(mem: CompiledMemory, bank: String): Array[Byte] = { + def packageOutput(flc: FileLayoutCollector, mem: CompiledMemory, bank: String): Array[Byte] = { val b = mem.banks(bank) val x = b.end + bonus Array(x.>>(8).toByte, x.toByte) @@ -96,7 +134,7 @@ case class EndAddressOutputBe(bonus: Int) extends OutputPackager { case class SymbolAddressOutput(symbol: String, bonus: Int) extends OutputPackager { - def packageOutput(mem: CompiledMemory, bank: String): Array[Byte] = { + def packageOutput(flc: FileLayoutCollector, mem: CompiledMemory, bank: String): Array[Byte] = { val b = mem.banks(bank) val x = mem.getAddress(symbol) + bonus Array(b.end.toByte, b.end.>>(8).toByte) @@ -104,7 +142,7 @@ case class SymbolAddressOutput(symbol: String, bonus: Int) extends OutputPackage } case class SymbolAddressOutputBe(symbol: String, bonus: Int) extends OutputPackager { - def packageOutput(mem: CompiledMemory, bank: String): Array[Byte] = { + def packageOutput(flc: FileLayoutCollector, mem: CompiledMemory, bank: String): Array[Byte] = { val b = mem.banks(bank) val x = mem.getAddress(symbol) + bonus Array(x.>>(8).toByte, x.toByte) @@ -112,7 +150,7 @@ case class SymbolAddressOutputBe(symbol: String, bonus: Int) extends OutputPacka } object PageCountOutput extends OutputPackager { - def packageOutput(mem: CompiledMemory, bank: String): Array[Byte] = { + def packageOutput(flc: FileLayoutCollector, mem: CompiledMemory, bank: String): Array[Byte] = { val e = mem.banks(bank).end.>>(8) val s = mem.banks(bank).start.>>(8) Array((e - s + 1).toByte) @@ -120,15 +158,16 @@ object PageCountOutput extends OutputPackager { } object AllocatedDataOutput extends OutputPackager { - def packageOutput(mem: CompiledMemory, bank: String): Array[Byte] = { + def packageOutput(flc: FileLayoutCollector, mem: CompiledMemory, bank: String): Array[Byte] = { val b = mem.banks(bank) b.markAsOutputted(b.start, b.end + 1) + flc.reportBankChunk(bank, 0, b.start) b.output.slice(b.start, b.end + 1) } } case class AllocatedDataLength(bonus: Int) extends OutputPackager { - def packageOutput(mem: CompiledMemory, bank: String): Array[Byte] = { + def packageOutput(flc: FileLayoutCollector, mem: CompiledMemory, bank: String): Array[Byte] = { val b = mem.banks(bank) val size = b.end - b.start + 1 + bonus Array(size.toByte, size.>>(8).toByte) @@ -136,7 +175,7 @@ case class AllocatedDataLength(bonus: Int) extends OutputPackager { } case class AllocatedDataLengthBe(bonus: Int) extends OutputPackager { - def packageOutput(mem: CompiledMemory, bank: String): Array[Byte] = { + def packageOutput(flc: FileLayoutCollector, mem: CompiledMemory, bank: String): Array[Byte] = { val b = mem.banks(bank) val size = b.end - b.start + 1 + bonus Array(size.>>(8).toByte, size.toByte) diff --git a/src/main/scala/millfork/output/TapOutput.scala b/src/main/scala/millfork/output/TapOutput.scala index 13ae2055..8e77cd66 100644 --- a/src/main/scala/millfork/output/TapOutput.scala +++ b/src/main/scala/millfork/output/TapOutput.scala @@ -9,7 +9,7 @@ class TapOutput(val symbol: String) extends OutputPackager { def isAlphanum(c: Char): Boolean = (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') - override def packageOutput(mem: CompiledMemory, bank: String): Array[Byte] = { + override def packageOutput(flc: FileLayoutCollector, mem: CompiledMemory, bank: String): Array[Byte] = { val filteredName: String = mem.programName.filter(isAlphanum) val b = mem.banks(bank) val code = b.output.slice(b.start, b.end + 1) diff --git a/src/main/scala/millfork/output/TrsCmdOutput.scala b/src/main/scala/millfork/output/TrsCmdOutput.scala index ee4a93d7..241e417f 100644 --- a/src/main/scala/millfork/output/TrsCmdOutput.scala +++ b/src/main/scala/millfork/output/TrsCmdOutput.scala @@ -4,7 +4,7 @@ package millfork.output * @author Karol Stasiak */ class TrsCmdOutput(symbol: String) extends OutputPackager { - override def packageOutput(mem: CompiledMemory, bank: String): Array[Byte] = { + override def packageOutput(flc: FileLayoutCollector, mem: CompiledMemory, bank: String): Array[Byte] = { val b = mem.banks(bank) val start = b.start val run = mem.getAddress(symbol) diff --git a/src/main/scala/millfork/output/Z80Assembler.scala b/src/main/scala/millfork/output/Z80Assembler.scala index 975340a4..53186835 100644 --- a/src/main/scala/millfork/output/Z80Assembler.scala +++ b/src/main/scala/millfork/output/Z80Assembler.scala @@ -97,7 +97,7 @@ class Z80Assembler(program: Program, try { instr match { case ZLine0(LABEL, NoRegisters, MemoryAddressConstant(Label(labelName))) => val bank0 = mem.banks(bank) - labelMap(labelName) = bank0.index -> index + labelMap(labelName) = bank -> index index case ZLine0(BYTE, NoRegisters, param) => writeByte(bank, index, param) @@ -846,7 +846,7 @@ class Z80Assembler(program: Program, } } - override def injectLabels(labelMap: Map[String, (Int, Int)], code: List[ZLine]): List[ZLine] = code // TODO + override def injectLabels(labelMap: Map[String, (String, Int)], code: List[ZLine]): List[ZLine] = code // TODO override def quickSimplify(code: List[ZLine]): List[ZLine] = code.map(a => a.copy(parameter = a.parameter.quickSimplify)) diff --git a/src/main/scala/millfork/output/Z80ToX86Crossassembler.scala b/src/main/scala/millfork/output/Z80ToX86Crossassembler.scala index 262bbf26..70c6d71c 100644 --- a/src/main/scala/millfork/output/Z80ToX86Crossassembler.scala +++ b/src/main/scala/millfork/output/Z80ToX86Crossassembler.scala @@ -22,7 +22,7 @@ class Z80ToX86Crossassembler(program: Program, } else code } - override def injectLabels(labelMap: Map[String, (Int, Int)], code: List[ZLine]): List[ZLine] = code // TODO + override def injectLabels(labelMap: Map[String, (String, Int)], code: List[ZLine]): List[ZLine] = code // TODO override def quickSimplify(code: List[ZLine]): List[ZLine] = code.map(a => a.copy(parameter = a.parameter.quickSimplify)) @@ -83,7 +83,7 @@ class Z80ToX86Crossassembler(program: Program, instr match { case ZLine0(LABEL, NoRegisters, MemoryAddressConstant(Label(labelName))) => val bank0 = mem.banks(bank) - labelMap(labelName) = bank0.index -> index + labelMap(labelName) = bank -> index index case ZLine0(BYTE, NoRegisters, param) => writeByte(bank, index, param)