1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-12-25 06:29:17 +00:00

#101: Allow using local labels in all assembly instructions and all assembly expressions

This commit is contained in:
Karol Stasiak 2021-02-03 09:50:44 +01:00
parent 9c7e946f4c
commit 919f11af2e
8 changed files with 55 additions and 13 deletions

View File

@ -52,10 +52,7 @@ object FlowAnalyzer {
} }
val labelMap: () => Option[Map[String, Int]] = () => req match { val labelMap: () => Option[Map[String, Int]] = () => req match {
case FlowInfoRequirement.NoRequirement => None case FlowInfoRequirement.NoRequirement => None
case _ => Some(code.flatMap { case _ => Some(code.flatMap(_.parameter.extractLabels).groupBy(identity).mapValues(_.size).view.force)
case MLine0(op, _, MemoryAddressConstant(Label(l))) if op != MOpcode.LABEL => Some(l)
case _ => None
}.groupBy(identity).mapValues(_.size).view.force)
} }
val holder = new FlowHolder(forwardFlow, reverseFlow) val holder = new FlowHolder(forwardFlow, reverseFlow)
code.zipWithIndex.map{ case (line, i) => FlowInfo(holder, i, labelMap) -> line} code.zipWithIndex.map{ case (line, i) => FlowInfo(holder, i, labelMap) -> line}

View File

@ -52,11 +52,7 @@ object FlowAnalyzer {
} }
val labelMap: () => Option[Map[String, Int]] = () => req match { val labelMap: () => Option[Map[String, Int]] = () => req match {
case FlowInfoRequirement.NoRequirement => None case FlowInfoRequirement.NoRequirement => None
case _ => Some(code.flatMap { case _ => Some(code.flatMap(_.parameter.extractLabels).groupBy(identity).mapValues(_.size).view.force)
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)
} }
val holder = new FlowHolder(forwardFlow, reverseFlow) val holder = new FlowHolder(forwardFlow, reverseFlow)
code.zipWithIndex.map{ case (line, i) => FlowInfo(holder, i, labelMap) -> line} code.zipWithIndex.map{ case (line, i) => FlowInfo(holder, i, labelMap) -> line}

View File

@ -47,10 +47,7 @@ object FlowAnalyzer {
} }
val labelMap: (() => Option[Map[String, Int]]) = () => req match { val labelMap: (() => Option[Map[String, Int]]) = () => req match {
case FlowInfoRequirement.NoRequirement => None case FlowInfoRequirement.NoRequirement => None
case _ => Some(code.flatMap { case _ => Some(code.flatMap(_.parameter.extractLabels).groupBy(identity).mapValues(_.size).view.force)
case ZLine0(op, _, MemoryAddressConstant(Label(l))) if op != ZOpcode.LABEL => Some(l)
case _ => None
}.groupBy(identity).mapValues(_.size).view.force)
} }
val holder = new FlowHolder(forwardFlow, reverseFlow) val holder = new FlowHolder(forwardFlow, reverseFlow)
code.zipWithIndex.map{ case (line, i) => FlowInfo(holder, i, labelMap) -> line} code.zipWithIndex.map{ case (line, i) => FlowInfo(holder, i, labelMap) -> line}

View File

@ -5,6 +5,8 @@ import millfork.DecimalUtils._
import millfork.node.{ResolvedFieldDesc, SumExpression} import millfork.node.{ResolvedFieldDesc, SumExpression}
import millfork.output.DivisibleAlignment import millfork.output.DivisibleAlignment
import scala.collection.GenTraversableOnce
object Constant { object Constant {
val Zero: Constant = NumericConstant(0, 1) val Zero: Constant = NumericConstant(0, 1)
val WordZero: Constant = NumericConstant(0, 2) val WordZero: Constant = NumericConstant(0, 2)
@ -129,6 +131,8 @@ sealed trait Constant {
def refersTo(name: String): Boolean def refersTo(name: String): Boolean
def extractLabels: List[String]
def fitsInto(typ: Type): Boolean = true // TODO def fitsInto(typ: Type): Boolean = true // TODO
def fitInto(typ: Type): Constant = { 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 fitsInto(typ: Type): Boolean = true
override def toIntelString: String = c.toIntelString override def toIntelString: String = c.toIntelString
override def rootThingName: String = c.rootThingName override def rootThingName: String = c.rootThingName
override def extractLabels: List[String] = c.extractLabels
} }
case class StructureConstant(typ: StructType, fields: List[Constant]) extends Constant { 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 Constant.Zero
} }
override def rootThingName: String = "?" override def rootThingName: String = "?"
override def extractLabels: List[String] = this.fields.flatMap(_.extractLabels)
} }
case class UnexpandedConstant(name: String, requiredSize: Int) extends Constant { 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 refersTo(name: String): Boolean = name == this.name
override def rootThingName: String = "?" override def rootThingName: String = "?"
override def extractLabels: List[String] = Nil
} }
case class NumericConstant(value: Long, requiredSize: Int) extends Constant { 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 rootThingName: String = ""
override def extractLabels: List[String] = Nil
} }
case class MemoryAddressConstant(var thing: ThingInMemory) extends Constant { 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 refersTo(name: String): Boolean = name == thing.name
override def rootThingName: String = thing.rootName 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 { 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 refersTo(name: String): Boolean = base.refersTo(name)
override def rootThingName: String = base.rootThingName override def rootThingName: String = base.rootThingName
override def extractLabels: List[String] = base.extractLabels
} }
object MathOperator extends Enumeration { object MathOperator extends Enumeration {
@ -758,4 +777,6 @@ case class CompoundConstant(operator: MathOperator.Value, lhs: Constant, rhs: Co
case (x, "") => x case (x, "") => x
case _ => "?" case _ => "?"
} }
override def extractLabels: List[String] = lhs.extractLabels ++ rhs.extractLabels
} }

View File

@ -21,6 +21,21 @@ class AssemblySuite extends FunSuite with Matchers with AppendedClues {
""".stripMargin)(_.readByte(0xc000) should equal(1)) """.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") { test("Assembly functions") {
EmuBenchmarkRun( EmuBenchmarkRun(
""" """
@ -32,6 +47,7 @@ class AssemblySuite extends FunSuite with Matchers with AppendedClues {
| asm void thing() { | asm void thing() {
| inc $c000 | inc $c000
| rts | rts
| ignored:
| } | }
""".stripMargin)(_.readByte(0xc000) should equal(1)) """.stripMargin)(_.readByte(0xc000) should equal(1))
} }

View File

@ -175,6 +175,11 @@ class EmuM6809Run(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimizat
if (memoryBank.readable(i)) memoryBank.readable(i + 1) = true 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) val timings = run(log, memoryBank, platform.codeAllocators("default").startAt)
log.clearErrors() log.clearErrors()
timings timings

View File

@ -281,6 +281,11 @@ class EmuRun(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimization],
if (memoryBank.readable(i)) memoryBank.readable(i + 1) = true 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(_)) (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 { val timings = platform.cpu match {
case millfork.Cpu.Cmos => case millfork.Cpu.Cmos =>

View File

@ -173,6 +173,11 @@ class EmuZ80Run(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimizatio
memoryBank.readable(i) = true memoryBank.readable(i) = true
memoryBank.writeable(i) = true memoryBank.writeable(i) = true
} }
if (source.contains("w&x")) {
for (i <- 0 until 0x10000) {
memoryBank.writeable(i) = true
}
}
// LD SP,$fffe // LD SP,$fffe
// CALL $0200 // CALL $0200