From 919f11af2edcb3274ea2b1232900cf5b2de4e12e Mon Sep 17 00:00:00 2001 From: Karol Stasiak Date: Wed, 3 Feb 2021 09:50:44 +0100 Subject: [PATCH] #101: Allow using local labels in all assembly instructions and all assembly expressions --- .../assembly/m6809/opt/FlowAnalyzer.scala | 5 +---- .../assembly/mos/opt/FlowAnalyzer.scala | 6 +----- .../assembly/z80/opt/FlowAnalyzer.scala | 5 +---- src/main/scala/millfork/env/Constant.scala | 21 +++++++++++++++++++ .../scala/millfork/test/AssemblySuite.scala | 16 ++++++++++++++ .../scala/millfork/test/emu/EmuM6809Run.scala | 5 +++++ src/test/scala/millfork/test/emu/EmuRun.scala | 5 +++++ .../scala/millfork/test/emu/EmuZ80Run.scala | 5 +++++ 8 files changed, 55 insertions(+), 13 deletions(-) diff --git a/src/main/scala/millfork/assembly/m6809/opt/FlowAnalyzer.scala b/src/main/scala/millfork/assembly/m6809/opt/FlowAnalyzer.scala index da1a038d..d749f915 100644 --- a/src/main/scala/millfork/assembly/m6809/opt/FlowAnalyzer.scala +++ b/src/main/scala/millfork/assembly/m6809/opt/FlowAnalyzer.scala @@ -52,10 +52,7 @@ object FlowAnalyzer { } val labelMap: () => Option[Map[String, Int]] = () => req match { case FlowInfoRequirement.NoRequirement => None - case _ => Some(code.flatMap { - case MLine0(op, _, MemoryAddressConstant(Label(l))) if op != MOpcode.LABEL => Some(l) - case _ => None - }.groupBy(identity).mapValues(_.size).view.force) + case _ => Some(code.flatMap(_.parameter.extractLabels).groupBy(identity).mapValues(_.size).view.force) } val holder = new FlowHolder(forwardFlow, reverseFlow) code.zipWithIndex.map{ case (line, i) => FlowInfo(holder, i, labelMap) -> line} diff --git a/src/main/scala/millfork/assembly/mos/opt/FlowAnalyzer.scala b/src/main/scala/millfork/assembly/mos/opt/FlowAnalyzer.scala index a6a91aec..3e1d2375 100644 --- a/src/main/scala/millfork/assembly/mos/opt/FlowAnalyzer.scala +++ b/src/main/scala/millfork/assembly/mos/opt/FlowAnalyzer.scala @@ -52,11 +52,7 @@ object FlowAnalyzer { } val labelMap: () => Option[Map[String, Int]] = () => req match { case FlowInfoRequirement.NoRequirement => None - case _ => Some(code.flatMap { - case AssemblyLine0(op, _, MemoryAddressConstant(Label(l))) if op != Opcode.LABEL => Some(l) - case AssemblyLine0(op, _, StructureConstant(_, List(_, MemoryAddressConstant(Label(l))))) => Some(l) - case _ => None - }.groupBy(identity).mapValues(_.size).view.force) + case _ => Some(code.flatMap(_.parameter.extractLabels).groupBy(identity).mapValues(_.size).view.force) } val holder = new FlowHolder(forwardFlow, reverseFlow) code.zipWithIndex.map{ case (line, i) => FlowInfo(holder, i, labelMap) -> line} diff --git a/src/main/scala/millfork/assembly/z80/opt/FlowAnalyzer.scala b/src/main/scala/millfork/assembly/z80/opt/FlowAnalyzer.scala index b84bd8ec..53c10ab9 100644 --- a/src/main/scala/millfork/assembly/z80/opt/FlowAnalyzer.scala +++ b/src/main/scala/millfork/assembly/z80/opt/FlowAnalyzer.scala @@ -47,10 +47,7 @@ object FlowAnalyzer { } val labelMap: (() => Option[Map[String, Int]]) = () => req match { case FlowInfoRequirement.NoRequirement => None - case _ => Some(code.flatMap { - case ZLine0(op, _, MemoryAddressConstant(Label(l))) if op != ZOpcode.LABEL => Some(l) - case _ => None - }.groupBy(identity).mapValues(_.size).view.force) + case _ => Some(code.flatMap(_.parameter.extractLabels).groupBy(identity).mapValues(_.size).view.force) } val holder = new FlowHolder(forwardFlow, reverseFlow) code.zipWithIndex.map{ case (line, i) => FlowInfo(holder, i, labelMap) -> line} diff --git a/src/main/scala/millfork/env/Constant.scala b/src/main/scala/millfork/env/Constant.scala index cec4aa53..7776c572 100644 --- a/src/main/scala/millfork/env/Constant.scala +++ b/src/main/scala/millfork/env/Constant.scala @@ -5,6 +5,8 @@ import millfork.DecimalUtils._ import millfork.node.{ResolvedFieldDesc, SumExpression} import millfork.output.DivisibleAlignment +import scala.collection.GenTraversableOnce + object Constant { val Zero: Constant = NumericConstant(0, 1) val WordZero: Constant = NumericConstant(0, 2) @@ -129,6 +131,8 @@ sealed trait Constant { def refersTo(name: String): Boolean + def extractLabels: List[String] + def fitsInto(typ: Type): Boolean = true // TODO def fitInto(typ: Type): Constant = { @@ -196,6 +200,8 @@ case class AssertByte(c: Constant) extends Constant { override def fitsInto(typ: Type): Boolean = true override def toIntelString: String = c.toIntelString override def rootThingName: String = c.rootThingName + + override def extractLabels: List[String] = c.extractLabels } case class StructureConstant(typ: StructType, fields: List[Constant]) extends Constant { @@ -240,6 +246,8 @@ case class StructureConstant(typ: StructType, fields: List[Constant]) extends Co Constant.Zero } override def rootThingName: String = "?" + + override def extractLabels: List[String] = this.fields.flatMap(_.extractLabels) } case class UnexpandedConstant(name: String, requiredSize: Int) extends Constant { @@ -252,6 +260,8 @@ case class UnexpandedConstant(name: String, requiredSize: Int) extends Constant override def refersTo(name: String): Boolean = name == this.name override def rootThingName: String = "?" + + override def extractLabels: List[String] = Nil } case class NumericConstant(value: Long, requiredSize: Int) extends Constant { @@ -336,6 +346,8 @@ case class NumericConstant(value: Long, requiredSize: Int) extends Constant { } override def rootThingName: String = "" + + override def extractLabels: List[String] = Nil } case class MemoryAddressConstant(var thing: ThingInMemory) extends Constant { @@ -376,6 +388,11 @@ case class MemoryAddressConstant(var thing: ThingInMemory) extends Constant { override def refersTo(name: String): Boolean = name == thing.name override def rootThingName: String = thing.rootName + + override def extractLabels: List[String] = thing match { + case Label(n) => List(n) + case _ => Nil + } } case class SubbyteConstant(base: Constant, index: Int) extends Constant { @@ -416,6 +433,8 @@ case class SubbyteConstant(base: Constant, index: Int) extends Constant { override def refersTo(name: String): Boolean = base.refersTo(name) override def rootThingName: String = base.rootThingName + + override def extractLabels: List[String] = base.extractLabels } object MathOperator extends Enumeration { @@ -758,4 +777,6 @@ case class CompoundConstant(operator: MathOperator.Value, lhs: Constant, rhs: Co case (x, "") => x case _ => "?" } + + override def extractLabels: List[String] = lhs.extractLabels ++ rhs.extractLabels } diff --git a/src/test/scala/millfork/test/AssemblySuite.scala b/src/test/scala/millfork/test/AssemblySuite.scala index df934f0c..cdb88b47 100644 --- a/src/test/scala/millfork/test/AssemblySuite.scala +++ b/src/test/scala/millfork/test/AssemblySuite.scala @@ -21,6 +21,21 @@ class AssemblySuite extends FunSuite with Matchers with AppendedClues { """.stripMargin)(_.readByte(0xc000) should equal(1)) } + test("Self-modifying assembly") { + EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Motorola6809)( + """ + | byte output @$c000 + | // w&x + | asm void main () { + | lda #3 + | sta .l+1 + | .l: lda #55 + | sta output + | rts + | ignored:} + """.stripMargin)(_.readByte(0xc000) should equal(3)) + } + test("Assembly functions") { EmuBenchmarkRun( """ @@ -32,6 +47,7 @@ class AssemblySuite extends FunSuite with Matchers with AppendedClues { | asm void thing() { | inc $c000 | rts + | ignored: | } """.stripMargin)(_.readByte(0xc000) should equal(1)) } diff --git a/src/test/scala/millfork/test/emu/EmuM6809Run.scala b/src/test/scala/millfork/test/emu/EmuM6809Run.scala index dda4ca35..f2d1c70f 100644 --- a/src/test/scala/millfork/test/emu/EmuM6809Run.scala +++ b/src/test/scala/millfork/test/emu/EmuM6809Run.scala @@ -175,6 +175,11 @@ class EmuM6809Run(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimizat if (memoryBank.readable(i)) memoryBank.readable(i + 1) = true } } + if (source.contains("w&x")) { + for (i <- 0 until 0x10000) { + memoryBank.writeable(i) = true + } + } val timings = run(log, memoryBank, platform.codeAllocators("default").startAt) log.clearErrors() timings diff --git a/src/test/scala/millfork/test/emu/EmuRun.scala b/src/test/scala/millfork/test/emu/EmuRun.scala index 1a0c6f83..4710179e 100644 --- a/src/test/scala/millfork/test/emu/EmuRun.scala +++ b/src/test/scala/millfork/test/emu/EmuRun.scala @@ -281,6 +281,11 @@ class EmuRun(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimization], if (memoryBank.readable(i)) memoryBank.readable(i + 1) = true } } + if (source.contains("w&x")) { + for (i <- 0 until 0x10000) { + memoryBank.writeable(i) = true + } + } (0x200 until 0x2000).takeWhile(memoryBank.occupied(_)).map(memoryBank.output).grouped(16).map(_.map(i => f"$i%02x").mkString(" ")).foreach(log.debug(_)) val timings = platform.cpu match { case millfork.Cpu.Cmos => diff --git a/src/test/scala/millfork/test/emu/EmuZ80Run.scala b/src/test/scala/millfork/test/emu/EmuZ80Run.scala index d0a538a4..8e77c0b0 100644 --- a/src/test/scala/millfork/test/emu/EmuZ80Run.scala +++ b/src/test/scala/millfork/test/emu/EmuZ80Run.scala @@ -173,6 +173,11 @@ class EmuZ80Run(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimizatio memoryBank.readable(i) = true memoryBank.writeable(i) = true } + if (source.contains("w&x")) { + for (i <- 0 until 0x10000) { + memoryBank.writeable(i) = true + } + } // LD SP,$fffe // CALL $0200