mirror of
https://github.com/KarolS/millfork.git
synced 2024-06-12 22:29:33 +00:00
Add support for Mesen label file format by tracking file-relative positions of segments (#128)
This commit is contained in:
parent
b168818bab
commit
73a223b9b6
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -35,6 +35,7 @@ issue*.mfk
|
||||||
*.nl
|
*.nl
|
||||||
*.fns
|
*.fns
|
||||||
*.sym
|
*.sym
|
||||||
|
*.mlb
|
||||||
*.deb
|
*.deb
|
||||||
*.xex
|
*.xex
|
||||||
*.nes
|
*.nes
|
||||||
|
|
|
@ -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 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.
|
* `-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` –
|
* `-fbreakpoints`, `-fno-breakpoints` –
|
||||||
|
|
|
@ -267,3 +267,5 @@ Default: `main,*`
|
||||||
* `sym` – format used by the WLA/DX assembler. The extension is `.sym`.
|
* `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`.
|
* `fceux` – multi-file format used by the FCEUX emulator. The extension is `.nl`.
|
||||||
|
|
||||||
|
* `mesen` – format used by the Mesen emulator. The extension is `.mlb`.
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
package millfork
|
package millfork
|
||||||
|
|
||||||
|
import millfork.output.{BankLayoutInFile, FormattableLabel}
|
||||||
|
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
import scala.util.control.Breaks.{break, breakable}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Karol Stasiak
|
* @author Karol Stasiak
|
||||||
*/
|
*/
|
||||||
|
@ -12,13 +17,16 @@ object DebugOutputFormat {
|
||||||
"fns" -> NesasmDebugOutputFormat,
|
"fns" -> NesasmDebugOutputFormat,
|
||||||
"fceux" -> FceuxDebugOutputFormat,
|
"fceux" -> FceuxDebugOutputFormat,
|
||||||
"nl" -> FceuxDebugOutputFormat,
|
"nl" -> FceuxDebugOutputFormat,
|
||||||
|
"mlb" -> MesenOutputFormat,
|
||||||
|
"mesen" -> MesenOutputFormat,
|
||||||
|
"asm6f" -> MesenOutputFormat,
|
||||||
"sym" -> SymDebugOutputFormat)
|
"sym" -> SymDebugOutputFormat)
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed trait DebugOutputFormat {
|
sealed trait DebugOutputFormat {
|
||||||
|
|
||||||
def formatAll(labels: Seq[(String, Int, Int, Char, Option[Int])], breakpoints: Seq[(Int, Int)]): String = {
|
def formatAll(b: BankLayoutInFile, labels: Seq[FormattableLabel], breakpoints: Seq[(Int, Int)]): String = {
|
||||||
val labelPart = labelsHeader + labels.map(formatLineTupled).mkString("\n") + "\n"
|
val labelPart = labelsHeader + labels.map(formatLine).mkString("\n") + "\n"
|
||||||
if (breakpoints.isEmpty) {
|
if (breakpoints.isEmpty) {
|
||||||
labelPart
|
labelPart
|
||||||
} else {
|
} else {
|
||||||
|
@ -26,10 +34,7 @@ sealed trait DebugOutputFormat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final def formatLineTupled(labelAndValue: (String, Int, Int, Char, Option[Int])): String =
|
def formatLine(label: FormattableLabel): 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
|
|
||||||
|
|
||||||
final def formatBreakpointTupled(value: (Int, Int)): Seq[String] = formatBreakpoint(value._1, value._2).toSeq
|
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 {
|
object RawDebugOutputFormat extends DebugOutputFormat {
|
||||||
override def formatLine(label: String, bank: Int, startValue: Int, category: Char, endValue: Option[Int]): String = {
|
override def formatLine(label: FormattableLabel): String = {
|
||||||
f"$bank%02X:$startValue%04X:${endValue.fold("")(_.formatted("%04X"))}%s:$category%s:$label%s"
|
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"
|
override def fileExtension(bank: Int): String = ".labels"
|
||||||
|
@ -63,9 +68,9 @@ object RawDebugOutputFormat extends DebugOutputFormat {
|
||||||
}
|
}
|
||||||
|
|
||||||
object ViceDebugOutputFormat extends DebugOutputFormat {
|
object ViceDebugOutputFormat extends DebugOutputFormat {
|
||||||
override def formatLine(label: String, bank: Int, startValue: Int, category: Char, endValue: Option[Int]): String = {
|
override def formatLine(label: FormattableLabel): String = {
|
||||||
val normalized = label.replace('$', '_').replace('.', '_')
|
val normalized = label.labelName.replace('$', '_').replace('.', '_')
|
||||||
s"al ${startValue.toHexString} .$normalized"
|
s"al ${label.startValue.toHexString} .$normalized"
|
||||||
}
|
}
|
||||||
|
|
||||||
override def fileExtension(bank: Int): String = ".lbl"
|
override def fileExtension(bank: Int): String = ".lbl"
|
||||||
|
@ -78,8 +83,8 @@ object ViceDebugOutputFormat extends DebugOutputFormat {
|
||||||
}
|
}
|
||||||
|
|
||||||
object NesasmDebugOutputFormat extends DebugOutputFormat {
|
object NesasmDebugOutputFormat extends DebugOutputFormat {
|
||||||
override def formatLine(label: String, bank: Int, startValue: Int, category: Char, endValue: Option[Int]): String = {
|
override def formatLine(label: FormattableLabel): String = {
|
||||||
label + " = $" + startValue.toHexString
|
label.labelName + " = $" + label.startValue.toHexString
|
||||||
}
|
}
|
||||||
|
|
||||||
override def fileExtension(bank: Int): String = ".fns"
|
override def fileExtension(bank: Int): String = ".fns"
|
||||||
|
@ -92,8 +97,8 @@ object NesasmDebugOutputFormat extends DebugOutputFormat {
|
||||||
}
|
}
|
||||||
|
|
||||||
object SymDebugOutputFormat extends DebugOutputFormat {
|
object SymDebugOutputFormat extends DebugOutputFormat {
|
||||||
override def formatLine(label: String, bank: Int, startValue: Int, category: Char, endValue:Option[Int]): String = {
|
override def formatLine(label: FormattableLabel): String = {
|
||||||
f"$bank%02x:$startValue%04x $label%s"
|
f"${label.bankNumber}%02x:${label.startValue}%04x ${label.labelName}%s"
|
||||||
}
|
}
|
||||||
|
|
||||||
override def fileExtension(bank: Int): String = ".sym"
|
override def fileExtension(bank: Int): String = ".sym"
|
||||||
|
@ -110,8 +115,8 @@ object SymDebugOutputFormat extends DebugOutputFormat {
|
||||||
}
|
}
|
||||||
|
|
||||||
object FceuxDebugOutputFormat extends DebugOutputFormat {
|
object FceuxDebugOutputFormat extends DebugOutputFormat {
|
||||||
override def formatLine(label: String, bank: Int, startValue: Int, category: Char, endValue: Option[Int]): String = {
|
override def formatLine(label: FormattableLabel): String = {
|
||||||
f"$$$startValue%04x#$label%s#"
|
f"$$${label.startValue}%04x#${label.labelName}%s#"
|
||||||
}
|
}
|
||||||
|
|
||||||
override def fileExtension(bank: Int): String = if (bank == 0xff) ".ram.nl" else s".$bank.nl"
|
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
|
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
|
||||||
|
}
|
|
@ -119,33 +119,35 @@ object Main {
|
||||||
else if (l.startsWith("__")) 7
|
else if (l.startsWith("__")) 7
|
||||||
else 0
|
else 0
|
||||||
}
|
}
|
||||||
val sortedLabels: Seq[(String, Int, Int, Char, Option[Int])] =
|
val sortedLabels: Seq[FormattableLabel] =
|
||||||
result.labels.groupBy(_._2).values
|
result.labels.groupBy(_._2).values
|
||||||
.map(_.minBy(a => labelUnimportance(a._1) -> a._1)).toSeq.sortBy(_._2)
|
.map(_.minBy(a => labelUnimportance(a._1) -> a._1)).toSeq.sortBy(_._2)
|
||||||
.map { case (l, (b, s)) =>
|
.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 {
|
result.endLabels.get(l) match {
|
||||||
case Some((c, e)) => (l, b, s, c, Some(e))
|
case Some((c, e)) => FormattableLabel(l, b, bankNumber, s, Some(e), c, mesenCategory)
|
||||||
case _ => (l, b, s, 'x', None)
|
case _ => FormattableLabel(l, b, bankNumber, s, None, 'x', mesenCategory)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val sortedBreakpoints = result.breakpoints
|
val sortedBreakpoints = result.breakpoints
|
||||||
val format = c.outputLabelsFormatOverride.getOrElse(platform.outputLabelsFormat)
|
val format = c.outputLabelsFormatOverride.getOrElse(platform.outputLabelsFormat)
|
||||||
val basename = if (format.addOutputExtension) output + platform.fileExtension else output
|
val basename = if (format.addOutputExtension) output + platform.fileExtension else output
|
||||||
if (format.filePerBank) {
|
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 =>
|
banks.foreach{ bank =>
|
||||||
val labels = sortedLabels.filter(_._2.==(bank))
|
val labels = sortedLabels.filter(_.bankNumber.==(bank))
|
||||||
val breakpoints = sortedBreakpoints.filter(_._1.==(bank))
|
val breakpoints = sortedBreakpoints.filter(_._1.==(bank))
|
||||||
val labelOutput = basename + format.fileExtension(bank)
|
val labelOutput = basename + format.fileExtension(bank)
|
||||||
val path = Paths.get(labelOutput)
|
val path = Paths.get(labelOutput)
|
||||||
errorReporting.debug("Writing labels to " + path.toAbsolutePath)
|
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 {
|
} else {
|
||||||
val labelOutput = basename + format.fileExtension(0)
|
val labelOutput = basename + format.fileExtension(0)
|
||||||
val path = Paths.get(labelOutput)
|
val path = Paths.get(labelOutput)
|
||||||
errorReporting.debug("Writing labels to " + path.toAbsolutePath)
|
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
|
val defaultPrgOutput = if (output.endsWith(platform.fileExtension)) output else output + platform.fileExtension
|
||||||
|
|
|
@ -42,6 +42,7 @@ class Platform(
|
||||||
val outputLabelsFormat: DebugOutputFormat,
|
val outputLabelsFormat: DebugOutputFormat,
|
||||||
val outputStyle: OutputStyle.Value
|
val outputStyle: OutputStyle.Value
|
||||||
) {
|
) {
|
||||||
|
|
||||||
def hasZeroPage: Boolean = cpuFamily == CpuFamily.M6502
|
def hasZeroPage: Boolean = cpuFamily == CpuFamily.M6502
|
||||||
|
|
||||||
def cpuFamily: CpuFamily.Value = CpuFamily.forType(this.cpu)
|
def cpuFamily: CpuFamily.Value = CpuFamily.forType(this.cpu)
|
||||||
|
@ -60,6 +61,18 @@ class Platform(
|
||||||
val e2 = bankEndBefore(bank2)
|
val e2 = bankEndBefore(bank2)
|
||||||
e2 > s1 && s2 < e1
|
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 {
|
object Platform {
|
||||||
|
|
|
@ -10,7 +10,7 @@ import millfork.node.NiceFunctionProperty
|
||||||
* @author Karol Stasiak
|
* @author Karol Stasiak
|
||||||
*/
|
*/
|
||||||
case class OptimizationContext(options: CompilationOptions,
|
case class OptimizationContext(options: CompilationOptions,
|
||||||
labelMap: Map[String, (Int, Int)],
|
labelMap: Map[String, (String, Int)],
|
||||||
zreg: Option[ThingInMemory],
|
zreg: Option[ThingInMemory],
|
||||||
niceFunctionProperties: Set[(NiceFunctionProperty, String)]) {
|
niceFunctionProperties: Set[(NiceFunctionProperty, String)]) {
|
||||||
@inline
|
@inline
|
||||||
|
|
|
@ -101,7 +101,7 @@ class RuleBasedAssemblyOptimization(val name: String, val needsFlowInfo: FlowInf
|
||||||
}
|
}
|
||||||
|
|
||||||
class AssemblyMatchingContext(val compilationOptions: CompilationOptions,
|
class AssemblyMatchingContext(val compilationOptions: CompilationOptions,
|
||||||
val labelMap: Map[String, (Int, Int)],
|
val labelMap: Map[String, (String, Int)],
|
||||||
val niceFunctionProperties: Set[(NiceFunctionProperty, String)],
|
val niceFunctionProperties: Set[(NiceFunctionProperty, String)],
|
||||||
val labelUseCount: String => Int) {
|
val labelUseCount: String => Int) {
|
||||||
@inline
|
@inline
|
||||||
|
|
|
@ -102,7 +102,7 @@ class RuleBasedAssemblyOptimization(val name: String, val needsFlowInfo: FlowInf
|
||||||
}
|
}
|
||||||
|
|
||||||
class AssemblyMatchingContext(val compilationOptions: CompilationOptions,
|
class AssemblyMatchingContext(val compilationOptions: CompilationOptions,
|
||||||
val labelMap: Map[String, (Int, Int)],
|
val labelMap: Map[String, (String, Int)],
|
||||||
val zeropageRegister: Option[ThingInMemory],
|
val zeropageRegister: Option[ThingInMemory],
|
||||||
val niceFunctionProperties: Set[(NiceFunctionProperty, String)],
|
val niceFunctionProperties: Set[(NiceFunctionProperty, String)],
|
||||||
val labelUseCount: String => Int) {
|
val labelUseCount: String => Int) {
|
||||||
|
|
|
@ -117,7 +117,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
|
||||||
callGraph: CallGraph,
|
callGraph: CallGraph,
|
||||||
allocators: Map[String, VariableAllocator],
|
allocators: Map[String, VariableAllocator],
|
||||||
options: CompilationOptions,
|
options: CompilationOptions,
|
||||||
onEachVariable: (String, (Int, Int)) => Unit,
|
onEachVariable: (String, (String, Int)) => Unit,
|
||||||
onEachVariableEnd: (String, (Char, Int)) => Unit,
|
onEachVariableEnd: (String, (Char, Int)) => Unit,
|
||||||
pass: Int,
|
pass: Int,
|
||||||
forZpOnly: Boolean): Unit = {
|
forZpOnly: Boolean): Unit = {
|
||||||
|
@ -184,7 +184,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
|
||||||
val addr =
|
val addr =
|
||||||
allocators(bank).allocateBytes(bank0, callGraph, vertex, options, m.sizeInBytes, initialized = false, writeable = true, location = AllocationLocation.Zeropage, alignment = m.alignment)
|
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)
|
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))
|
onEachVariableEnd(m.name, (if (m.isInstanceOf[MfArray])'a' else 'v') -> (addr + m.sizeInBytes - 1))
|
||||||
List(
|
List(
|
||||||
ConstantThing(m.name.stripPrefix(prefix) + "`", NumericConstant(addr, 2), p)
|
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 None => Nil
|
||||||
case Some(addr) =>
|
case Some(addr) =>
|
||||||
if (log.traceEnabled) log.trace("addr $" + addr.toHexString)
|
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))
|
onEachVariableEnd(m.name, (if (m.isInstanceOf[MfArray])'a' else 'v') -> (addr + m.sizeInBytes - 1))
|
||||||
List(
|
List(
|
||||||
ConstantThing(m.name.stripPrefix(prefix) + "`", NumericConstant(addr, 2), p)
|
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 {
|
} else {
|
||||||
val addr = allocators(bank).allocateBytes(bank0, callGraph, vertex, options, m.sizeInBytes, initialized = false, writeable = true, location = AllocationLocation.Either, alignment = m.alignment)
|
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)
|
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))
|
onEachVariableEnd(m.name, (if (m.isInstanceOf[MfArray])'a' else 'v') -> (addr + m.sizeInBytes - 1))
|
||||||
List(
|
List(
|
||||||
ConstantThing(graveName, NumericConstant(addr, 2), p)
|
ConstantThing(graveName, NumericConstant(addr, 2), p)
|
||||||
|
|
|
@ -19,7 +19,12 @@ import scala.collection.mutable.ArrayBuffer
|
||||||
* @author Karol Stasiak
|
* @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,
|
abstract class AbstractAssembler[T <: AbstractCode](private val program: Program,
|
||||||
private val rootEnv: Environment,
|
private val rootEnv: Environment,
|
||||||
|
@ -33,9 +38,9 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
|
||||||
var initializedVariablesSize: Int = 0
|
var initializedVariablesSize: Int = 0
|
||||||
protected val log: Logger = rootEnv.log
|
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 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 mem = new CompiledMemory(platform.bankNumbers.toList, platform.bankFill, platform.isBigEndian, labelMap, log)
|
||||||
val breakpointSet: mutable.Set[(Int, Int)] = mutable.Set()
|
val breakpointSet: mutable.Set[(Int, Int)] = mutable.Set()
|
||||||
private val bytesToWriteLater = mutable.ListBuffer[(String, Int, Constant, Option[Position])]()
|
private val bytesToWriteLater = mutable.ListBuffer[(String, Int, Constant, Option[Position])]()
|
||||||
|
@ -116,7 +121,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
|
||||||
try {
|
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 + "`")) 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
|
if (unimportantLabelMap.contains(th.name)) return labelMap(th.name)._2
|
||||||
val x1 = env.maybeGet[ConstantThing](th.name).map(_.value)
|
val x1 = env.maybeGet[ConstantThing](th.name).map(_.value)
|
||||||
val x2 = 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 =>
|
case tim: VariableInMemory =>
|
||||||
tim.toAddress match {
|
tim.toAddress match {
|
||||||
case NumericConstant(n, _) =>
|
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) {
|
for (i <- 0 until tim.typ.size) {
|
||||||
m.occupied(i + n.toInt) = true
|
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,
|
endLabelMap.put(tim.name,
|
||||||
(if (tim.isInstanceOf[InitializedMemoryVariable]) 'V' else 'v') ->
|
(if (tim.isInstanceOf[InitializedMemoryVariable]) 'V' else 'v') ->
|
||||||
(n.toInt + tim.typ.size - 1))
|
(n.toInt + tim.typ.size - 1))
|
||||||
|
@ -260,11 +266,12 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
|
||||||
case arr: MfArray =>
|
case arr: MfArray =>
|
||||||
arr.toAddress match {
|
arr.toAddress match {
|
||||||
case NumericConstant(n, _) =>
|
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) {
|
for (i <- 0 until arr.sizeInBytes) {
|
||||||
m.occupied(i + n.toInt) = true
|
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,
|
endLabelMap.put(arr.name,
|
||||||
(if (arr.isInstanceOf[InitializedArray]) 'A' else 'a') ->
|
(if (arr.isInstanceOf[InitializedArray]) 'A' else 'a') ->
|
||||||
(n.toInt + arr.sizeInBytes - 1))
|
(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
|
val index = f.address.get.asInstanceOf[NumericConstant].value.toInt
|
||||||
compiledFunctions(f.name) match {
|
compiledFunctions(f.name) match {
|
||||||
case NormalCompiledFunction(_, functionCode, _, _, _) =>
|
case NormalCompiledFunction(_, functionCode, _, _, _) =>
|
||||||
labelMap(f.name) = bank0.index -> index
|
labelMap(f.name) = bank -> index
|
||||||
val end = outputFunction(bank, functionCode, index, assembly, options)
|
val end = outputFunction(bank, functionCode, index, assembly, options)
|
||||||
endLabelMap(f.name) = 'F' -> (end - 1)
|
endLabelMap(f.name) = 'F' -> (end - 1)
|
||||||
for (i <- index until end) {
|
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 size = functionCode.map(_.sizeInBytes).sum
|
||||||
val bank0 = mem.banks(bank)
|
val bank0 = mem.banks(bank)
|
||||||
val index = codeAllocators(bank).allocateBytes(bank0, options, size, initialized = true, writeable = false, location = AllocationLocation.High, alignment = alignment)
|
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)
|
endLabelMap(name) = 'F' -> (index + size - 1)
|
||||||
justAfterCode += bank -> outputFunction(bank, functionCode, index, assembly, options)
|
justAfterCode += bank -> outputFunction(bank, functionCode, index, assembly, options)
|
||||||
case _ =>
|
case _ =>
|
||||||
|
@ -486,7 +493,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
|
||||||
if (bank != "default") ???
|
if (bank != "default") ???
|
||||||
val bank0 = mem.banks(bank)
|
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)
|
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 altName = m.name.stripPrefix(env.prefix) + "`"
|
||||||
val thing = if (name.endsWith(".addr")) env.get[ThingInMemory](name.stripSuffix(".addr")) else env.get[ThingInMemory](name + ".array")
|
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"))
|
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)
|
val bank0 = mem.banks(bank)
|
||||||
var index = codeAllocators(bank).allocateBytes(bank0, options, thing.sizeInBytes, initialized = true, writeable = true, location = AllocationLocation.High, alignment = alignment)
|
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)
|
endLabelMap(name) = 'A' -> (index + thing.sizeInBytes - 1)
|
||||||
if (!readOnlyPass) {
|
if (!readOnlyPass) {
|
||||||
rwDataStart = rwDataStart.min(index)
|
rwDataStart = rwDataStart.min(index)
|
||||||
|
@ -568,7 +575,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
|
||||||
}
|
}
|
||||||
val bank0 = mem.banks(bank)
|
val bank0 = mem.banks(bank)
|
||||||
var index = codeAllocators(bank).allocateBytes(bank0, options, typ.alignedSize, initialized = true, writeable = true, location = AllocationLocation.High, alignment = alignment)
|
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)
|
endLabelMap(name) = 'V' -> (index + typ.size - 1)
|
||||||
if (!readOnlyPass) {
|
if (!readOnlyPass) {
|
||||||
rwDataStart = rwDataStart.min(index)
|
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.")
|
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)
|
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_start" -> (ivBank -> ivAddr)
|
||||||
unimportantLabelMap += "__rwdata_init_end" -> (ib.index -> (ivAddr + size))
|
unimportantLabelMap += "__rwdata_init_end" -> (ivBank -> (ivAddr + size))
|
||||||
unimportantLabelMap += "__rwdata_size" -> (ib.index -> size)
|
unimportantLabelMap += "__rwdata_size" -> (ivBank -> size)
|
||||||
for (i <- 0 until size) {
|
for (i <- 0 until size) {
|
||||||
ib.output(ivAddr + i) = db.output(rwDataStart + i)
|
ib.output(ivAddr + i) = db.output(rwDataStart + i)
|
||||||
db.outputted(rwDataStart + i) = true
|
db.outputted(rwDataStart + i) = true
|
||||||
|
@ -650,30 +657,30 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
|
||||||
if (platform.freeZpBytes.nonEmpty) {
|
if (platform.freeZpBytes.nonEmpty) {
|
||||||
val zpUsageOffset = platform.freeZpBytes.min
|
val zpUsageOffset = platform.freeZpBytes.min
|
||||||
val zeropageOccupation = zpOccupied.slice(zpUsageOffset, platform.freeZpBytes.max + 1)
|
val zeropageOccupation = zpOccupied.slice(zpUsageOffset, platform.freeZpBytes.max + 1)
|
||||||
unimportantLabelMap += "__zeropage_usage" -> (defaultBank, zeropageOccupation.lastIndexOf(true) - zeropageOccupation.indexOf(true) + 1)
|
unimportantLabelMap += "__zeropage_usage" -> ("default", zeropageOccupation.lastIndexOf(true) - zeropageOccupation.indexOf(true) + 1)
|
||||||
unimportantLabelMap += "__zeropage_first" -> (defaultBank, zpUsageOffset + (zeropageOccupation.indexOf(true) max 0))
|
unimportantLabelMap += "__zeropage_first" -> ("default", zpUsageOffset + (zeropageOccupation.indexOf(true) max 0))
|
||||||
unimportantLabelMap += "__zeropage_last" -> (defaultBank, zpUsageOffset + (zeropageOccupation.lastIndexOf(true) max 0))
|
unimportantLabelMap += "__zeropage_last" -> ("default", zpUsageOffset + (zeropageOccupation.lastIndexOf(true) max 0))
|
||||||
unimportantLabelMap += "__zeropage_end" -> (defaultBank, zpUsageOffset + zeropageOccupation.lastIndexOf(true) + 1)
|
unimportantLabelMap += "__zeropage_end" -> ("default", zpUsageOffset + zeropageOccupation.lastIndexOf(true) + 1)
|
||||||
} else {
|
} else {
|
||||||
unimportantLabelMap += "__zeropage_usage" -> (defaultBank -> 0)
|
unimportantLabelMap += "__zeropage_usage" -> ("default" -> 0)
|
||||||
unimportantLabelMap += "__zeropage_first" -> (defaultBank -> 3)
|
unimportantLabelMap += "__zeropage_first" -> ("default" -> 3)
|
||||||
unimportantLabelMap += "__zeropage_last" -> (defaultBank -> 2)
|
unimportantLabelMap += "__zeropage_last" -> ("default" -> 2)
|
||||||
unimportantLabelMap += "__zeropage_end" -> (defaultBank -> 3)
|
unimportantLabelMap += "__zeropage_end" -> ("default" -> 3)
|
||||||
}
|
}
|
||||||
unimportantLabelMap += "__rwdata_start" -> (defaultBank -> rwDataStart)
|
unimportantLabelMap += "__rwdata_start" -> ("default" -> rwDataStart)
|
||||||
unimportantLabelMap += "__rwdata_end" -> (defaultBank -> rwDataEnd)
|
unimportantLabelMap += "__rwdata_end" -> ("default" -> rwDataEnd)
|
||||||
unimportantLabelMap += "__heap_start" -> (defaultBank -> variableAllocators("default").heapStart)
|
unimportantLabelMap += "__heap_start" -> ("default" -> variableAllocators("default").heapStart)
|
||||||
for (segment <- platform.bankNumbers.keys) {
|
for (segment <- platform.bankNumbers.keys) {
|
||||||
val variableAllocator = options.platform.variableAllocators(segment)
|
val variableAllocator = options.platform.variableAllocators(segment)
|
||||||
val codeAllocator = options.platform.codeAllocators(segment)
|
val codeAllocator = options.platform.codeAllocators(segment)
|
||||||
unimportantLabelMap += s"segment.$segment.start" -> (defaultBank -> codeAllocator.startAt)
|
unimportantLabelMap += s"segment.$segment.start" -> ("default" -> codeAllocator.startAt)
|
||||||
unimportantLabelMap += s"segment.$segment.codeend" -> (defaultBank -> (codeAllocator.endBefore - 1))
|
unimportantLabelMap += s"segment.$segment.codeend" -> ("default" -> (codeAllocator.endBefore - 1))
|
||||||
unimportantLabelMap += s"segment.$segment.datastart" -> (defaultBank -> variableAllocator.startAt)
|
unimportantLabelMap += s"segment.$segment.datastart" -> ("default" -> variableAllocator.startAt)
|
||||||
unimportantLabelMap += s"segment.$segment.heapstart" -> (defaultBank -> variableAllocator.heapStart)
|
unimportantLabelMap += s"segment.$segment.heapstart" -> ("default" -> variableAllocator.heapStart)
|
||||||
unimportantLabelMap += s"segment.$segment.end" -> (defaultBank -> (variableAllocator.endBefore - 1))
|
unimportantLabelMap += s"segment.$segment.end" -> ("default" -> (variableAllocator.endBefore - 1))
|
||||||
unimportantLabelMap += s"segment.$segment.length" -> (defaultBank -> (variableAllocator.endBefore - codeAllocator.startAt))
|
unimportantLabelMap += s"segment.$segment.length" -> ("default" -> (variableAllocator.endBefore - codeAllocator.startAt))
|
||||||
unimportantLabelMap += s"segment.$segment.bank" -> (defaultBank -> platform.bankNumbers(segment))
|
unimportantLabelMap += s"segment.$segment.bank" -> ("default" -> platform.bankNumbers(segment))
|
||||||
unimportantLabelMap += s"segment.$segment.fill" -> (defaultBank -> platform.bankFill(segment))
|
unimportantLabelMap += s"segment.$segment.fill" -> ("default" -> platform.bankFill(segment))
|
||||||
}
|
}
|
||||||
|
|
||||||
env = rootEnv.allThings
|
env = rootEnv.allThings
|
||||||
|
@ -754,13 +761,18 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
|
||||||
assembly += f" ; $$$v%04X = $l%s"
|
assembly += f" ; $$$v%04X = $l%s"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var bankLayoutInFile = BankLayoutInFile.empty
|
||||||
// TODO:
|
// TODO:
|
||||||
val code = (platform.outputStyle match {
|
val code = (platform.outputStyle match {
|
||||||
case OutputStyle.Single | OutputStyle.LUnix => List("default")
|
case OutputStyle.Single | OutputStyle.LUnix => List("default")
|
||||||
case OutputStyle.PerBank => platform.bankNumbers.keys.toList
|
case OutputStyle.PerBank => platform.bankNumbers.keys.toList
|
||||||
}).map{b =>
|
}).map{b =>
|
||||||
val outputPackager = platform.outputPackagers.getOrElse(b, platform.defaultOutputPackager)
|
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
|
}.toMap
|
||||||
if (options.flag(CompilationFlag.DataMissingInOutputWarning)) {
|
if (options.flag(CompilationFlag.DataMissingInOutputWarning)) {
|
||||||
for (bank <- mem.banks.keys.toSeq.sorted) {
|
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 = {
|
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,
|
private def compileFunction(f: NormalFunction,
|
||||||
optimizations: Seq[AssemblyOptimization[T]],
|
optimizations: Seq[AssemblyOptimization[T]],
|
||||||
options: CompilationOptions,
|
options: CompilationOptions,
|
||||||
inlinedFunctions: Map[String, List[T]],
|
inlinedFunctions: Map[String, List[T]],
|
||||||
labelMap: Map[String, (Int, Int)],
|
labelMap: Map[String, (String, Int)],
|
||||||
niceFunctionProperties: Set[(NiceFunctionProperty, String)]): List[T] = {
|
niceFunctionProperties: Set[(NiceFunctionProperty, String)]): List[T] = {
|
||||||
log.debug("Compiling: " + f.name, f.position)
|
log.debug("Compiling: " + f.name, f.position)
|
||||||
val unoptimized: List[T] =
|
val unoptimized: List[T] =
|
||||||
|
|
32
src/main/scala/millfork/output/BankLayoutInFile.scala
Normal file
32
src/main/scala/millfork/output/BankLayoutInFile.scala
Normal file
|
@ -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)
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ import scala.collection.mutable
|
||||||
/**
|
/**
|
||||||
* @author Karol Stasiak
|
* @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"
|
var programName = "MILLFORK"
|
||||||
val banks: mutable.Map[String, MemoryBank] = mutable.Map(bankNames.map{p =>
|
val banks: mutable.Map[String, MemoryBank] = mutable.Map(bankNames.map{p =>
|
||||||
val bank = new MemoryBank(p._2, bigEndian)
|
val bank = new MemoryBank(p._2, bigEndian)
|
||||||
|
|
|
@ -23,7 +23,7 @@ object D88Output extends OutputPackager {
|
||||||
).map(_.toByte)
|
).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 b = mem.banks(bank)
|
||||||
val start = b.start
|
val start = b.start
|
||||||
val header = new D88Header(mem.programName.take(16))
|
val header = new D88Header(mem.programName.take(16))
|
||||||
|
|
14
src/main/scala/millfork/output/FormattableLabel.scala
Normal file
14
src/main/scala/millfork/output/FormattableLabel.scala
Normal file
|
@ -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
|
||||||
|
)
|
|
@ -20,7 +20,7 @@ class M6809Assembler(program: Program,
|
||||||
|
|
||||||
override def deduplicate(options: CompilationOptions, compiledFunctions: mutable.Map[String, CompiledFunction[MLine]]): Unit = ()
|
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
|
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(_, RawByte, _) => log.fatal("BYTE opcode failure")
|
||||||
case MLine0(LABEL, NonExistent, MemoryAddressConstant(Label(labelName))) =>
|
case MLine0(LABEL, NonExistent, MemoryAddressConstant(Label(labelName))) =>
|
||||||
val bank0 = mem.banks(bank)
|
val bank0 = mem.banks(bank)
|
||||||
labelMap(labelName) = bank0.index -> index
|
labelMap(labelName) = bank -> index
|
||||||
index
|
index
|
||||||
case MLine0(op, NonExistent, _) if MOpcode.NoopDiscard(op) =>
|
case MLine0(op, NonExistent, _) if MOpcode.NoopDiscard(op) =>
|
||||||
index
|
index
|
||||||
|
|
|
@ -42,7 +42,7 @@ class MosAssembler(program: Program,
|
||||||
case AssemblyLine0(_, RawByte, _) => log.fatal("BYTE opcode failure")
|
case AssemblyLine0(_, RawByte, _) => log.fatal("BYTE opcode failure")
|
||||||
case AssemblyLine0(LABEL, _, MemoryAddressConstant(Label(labelName))) =>
|
case AssemblyLine0(LABEL, _, MemoryAddressConstant(Label(labelName))) =>
|
||||||
val bank0 = mem.banks(bank)
|
val bank0 = mem.banks(bank)
|
||||||
labelMap(labelName) = bank0.index -> index
|
labelMap(labelName) = bank -> index
|
||||||
index
|
index
|
||||||
case AssemblyLine0(CHANGED_MEM, DoesNotExist, MemoryAddressConstant(Label(l))) if l.contains("..brk") =>
|
case AssemblyLine0(CHANGED_MEM, DoesNotExist, MemoryAddressConstant(Label(l))) if l.contains("..brk") =>
|
||||||
breakpointSet += mem.banks(bank).index -> index
|
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._
|
import Opcode._
|
||||||
code.map {
|
code.map {
|
||||||
case l@AssemblyLine(LDA | STA | CMP |
|
case l@AssemblyLine(LDA | STA | CMP |
|
||||||
|
|
|
@ -3,60 +3,98 @@ package millfork.output
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
import scala.collection.mutable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Karol Stasiak
|
* @author Karol Stasiak
|
||||||
*/
|
*/
|
||||||
trait OutputPackager {
|
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 {
|
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
|
val baos = new ByteArrayOutputStream
|
||||||
children.foreach { c =>
|
var f = flc
|
||||||
val a = c.packageOutput(mem, bank)
|
for (c <- children) {
|
||||||
|
val a = c.packageOutput(f, mem, bank)
|
||||||
baos.write(a, 0, a.length)
|
baos.write(a, 0, a.length)
|
||||||
|
f += a.length
|
||||||
}
|
}
|
||||||
baos.toByteArray
|
baos.toByteArray
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override def writes(b: String): Boolean = children.exists(_.writes(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
case class ConstOutput(byte: Byte) extends OutputPackager {
|
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 {
|
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)
|
val b = mem.banks(bank)
|
||||||
b.markAsOutputted(start, end + 1)
|
b.markAsOutputted(start, end + 1)
|
||||||
|
flc.reportBankChunk(bank, 0, start)
|
||||||
b.output.slice(start, end + 1)
|
b.output.slice(start, end + 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case class BankFragmentOutput(alwaysBank: String, start: Int, end: Int) extends OutputPackager {
|
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)
|
val b = mem.banks(alwaysBank)
|
||||||
b.markAsOutputted(start, end + 1)
|
b.markAsOutputted(start, end + 1)
|
||||||
|
flc.reportBankChunk(alwaysBank, 0, start)
|
||||||
b.output.slice(start, end + 1)
|
b.output.slice(start, end + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override def writes(b: String): Boolean = b == alwaysBank
|
||||||
}
|
}
|
||||||
|
|
||||||
case class ProgramNameOutput(length: Int) extends OutputPackager {
|
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 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)
|
mem.programName.toUpperCase(Locale.ROOT).filter(isAlphanum).take(length).padTo(length, ' ').getBytes(StandardCharsets.US_ASCII)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case class StringOutput(string: String) extends OutputPackager {
|
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)
|
string.getBytes(StandardCharsets.US_ASCII)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case class StartAddressOutput(bonus: Int) extends OutputPackager {
|
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 b = mem.banks(bank)
|
||||||
val x = b.start + bonus
|
val x = b.start + bonus
|
||||||
Array(x.toByte, x.>>(8).toByte)
|
Array(x.toByte, x.>>(8).toByte)
|
||||||
|
@ -64,7 +102,7 @@ case class StartAddressOutput(bonus: Int) extends OutputPackager {
|
||||||
}
|
}
|
||||||
|
|
||||||
case class StartAddressOutputBe(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 b = mem.banks(bank)
|
||||||
val x = b.start + bonus
|
val x = b.start + bonus
|
||||||
Array(x.>>(8).toByte, x.toByte)
|
Array(x.>>(8).toByte, x.toByte)
|
||||||
|
@ -72,14 +110,14 @@ case class StartAddressOutputBe(bonus: Int) extends OutputPackager {
|
||||||
}
|
}
|
||||||
|
|
||||||
object StartPageOutput 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)
|
val b = mem.banks(bank)
|
||||||
Array(b.start.>>(8).toByte)
|
Array(b.start.>>(8).toByte)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case class EndAddressOutput(bonus: Int) extends OutputPackager {
|
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 b = mem.banks(bank)
|
||||||
val x = b.end + bonus
|
val x = b.end + bonus
|
||||||
Array(x.toByte, x.>>(8).toByte)
|
Array(x.toByte, x.>>(8).toByte)
|
||||||
|
@ -87,7 +125,7 @@ case class EndAddressOutput(bonus: Int) extends OutputPackager {
|
||||||
}
|
}
|
||||||
|
|
||||||
case class EndAddressOutputBe(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 b = mem.banks(bank)
|
||||||
val x = b.end + bonus
|
val x = b.end + bonus
|
||||||
Array(x.>>(8).toByte, x.toByte)
|
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 {
|
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 b = mem.banks(bank)
|
||||||
val x = mem.getAddress(symbol) + bonus
|
val x = mem.getAddress(symbol) + bonus
|
||||||
Array(b.end.toByte, b.end.>>(8).toByte)
|
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 {
|
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 b = mem.banks(bank)
|
||||||
val x = mem.getAddress(symbol) + bonus
|
val x = mem.getAddress(symbol) + bonus
|
||||||
Array(x.>>(8).toByte, x.toByte)
|
Array(x.>>(8).toByte, x.toByte)
|
||||||
|
@ -112,7 +150,7 @@ case class SymbolAddressOutputBe(symbol: String, bonus: Int) extends OutputPacka
|
||||||
}
|
}
|
||||||
|
|
||||||
object PageCountOutput extends OutputPackager {
|
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 e = mem.banks(bank).end.>>(8)
|
||||||
val s = mem.banks(bank).start.>>(8)
|
val s = mem.banks(bank).start.>>(8)
|
||||||
Array((e - s + 1).toByte)
|
Array((e - s + 1).toByte)
|
||||||
|
@ -120,15 +158,16 @@ object PageCountOutput extends OutputPackager {
|
||||||
}
|
}
|
||||||
|
|
||||||
object AllocatedDataOutput 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)
|
val b = mem.banks(bank)
|
||||||
b.markAsOutputted(b.start, b.end + 1)
|
b.markAsOutputted(b.start, b.end + 1)
|
||||||
|
flc.reportBankChunk(bank, 0, b.start)
|
||||||
b.output.slice(b.start, b.end + 1)
|
b.output.slice(b.start, b.end + 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case class AllocatedDataLength(bonus: Int) extends OutputPackager {
|
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 b = mem.banks(bank)
|
||||||
val size = b.end - b.start + 1 + bonus
|
val size = b.end - b.start + 1 + bonus
|
||||||
Array(size.toByte, size.>>(8).toByte)
|
Array(size.toByte, size.>>(8).toByte)
|
||||||
|
@ -136,7 +175,7 @@ case class AllocatedDataLength(bonus: Int) extends OutputPackager {
|
||||||
}
|
}
|
||||||
|
|
||||||
case class AllocatedDataLengthBe(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 b = mem.banks(bank)
|
||||||
val size = b.end - b.start + 1 + bonus
|
val size = b.end - b.start + 1 + bonus
|
||||||
Array(size.>>(8).toByte, size.toByte)
|
Array(size.>>(8).toByte, size.toByte)
|
||||||
|
|
|
@ -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')
|
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 filteredName: String = mem.programName.filter(isAlphanum)
|
||||||
val b = mem.banks(bank)
|
val b = mem.banks(bank)
|
||||||
val code = b.output.slice(b.start, b.end + 1)
|
val code = b.output.slice(b.start, b.end + 1)
|
||||||
|
|
|
@ -4,7 +4,7 @@ package millfork.output
|
||||||
* @author Karol Stasiak
|
* @author Karol Stasiak
|
||||||
*/
|
*/
|
||||||
class TrsCmdOutput(symbol: String) extends OutputPackager {
|
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 b = mem.banks(bank)
|
||||||
val start = b.start
|
val start = b.start
|
||||||
val run = mem.getAddress(symbol)
|
val run = mem.getAddress(symbol)
|
||||||
|
|
|
@ -97,7 +97,7 @@ class Z80Assembler(program: Program,
|
||||||
try { instr match {
|
try { instr match {
|
||||||
case ZLine0(LABEL, NoRegisters, MemoryAddressConstant(Label(labelName))) =>
|
case ZLine0(LABEL, NoRegisters, MemoryAddressConstant(Label(labelName))) =>
|
||||||
val bank0 = mem.banks(bank)
|
val bank0 = mem.banks(bank)
|
||||||
labelMap(labelName) = bank0.index -> index
|
labelMap(labelName) = bank -> index
|
||||||
index
|
index
|
||||||
case ZLine0(BYTE, NoRegisters, param) =>
|
case ZLine0(BYTE, NoRegisters, param) =>
|
||||||
writeByte(bank, index, 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))
|
override def quickSimplify(code: List[ZLine]): List[ZLine] = code.map(a => a.copy(parameter = a.parameter.quickSimplify))
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ class Z80ToX86Crossassembler(program: Program,
|
||||||
} else code
|
} 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))
|
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 {
|
instr match {
|
||||||
case ZLine0(LABEL, NoRegisters, MemoryAddressConstant(Label(labelName))) =>
|
case ZLine0(LABEL, NoRegisters, MemoryAddressConstant(Label(labelName))) =>
|
||||||
val bank0 = mem.banks(bank)
|
val bank0 = mem.banks(bank)
|
||||||
labelMap(labelName) = bank0.index -> index
|
labelMap(labelName) = bank -> index
|
||||||
index
|
index
|
||||||
case ZLine0(BYTE, NoRegisters, param) =>
|
case ZLine0(BYTE, NoRegisters, param) =>
|
||||||
writeByte(bank, index, param)
|
writeByte(bank, index, param)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user