mirror of
https://github.com/KarolS/millfork.git
synced 2024-06-09 16:29:34 +00:00
Add raw label file format
This commit is contained in:
parent
fc2f0782c5
commit
c9ef5e636b
|
@ -47,6 +47,8 @@ The extension and the file format are platform-dependent.
|
||||||
* `-G sym` – format used by the WLA DX assembler. The extension is `.sym`.
|
* `-G sym` – format used by the WLA DX assembler. The extension is `.sym`.
|
||||||
|
|
||||||
* `-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 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` –
|
||||||
Whether the compiler should use the `breakpoint` macro.
|
Whether the compiler should use the `breakpoint` macro.
|
||||||
|
|
141
examples/crossplatform/fire.labels
Normal file
141
examples/crossplatform/fire.labels
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
00:0000:0000:v:cpu6510_ddr
|
||||||
|
00:0001:0001:v:cpu6510_port
|
||||||
|
00:0043:0044:v:fire$p
|
||||||
|
00:0045:0045:v:fire$noise
|
||||||
|
00:0046:0046:v:fire$column
|
||||||
|
00:0047:0047:v:fire$heat
|
||||||
|
00:0048:0048:v:fire$entropy
|
||||||
|
00:004B:004B:v:fire$row
|
||||||
|
00:004C:004C:v:cls$i
|
||||||
|
00:009E:009E:v:main$i
|
||||||
|
00:00F7:00F7:v:build_reverse_palette$j
|
||||||
|
00:00F8:00F8:v:build_reverse_palette$i
|
||||||
|
00:00F9:00FA:v:rand_seed
|
||||||
|
00:00FB:00FE:v:__reg
|
||||||
|
00:0314:0315:v:irq_pointer
|
||||||
|
00:0315:0315:v:irq_pointer.hi
|
||||||
|
00:0400:07E7:a:screen.array
|
||||||
|
00:0801:080C:A:_basic_loader.array
|
||||||
|
00:080D:083B:F:main
|
||||||
|
00:0824::x:.do__00031
|
||||||
|
00:0832::x:.od__00033
|
||||||
|
00:0838::x:.fp__00037
|
||||||
|
00:083B::x:.ew__00038
|
||||||
|
00:083C:0846:F:wait_frame
|
||||||
|
00:083F::x:.fp__00018
|
||||||
|
00:0846::x:.ew__00019
|
||||||
|
00:0847:08A8:F:fire
|
||||||
|
00:0857::x:.do__00001
|
||||||
|
00:085D::x:.do__00004
|
||||||
|
00:086C::x:.fi__00007
|
||||||
|
00:0886::x:.fi__00008
|
||||||
|
00:0897::x:.od__00006
|
||||||
|
00:08A8::x:.od__00003
|
||||||
|
00:08A9:08F5:F:cls
|
||||||
|
00:08AD::x:.do__00010
|
||||||
|
00:08CF::x:.od__00012
|
||||||
|
00:08D3::x:.do__00013
|
||||||
|
00:08F5::x:.od__00015
|
||||||
|
00:08F6:0928:F:build_reverse_palette
|
||||||
|
00:08FA::x:.do__00020
|
||||||
|
00:0900::x:.wh__00023
|
||||||
|
00:0913::x:.fp__00025
|
||||||
|
00:091F::x:.el__00027
|
||||||
|
00:0921::x:.fi__00028
|
||||||
|
00:0924::x:.ew__00026
|
||||||
|
00:0928::x:.od__00022
|
||||||
|
00:0929:0939:F:rand
|
||||||
|
00:092D::x:__rand_loop
|
||||||
|
00:0934::x:__no_eor
|
||||||
|
00:093A:093E:A:palette.array
|
||||||
|
00:0A00:0AFF:a:reverse_palette.array
|
||||||
|
00:D000:D000:v:vic_spr0_x
|
||||||
|
00:D001:D001:v:vic_spr0_y
|
||||||
|
00:D002:D002:v:vic_spr1_x
|
||||||
|
00:D003:D003:v:vic_spr1_y
|
||||||
|
00:D004:D004:v:vic_spr2_x
|
||||||
|
00:D005:D005:v:vic_spr2_y
|
||||||
|
00:D006:D006:v:vic_spr3_x
|
||||||
|
00:D007:D007:v:vic_spr3_y
|
||||||
|
00:D008:D008:v:vic_spr4_x
|
||||||
|
00:D009:D009:v:vic_spr4_y
|
||||||
|
00:D00A:D00A:v:vic_spr5_x
|
||||||
|
00:D00B:D00B:v:vic_spr5_y
|
||||||
|
00:D00C:D00C:v:vic_spr6_x
|
||||||
|
00:D00D:D00D:v:vic_spr6_y
|
||||||
|
00:D00E:D00E:v:vic_spr7_x
|
||||||
|
00:D00F:D00F:v:vic_spr7_y
|
||||||
|
00:D010:D010:v:vic_spr_hi_x
|
||||||
|
00:D011:D011:v:vic_cr1
|
||||||
|
00:D012:D012:v:vic_raster
|
||||||
|
00:D013:D013:v:vic_lp_x
|
||||||
|
00:D014:D014:v:vic_lp_y
|
||||||
|
00:D015:D015:v:vic_spr_ena
|
||||||
|
00:D016:D016:v:vic_cr2
|
||||||
|
00:D017:D017:v:vic_spr_exp_y
|
||||||
|
00:D018:D018:v:vic_mem
|
||||||
|
00:D019:D019:v:vic_irq
|
||||||
|
00:D01A:D01A:v:vic_irq_ena
|
||||||
|
00:D01B:D01B:v:vic_spr_dp
|
||||||
|
00:D01C:D01C:v:vic_spr_mcolor
|
||||||
|
00:D01D:D01D:v:vic_spr_exp_x
|
||||||
|
00:D01E:D01E:v:vic_spr_ss_col
|
||||||
|
00:D01F:D01F:v:vic_spr_sd_col
|
||||||
|
00:D020:D020:v:vic_border
|
||||||
|
00:D021:D021:v:vic_bg_color0
|
||||||
|
00:D022:D022:v:vic_bg_color1
|
||||||
|
00:D023:D023:v:vic_bg_color2
|
||||||
|
00:D024:D024:v:vic_bg_color3
|
||||||
|
00:D025:D025:v:vic_spr_color1
|
||||||
|
00:D026:D026:v:vic_spr_color2
|
||||||
|
00:D027:D027:v:vic_spr0_color
|
||||||
|
00:D028:D028:v:vic_spr1_color
|
||||||
|
00:D029:D029:v:vic_spr2_color
|
||||||
|
00:D02A:D02A:v:vic_spr3_color
|
||||||
|
00:D02B:D02B:v:vic_spr4_color
|
||||||
|
00:D02C:D02C:v:vic_spr5_color
|
||||||
|
00:D02D:D02D:v:vic_spr6_color
|
||||||
|
00:D02E:D02E:v:vic_spr7_color
|
||||||
|
00:D400:D401:v:sid_v1_freq
|
||||||
|
00:D401:D401:v:sid_v1_freq.hi
|
||||||
|
00:D402:D403:v:sid_v1_pulse
|
||||||
|
00:D403:D403:v:sid_v1_pulse.hi
|
||||||
|
00:D404:D404:v:sid_v1_cr
|
||||||
|
00:D405:D405:v:sid_v1_ad
|
||||||
|
00:D407:D408:v:sid_v2_freq
|
||||||
|
00:D408:D408:v:sid_v2_freq.hi
|
||||||
|
00:D409:D409:v:sid_v1_sr
|
||||||
|
00:D40A:D40A:v:sid_v2_pulse.hi
|
||||||
|
00:D40B:D40B:v:sid_v2_cr
|
||||||
|
00:D40C:D40C:v:sid_v2_ad
|
||||||
|
00:D40D:D40D:v:sid_v2_sr
|
||||||
|
00:D40E:D40F:v:sid_v3_freq
|
||||||
|
00:D40F:D40F:v:sid_v3_freq.hi
|
||||||
|
00:D410:D411:v:sid_v3_pulse
|
||||||
|
00:D411:D411:v:sid_v3_pulse.hi
|
||||||
|
00:D412:D412:v:sid_v3_cr
|
||||||
|
00:D413:D413:v:sid_v3_ad
|
||||||
|
00:D414:D414:v:sid_v3_sr
|
||||||
|
00:D415:D416:v:sid_filt_cutoff
|
||||||
|
00:D416:D416:v:sid_filt_cutoff.hi
|
||||||
|
00:D417:D417:v:sid_filt_cr
|
||||||
|
00:D418:D418:v:sid_filt_mode
|
||||||
|
00:D419:D419:v:sid_paddle_x
|
||||||
|
00:D41A:D41A:v:sid_paddle_y
|
||||||
|
00:D41B:D41B:v:sid_v3_osc_out
|
||||||
|
00:D41C:D41C:v:sid_v3_adsr_out
|
||||||
|
00:D800:DBE7:a:c64_color_ram.array
|
||||||
|
00:DC00:DC00:v:cia1_pra
|
||||||
|
00:DC01:DC01:v:cia1_prb
|
||||||
|
00:DC02:DC02:v:cia1_ddra
|
||||||
|
00:DC03:DC03:v:cia1_ddrb
|
||||||
|
00:DD00:DD00:v:cia2_pra
|
||||||
|
00:DD01:DD01:v:cia2_prb
|
||||||
|
00:DD02:DD02:v:cia2_ddra
|
||||||
|
00:DD03:DD03:v:cia2_ddrb
|
||||||
|
00:FFFA:FFFB:v:nmi_routine_addr
|
||||||
|
00:FFFB:FFFB:v:nmi_routine_addr.hi
|
||||||
|
00:FFFC:FFFD:v:reset_routine_addr
|
||||||
|
00:FFFD:FFFD:v:reset_routine_addr.hi
|
||||||
|
00:FFFE:FFFF:v:irq_routine_addr
|
||||||
|
00:FFFF:FFFF:v:irq_routine_addr.hi
|
|
@ -6,6 +6,7 @@ package millfork
|
||||||
|
|
||||||
object DebugOutputFormat {
|
object DebugOutputFormat {
|
||||||
val map: Map[String, DebugOutputFormat] = Map(
|
val map: Map[String, DebugOutputFormat] = Map(
|
||||||
|
"raw" -> RawDebugOutputFormat,
|
||||||
"vice" -> ViceDebugOutputFormat,
|
"vice" -> ViceDebugOutputFormat,
|
||||||
"nesasm" -> NesasmDebugOutputFormat,
|
"nesasm" -> NesasmDebugOutputFormat,
|
||||||
"fns" -> NesasmDebugOutputFormat,
|
"fns" -> NesasmDebugOutputFormat,
|
||||||
|
@ -16,7 +17,7 @@ object DebugOutputFormat {
|
||||||
|
|
||||||
sealed trait DebugOutputFormat {
|
sealed trait DebugOutputFormat {
|
||||||
|
|
||||||
def formatAll(labels: Seq[(String, (Int, Int))], breakpoints: Seq[(Int, Int)]): String = {
|
def formatAll(labels: Seq[(String, Int, Int, Char, Option[Int])], breakpoints: Seq[(Int, Int)]): String = {
|
||||||
val labelPart = labelsHeader + labels.map(formatLineTupled).mkString("\n") + "\n"
|
val labelPart = labelsHeader + labels.map(formatLineTupled).mkString("\n") + "\n"
|
||||||
if (breakpoints.isEmpty) {
|
if (breakpoints.isEmpty) {
|
||||||
labelPart
|
labelPart
|
||||||
|
@ -25,9 +26,10 @@ sealed trait DebugOutputFormat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final def formatLineTupled(labelAndValue: (String, (Int, Int))): String = formatLine(labelAndValue._1, labelAndValue._2._1, labelAndValue._2._2)
|
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, value: Int): String
|
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
|
||||||
|
|
||||||
|
@ -45,10 +47,25 @@ sealed trait DebugOutputFormat {
|
||||||
def breakpointsHeader: String = ""
|
def breakpointsHeader: String = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 fileExtension(bank: Int): String = ".labels"
|
||||||
|
|
||||||
|
override def filePerBank: Boolean = false
|
||||||
|
|
||||||
|
override def addOutputExtension: Boolean = false
|
||||||
|
|
||||||
|
override def formatBreakpoint(bank: Int, value: Int): Option[String] =
|
||||||
|
Some(f"$bank%02X:$value%04X::b:<breakpoint@$value%04X>")
|
||||||
|
}
|
||||||
|
|
||||||
object ViceDebugOutputFormat extends DebugOutputFormat {
|
object ViceDebugOutputFormat extends DebugOutputFormat {
|
||||||
override def formatLine(label: String, bank: Int, value: Int): String = {
|
override def formatLine(label: String, bank: Int, startValue: Int, category: Char, endValue: Option[Int]): String = {
|
||||||
val normalized = label.replace('$', '_').replace('.', '_')
|
val normalized = label.replace('$', '_').replace('.', '_')
|
||||||
s"al ${value.toHexString} .$normalized"
|
s"al ${startValue.toHexString} .$normalized"
|
||||||
}
|
}
|
||||||
|
|
||||||
override def fileExtension(bank: Int): String = ".lbl"
|
override def fileExtension(bank: Int): String = ".lbl"
|
||||||
|
@ -61,8 +78,8 @@ object ViceDebugOutputFormat extends DebugOutputFormat {
|
||||||
}
|
}
|
||||||
|
|
||||||
object NesasmDebugOutputFormat extends DebugOutputFormat {
|
object NesasmDebugOutputFormat extends DebugOutputFormat {
|
||||||
override def formatLine(label: String, bank: Int, value: Int): String = {
|
override def formatLine(label: String, bank: Int, startValue: Int, category: Char, endValue: Option[Int]): String = {
|
||||||
label + " = $" + value.toHexString
|
label + " = $" + startValue.toHexString
|
||||||
}
|
}
|
||||||
|
|
||||||
override def fileExtension(bank: Int): String = ".fns"
|
override def fileExtension(bank: Int): String = ".fns"
|
||||||
|
@ -75,8 +92,8 @@ object NesasmDebugOutputFormat extends DebugOutputFormat {
|
||||||
}
|
}
|
||||||
|
|
||||||
object SymDebugOutputFormat extends DebugOutputFormat {
|
object SymDebugOutputFormat extends DebugOutputFormat {
|
||||||
override def formatLine(label: String, bank: Int, value: Int): String = {
|
override def formatLine(label: String, bank: Int, startValue: Int, category: Char, endValue:Option[Int]): String = {
|
||||||
f"$bank%02x:$value%04x $label%s"
|
f"$bank%02x:$startValue%04x $label%s"
|
||||||
}
|
}
|
||||||
|
|
||||||
override def fileExtension(bank: Int): String = ".sym"
|
override def fileExtension(bank: Int): String = ".sym"
|
||||||
|
@ -93,8 +110,8 @@ object SymDebugOutputFormat extends DebugOutputFormat {
|
||||||
}
|
}
|
||||||
|
|
||||||
object FceuxDebugOutputFormat extends DebugOutputFormat {
|
object FceuxDebugOutputFormat extends DebugOutputFormat {
|
||||||
override def formatLine(label: String, bank: Int, value: Int): String = {
|
override def formatLine(label: String, bank: Int, startValue: Int, category: Char, endValue: Option[Int]): String = {
|
||||||
f"$$$value%04x#$label%s#"
|
f"$$$startValue%04x#$label%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"
|
||||||
|
|
|
@ -119,14 +119,22 @@ object Main {
|
||||||
else if (l.startsWith("__")) 7
|
else if (l.startsWith("__")) 7
|
||||||
else 0
|
else 0
|
||||||
}
|
}
|
||||||
val sortedLabels = result.labels.groupBy(_._2).values.map(_.minBy(a => labelUnimportance(a._1) -> a._1)).toSeq.sortBy(_._2)
|
val sortedLabels: Seq[(String, Int, Int, Char, Option[Int])] =
|
||||||
|
result.labels.groupBy(_._2).values
|
||||||
|
.map(_.minBy(a => labelUnimportance(a._1) -> a._1)).toSeq.sortBy(_._2)
|
||||||
|
.map { case (l, (b, s)) =>
|
||||||
|
result.endLabels.get(l) match {
|
||||||
|
case Some((c, e)) => (l, b, s, c, Some(e))
|
||||||
|
case _ => (l, b, s, 'x', None)
|
||||||
|
}
|
||||||
|
}
|
||||||
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 = sortedLabels.map(_._2._1).toSet ++ sortedBreakpoints.map(_._2).toSet
|
val banks: Set[Int] = sortedLabels.map(_._2).toSet ++ sortedBreakpoints.map(_._1).toSet
|
||||||
banks.foreach{ bank =>
|
banks.foreach{ bank =>
|
||||||
val labels = sortedLabels.filter(_._2._1.==(bank))
|
val labels = sortedLabels.filter(_._2.==(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)
|
||||||
|
@ -429,7 +437,7 @@ object Main {
|
||||||
p.toLowerCase(Locale.ROOT),
|
p.toLowerCase(Locale.ROOT),
|
||||||
errorReporting.fatal("Invalid label file format: " + p))
|
errorReporting.fatal("Invalid label file format: " + p))
|
||||||
c.copy(outputLabels = true, outputLabelsFormatOverride = Some(f))
|
c.copy(outputLabels = true, outputLabelsFormatOverride = Some(f))
|
||||||
}.description("Generate also the label file in the given format. Available options: vice, nesasm, sym.")
|
}.description("Generate also the label file in the given format. Available options: vice, nesasm, sym, raw.")
|
||||||
|
|
||||||
boolean("-fbreakpoints", "-fno-breakpoints").action((c,v) =>
|
boolean("-fbreakpoints", "-fno-breakpoints").action((c,v) =>
|
||||||
c.changeFlag(CompilationFlag.EnableBreakpoints, v)
|
c.changeFlag(CompilationFlag.EnableBreakpoints, v)
|
||||||
|
|
|
@ -118,6 +118,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
|
||||||
allocators: Map[String, VariableAllocator],
|
allocators: Map[String, VariableAllocator],
|
||||||
options: CompilationOptions,
|
options: CompilationOptions,
|
||||||
onEachVariable: (String, (Int, Int)) => Unit,
|
onEachVariable: (String, (Int, Int)) => Unit,
|
||||||
|
onEachVariableEnd: (String, (Char, Int)) => Unit,
|
||||||
pass: Int,
|
pass: Int,
|
||||||
forZpOnly: Boolean): Unit = {
|
forZpOnly: Boolean): Unit = {
|
||||||
if (forZpOnly && !options.platform.hasZeroPage) {
|
if (forZpOnly && !options.platform.hasZeroPage) {
|
||||||
|
@ -184,6 +185,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
|
||||||
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, bank0.index -> addr)
|
||||||
|
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)
|
||||||
)
|
)
|
||||||
|
@ -207,6 +209,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
|
||||||
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, bank0.index -> addr)
|
||||||
|
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)
|
||||||
)
|
)
|
||||||
|
@ -218,6 +221,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.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, bank0.index -> addr)
|
||||||
|
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)
|
||||||
)
|
)
|
||||||
|
@ -225,7 +229,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case f: NormalFunction =>
|
case f: NormalFunction =>
|
||||||
f.environment.allocateVariables(Some(f), mem, callGraph, allocators, options, onEachVariable, pass, forZpOnly)
|
f.environment.allocateVariables(Some(f), mem, callGraph, allocators, options, onEachVariable, onEachVariableEnd, pass, forZpOnly)
|
||||||
Nil
|
Nil
|
||||||
case _ => Nil
|
case _ => Nil
|
||||||
}.toList
|
}.toList
|
||||||
|
|
|
@ -19,7 +19,7 @@ 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))], breakpoints: List[(Int, Int)])
|
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)])
|
||||||
|
|
||||||
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,
|
||||||
|
@ -34,6 +34,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
|
||||||
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, (Int, 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, (Int, 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()
|
||||||
|
@ -251,6 +252,9 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
|
||||||
m.occupied(i + n.toInt) = true
|
m.occupied(i + n.toInt) = true
|
||||||
}
|
}
|
||||||
labelMap.put(tim.name, m.index -> n.toInt)
|
labelMap.put(tim.name, m.index -> n.toInt)
|
||||||
|
endLabelMap.put(tim.name,
|
||||||
|
(if (tim.isInstanceOf[InitializedMemoryVariable]) 'V' else 'v') ->
|
||||||
|
(n.toInt + tim.typ.size - 1))
|
||||||
case _ =>
|
case _ =>
|
||||||
}
|
}
|
||||||
case arr: MfArray =>
|
case arr: MfArray =>
|
||||||
|
@ -261,15 +265,18 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
|
||||||
m.occupied(i + n.toInt) = true
|
m.occupied(i + n.toInt) = true
|
||||||
}
|
}
|
||||||
labelMap.put(arr.name, m.index -> n.toInt)
|
labelMap.put(arr.name, m.index -> n.toInt)
|
||||||
|
endLabelMap.put(arr.name,
|
||||||
|
(if (arr.isInstanceOf[InitializedArray]) 'A' else 'a') ->
|
||||||
|
(n.toInt + arr.sizeInBytes - 1))
|
||||||
case _ =>
|
case _ =>
|
||||||
}
|
}
|
||||||
case _ =>
|
case _ =>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
env.allocateVariables(None, mem, callGraph, variableAllocators, options, labelMap.put, 1, forZpOnly = true)
|
env.allocateVariables(None, mem, callGraph, variableAllocators, options, labelMap.put, endLabelMap.put, 1, forZpOnly = true)
|
||||||
env.allocateVariables(None, mem, callGraph, variableAllocators, options, labelMap.put, 2, forZpOnly = true)
|
env.allocateVariables(None, mem, callGraph, variableAllocators, options, labelMap.put, endLabelMap.put, 2, forZpOnly = true)
|
||||||
env.allocateVariables(None, mem, callGraph, variableAllocators, options, labelMap.put, 3, forZpOnly = true)
|
env.allocateVariables(None, mem, callGraph, variableAllocators, options, labelMap.put, endLabelMap.put, 3, forZpOnly = true)
|
||||||
|
|
||||||
var inlinedFunctions = Map[String, List[T]]()
|
var inlinedFunctions = Map[String, List[T]]()
|
||||||
val compiledFunctions = mutable.Map[String, CompiledFunction[T]]()
|
val compiledFunctions = mutable.Map[String, CompiledFunction[T]]()
|
||||||
|
@ -396,6 +403,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
|
||||||
case NormalCompiledFunction(_, functionCode, _, _, _) =>
|
case NormalCompiledFunction(_, functionCode, _, _, _) =>
|
||||||
labelMap(f.name) = bank0.index -> index
|
labelMap(f.name) = bank0.index -> index
|
||||||
val end = outputFunction(bank, functionCode, index, assembly, options)
|
val end = outputFunction(bank, functionCode, index, assembly, options)
|
||||||
|
endLabelMap(f.name) = 'F' -> (end - 1)
|
||||||
for (i <- index until end) {
|
for (i <- index until end) {
|
||||||
bank0.occupied(index) = true
|
bank0.occupied(index) = true
|
||||||
bank0.initialized(index) = true
|
bank0.initialized(index) = true
|
||||||
|
@ -444,6 +452,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
|
||||||
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) = bank0.index -> index
|
||||||
|
endLabelMap(name) = 'F' -> (index + size - 1)
|
||||||
justAfterCode += bank -> outputFunction(bank, functionCode, index, assembly, options)
|
justAfterCode += bank -> outputFunction(bank, functionCode, index, assembly, options)
|
||||||
case _ =>
|
case _ =>
|
||||||
}
|
}
|
||||||
|
@ -529,6 +538,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) = bank0.index -> index
|
||||||
|
endLabelMap(name) = 'A' -> (index + thing.sizeInBytes - 1)
|
||||||
if (!readOnlyPass) {
|
if (!readOnlyPass) {
|
||||||
rwDataStart = rwDataStart.min(index)
|
rwDataStart = rwDataStart.min(index)
|
||||||
rwDataEnd = rwDataEnd.max(index + thing.sizeInBytes)
|
rwDataEnd = rwDataEnd.max(index + thing.sizeInBytes)
|
||||||
|
@ -559,6 +569,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) = bank0.index -> index
|
||||||
|
endLabelMap(name) = 'V' -> (index + typ.size - 1)
|
||||||
if (!readOnlyPass) {
|
if (!readOnlyPass) {
|
||||||
rwDataStart = rwDataStart.min(index)
|
rwDataStart = rwDataStart.min(index)
|
||||||
rwDataEnd = rwDataEnd.max(index + typ.alignedSize)
|
rwDataEnd = rwDataEnd.max(index + typ.alignedSize)
|
||||||
|
@ -632,8 +643,8 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
|
||||||
variableAllocators("default").notifyAboutEndOfData(rwDataEnd)
|
variableAllocators("default").notifyAboutEndOfData(rwDataEnd)
|
||||||
}
|
}
|
||||||
variableAllocators.foreach { case (b, a) => a.notifyAboutEndOfCode(justAfterCode(b)) }
|
variableAllocators.foreach { case (b, a) => a.notifyAboutEndOfCode(justAfterCode(b)) }
|
||||||
env.allocateVariables(None, mem, callGraph, variableAllocators, options, labelMap.put, 2, forZpOnly = false)
|
env.allocateVariables(None, mem, callGraph, variableAllocators, options, labelMap.put, endLabelMap.put, 2, forZpOnly = false)
|
||||||
env.allocateVariables(None, mem, callGraph, variableAllocators, options, labelMap.put, 3, forZpOnly = false)
|
env.allocateVariables(None, mem, callGraph, variableAllocators, options, labelMap.put, endLabelMap.put, 3, forZpOnly = false)
|
||||||
|
|
||||||
val defaultBank = mem.banks("default").index
|
val defaultBank = mem.banks("default").index
|
||||||
if (platform.freeZpBytes.nonEmpty) {
|
if (platform.freeZpBytes.nonEmpty) {
|
||||||
|
@ -695,6 +706,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
|
||||||
val holes = (b.start to b.end).count(i => !b.occupied(i))
|
val holes = (b.start to b.end).count(i => !b.occupied(i))
|
||||||
val size = b.end - b.start + 1
|
val size = b.end - b.start + 1
|
||||||
log.info(f"Segment ${bank}%s: $$${b.start}%04x-$$${b.end}%04x, size: $size%d B ($holes%d B unused)")
|
log.info(f"Segment ${bank}%s: $$${b.start}%04x-$$${b.end}%04x, size: $size%d B ($holes%d B unused)")
|
||||||
|
// TODO: report holes:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (platform.cpuFamily == CpuFamily.M6502) {
|
if (platform.cpuFamily == CpuFamily.M6502) {
|
||||||
|
@ -706,7 +718,12 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
|
||||||
|
|
||||||
val allLabelList = labelMap.toList ++ unimportantLabelMap.toList
|
val allLabelList = labelMap.toList ++ unimportantLabelMap.toList
|
||||||
allLabelList.sorted.foreach { case (l, (_, v)) =>
|
allLabelList.sorted.foreach { case (l, (_, v)) =>
|
||||||
assembly += f"$l%-30s = $$$v%04X"
|
endLabelMap.get(l) match {
|
||||||
|
case Some((category, end)) =>
|
||||||
|
assembly += f"$l%-30s = $$$v%04X ;-$$$end%04X $category%s"
|
||||||
|
case _ =>
|
||||||
|
assembly += f"$l%-30s = $$$v%04X"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
allLabelList.sortBy { case (a, (_, v)) => v -> a }.foreach { case (l, (_, v)) =>
|
allLabelList.sortBy { case (a, (_, v)) => v -> a }.foreach { case (l, (_, v)) =>
|
||||||
assembly += f" ; $$$v%04X = $l%s"
|
assembly += f" ; $$$v%04X = $l%s"
|
||||||
|
@ -729,7 +746,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AssemblerOutput(code, assembly.toArray, labelMap.toList, breakpointSet.toList.sorted)
|
AssemblerOutput(code, 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 = {
|
||||||
|
|
|
@ -154,7 +154,7 @@ class EmuM6809Run(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimizat
|
||||||
println(";;; compiled: -----------------")
|
println(";;; compiled: -----------------")
|
||||||
output.asm.takeWhile(s => !(s.startsWith(".") && s.contains("= $"))).filterNot(_.contains("; DISCARD_")).foreach(println)
|
output.asm.takeWhile(s => !(s.startsWith(".") && s.contains("= $"))).filterNot(_.contains("; DISCARD_")).foreach(println)
|
||||||
println(";;; ---------------------------")
|
println(";;; ---------------------------")
|
||||||
assembler.labelMap.foreach { case (l, (_, addr)) => println(f"$l%-15s $$$addr%04x") }
|
assembler.labelMap.foreach { case (l, (_, addr)) => println(f"$l%-15s $$$addr%04x${assembler.endLabelMap.get(l)match{case Some((c,e)) => f"-$$$e%04x $c%s"; case _ => ""}}%s") }
|
||||||
|
|
||||||
val optimizedSize = assembler.mem.banks("default").initialized.count(identity).toLong
|
val optimizedSize = assembler.mem.banks("default").initialized.count(identity).toLong
|
||||||
if (unoptimizedSize == optimizedSize) {
|
if (unoptimizedSize == optimizedSize) {
|
||||||
|
|
|
@ -260,7 +260,7 @@ class EmuRun(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimization],
|
||||||
println(";;; compiled: -----------------")
|
println(";;; compiled: -----------------")
|
||||||
output.asm.takeWhile(s => !(s.startsWith(".") && s.contains("= $"))).filterNot(_.contains("; DISCARD_")).foreach(println)
|
output.asm.takeWhile(s => !(s.startsWith(".") && s.contains("= $"))).filterNot(_.contains("; DISCARD_")).foreach(println)
|
||||||
println(";;; ---------------------------")
|
println(";;; ---------------------------")
|
||||||
assembler.labelMap.foreach { case (l, (_, addr)) => println(f"$l%-15s $$$addr%04x") }
|
assembler.labelMap.foreach { case (l, (_, addr)) => println(f"$l%-15s $$$addr%04x${assembler.endLabelMap.get(l)match{case Some((c,e)) => f"-$$$e%04x $c%s"; case _ => ""}}%s") }
|
||||||
|
|
||||||
val optimizedSize = assembler.mem.banks("default").initialized.count(identity).toLong
|
val optimizedSize = assembler.mem.banks("default").initialized.count(identity).toLong
|
||||||
if (unoptimizedSize == optimizedSize) {
|
if (unoptimizedSize == optimizedSize) {
|
||||||
|
|
|
@ -155,7 +155,7 @@ class EmuZ80Run(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimizatio
|
||||||
println(";;; compiled: -----------------")
|
println(";;; compiled: -----------------")
|
||||||
output.asm.takeWhile(s => !(s.startsWith(".") && s.contains("= $"))).filterNot(_.contains("////; DISCARD_")).foreach(println)
|
output.asm.takeWhile(s => !(s.startsWith(".") && s.contains("= $"))).filterNot(_.contains("////; DISCARD_")).foreach(println)
|
||||||
println(";;; ---------------------------")
|
println(";;; ---------------------------")
|
||||||
assembler.labelMap.foreach { case (l, (_, addr)) => println(f"$l%-15s $$$addr%04x") }
|
assembler.labelMap.foreach { case (l, (_, addr)) => println(f"$l%-15s $$$addr%04x${assembler.endLabelMap.get(l)match{case Some((c,e)) => f"-$$$e%04x $c%s"; case _ => ""}}%s") }
|
||||||
|
|
||||||
val optimizedSize = assembler.mem.banks("default").initialized.count(identity).toLong
|
val optimizedSize = assembler.mem.banks("default").initialized.count(identity).toLong
|
||||||
if (unoptimizedSize == optimizedSize) {
|
if (unoptimizedSize == optimizedSize) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user