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:
parent
9c7e946f4c
commit
919f11af2e
@ -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}
|
||||||
|
@ -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}
|
||||||
|
@ -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}
|
||||||
|
21
src/main/scala/millfork/env/Constant.scala
vendored
21
src/main/scala/millfork/env/Constant.scala
vendored
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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))
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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 =>
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user