1
0
mirror of https://github.com/KarolS/millfork.git synced 2025-01-10 20:29:35 +00:00

Preparations for work on LR35902 support

This commit is contained in:
Karol Stasiak 2018-07-24 23:44:00 +02:00
parent c5b45947dc
commit 2ca30315ca
8 changed files with 103 additions and 8 deletions

View File

@ -14,15 +14,18 @@ libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.4" % "test"
libraryDependencies += "com.codingrodent.microprocessor" % "Z80Processor" % "2.0.2" % "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: // get them from the following links or just build millfork without tests:
// https://github.com/sethm/symon/tree/71905fdb1998ee4f142260879504bc46cf27648f // https://github.com/sethm/symon/tree/71905fdb1998ee4f142260879504bc46cf27648f
// https://github.com/andrew-hoffman/halfnes/tree/061 // 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.loomcom.symon" % "symon" % "1.3.0-SNAPSHOT" % "test"
libraryDependencies += "com.grapeshot" % "halfnes" % "061" % "test" libraryDependencies += "com.grapeshot" % "halfnes" % "061" % "test"
libraryDependencies += "eu.rekawek.coffeegb" % "coffee-gb" % "1.0.0" % "test"
mainClass in Compile := Some("millfork.Main") mainClass in Compile := Some("millfork.Main")
assemblyJarName := "millfork.jar" assemblyJarName := "millfork.jar"

View File

@ -9,7 +9,7 @@ import org.scalatest.{FunSuite, Matchers}
*/ */
class BasicSymonTest extends FunSuite with Matchers { class BasicSymonTest extends FunSuite with Matchers {
test("Empty test") { test("Empty test") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)( EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp)(
""" """
| void main () { | void main () {
| |
@ -80,13 +80,13 @@ class BasicSymonTest extends FunSuite with Matchers {
output += 1 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(_ == '+')) m.readByte(0xc000) should equal(src.count(_ == '+'))
} }
} }
test("Byte assignment") { test("Byte assignment") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)( EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp)(
""" """
| byte output @$c000 | byte output @$c000
| void main () { | void main () {
@ -98,7 +98,7 @@ class BasicSymonTest extends FunSuite with Matchers {
} }
test("Preallocated variables") { test("Preallocated variables") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)( EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp)(
""" """
| array output [2] @$c000 | array output [2] @$c000
| byte number = 4 | byte number = 4
@ -127,7 +127,7 @@ class BasicSymonTest extends FunSuite with Matchers {
} }
test("Else if") { test("Else if") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)( EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp)(
""" """
| byte output @$c000 | byte output @$c000
| void main () { | void main () {
@ -145,7 +145,7 @@ class BasicSymonTest extends FunSuite with Matchers {
} }
test("Segment syntax") { 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)byte output @$c000
| segment(default)array x[3] | segment(default)array x[3]
@ -174,7 +174,7 @@ class BasicSymonTest extends FunSuite with Matchers {
} }
test("Preprocessor test") { test("Preprocessor test") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)( EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp)(
""" """
| byte output @$c000 | byte output @$c000
| |

View File

@ -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 { object EmuCrossPlatformBenchmarkRun {
def apply(platforms: millfork.Cpu.Value*)(source: String)(verifier: MemoryBank => Unit): Unit = { def apply(platforms: millfork.Cpu.Value*)(source: String)(verifier: MemoryBank => Unit): Unit = {
if (platforms.isEmpty) { if (platforms.isEmpty) {
@ -77,5 +96,11 @@ object EmuCrossPlatformBenchmarkRun {
if (platforms.contains(millfork.Cpu.Z80)) { if (platforms.contains(millfork.Cpu.Z80)) {
EmuZ80BenchmarkRun.apply(source)(verifier) EmuZ80BenchmarkRun.apply(source)(verifier)
} }
if (platforms.contains(millfork.Cpu.Intel8080)) {
EmuIntel8080BenchmarkRun.apply(source)(verifier)
}
if (platforms.contains(millfork.Cpu.Sharp)) {
EmuSharpBenchmarkRun.apply(source)(verifier)
}
} }
} }

View File

@ -11,6 +11,7 @@ object EmuUnoptimizedCrossPlatformRun {
val (_, mm) = if (platforms.contains(Cpu.Mos)) EmuUnoptimizedRun.apply2(source) else Timings(-1, -1) -> null 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 (_, 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 (_, 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)) { if (platforms.contains(Cpu.Mos)) {
println(f"Running MOS") println(f"Running MOS")
verifier(mm) verifier(mm)
@ -23,5 +24,9 @@ object EmuUnoptimizedCrossPlatformRun {
println(f"Running 8080") println(f"Running 8080")
verifier(mi) verifier(mi)
} }
if (platforms.contains(Cpu.Sharp)) {
println(f"Running LR35902")
verifier(ms)
}
} }
} }

View File

@ -11,3 +11,5 @@ object EmuUnoptimizedRun extends EmuRun(Cpu.StrictMos, Nil, Nil)
object EmuUnoptimizedZ80Run extends EmuZ80Run(Cpu.Z80, Nil, Nil) object EmuUnoptimizedZ80Run extends EmuZ80Run(Cpu.Z80, Nil, Nil)
object EmuUnoptimizedIntel8080Run extends EmuZ80Run(Cpu.Intel8080, Nil, Nil) object EmuUnoptimizedIntel8080Run extends EmuZ80Run(Cpu.Intel8080, Nil, Nil)
object EmuUnoptimizedSharpRun extends EmuZ80Run(Cpu.Sharp, Nil, Nil)

View File

@ -1,6 +1,9 @@
package millfork.test.emu package millfork.test.emu
import com.codingrodent.microprocessor.Z80.{CPUConstants, Z80Core} 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 fastparse.core.Parsed.{Failure, Success}
import millfork.assembly.AssemblyOptimization import millfork.assembly.AssemblyOptimization
import millfork.assembly.z80.ZLine import millfork.assembly.z80.ZLine
@ -123,6 +126,16 @@ class EmuZ80Run(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimizatio
} }
val tStates = cpu.getTStates val tStates = cpu.getTStates
Timings(tStates, tStates) -> memoryBank 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 _ => case _ =>
Timings(-1, -1) -> memoryBank Timings(-1, -1) -> memoryBank
} }

View File

@ -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)
}

View File

@ -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)
}