diff --git a/src/main/scala/millfork/assembly/mos/AssemblyLine.scala b/src/main/scala/millfork/assembly/mos/AssemblyLine.scala index 4325aaf1..3b681834 100644 --- a/src/main/scala/millfork/assembly/mos/AssemblyLine.scala +++ b/src/main/scala/millfork/assembly/mos/AssemblyLine.scala @@ -339,6 +339,21 @@ object OpcodeClasses { val DiscardsD = OverwritesD val DiscardsI = NoopDiscardsFlags | OverwritesI + val SupportsZeropage = Set( + LDA, LDX, LDY, LAX, // LDZ doesn't! + LDA_W, LDX_W, LDY_W, + STA, STX, STY, SAX, STZ, + STA_W, LDX_W, LDY_W, + BIT, + CPX, CPY, CPZ, + ADC, SBC, CMP, AND, ORA, EOR, + ADC_W, SBC_W, CMP_W, AND_W, ORA_W, EOR_W, + INC, DEC, ROL, ROR, ASL, LSR, + INC_W, DEC_W, ROL_W, ROR_W, ASL_W, LSR_W, + ISC, DCP, RLA, RRA, SLO, SRE, + TSB, TRB, + ) + } object AssemblyLine { diff --git a/src/main/scala/millfork/compiler/mos/MosStatementCompiler.scala b/src/main/scala/millfork/compiler/mos/MosStatementCompiler.scala index 48561af2..07fedf2d 100644 --- a/src/main/scala/millfork/compiler/mos/MosStatementCompiler.scala +++ b/src/main/scala/millfork/compiler/mos/MosStatementCompiler.scala @@ -156,6 +156,7 @@ object MosStatementCompiler extends AbstractStatementCompiler[AssemblyLine] { } val actualAddrMode = a match { case Absolute if OpcodeClasses.ShortBranching(o) => Relative + case Absolute if OpcodeClasses.SupportsZeropage(o) && c.fitsProvablyIntoByte => ZeroPage case IndexedX if o == JMP => AbsoluteIndexedX case Indirect if o != JMP => IndexedZ case _ => a diff --git a/src/main/scala/millfork/env/Constant.scala b/src/main/scala/millfork/env/Constant.scala index 5bc989f1..ed5e7bf8 100644 --- a/src/main/scala/millfork/env/Constant.scala +++ b/src/main/scala/millfork/env/Constant.scala @@ -26,6 +26,7 @@ sealed trait Constant { case NumericConstant(0, _) => true case _ => false } + def fitsProvablyIntoByte: Boolean = false def asl(i: Constant): Constant = i match { case NumericConstant(sa, _) => asl(sa.toInt) @@ -100,6 +101,7 @@ case class AssertByte(c: Constant) extends Constant { override def isProvablyZero: Boolean = c.isProvablyZero override def isProvably(i: Int): Boolean = c.isProvably(i) override def isProvablyNonnegative: Boolean = c.isProvablyNonnegative + override def fitsProvablyIntoByte: Boolean = true override def requiredSize: Int = 1 @@ -132,6 +134,7 @@ case class NumericConstant(value: Long, requiredSize: Int) extends Constant { override def isProvablyZero: Boolean = value == 0 override def isProvably(i: Int): Boolean = value == i override def isProvablyNonnegative: Boolean = value >= 0 + override def fitsProvablyIntoByte: Boolean = requiredSize == 1 override def isLowestByteAlwaysEqual(i: Int) : Boolean = (value & 0xff) == (i&0xff) @@ -211,6 +214,7 @@ case class SubbyteConstant(base: Constant, index: Int) extends Constant { override def requiredSize = 1 override def isProvablyNonnegative: Boolean = true + override def fitsProvablyIntoByte: Boolean = true override def toString: String = index match { case 0 => s"lo($base)" diff --git a/src/test/scala/millfork/test/AssemblySuite.scala b/src/test/scala/millfork/test/AssemblySuite.scala index 9618c9c9..78a819ab 100644 --- a/src/test/scala/millfork/test/AssemblySuite.scala +++ b/src/test/scala/millfork/test/AssemblySuite.scala @@ -1,11 +1,11 @@ package millfork.test -import millfork.test.emu.EmuBenchmarkRun -import org.scalatest.{FunSuite, Matchers} +import millfork.test.emu.{EmuBenchmarkRun, EmuOptimizedCmosRun, EmuOptimizedRun} +import org.scalatest.{AppendedClues, FunSuite, Matchers} /** * @author Karol Stasiak */ -class AssemblySuite extends FunSuite with Matchers { +class AssemblySuite extends FunSuite with Matchers with AppendedClues { test("Inline assembly") { EmuBenchmarkRun( @@ -163,4 +163,52 @@ class AssemblySuite extends FunSuite with Matchers { | } """.stripMargin)(_.readByte(0xc000) should equal(10)) } + + test("Correctly use zeropage for CPU port on C64") { + val m = EmuOptimizedRun( + """ + | byte port @1 + | const byte port_addr = 1 + | byte port_alt @port_addr + | void main () { + | a() + | b() + | c() + | d() + | e() + | f() + | } + | noinline void a() { + | port = 1 + | } + | noinline void b() { + | port_alt = 2 + | } + | noinline asm void c() { + | lda #3 + | sta 1 + | rts + | } + | noinline asm void d() { + | lda #4 + | sta port + | rts + | } + | noinline asm void e() { + | lda #5 + | sta port_addr + | rts + | } + | noinline asm void f() { + | lda #6 + | sta port_alt + | rts + | } + """.stripMargin) + for (addr <- 0x0200 to 0x02ff) { + m.readable(addr) = true + m.readByte(addr) should not equal 0x8d withClue f"STA abs at $addr%04x" + } + } + }