From 2ca30315ca0bec874b3058cc4a849b1e137d1a77 Mon Sep 17 00:00:00 2001 From: Karol Stasiak Date: Tue, 24 Jul 2018 23:44:00 +0200 Subject: [PATCH] Preparations for work on LR35902 support --- build.sbt | 5 +++- .../scala/millfork/test/BasicSymonTest.scala | 14 ++++----- .../millfork/test/emu/EmuBenchmarkRun.scala | 25 ++++++++++++++++ .../emu/EmuUnoptimizedCrossPlatformRun.scala | 5 ++++ .../millfork/test/emu/EmuUnoptimizedRun.scala | 2 ++ .../scala/millfork/test/emu/EmuZ80Run.scala | 13 +++++++++ .../millfork/test/emu/GameboyMemory.scala | 18 ++++++++++++ .../millfork/test/emu/GameboyStubs.scala | 29 +++++++++++++++++++ 8 files changed, 103 insertions(+), 8 deletions(-) create mode 100644 src/test/scala/millfork/test/emu/GameboyMemory.scala create mode 100644 src/test/scala/millfork/test/emu/GameboyStubs.scala diff --git a/build.sbt b/build.sbt index 7c7f876a..bd4de5fe 100644 --- a/build.sbt +++ b/build.sbt @@ -14,15 +14,18 @@ libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.4" % "test" libraryDependencies += "com.codingrodent.microprocessor" % "Z80Processor" % "2.0.2" % "test" -// these two are not in Maven Central or any other public repo +// these three are not in Maven Central or any other public repo // get them from the following links or just build millfork without tests: // https://github.com/sethm/symon/tree/71905fdb1998ee4f142260879504bc46cf27648f // https://github.com/andrew-hoffman/halfnes/tree/061 +// https://github.com/trekawek/coffee-gb/tree/coffee-gb-1.0.0 libraryDependencies += "com.loomcom.symon" % "symon" % "1.3.0-SNAPSHOT" % "test" libraryDependencies += "com.grapeshot" % "halfnes" % "061" % "test" +libraryDependencies += "eu.rekawek.coffeegb" % "coffee-gb" % "1.0.0" % "test" + mainClass in Compile := Some("millfork.Main") assemblyJarName := "millfork.jar" diff --git a/src/test/scala/millfork/test/BasicSymonTest.scala b/src/test/scala/millfork/test/BasicSymonTest.scala index e3c42db8..b173dead 100644 --- a/src/test/scala/millfork/test/BasicSymonTest.scala +++ b/src/test/scala/millfork/test/BasicSymonTest.scala @@ -9,7 +9,7 @@ import org.scalatest.{FunSuite, Matchers} */ class BasicSymonTest extends FunSuite with Matchers { test("Empty test") { - EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)( + EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp)( """ | void main () { | @@ -80,13 +80,13 @@ class BasicSymonTest extends FunSuite with Matchers { output += 1 } """ - EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(src){m => + EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp)(src){m => m.readByte(0xc000) should equal(src.count(_ == '+')) } } test("Byte assignment") { - EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)( + EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp)( """ | byte output @$c000 | void main () { @@ -98,7 +98,7 @@ class BasicSymonTest extends FunSuite with Matchers { } test("Preallocated variables") { - EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)( + EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp)( """ | array output [2] @$c000 | byte number = 4 @@ -127,7 +127,7 @@ class BasicSymonTest extends FunSuite with Matchers { } test("Else if") { - EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)( + EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp)( """ | byte output @$c000 | void main () { @@ -145,7 +145,7 @@ class BasicSymonTest extends FunSuite with Matchers { } test("Segment syntax") { - EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)( + EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp)( """ | segment(default)byte output @$c000 | segment(default)array x[3] @@ -174,7 +174,7 @@ class BasicSymonTest extends FunSuite with Matchers { } test("Preprocessor test") { - EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)( + EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp)( """ | byte output @$c000 | diff --git a/src/test/scala/millfork/test/emu/EmuBenchmarkRun.scala b/src/test/scala/millfork/test/emu/EmuBenchmarkRun.scala index 82d0b213..6f292f76 100644 --- a/src/test/scala/millfork/test/emu/EmuBenchmarkRun.scala +++ b/src/test/scala/millfork/test/emu/EmuBenchmarkRun.scala @@ -63,6 +63,25 @@ object EmuIntel8080BenchmarkRun { } } +object EmuSharpBenchmarkRun { + def apply(source: String)(verifier: MemoryBank => Unit): Unit = { + val (Timings(t0, _), m0) = EmuUnoptimizedSharpRun.apply2(source) +// val (Timings(t1, _), m1) = EmuOptimizedZ80Run.apply2(source) +// val (Timings(t2, _), m2) = EmuOptimizedInlinedZ80Run.apply2(source) + println(f"Before optimization: $t0%7d") +// println(f"After optimization: $t1%7d") +// println(f"After inlining: $t2%7d") +// println(f"Gain: ${(100L * (t0 - t1) / t0.toDouble).round}%7d%%") +// println(f"Gain with inlining: ${(100L * (t0 - t2) / t0.toDouble).round}%7d%%") + println(f"Running unoptimized") + verifier(m0) +// println(f"Running optimized") +// verifier(m1) +// println(f"Running optimized inlined") +// verifier(m2) + } +} + object EmuCrossPlatformBenchmarkRun { def apply(platforms: millfork.Cpu.Value*)(source: String)(verifier: MemoryBank => Unit): Unit = { if (platforms.isEmpty) { @@ -77,5 +96,11 @@ object EmuCrossPlatformBenchmarkRun { if (platforms.contains(millfork.Cpu.Z80)) { EmuZ80BenchmarkRun.apply(source)(verifier) } + if (platforms.contains(millfork.Cpu.Intel8080)) { + EmuIntel8080BenchmarkRun.apply(source)(verifier) + } + if (platforms.contains(millfork.Cpu.Sharp)) { + EmuSharpBenchmarkRun.apply(source)(verifier) + } } } diff --git a/src/test/scala/millfork/test/emu/EmuUnoptimizedCrossPlatformRun.scala b/src/test/scala/millfork/test/emu/EmuUnoptimizedCrossPlatformRun.scala index 0c0c1825..e1689f76 100644 --- a/src/test/scala/millfork/test/emu/EmuUnoptimizedCrossPlatformRun.scala +++ b/src/test/scala/millfork/test/emu/EmuUnoptimizedCrossPlatformRun.scala @@ -11,6 +11,7 @@ object EmuUnoptimizedCrossPlatformRun { val (_, mm) = if (platforms.contains(Cpu.Mos)) EmuUnoptimizedRun.apply2(source) else Timings(-1, -1) -> null val (_, mz) = if (platforms.contains(Cpu.Z80)) EmuUnoptimizedZ80Run.apply2(source) else Timings(-1, -1) -> null val (_, mi) = if (platforms.contains(Cpu.Intel8080)) EmuUnoptimizedIntel8080Run.apply2(source) else Timings(-1, -1) -> null + val (_, ms) = if (platforms.contains(Cpu.Sharp)) EmuUnoptimizedSharpRun.apply2(source) else Timings(-1, -1) -> null if (platforms.contains(Cpu.Mos)) { println(f"Running MOS") verifier(mm) @@ -23,5 +24,9 @@ object EmuUnoptimizedCrossPlatformRun { println(f"Running 8080") verifier(mi) } + if (platforms.contains(Cpu.Sharp)) { + println(f"Running LR35902") + verifier(ms) + } } } diff --git a/src/test/scala/millfork/test/emu/EmuUnoptimizedRun.scala b/src/test/scala/millfork/test/emu/EmuUnoptimizedRun.scala index f55f05ad..358d8f94 100644 --- a/src/test/scala/millfork/test/emu/EmuUnoptimizedRun.scala +++ b/src/test/scala/millfork/test/emu/EmuUnoptimizedRun.scala @@ -11,3 +11,5 @@ object EmuUnoptimizedRun extends EmuRun(Cpu.StrictMos, Nil, Nil) object EmuUnoptimizedZ80Run extends EmuZ80Run(Cpu.Z80, Nil, Nil) object EmuUnoptimizedIntel8080Run extends EmuZ80Run(Cpu.Intel8080, Nil, Nil) + +object EmuUnoptimizedSharpRun extends EmuZ80Run(Cpu.Sharp, Nil, Nil) diff --git a/src/test/scala/millfork/test/emu/EmuZ80Run.scala b/src/test/scala/millfork/test/emu/EmuZ80Run.scala index 050091c3..41c632f9 100644 --- a/src/test/scala/millfork/test/emu/EmuZ80Run.scala +++ b/src/test/scala/millfork/test/emu/EmuZ80Run.scala @@ -1,6 +1,9 @@ package millfork.test.emu import com.codingrodent.microprocessor.Z80.{CPUConstants, Z80Core} +import eu.rekawek.coffeegb.AddressSpace +import eu.rekawek.coffeegb.cpu.{Cpu, InterruptManager, SpeedMode} +import eu.rekawek.coffeegb.gpu.Gpu import fastparse.core.Parsed.{Failure, Success} import millfork.assembly.AssemblyOptimization import millfork.assembly.z80.ZLine @@ -123,6 +126,16 @@ class EmuZ80Run(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimizatio } val tStates = cpu.getTStates Timings(tStates, tStates) -> memoryBank + case millfork.Cpu.Sharp => + var ticks = 0L + val cpu = GameboyStubs(memoryBank).cpu + cpu.getRegisters.setPC(0x1f0) + while (cpu.getState != Cpu.State.HALTED) { + cpu.tick() + ticks += 4 + ticks should be < TooManyCycles + } + Timings(ticks, ticks) -> memoryBank case _ => Timings(-1, -1) -> memoryBank } diff --git a/src/test/scala/millfork/test/emu/GameboyMemory.scala b/src/test/scala/millfork/test/emu/GameboyMemory.scala new file mode 100644 index 00000000..17e7ce9c --- /dev/null +++ b/src/test/scala/millfork/test/emu/GameboyMemory.scala @@ -0,0 +1,18 @@ +package millfork.test.emu + +import eu.rekawek.coffeegb.AddressSpace +import millfork.output.MemoryBank + +/** + * @author Karol Stasiak + */ +case class GameboyMemory(memoryBank: MemoryBank) extends AddressSpace { + override def accepts(i: Int): Boolean = true + + override def setByte(address: Int, data: Int): Unit = { + // if (!memoryBank.writeable(address)) throw new RuntimeException("Can't write to $" + address.toHexString) + memoryBank.output(address) = data.toByte + } + + override def getByte(address: Int): Int = memoryBank.readByte(address) +} diff --git a/src/test/scala/millfork/test/emu/GameboyStubs.scala b/src/test/scala/millfork/test/emu/GameboyStubs.scala new file mode 100644 index 00000000..c8a119bc --- /dev/null +++ b/src/test/scala/millfork/test/emu/GameboyStubs.scala @@ -0,0 +1,29 @@ +package millfork.test.emu + +import eu.rekawek.coffeegb.AddressSpace +import eu.rekawek.coffeegb.cpu.{Cpu, InterruptManager, SpeedMode} +import eu.rekawek.coffeegb.gpu.{Display, Gpu} +import eu.rekawek.coffeegb.memory.{Dma, Ram} +import millfork.output.MemoryBank + +/** + * @author Karol Stasiak + */ +case class GameboyStubs(memoryBank: MemoryBank) { + val display: Display = Display.NULL_DISPLAY + + val interruptManager: InterruptManager = new InterruptManager(false) + interruptManager.disableInterrupts(false) + + val addressSpace: AddressSpace = GameboyMemory(memoryBank) + + val oamRam: Ram = new Ram(0, 0) + + val speedMode: SpeedMode = new SpeedMode + + val dma: Dma = new Dma(addressSpace, oamRam, speedMode) + + val gpu: Gpu = new Gpu(display, interruptManager, dma, oamRam, false) + + val cpu: Cpu = new Cpu(addressSpace, interruptManager, gpu, display, speedMode) +}