From 4ff6120702def7d461f067e2ef2673bbb5d347cf Mon Sep 17 00:00:00 2001 From: Karol Stasiak Date: Wed, 24 Feb 2021 02:22:38 +0100 Subject: [PATCH] Warn about data not being included in the output --- src/main/scala/millfork/MathUtils.scala | 24 +++++++++++++++++++ .../millfork/output/AbstractAssembler.scala | 8 +++++++ .../millfork/output/CompiledMemory.scala | 5 ++++ .../scala/millfork/output/D88Output.scala | 5 +++- .../millfork/output/OutputPackager.scala | 3 +++ .../scala/millfork/output/TapOutput.scala | 1 + .../scala/millfork/output/TrsCmdOutput.scala | 1 + .../scala/millfork/test/MathUtilsSuite.scala | 11 ++++++++- 8 files changed, 56 insertions(+), 2 deletions(-) diff --git a/src/main/scala/millfork/MathUtils.scala b/src/main/scala/millfork/MathUtils.scala index e6e380a0..d1f8e8fb 100644 --- a/src/main/scala/millfork/MathUtils.scala +++ b/src/main/scala/millfork/MathUtils.scala @@ -12,4 +12,28 @@ object MathUtils { def lcm(a: Int, b: Int): Int = (a.toLong * b.toLong / gcd(a, b)).toInt + + def collapseConsecutiveInts(nums :Seq[Int], format: Int=>String): String = { + val result = Seq.newBuilder[String] + var lastIntervalStart = -2 + var lastIntervalEnd = -2 + def flushInterval(): Unit = { + if (lastIntervalEnd >= 0) { + if (lastIntervalStart == lastIntervalEnd) { + result += format(lastIntervalEnd) + } else { + result += format(lastIntervalStart) + "-" + format(lastIntervalEnd) + } + } + } + for(n <- nums) { + if (n != lastIntervalEnd + 1) { + flushInterval() + lastIntervalStart = n + } + lastIntervalEnd = n + } + flushInterval() + result.result().mkString(",") + } } diff --git a/src/main/scala/millfork/output/AbstractAssembler.scala b/src/main/scala/millfork/output/AbstractAssembler.scala index 6c36eb92..e972c5da 100644 --- a/src/main/scala/millfork/output/AbstractAssembler.scala +++ b/src/main/scala/millfork/output/AbstractAssembler.scala @@ -604,6 +604,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program unimportantLabelMap += "__rwdata_size" -> (ib.index -> size) for (i <- 0 until size) { ib.output(ivAddr + i) = db.output(rwDataStart + i) + db.outputted(rwDataStart + i) = true } val debugArray = Array.fill[Option[Constant]](size)(None) bytesToWriteLater ++= bytesToWriteLater.flatMap{ @@ -704,6 +705,13 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program val outputPackager = platform.outputPackagers.getOrElse(b, platform.defaultOutputPackager) b -> outputPackager.packageOutput(mem, b) }.toMap + for (bank <- mem.banks.keys.toSeq.sorted) { + val missing = mem.banks(bank).initializedNotOutputted + if (missing.nonEmpty) { + val missingFormatted = MathUtils.collapseConsecutiveInts(missing, i => f"$$$i%04x") + log.warn(s"Fragments of segment ${bank} are not contained in any output: $missingFormatted") + } + } AssemblerOutput(code, assembly.toArray, labelMap.toList, breakpointSet.toList.sorted) } diff --git a/src/main/scala/millfork/output/CompiledMemory.scala b/src/main/scala/millfork/output/CompiledMemory.scala index 1ce60ff7..982aa614 100644 --- a/src/main/scala/millfork/output/CompiledMemory.scala +++ b/src/main/scala/millfork/output/CompiledMemory.scala @@ -56,9 +56,14 @@ class MemoryBank(val index: Int, val isBigEndian: Boolean) { val initialized: Array[Boolean] = Array.fill(1 << 16)(false) val readable: Array[Boolean] = Array.fill(1 << 16)(false) val writeable: Array[Boolean] = Array.fill(1 << 16)(false) + val outputted: Array[Boolean] = Array.fill(1 << 16)(false) var start: Int = 0 var end: Int = 0 + def markAsOutputted(start: Int, pastEnd: Int): Unit = for (i <- start until pastEnd) outputted(i) = true + + def initializedNotOutputted: Seq[Int] = (0 until 0x10000).filter(i => initialized(i) && !outputted(i)) + def dump(startAddr: Int, count: Int)(dumper: String => Any): Unit = { (0 until count).map(i => (i + startAddr) -> output(i + startAddr)).grouped(16).zipWithIndex.map { case (c, i) => f"${c.head._1}%04X: " + c.map(i => f"${i._2}%02x").mkString(" ") }.foreach(dumper) } diff --git a/src/main/scala/millfork/output/D88Output.scala b/src/main/scala/millfork/output/D88Output.scala index 95bf48ba..5a595a45 100644 --- a/src/main/scala/millfork/output/D88Output.scala +++ b/src/main/scala/millfork/output/D88Output.scala @@ -58,7 +58,10 @@ object D88Output extends OutputPackager { val sizeInPages = size.|(0xff).+(1).>>(8) addSector(bootloader(b.start, sizeInPages)) for (page <- 0 until sizeInPages) { - addSector(b.output.slice(b.start + (page << 8), b.start + (page << 8) + 0x100)) + val pageStart = b.start + (page << 8) + val pagePastEnd = pageStart + 0x100 + b.markAsOutputted(pageStart, pagePastEnd) + addSector(b.output.slice(pageStart, pagePastEnd)) } header.totalSize = trackOffset sectors.map(_.toArray).foldLeft(header.toArray ++ trackList.toArray)(_ ++ _) diff --git a/src/main/scala/millfork/output/OutputPackager.scala b/src/main/scala/millfork/output/OutputPackager.scala index bc36d695..3f4eb7a6 100644 --- a/src/main/scala/millfork/output/OutputPackager.scala +++ b/src/main/scala/millfork/output/OutputPackager.scala @@ -29,6 +29,7 @@ case class ConstOutput(byte: Byte) extends OutputPackager { case class CurrentBankFragmentOutput(start: Int, end: Int) extends OutputPackager { def packageOutput(mem: CompiledMemory, bank: String): Array[Byte] = { val b = mem.banks(bank) + b.markAsOutputted(start, end + 1) b.output.slice(start, end + 1) } } @@ -36,6 +37,7 @@ case class CurrentBankFragmentOutput(start: Int, end: Int) extends OutputPackage case class BankFragmentOutput(alwaysBank: String, start: Int, end: Int) extends OutputPackager { def packageOutput(mem: CompiledMemory, bank: String): Array[Byte] = { val b = mem.banks(alwaysBank) + b.markAsOutputted(start, end + 1) b.output.slice(start, end + 1) } } @@ -120,6 +122,7 @@ object PageCountOutput extends OutputPackager { object AllocatedDataOutput extends OutputPackager { def packageOutput(mem: CompiledMemory, bank: String): Array[Byte] = { val b = mem.banks(bank) + b.markAsOutputted(b.start, b.end + 1) b.output.slice(b.start, b.end + 1) } } diff --git a/src/main/scala/millfork/output/TapOutput.scala b/src/main/scala/millfork/output/TapOutput.scala index afa05318..13ae2055 100644 --- a/src/main/scala/millfork/output/TapOutput.scala +++ b/src/main/scala/millfork/output/TapOutput.scala @@ -13,6 +13,7 @@ class TapOutput(val symbol: String) extends OutputPackager { val filteredName: String = mem.programName.filter(isAlphanum) val b = mem.banks(bank) val code = b.output.slice(b.start, b.end + 1) + b.markAsOutputted(b.start, b.end + 1) val codeDataBlock = new DataBlock(code) val codeHeaderBlock = new HeaderBlock(3, "CODE", code.length, b.start, 32768) val loaderDataBlock = new DataBlock(ZxSpectrumBasic.loader("CODE", filteredName, b.start, mem.getAddress(symbol))) diff --git a/src/main/scala/millfork/output/TrsCmdOutput.scala b/src/main/scala/millfork/output/TrsCmdOutput.scala index a642df94..ee4a93d7 100644 --- a/src/main/scala/millfork/output/TrsCmdOutput.scala +++ b/src/main/scala/millfork/output/TrsCmdOutput.scala @@ -8,6 +8,7 @@ class TrsCmdOutput(symbol: String) extends OutputPackager { val b = mem.banks(bank) val start = b.start val run = mem.getAddress(symbol) + b.markAsOutputted(start, b.end + 1) b.output.slice(start, b.end + 1).grouped(256).zipWithIndex.flatMap{ case (chunk, index) => // chunk type 1: data // chunk length: 1 byte, includes the load address, goes 3-258 diff --git a/src/test/scala/millfork/test/MathUtilsSuite.scala b/src/test/scala/millfork/test/MathUtilsSuite.scala index e0219f45..31eef396 100644 --- a/src/test/scala/millfork/test/MathUtilsSuite.scala +++ b/src/test/scala/millfork/test/MathUtilsSuite.scala @@ -1,7 +1,7 @@ package millfork.test import millfork.MathUtils -import millfork.MathUtils.gcd +import millfork.MathUtils.{collapseConsecutiveInts, gcd} import org.scalatest.{AppendedClues, FunSuite, Matchers} /** @@ -20,4 +20,13 @@ class MathUtilsSuite extends FunSuite with Matchers with AppendedClues { gcd(12, 9) should equal(3) } + test("Collapse consecutive ints") { + collapseConsecutiveInts(Seq(1), _.toString) should equal("1") + collapseConsecutiveInts(Seq(1,2), _.toString) should equal("1-2") + collapseConsecutiveInts(Seq(1,2,3), _.toString) should equal("1-3") + collapseConsecutiveInts(Seq(1,2,3,6), _.toString) should equal("1-3,6") + collapseConsecutiveInts(Seq(1,3,6), _.toString) should equal("1,3,6") + collapseConsecutiveInts(Seq(1,3,4,5,6), _.toString) should equal("1,3-6") + } + }