1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-07-05 09:28:54 +00:00

Preliminary support for Intel 8080

This commit is contained in:
Karol Stasiak 2018-07-24 23:14:41 +02:00
parent 749defd05a
commit c5b45947dc
45 changed files with 561 additions and 241 deletions

View File

@ -28,10 +28,10 @@ case class CompilationOptions(platform: Platform, commandLineFlags: Map[Compilat
invalids = invalids.filter(flags)
if (invalids.nonEmpty) {
ErrorReporting.error("Invalid flags enabled for the currect CPU family: " + invalids.mkString(", "))
ErrorReporting.error("Invalid flags enabled for the current CPU family: " + invalids.mkString(", "))
}
if (CpuFamily.forType(platform.cpu) != CpuFamily.M6502 && zpRegisterSize > 0) {
ErrorReporting.error("Invalid flags enabled for the currect CPU family: zp_register" + invalids.mkString(", "))
ErrorReporting.error("Invalid flags enabled for the current CPU family: zp_register" + invalids.mkString(", "))
}
CpuFamily.forType(platform.cpu) match {
case CpuFamily.M6502 =>
@ -97,39 +97,49 @@ case class CompilationOptions(platform: Platform, commandLineFlags: Map[Compilat
}
}
if (flags(EmitZ80Opcodes)) {
if (platform.cpu != Z80) {
if (platform.cpu != Z80 && platform.cpu != EZ80) {
ErrorReporting.error("Z80 opcodes enabled for architecture that doesn't support them")
}
}
if (flags(EmitEZ80Opcodes)) {
if (platform.cpu != Z80 && platform.cpu != EZ80) {
ErrorReporting.error("eZ80 opcodes enabled for architecture that doesn't support them")
}
}
if (flags(EmitSharpOpcodes)) {
if (platform.cpu != Sharp) {
ErrorReporting.error("Sharp LR35902 opcodes enabled for architecture that doesn't support them")
}
}
if (flags(EmitExtended80Opcodes)) {
if (platform.cpu != Sharp && platform.cpu != Z80) {
if (platform.cpu != Sharp && platform.cpu != Z80 && platform.cpu != EZ80) {
ErrorReporting.error("Extended 8080-like opcodes enabled for architecture that doesn't support them")
}
}
if (flags(EmitIntel8080Opcodes)) {
if (platform.cpu != Intel8080 && platform.cpu != Z80 && platform.cpu != EZ80) {
ErrorReporting.error("Intel 8080 opcodes enabled for architecture that doesn't support them")
}
}
}
}
}
object CpuFamily extends Enumeration {
val M6502, I80, M6809, I86, M68K, ARM = Value
val M6502, I80, M6800, I86, M68K, ARM = Value
def forType(cpu: Cpu.Value): CpuFamily.Value = {
import Cpu._
cpu match {
case Mos | StrictMos | Ricoh | StrictRicoh | Cmos | HuC6280 | CE02 | Sixteen => M6502
case Intel8080 | Sharp | Z80 => I80
case Intel8080 | Sharp | Z80 | EZ80 => I80
}
}
}
object Cpu extends Enumeration {
val Mos, StrictMos, Ricoh, StrictRicoh, Cmos, HuC6280, CE02, Sixteen, Intel8080, Z80, Sharp = Value
val Mos, StrictMos, Ricoh, StrictRicoh, Cmos, HuC6280, CE02, Sixteen, Intel8080, Z80, EZ80, Sharp = Value
val CmosCompatible = Set(Cmos, HuC6280, CE02, Sixteen)
@ -139,7 +149,7 @@ object Cpu extends Enumeration {
VariableOverlap, CompactReturnDispatchParams
)
private val i8080AlwaysDefaultFlags = Set(
private val i80AlwaysDefaultFlags = Set(
VariableOverlap, CompactReturnDispatchParams
)
@ -161,11 +171,13 @@ object Cpu extends Enumeration {
case Sixteen =>
mosAlwaysDefaultFlags ++ Set(DecimalMode, EmitCmosOpcodes, EmitEmulation65816Opcodes, EmitNative65816Opcodes, ReturnWordsViaAccumulator)
case Intel8080 =>
i8080AlwaysDefaultFlags
i80AlwaysDefaultFlags ++ Set(EmitIntel8080Opcodes)
case Z80 =>
i8080AlwaysDefaultFlags ++ Set(EmitExtended80Opcodes, EmitZ80Opcodes, UseIxForStack)
i80AlwaysDefaultFlags ++ Set(EmitIntel8080Opcodes, EmitExtended80Opcodes, EmitZ80Opcodes, UseIxForStack)
case EZ80 =>
i80AlwaysDefaultFlags ++ Set(EmitIntel8080Opcodes, EmitExtended80Opcodes, EmitZ80Opcodes, UseIxForStack, EmitEZ80Opcodes)
case Sharp =>
i8080AlwaysDefaultFlags ++ Set(EmitExtended80Opcodes, EmitSharpOpcodes)
i80AlwaysDefaultFlags ++ Set(EmitExtended80Opcodes, EmitSharpOpcodes)
}
def fromString(name: String): Cpu.Value = name match {
@ -196,6 +208,15 @@ object Cpu extends Enumeration {
case "strict2a03" => StrictRicoh
case "strict2a07" => StrictRicoh
case "z80" => Z80
// disabled for now:
// case "ez80" => EZ80
// case "gameboy" => Sharp
// case "gb" => Sharp
// case "sharp" => Sharp
// case "lr35902" => Sharp
// case "8080" => Intel8080
// case "i8080" => Intel8080
// case "intel8080" => Intel8080
case _ => ErrorReporting.fatal("Unknown CPU achitecture: " + name)
}
}
@ -207,8 +228,8 @@ object CompilationFlag extends Enumeration {
// compilation options for MOS:
EmitCmosOpcodes, EmitCmosNopOpcodes, EmitHudsonOpcodes, Emit65CE02Opcodes, EmitEmulation65816Opcodes, EmitNative65816Opcodes,
PreventJmpIndirectBug, LargeCode, ReturnWordsViaAccumulator,
// compilation options for Z80
EmitExtended80Opcodes, EmitZ80Opcodes, EmitSharpOpcodes, UseIxForStack,
// compilation options for I80
EmitIntel8080Opcodes, EmitExtended80Opcodes, EmitZ80Opcodes, EmitEZ80Opcodes, EmitSharpOpcodes, UseIxForStack,
// optimization options:
DangerousOptimizations, InlineFunctions, InterproceduralOptimization, OptimizeForSize, OptimizeForSpeed, OptimizeForSonicSpeed,
// memory allocation options
@ -233,7 +254,9 @@ object CompilationFlag extends Enumeration {
"emit_65ce02" -> Emit65CE02Opcodes,
"emit_huc6280" -> EmitHudsonOpcodes,
"emit_z80" -> EmitZ80Opcodes,
"emit_ez80" -> EmitEZ80Opcodes,
"emit_x80" -> EmitExtended80Opcodes,
"emit_8080" -> EmitIntel8080Opcodes,
"emit_sharp" -> EmitSharpOpcodes,
"ix_stack" -> UseIxForStack,
"ipo" -> InterproceduralOptimization,

View File

@ -232,14 +232,18 @@ object Platform {
def builtInCpuFeatures(cpu: Cpu.Value): Map[String, Long] = {
Map[String, Long](
"ARCH_6502" -> toLong(CpuFamily.forType(cpu) == CpuFamily.M6502),
"ARCH_Z80" -> toLong(CpuFamily.forType(cpu) == CpuFamily.I80),
"ARCH_I80" -> toLong(CpuFamily.forType(cpu) == CpuFamily.I80),
"ARCH_Z80" -> toLong(cpu == Cpu.Z80 || cpu == Cpu.EZ80),
"ARCH_X86" -> toLong(CpuFamily.forType(cpu) == CpuFamily.I86),
"ARCH_6509" -> toLong(CpuFamily.forType(cpu) == CpuFamily.M6809),
"ARCH_6500" -> toLong(CpuFamily.forType(cpu) == CpuFamily.M6800),
"ARCH_ARM" -> toLong(CpuFamily.forType(cpu) == CpuFamily.ARM),
"ARCH_68K" -> toLong(CpuFamily.forType(cpu) == CpuFamily.M68K),
"HAS_HARDWARE_MULTIPLY" -> (CpuFamily.forType(cpu) match {
case CpuFamily.M6502 | CpuFamily.I80 | CpuFamily.M6809 => 0L
case CpuFamily.I86 | CpuFamily.ARM | CpuFamily.M68K => 1L
"HAS_HARDWARE_MULTIPLY" -> (cpu match {
case Cpu.EZ80 => 1L
case _ => CpuFamily.forType(cpu) match {
case CpuFamily.M6502 | CpuFamily.I80 | CpuFamily.M6800 => 0L
case CpuFamily.I86 | CpuFamily.ARM | CpuFamily.M68K => 1L
}
})
// TODO
)

View File

@ -1,6 +1,8 @@
package millfork.assembly.z80
import millfork.CompilationFlag
import millfork.assembly.AbstractCode
import millfork.compiler.CompilationContext
import millfork.env.{Constant, Label, NumericConstant, ThingInMemory}
import millfork.node.ZRegister
@ -89,17 +91,21 @@ object ZLine {
def jump(label: Label, condition: ZRegisters): ZLine = ZLine(JP, condition, label.toAddress)
def jumpR(label: String): ZLine = ZLine(JR, NoRegisters, Label(label).toAddress)
def jumpR(ctx: CompilationContext, label: String): ZLine = ZLine(if (ctx.options.flag(CompilationFlag.EmitExtended80Opcodes)) JR else JP, NoRegisters, Label(label).toAddress)
def jumpR(label: Label): ZLine = ZLine(JR, NoRegisters, label.toAddress)
def jumpR(ctx: CompilationContext, label: Label): ZLine = ZLine(if (ctx.options.flag(CompilationFlag.EmitExtended80Opcodes)) JR else JP, NoRegisters, label.toAddress)
def jumpR(label: String, condition: ZRegisters): ZLine = ZLine(JR, condition, Label(label).toAddress)
def jumpR(ctx: CompilationContext, label: String, condition: ZRegisters): ZLine = ZLine(if (ctx.options.flag(CompilationFlag.EmitExtended80Opcodes)) JR else JP, condition, Label(label).toAddress)
def jumpR(label: Label, condition: ZRegisters): ZLine = ZLine(JR, condition, label.toAddress)
def jumpR(ctx: CompilationContext, label: Label, condition: ZRegisters): ZLine = ZLine(if (ctx.options.flag(CompilationFlag.EmitExtended80Opcodes)) JR else JP, condition, label.toAddress)
def djnz(label: String): ZLine = ZLine(DJNZ, NoRegisters, Label(label).toAddress)
def djnz(ctx: CompilationContext, label: String): List[ZLine] =
if (ctx.options.flag(CompilationFlag.EmitZ80Opcodes)) List(ZLine(DJNZ, NoRegisters, Label(label).toAddress))
else List(ZLine.register(DEC, ZRegister.B), ZLine.jumpR(ctx, label, IfFlagClear(ZFlag.Z)))
def djnz(label: Label): ZLine = ZLine(DJNZ, NoRegisters, label.toAddress)
def djnz(ctx: CompilationContext, label: Label): List[ZLine] =
if (ctx.options.flag(CompilationFlag.EmitZ80Opcodes)) List(ZLine(DJNZ, NoRegisters, label.toAddress))
else List(ZLine.register(DEC, ZRegister.B), ZLine.jumpR(ctx, label, IfFlagClear(ZFlag.Z)))
def implied(opcode: ZOpcode.Value): ZLine = ZLine(opcode, NoRegisters, Constant.Zero)

View File

@ -22,6 +22,8 @@ object ZOpcode extends Enumeration {
EXX, EX_DE_HL, EX_AF_AF, EX_SP,
RST, IM, EI, DI,
DJNZ, JP, JR, CALL, RET, RETN, RETI, HALT,
//sharp:
LD_AHLI, LD_AHLD, LD_HLIA, LD_HLDA, SWAP, LD_H,
DISCARD_A, DISCARD_F, DISCARD_HL, DISCARD_BCDEIX,
LABEL, BYTE = Value
}

View File

@ -462,6 +462,12 @@ object AlwaysGoodZ80Optimizations {
ZLine.registers(code.last.opcode, ZRegister.HL, ZRegister.DE) :: code.take(2)
},
(Elidable & HasOpcode(INC) & HasRegisterParam(ZRegister.A)) ~
(Elidable & HasOpcode(ADD) & Has8BitImmediate(0xff) & DoesntMatterWhatItDoesWithFlags) ~~> (_ => Nil),
(Elidable & HasOpcode(NEG)) ~
(Elidable & HasOpcode(ADD) & Has8BitImmediate(0xff) & DoesntMatterWhatItDoesWithFlags) ~~> (_ => List(ZLine.implied(CPL))),
)
val FreeHL = new RuleBasedAssemblyOptimization("Free HL",

View File

@ -353,10 +353,7 @@ object Z80BulkMemoryOperations {
List(ZLine.implied(ldr.get))
} else {
ZLine.label(label) :: calculateSourceValue ++ (if (smallCount) {
List(
ZLine.register(next, if (useDEForTarget) ZRegister.DE else ZRegister.HL),
ZLine.djnz(label)
)
ZLine.register(next, if (useDEForTarget) ZRegister.DE else ZRegister.HL) :: ZLine.djnz(ctx, label)
} else {
List(
ZLine.register(next, if (useDEForTarget) ZRegister.DE else ZRegister.HL),

View File

@ -210,6 +210,16 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
case 1 => targetifyA(target, ZBuiltIns.compile8BitSum(ctx, params, decimal), isSigned = false)
case 2 => targetifyHL(target, ZBuiltIns.compile16BitSum(ctx, params, decimal))
}
case SeparateBytesExpression(h, l) =>
val hi = compileToA(ctx, h)
val lo = compileToA(ctx, l)
if (!lo.exists(x => x.changesRegister(ZRegister.H) || x.readsRegister(ZRegister.H))) {
hi ++ List(ZLine.ld8(ZRegister.H, ZRegister.A)) ++
lo ++ List(ZLine.ld8(ZRegister.L, ZRegister.A))
} else if (!hi.exists(x => x.changesRegister(ZRegister.L) || x.readsRegister(ZRegister.L))) {
lo ++ List(ZLine.ld8(ZRegister.L, ZRegister.A)) ++
hi ++ List(ZLine.ld8(ZRegister.H, ZRegister.A))
} else ???
case f@FunctionCallExpression(name, params) =>
name match {
case "not" =>
@ -423,20 +433,19 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
case 1 => ZBuiltIns.perform8BitInPlace(ctx, l, r, SUB, decimal = true)
case _ => ZBuiltIns.performLongInPlace(ctx, l, r, SUB, SBC, size, decimal = true)
}
Nil
case "<<=" =>
val (l, r, size) = assertArithmeticAssignmentLike(ctx, params)
size match {
case 1 => Z80Shifting.compile8BitShiftInPlace(ctx, l, r, left = true)
case 2 => Z80Shifting.compile16BitShift(ctx, l, r, left = true) ++ storeHL(ctx, l, signedSource = false)
case _ => ???
case _ => Z80Shifting.compileLongShiftInPlace(ctx, l, r, size, left = true)
}
case ">>=" =>
val (l, r, size) = assertArithmeticAssignmentLike(ctx, params)
size match {
case 1 => Z80Shifting.compile8BitShiftInPlace(ctx, l, r, left = false)
case 2 => Z80Shifting.compile16BitShift(ctx, l, r, left = false) ++ storeHL(ctx, l, signedSource = false)
case _ => ???
case _ => Z80Shifting.compileLongShiftInPlace(ctx, l, r, size, left = false)
}
case "<<'=" =>
val (l, r, size) = assertArithmeticAssignmentLike(ctx, params)

View File

@ -13,7 +13,7 @@ object Z80Multiply {
/**
* Compiles A = A * D
*/
private def multiplication(): List[ZLine] = {
private def multiplication(ctx: CompilationContext): List[ZLine] = {
import millfork.assembly.z80.ZOpcode._
import ZRegister._
import ZLine._
@ -23,15 +23,15 @@ object Z80Multiply {
List(
ld8(E, A),
ldImm8(A, 0),
jumpR(lblStart),
jumpR(ctx, lblStart),
label(lblAdd),
register(ADD, E),
label(lblLoop),
register(SLA, E),
label(lblStart),
register(SRL, D),
jumpR(lblAdd, IfFlagSet(ZFlag.C)),
jumpR(lblLoop, IfFlagClear(ZFlag.Z)))
jumpR(ctx, lblAdd, IfFlagSet(ZFlag.C)),
jumpR(ctx, lblLoop, IfFlagClear(ZFlag.Z)))
}
/**
@ -81,7 +81,7 @@ object Z80Multiply {
} else {
rb ++ List(ZLine.ld8(ZRegister.D, ZRegister.A)) ++ lb
}
load ++ multiplication()
load ++ multiplication(ctx)
}
}
@ -95,7 +95,7 @@ object Z80Multiply {
load ++ compile8BitMultiply(count.toInt) ++ store
case Some(c) =>
val (load, store) = Z80ExpressionCompiler.calculateLoadAndStoreForByte(ctx, l)
load ++ List(ZLine.ldImm8(ZRegister.D, c)) ++ multiplication() ++ store
load ++ List(ZLine.ldImm8(ZRegister.D, c)) ++ multiplication(ctx) ++ store
case _ =>
val (load, store) = Z80ExpressionCompiler.calculateLoadAndStoreForByte(ctx, l)
val rb = Z80ExpressionCompiler.compileToA(ctx, r)
@ -104,7 +104,7 @@ object Z80Multiply {
} else {
rb ++ List(ZLine.ld8(ZRegister.D, ZRegister.A)) ++ load
}
loadRegisters ++ multiplication() ++ store
loadRegisters ++ multiplication(ctx) ++ store
}
}

View File

@ -30,7 +30,7 @@ object Z80Shifting {
if (extendedOps) {
if (left) ZOpcode.SLA else ZOpcode.SRL
} else {
if (left) ZOpcode.RL else ZOpcode.RR
if (left) ZOpcode.RLC else ZOpcode.RRC
}
val l = Z80ExpressionCompiler.compileToA(ctx, lhs)
env.eval(rhs) match {
@ -47,7 +47,7 @@ object Z80Shifting {
val l = Z80ExpressionCompiler.stashBCIfChanged(Z80ExpressionCompiler.compileToA(ctx, lhs))
val loopBody = ZLine.register(op, ZRegister.A) :: fixAfterShiftIfNeeded(extendedOps, left, 1)
val label = Z80Compiler.nextLabel("sh")
calcCount ++ l ++ List(ZLine.label(label)) ++ loopBody :+ ZLine.djnz(label)
calcCount ++ l ++ List(ZLine.label(label)) ++ loopBody ++ ZLine.djnz(ctx, label)
}
}
@ -58,7 +58,7 @@ object Z80Shifting {
if (extendedOps) {
if (left) ZOpcode.SLA else ZOpcode.SRL
} else {
if (left) ZOpcode.RL else ZOpcode.RR
if (left) ZOpcode.RLC else ZOpcode.RRC
}
env.eval(rhs) match {
case Some(NumericConstant(i, _)) =>
@ -101,7 +101,7 @@ object Z80Shifting {
val l = Z80ExpressionCompiler.stashBCIfChanged(Z80ExpressionCompiler.compileToA(ctx, lhs))
val loopBody = ZLine.register(op, ZRegister.A) :: fixAfterShiftIfNeeded(extendedOps, left, 1)
val label = Z80Compiler.nextLabel("sh")
calcCount ++ l ++ List(ZLine.label(label)) ++ loopBody ++ List(ZLine.djnz(label)) ++ Z80ExpressionCompiler.storeA(ctx, lhs, signedSource = false)
calcCount ++ l ++ List(ZLine.label(label)) ++ loopBody ++ ZLine.djnz(ctx, label) ++ Z80ExpressionCompiler.storeA(ctx, lhs, signedSource = false)
}
}
@ -182,13 +182,14 @@ object Z80Shifting {
}
}
val label = Z80Compiler.nextLabel("sh")
calcCount ++ l ++ List(ZLine.label(label)) ++ loopBody :+ ZLine.djnz(label)
calcCount ++ l ++ List(ZLine.label(label)) ++ loopBody ++ ZLine.djnz(ctx, label)
}
}
def compileNonetShiftRight(ctx: CompilationContext, rhs: Expression): List[ZLine] = {
import ZOpcode._
import ZRegister._
val extended = ctx.options.flag(CompilationFlag.EmitExtended80Opcodes)
ctx.env.eval(rhs) match {
case Some(NumericConstant(0, _)) =>
List(ZLine.ld8(A, L))
@ -198,11 +199,17 @@ object Z80Shifting {
case Some(NumericConstant(n, _)) if n >= 9 =>
List(ZLine.ldImm8(A, 0))
case Some(NumericConstant(1, _)) =>
List(ZLine.register(SRL, H), ZLine.ld8(A, L), ZLine.register(RR, A))
case Some(NumericConstant(2, _)) =>
List(ZLine.register(SRL, H), ZLine.ld8(A, L), ZLine.register(RR, A), ZLine.register(SRL, A))
if (extended)
List(ZLine.register(SRL, H), ZLine.ld8(A, L), ZLine.register(RR, A))
else
List(ZLine.ld8(A, H), ZLine.register(RR, A), ZLine.ld8(A, L), ZLine.register(RR, A))
case Some(NumericConstant(2, _)) if extended=>
List(ZLine.register(SRL, H), ZLine.ld8(A, L), ZLine.register(RR, A), ZLine.register(SRL, A))
case Some(NumericConstant(n, _)) =>
List(ZLine.register(SRL, H), ZLine.ld8(A, L)) ++ (List.fill(n.toInt)(ZLine.register(RR, A)) :+ ZLine.imm8(AND, 0x1ff >> n))
if (extended)
List(ZLine.register(SRL, H), ZLine.ld8(A, L)) ++ (List.fill(n.toInt)(ZLine.register(RR, A)) :+ ZLine.imm8(AND, 0x1ff >> n))
else
List(ZLine.ld8(A, H), ZLine.register(RR, A), ZLine.ld8(A, L)) ++ (List.fill(n.toInt)(ZLine.register(RR, A)) :+ ZLine.imm8(AND, 0x1ff >> n))
case _ =>
ErrorReporting.error("Non-constant shift amount", rhs.position) // TODO
@ -210,4 +217,45 @@ object Z80Shifting {
}
}
def compileLongShiftInPlace(ctx: CompilationContext, lhs: LhsExpression, rhs: Expression, size: Int, left: Boolean): List[ZLine] = {
val extended = ctx.options.flag(CompilationFlag.EmitExtended80Opcodes)
val store = Z80ExpressionCompiler.compileByteStores(ctx, lhs, size)
val loadLeft = Z80ExpressionCompiler.compileByteReads(ctx, lhs, size, ZExpressionTarget.HL)
val shiftOne = if (left) {
loadLeft.zip(store).zipWithIndex.flatMap {
case ((ld, st), ix) =>
import ZOpcode._
import ZRegister._
val shiftByte = if (ix == 0) {
if (extended) List(ZLine.register(SLA, A))
else List(ZLine.register(RL, A), ZLine.imm8(AND, 0xfe))
} else List(ZLine.register(RL, A))
ld ++ shiftByte ++ st
}
} else {
loadLeft.reverse.zip(store.reverse).zipWithIndex.flatMap {
case ((ld, st), ix) =>
import ZOpcode._
import ZRegister._
val shiftByte = if (ix == 0) {
if (extended) List(ZLine.register(SRL, A))
else List(ZLine.register(RR, A), ZLine.imm8(AND, 0x7f))
} else List(ZLine.register(RR, A))
ld ++ shiftByte ++ st
}
}
ctx.env.eval(rhs) match {
case Some(NumericConstant(0, _)) => Nil
case Some(NumericConstant(n, _)) if n < 0 =>
ErrorReporting.error("Negative shift amount", rhs.position) // TODO
Nil
case Some(NumericConstant(n, _)) =>
List.fill(n.toInt)(shiftOne).flatten
case _ =>
val label = Z80Compiler.nextLabel("sh")
val calcCount = Z80ExpressionCompiler.compileToA(ctx, rhs) :+ ZLine.ld8(ZRegister.B, ZRegister.A)
calcCount ++ List(ZLine.label(label)) ++ shiftOne ++ ZLine.djnz(ctx, label)
}
}
}

View File

@ -120,6 +120,7 @@ object ZBuiltIns {
ctx.env.eval(expr) match {
case None =>
if (result.isEmpty) {
if (decimal) ???
result ++= Z80ExpressionCompiler.compileToA(ctx, expr)
if (ctx.options.flag(CompilationFlag.EmitExtended80Opcodes)) {
result += ZLine.implied(NEG)
@ -148,9 +149,19 @@ object ZBuiltIns {
}
}
if (hasConst) {
result += ZLine.imm8(ADD, const.loByte)
if (decimal) {
result += ZLine.implied(DAA)
const match {
case CompoundConstant(MathOperator.DecimalMinus | MathOperator.Minus, NumericConstant(0, _), c) =>
result += ZLine.imm8(SUB, c.loByte)
if (decimal) {
result += ZLine.implied(DAA)
}
case NumericConstant(n, _) if n < 0 && !decimal =>
result += ZLine.imm8(SUB, (-n.toInt) & 0xff)
case _ =>
result += ZLine.imm8(ADD, const.loByte)
if (decimal) {
result += ZLine.implied(DAA)
}
}
}
result.toList

View File

@ -30,6 +30,6 @@ class MemoryBank {
var end: Int = 0
def dump(startAddr: Int, count: Int)(dumper: String => Any): Unit = {
(0 until count).map(i => output(i + startAddr)).grouped(16).zipWithIndex.map { case (c, i) => f"$i%04X: " + c.map(i => f"$i%02x").mkString(" ") }.foreach(dumper)
(0 until count).map(i => (i + startAddr) -> output(i + startAddr)).grouped(16).zipWithIndex.map { case (c, i) => f"${c.head._1}%04X: " + c.map(i => f"${i._2}%02x").mkString(" ") }.foreach(dumper)
}
}

View File

@ -1,6 +1,6 @@
package millfork.output
import millfork.{CompilationOptions, Platform}
import millfork.{CompilationFlag, CompilationOptions, Cpu, Platform}
import millfork.assembly.z80._
import millfork.compiler.z80.Z80Compiler
import millfork.env._
@ -44,6 +44,25 @@ class Z80Assembler(program: Program,
import millfork.assembly.z80.ZOpcode._
import ZRegister._
import Z80Assembler._
import CompilationFlag._
def requireIntel8080(): Unit = if (!options.flag(EmitIntel8080Opcodes)) ErrorReporting.error("Unsupported instruction: " + instr)
def requireZ80(): Unit = if (!options.flag(EmitZ80Opcodes)) ErrorReporting.error("Unsupported instruction: " + instr)
def requireZ80Illegals(): Unit = if (!options.flag(EmitZ80Opcodes) || !options.flag(EmitIllegals)) ErrorReporting.error("Unsupported instruction: " + instr)
def requireExtended80(): Unit = if (!options.flag(EmitExtended80Opcodes)) ErrorReporting.error("Unsupported instruction: " + instr)
def requireSharp(): Unit = if (!options.flag(EmitSharpOpcodes)) ErrorReporting.error("Unsupported instruction: " + instr)
def requireEZ80(): Unit = if (!options.flag(EmitEZ80Opcodes)) ErrorReporting.error("Unsupported instruction: " + instr)
def useSharpOpcodes():Boolean = {
if (!options.flag(EmitSharpOpcodes) && !options.flag(EmitIntel8080Opcodes))
ErrorReporting.error("Cannot determine which variant to emit : " + instr)
options.flag(EmitSharpOpcodes)
}
instr match {
case ZLine(LABEL, NoRegisters, MemoryAddressConstant(Label(labelName)), _) =>
labelMap(labelName) = index
@ -63,6 +82,7 @@ class Z80Assembler(program: Program,
writeByte(bank, index, opcode)
index + 1
case ZLine(IM, NoRegisters, param, _) =>
requireZ80()
val opcode = param.quickSimplify match {
case NumericConstant(0, _) => 0x46
case NumericConstant(1, _) => 0x56
@ -73,13 +93,33 @@ class Z80Assembler(program: Program,
writeByte(bank, index + 1, opcode)
index + 2
case ZLine(op, OneRegister(reg), _, _) if ZOpcodeClasses.AllSingleBit(op) =>
requireExtended80()
writeByte(bank, index, 0xcb)
writeByte(bank, index + 1, ZOpcodeClasses.singleBitOpcode(op) + internalRegisterIndex(reg))
index + 2
case ZLine(op, NoRegisters, _, _) if implieds.contains(op) =>
writeByte(bank, index, implieds(op))
index + 1
case ZLine(EXX, NoRegisters, _, _)=>
requireZ80()
writeByte(bank, index, 0xd9)
index + 1
case ZLine(EX_AF_AF, NoRegisters, _, _)=>
requireZ80()
writeByte(bank, index, 8)
index + 1
case ZLine(RETI, NoRegisters, _, _) =>
requireExtended80()
if (useSharpOpcodes()) {
writeByte(bank, index, 0xd9)
index + 1
} else {
writeByte(bank, index, 0xed)
writeByte(bank, index + 1, 0x4d)
index + 2
}
case ZLine(op, NoRegisters, _, _) if edImplieds.contains(op) =>
requireZ80()
writeByte(bank, index, 0xed)
writeByte(bank, index + 1, edImplieds(op))
index + 2
@ -87,6 +127,7 @@ class Z80Assembler(program: Program,
writeByte(bank, index, 9 + 16 * internalRegisterIndex(source))
index + 1
case ZLine(ADD_16, TwoRegisters(ix@(ZRegister.IX | ZRegister.IY), source@(ZRegister.IX | ZRegister.IY)), _, _)=>
requireZ80()
if (ix == source) {
writeByte(bank, index, prefixByte(ix))
writeByte(bank, index + 1, 9 + 16 * internalRegisterIndex(HL))
@ -96,6 +137,7 @@ class Z80Assembler(program: Program,
index
}
case ZLine(ADD_16, TwoRegisters(ix@(ZRegister.IX | ZRegister.IY), source), _, _) =>
requireZ80()
writeByte(bank, index, prefixByte(ix))
writeByte(bank, index + 1, 9 + 16 * internalRegisterIndex(source))
index + 2
@ -108,6 +150,7 @@ class Z80Assembler(program: Program,
writeByte(bank, index + 1, 0x42 + 0x10 * internalRegisterIndex(reg))
index + 2
case ZLine(LD_16, TwoRegisters(ix@(ZRegister.IX | ZRegister.IY), ZRegister.IMM_16), param, _) =>
requireZ80()
writeByte(bank, index, prefixByte(ix))
writeByte(bank, index + 1, 0x21)
writeWord(bank, index + 2, param)
@ -117,29 +160,47 @@ class Z80Assembler(program: Program,
writeWord(bank, index + 1, param)
index + 3
case ZLine(LD_16, TwoRegisters(ix@(ZRegister.IX | ZRegister.IY), ZRegister.MEM_ABS_16), param, _) =>
requireZ80()
writeByte(bank, index, prefixByte(ix))
writeByte(bank, index + 1, 0x2a)
writeWord(bank, index + 2, param)
index + 4
case ZLine(LD_16, TwoRegisters(ZRegister.MEM_ABS_16, ix@(ZRegister.IX | ZRegister.IY)), param, _) =>
requireZ80()
writeByte(bank, index, prefixByte(ix))
writeByte(bank, index + 1, 0x22)
writeWord(bank, index + 2, param)
index + 4
case ZLine(LD_16, TwoRegisters(ZRegister.HL, ZRegister.MEM_ABS_16), param, _) =>
requireIntel8080()
writeByte(bank, index, 0x2a)
writeWord(bank, index + 1, param)
index + 3
case ZLine(LD_16, TwoRegisters(ZRegister.MEM_ABS_16, ZRegister.HL), param, _) =>
requireIntel8080()
writeByte(bank, index, 0x22)
writeWord(bank, index + 1, param)
index + 3
case ZLine(LD_16, TwoRegisters(reg@(ZRegister.BC | ZRegister.DE | ZRegister.SP), ZRegister.MEM_ABS_16), param, _) =>
requireZ80()
writeByte(bank, index, 0xed)
writeByte(bank, index+1, 0x4b + 0x10 * internalRegisterIndex(reg))
writeWord(bank, index + 2, param)
index + 4
case ZLine(LD_16, TwoRegisters(ZRegister.MEM_ABS_16, reg@(ZRegister.BC | ZRegister.DE | ZRegister.SP)), param, _) =>
case ZLine(LD_16, TwoRegisters(ZRegister.MEM_ABS_16, ZRegister.SP), param, _) =>
requireExtended80()
if (useSharpOpcodes()) {
writeByte(bank, index, 8)
writeWord(bank, index + 1, param)
index + 3
} else {
writeByte(bank, index, 0xed)
writeByte(bank, index + 1, 0x43 + 0x10 * internalRegisterIndex(SP))
writeWord(bank, index + 2, param)
index + 4
}
case ZLine(LD_16, TwoRegisters(ZRegister.MEM_ABS_16, reg@(ZRegister.BC | ZRegister.DE)), param, _) =>
requireZ80()
writeByte(bank, index, 0xed)
writeByte(bank, index+1, 0x43 + 0x10 * internalRegisterIndex(reg))
writeWord(bank, index + 2, param)
@ -148,6 +209,7 @@ class Z80Assembler(program: Program,
writeByte(bank, index, 0xF9)
index + 1
case ZLine(LD_16, TwoRegisters(ZRegister.SP, ix@(ZRegister.IX | ZRegister.IY)), _, _) =>
requireZ80()
writeByte(bank, index, prefixByte(ix))
writeByte(bank, index + 1, 0xF9)
index + 2
@ -157,18 +219,21 @@ class Z80Assembler(program: Program,
writeByte(bank, index + 1, param)
index + 2
case ZLine(op, OneRegisterOffset(ix@(ZRegister.MEM_IX_D | ZRegister.MEM_IY_D), offset), _, _) if ZOpcodeClasses.AllSingleBit(op) =>
requireZ80()
writeByte(bank, index, prefixByte(ix))
writeByte(bank, index + 1, 0xcb)
writeByte(bank, index + 2, offset)
writeByte(bank, index + 3, ZOpcodeClasses.singleBitOpcode(op) + internalRegisterIndex(ZRegister.MEM_HL))
index + 4
case ZLine(op, OneRegisterOffset(ix@(ZRegister.MEM_IX_D | ZRegister.MEM_IY_D), offset), _, _) if oneRegister.contains(op) =>
requireZ80()
val o = oneRegister(op)
writeByte(bank, index, prefixByte(ix))
writeByte(bank, index + 1, o.opcode + internalRegisterIndex(ZRegister.MEM_HL) * o.multiplier)
writeByte(bank, index + 2, offset)
index + 3
case ZLine(op, OneRegister(ix@(ZRegister.IX | ZRegister.IY)), _, _) if oneRegister.contains(op) =>
requireZ80()
val o = oneRegister(op)
writeByte(bank, index, prefixByte(ix))
writeByte(bank, index + 1, o.opcode + internalRegisterIndex(ZRegister.HL) * o.multiplier)
@ -181,12 +246,31 @@ class Z80Assembler(program: Program,
case ZLine(op@(RR|RRC|RL|RLC), OneRegister(A), _, _) =>
writeByte(bank, index, cbOneRegister(op).opcode + 7)
index + 1
case ZLine(SLL, OneRegister(reg), _, _) =>
requireZ80Illegals()
writeByte(bank, index, 0xcb)
writeByte(bank, index + 1, 0x30 + internalRegisterIndex(reg))
index + 2
case ZLine(SWAP, OneRegister(reg), _, _) =>
requireSharp()
writeByte(bank, index, 0xcb)
writeByte(bank, index + 1, 0x30 + internalRegisterIndex(reg))
index + 2
case ZLine(SLL, OneRegisterOffset(ix@(ZRegister.MEM_IX_D | ZRegister.MEM_IY_D), offset), _, _) =>
requireZ80Illegals()
writeByte(bank, index, prefixByte(ix))
writeByte(bank, index + 1, 0xcb)
writeByte(bank, index + 2, offset)
writeByte(bank, index + 3, 0x30 + internalRegisterIndex(MEM_HL))
index + 4
case ZLine(op, OneRegister(reg), _, _) if cbOneRegister.contains(op) =>
requireExtended80()
val o = cbOneRegister(op)
writeByte(bank, index, 0xcb)
writeByte(bank, index + 1, o.opcode + internalRegisterIndex(reg) * o.multiplier)
index + 2
case ZLine(op, OneRegisterOffset(ix@(ZRegister.MEM_IX_D | ZRegister.MEM_IY_D), offset), _, _) if cbOneRegister.contains(op) =>
requireZ80()
val o = cbOneRegister(op)
writeByte(bank, index, prefixByte(ix))
writeByte(bank, index + 1, 0xcb)
@ -196,18 +280,22 @@ class Z80Assembler(program: Program,
case ZLine(LD, registers, _, _) =>
registers match {
case TwoRegisters(I, A) =>
requireZ80()
writeByte(bank, index, 0xed)
writeByte(bank, index + 1, 0x47)
index + 2
case TwoRegisters(A, I) =>
requireZ80()
writeByte(bank, index, 0xed)
writeByte(bank, index + 1, 0x57)
index + 2
case TwoRegisters(R, A) =>
requireZ80()
writeByte(bank, index, 0xed)
writeByte(bank, index + 1, 0x4f)
index + 2
case TwoRegisters(A, R) =>
requireZ80()
writeByte(bank, index, 0xed)
writeByte(bank, index + 1, 0x5f)
index + 2
@ -219,17 +307,26 @@ class Z80Assembler(program: Program,
writeByte(bank, index + 1, instr.parameter)
index + 2
case TwoRegistersOffset(ix@(ZRegister.MEM_IX_D | ZRegister.MEM_IY_D), ZRegister.IMM_8, offset) =>
requireZ80()
writeByte(bank, index, prefixByte(ix))
writeByte(bank, index + 1, 0x36)
writeByte(bank, index + 2, offset)
writeByte(bank, index + 3, instr.parameter)
index + 4
case TwoRegisters(ZRegister.A, ZRegister.MEM_ABS_8) =>
writeByte(bank, index, 0x3a)
if (useSharpOpcodes()) {
writeByte(bank, index, 0xfa)
} else {
writeByte(bank, index, 0x3a)
}
writeWord(bank, index + 1, instr.parameter)
index + 3
case TwoRegisters(ZRegister.MEM_ABS_8, ZRegister.A) =>
writeByte(bank, index, 0x32)
if (useSharpOpcodes()) {
writeByte(bank, index, 0xea)
} else {
writeByte(bank, index, 0x32)
}
writeWord(bank, index + 1, instr.parameter)
index + 3
case TwoRegisters(ZRegister.MEM_BC, ZRegister.A) =>
@ -262,18 +359,22 @@ class Z80Assembler(program: Program,
index + 1
}
case ZLine(IN_IMM, OneRegister(ZRegister.A), param, _) =>
requireIntel8080()
writeByte(bank, index, 0xdb)
writeByte(bank, index + 1, param)
index + 2
case ZLine(IN_C, OneRegister(reg), param, _) =>
requireZ80()
writeByte(bank, index, 0xed)
writeByte(bank, index + 1, 0x40 + 8 * internalRegisterIndex(reg))
index + 2
case ZLine(OUT_IMM, OneRegister(ZRegister.A), param, _) =>
requireIntel8080()
writeByte(bank, index, 0xd3)
writeByte(bank, index + 1, param)
index + 2
case ZLine(OUT_C, OneRegister(reg), param, _) =>
requireZ80()
writeByte(bank, index, 0xed)
writeByte(bank, index + 1, 0x41 + 8 * internalRegisterIndex(reg))
index + 2
@ -286,35 +387,43 @@ class Z80Assembler(program: Program,
case ZLine(CALL, IfFlagClear(ZFlag.Z), param, _) =>
requireIntel8080()
writeByte(bank, index, 0xc4)
writeWord(bank, index + 1, param)
index + 3
case ZLine(CALL, IfFlagClear(ZFlag.C), param, _) =>
requireIntel8080()
writeByte(bank, index, 0xd4)
writeWord(bank, index + 1, param)
index + 3
case ZLine(CALL, IfFlagClear(ZFlag.P), param, _) =>
requireIntel8080()
writeByte(bank, index, 0xe4)
writeWord(bank, index + 1, param)
index + 3
case ZLine(CALL, IfFlagClear(ZFlag.S), param, _) =>
requireIntel8080()
writeByte(bank, index, 0xf4)
writeWord(bank, index + 1, param)
index + 3
case ZLine(CALL, IfFlagSet(ZFlag.Z), param, _) =>
requireIntel8080()
writeByte(bank, index, 0xcc)
writeWord(bank, index + 1, param)
index + 3
case ZLine(CALL, IfFlagSet(ZFlag.C), param, _) =>
requireIntel8080()
writeByte(bank, index, 0xdc)
writeWord(bank, index + 1, param)
index + 3
case ZLine(CALL, IfFlagSet(ZFlag.P), param, _) =>
requireIntel8080()
writeByte(bank, index, 0xec)
writeWord(bank, index + 1, param)
index + 3
case ZLine(CALL, IfFlagSet(ZFlag.S), param, _) =>
requireIntel8080()
writeByte(bank, index, 0xfc)
writeWord(bank, index + 1, param)
index + 3
@ -333,10 +442,12 @@ class Z80Assembler(program: Program,
writeWord(bank, index + 1, param)
index + 3
case ZLine(JP, IfFlagClear(ZFlag.P), param, _) =>
requireIntel8080()
writeByte(bank, index, 0xe2)
writeWord(bank, index + 1, param)
index + 3
case ZLine(JP, IfFlagClear(ZFlag.S), param, _) =>
requireIntel8080()
writeByte(bank, index, 0xf2)
writeWord(bank, index + 1, param)
index + 3
@ -350,10 +461,12 @@ class Z80Assembler(program: Program,
writeWord(bank, index + 1, param)
index + 3
case ZLine(JP, IfFlagSet(ZFlag.P), param, _) =>
requireIntel8080()
writeByte(bank, index, 0xea)
writeWord(bank, index + 1, param)
index + 3
case ZLine(JP, IfFlagSet(ZFlag.S), param, _) =>
requireIntel8080()
writeByte(bank, index, 0xfa)
writeWord(bank, index + 1, param)
index + 3
@ -361,78 +474,98 @@ class Z80Assembler(program: Program,
writeByte(bank, index, 0xe9)
index + 1
case ZLine(JP, OneRegister(IX), _, _) =>
requireZ80()
writeByte(bank, index, 0xdd)
writeByte(bank, index, 0xe9)
index + 2
case ZLine(JP, OneRegister(IY), _, _) =>
requireZ80()
writeByte(bank, index, 0xfd)
writeByte(bank, index, 0xe9)
index + 2
case ZLine(RET, IfFlagClear(ZFlag.Z), _, _) =>
requireIntel8080()
writeByte(bank, index, 0xc0)
index + 1
case ZLine(RET, IfFlagClear(ZFlag.C), _, _) =>
requireIntel8080()
writeByte(bank, index, 0xd0)
index + 1
case ZLine(RET, IfFlagClear(ZFlag.P), _, _) =>
requireIntel8080()
writeByte(bank, index, 0xe0)
index + 1
case ZLine(RET, IfFlagClear(ZFlag.S), _, _) =>
requireIntel8080()
writeByte(bank, index, 0xf0)
index + 1
case ZLine(RET, IfFlagSet(ZFlag.Z), _, _) =>
requireIntel8080()
writeByte(bank, index, 0xc8)
index + 1
case ZLine(RET, IfFlagSet(ZFlag.C), _, _) =>
requireIntel8080()
writeByte(bank, index, 0xd8)
index + 1
case ZLine(RET, IfFlagSet(ZFlag.P), _, _) =>
requireIntel8080()
writeByte(bank, index, 0xe8)
index + 1
case ZLine(RET, IfFlagSet(ZFlag.S), _, _) =>
requireIntel8080()
writeByte(bank, index, 0xf8)
index + 1
case ZLine(JR, IfFlagClear(ZFlag.Z), param, _) =>
requireExtended80()
writeByte(bank, index, 0x20)
writeByte(bank, index + 1, AssertByte(param - index - 2))
index + 2
case ZLine(JR, IfFlagClear(ZFlag.C), param, _) =>
requireExtended80()
writeByte(bank, index, 0x30)
writeByte(bank, index + 1, AssertByte(param - index - 2))
index + 2
case ZLine(JR, IfFlagSet(ZFlag.Z), param, _) =>
requireExtended80()
writeByte(bank, index, 0x28)
writeByte(bank, index + 1, AssertByte(param - index - 2))
index + 2
case ZLine(JR, IfFlagSet(ZFlag.C), param, _) =>
requireExtended80()
writeByte(bank, index, 0x38)
writeByte(bank, index + 1, AssertByte(param - index - 2))
index + 2
case ZLine(JR, NoRegisters, param, _) =>
requireExtended80()
writeByte(bank, index, 0x18)
writeByte(bank, index + 1, AssertByte(param - index - 2))
index + 2
case ZLine(DJNZ, NoRegisters, param, _) =>
requireZ80()
writeByte(bank, index, 0x10)
writeByte(bank, index + 1, AssertByte(param - index - 2))
index + 2
case ZLine(EX_SP, OneRegister(HL), _, _) =>
requireIntel8080()
writeByte(bank, index, 0xe3)
index + 1
case ZLine(EX_SP, OneRegister(IX), _, _) =>
requireZ80()
writeByte(bank, index, 0xdd)
writeByte(bank, index + 1, 0xe3)
index + 2
case ZLine(EX_SP, OneRegister(IY), _, _) =>
requireZ80()
writeByte(bank, index, 0xfd)
writeByte(bank, index + 1, 0xe3)
index + 2
case ZLine(EX_DE_HL, _, _, _) =>
requireIntel8080()
writeByte(bank, index, 0xeb)
index + 1
case _ =>
@ -463,11 +596,9 @@ object Z80Assembler {
implieds(NOP) = 0
implieds(DAA) = 0x27
implieds(SCF) = 0x37
implieds(CPL) = 0x37
implieds(CPL) = 0x2f
implieds(CCF) = 0x3f
implieds(EX_AF_AF) = 8
implieds(RET) = 0xc9
implieds(EXX) = 0xd9
implieds(EI) = 0xfb
implieds(DI) = 0xf3
implieds(HALT) = 0x76
@ -525,7 +656,6 @@ object Z80Assembler {
cbOneRegister(RR) = One(0x18, 1)
cbOneRegister(SLA) = One(0x20, 1)
cbOneRegister(SRA) = One(0x28, 1)
cbOneRegister(SLL) = One(0x30, 1)
cbOneRegister(SRL) = One(0x38, 1)
} while (false)

View File

@ -10,7 +10,7 @@ import org.scalatest.{FunSuite, Matchers}
class AlgorithmSuite extends FunSuite with Matchers {
test("RLE decoding") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| array output [4000] @$c000
| array input = [

View File

@ -175,7 +175,7 @@ class ArraySuite extends FunSuite with Matchers {
}
test("Syntax") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80)(
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| array a = [1, 2, 3]
| array b = "text" ascii
@ -187,7 +187,7 @@ class ArraySuite extends FunSuite with Matchers {
}
test("Negative subindex") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80)(
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
|
| array output [$fff] @$c000
@ -199,6 +199,7 @@ class ArraySuite extends FunSuite with Matchers {
| }
| noinline byte one() {return 1}
""".stripMargin) { m =>
m.dump(0xbf00, 0x200)(println(_))
m.readByte(0xc100) should equal(55)
m.readByte(0xc000) should equal(5)
}

View File

@ -11,7 +11,7 @@ import org.scalatest.{FunSuite, Matchers}
class AssemblyOptimizationSuite extends FunSuite with Matchers {
test("Duplicate RTS") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| void main () {
| if 1 == 1 {
@ -22,7 +22,7 @@ class AssemblyOptimizationSuite extends FunSuite with Matchers {
}
test("Inlining variable") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| array output [5] @$C000
| void main () {
@ -37,7 +37,7 @@ class AssemblyOptimizationSuite extends FunSuite with Matchers {
}
test("Inlining variable 2") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| array output [100] @$C000
| void main () {
@ -52,7 +52,7 @@ class AssemblyOptimizationSuite extends FunSuite with Matchers {
}
test("Loading modified variables") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$C000
| void main () {
@ -68,7 +68,7 @@ class AssemblyOptimizationSuite extends FunSuite with Matchers {
}
test("Bit ops") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$C000
| void main () {
@ -82,7 +82,7 @@ class AssemblyOptimizationSuite extends FunSuite with Matchers {
}
test("Inlining after a while") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| array output [2]@$C000
| void main () {
@ -99,7 +99,7 @@ class AssemblyOptimizationSuite extends FunSuite with Matchers {
}
test("Tail call") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$C000
| void main () {
@ -304,7 +304,7 @@ class AssemblyOptimizationSuite extends FunSuite with Matchers {
}
test("Adding a nonet") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| word output @$C000
| byte source @$C002
@ -323,7 +323,7 @@ class AssemblyOptimizationSuite extends FunSuite with Matchers {
}
test("Common indexing subexpression elimination") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| array output [55] @$C000
| array input = [0,1,2,3,4,5,6,7,8,9,10]
@ -342,7 +342,7 @@ class AssemblyOptimizationSuite extends FunSuite with Matchers {
}
test("Effectively const variable") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
|byte output @$c000
|void main() {
@ -410,7 +410,7 @@ class AssemblyOptimizationSuite extends FunSuite with Matchers {
}
test("Constant pointers") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
|byte output0 @$c000
|byte output1 @$c001
@ -430,7 +430,7 @@ class AssemblyOptimizationSuite extends FunSuite with Matchers {
}
test("Low bit") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| void main() {
@ -449,7 +449,7 @@ class AssemblyOptimizationSuite extends FunSuite with Matchers {
}
test("Low bit 2") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| void main() {
@ -468,7 +468,7 @@ class AssemblyOptimizationSuite extends FunSuite with Matchers {
}
test("Low bit 3") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| void main() {
@ -490,7 +490,7 @@ class AssemblyOptimizationSuite extends FunSuite with Matchers {
}
test("Low bit 4") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| void main() {
@ -530,7 +530,7 @@ class AssemblyOptimizationSuite extends FunSuite with Matchers {
}
test("Shift and increase") {
EmuBenchmarkRun(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| void main() {
@ -546,7 +546,7 @@ class AssemblyOptimizationSuite extends FunSuite with Matchers {
}
test("Add one bit") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| void main() {

View File

@ -9,7 +9,7 @@ import org.scalatest.{FunSuite, Matchers}
*/
class BasicSymonTest extends FunSuite with Matchers {
test("Empty test") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80)(
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| void main () {
|
@ -80,11 +80,13 @@ class BasicSymonTest extends FunSuite with Matchers {
output += 1
}
"""
EmuUnoptimizedRun(src).readByte(0xc000) should equal(src.count(_ == '+'))
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(src){m =>
m.readByte(0xc000) should equal(src.count(_ == '+'))
}
}
test("Byte assignment") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80)(
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| void main () {
@ -96,7 +98,7 @@ class BasicSymonTest extends FunSuite with Matchers {
}
test("Preallocated variables") {
val m = EmuUnoptimizedRun(
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| array output [2] @$c000
| byte number = 4
@ -105,13 +107,14 @@ class BasicSymonTest extends FunSuite with Matchers {
| number += 1
| output[1] = number
| }
""".stripMargin)
m.readByte(0xc000) should equal(4)
m.readByte(0xc001) should equal(5)
""".stripMargin) { m =>
m.readByte(0xc000) should equal(4)
m.readByte(0xc001) should equal(5)
}
}
test("Preallocated variables 2") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80)(
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| word output @$c000
| word number = 344
@ -124,7 +127,7 @@ class BasicSymonTest extends FunSuite with Matchers {
}
test("Else if") {
val m = EmuUnoptimizedRun(
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| void main () {
@ -136,12 +139,13 @@ class BasicSymonTest extends FunSuite with Matchers {
| output = 65
| }
| }
""".stripMargin)
""".stripMargin) { m =>
m.readWord(0xc000) should equal(4)
}
}
test("Segment syntax") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80)(
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| segment(default)byte output @$c000
| segment(default)array x[3]
@ -151,7 +155,7 @@ class BasicSymonTest extends FunSuite with Matchers {
}
test("Alias test") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos)(
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| alias small = byte
| alias big = word
@ -170,12 +174,12 @@ class BasicSymonTest extends FunSuite with Matchers {
}
test("Preprocessor test") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80)(
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
|
| #use ARCH_6502
| #use ARCH_Z80
| #use ARCH_I80
|
| #if 1
| asm void main () {
@ -183,8 +187,8 @@ class BasicSymonTest extends FunSuite with Matchers {
| lda #ARCH_6502
| sta output
| rts
| #elseif ARCH_Z80
| ld a,ARCH_Z80
| #elseif ARCH_I80
| ld a,ARCH_I80
| ld (output),a
| ret
| #else

View File

@ -10,7 +10,7 @@ import org.scalatest.{FunSuite, Matchers}
class BitOpSuite extends FunSuite with Matchers {
test("Word AND") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| word output @$c000
| void main () {
| byte b
@ -21,7 +21,7 @@ class BitOpSuite extends FunSuite with Matchers {
""".stripMargin)(_.readWord(0xc000) should equal(0x44))
}
test("Long AND and EOR") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| long output @$c000
| void main () {
| byte b
@ -36,7 +36,7 @@ class BitOpSuite extends FunSuite with Matchers {
}
test("Smart bit set/reset") {
EmuCrossPlatformBenchmarkRun(Cpu.Cmos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Cmos, Cpu.Z80, Cpu.Intel8080)("""
| byte output @$c000
| void main () {
| output = 5
@ -50,7 +50,7 @@ class BitOpSuite extends FunSuite with Matchers {
}
test("Smart bit set/reset 2") {
EmuCrossPlatformBenchmarkRun(Cpu.Cmos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Cmos, Cpu.Z80, Cpu.Intel8080)("""
| byte output @$c000
| void main () {
| output = 5

View File

@ -11,7 +11,7 @@ import org.scalatest.{FunSuite, Matchers}
class BitPackingSuite extends FunSuite with Matchers {
test("Unpack bits from a byte") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| array output[8]
| word output_addr @$c000
| void main () {
@ -40,7 +40,7 @@ class BitPackingSuite extends FunSuite with Matchers {
}
test("Unpack bits from a word") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| array output[16]
| word output_addr @$c000
| void main () {
@ -77,7 +77,7 @@ class BitPackingSuite extends FunSuite with Matchers {
}
test("Pack bits into byte") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| byte output @$C000
| array input = [$F0, 1, 0, $41, $10, 1, $61, 0]
| void main () {
@ -94,7 +94,7 @@ class BitPackingSuite extends FunSuite with Matchers {
}
test("Pack bits into word") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| word output @$C000
| array input = [$F0, 1, 0, $41, $10, 1, $61, 0,
| 1, 1, 0, 0, 0, 0, 1, 1]
@ -112,7 +112,7 @@ class BitPackingSuite extends FunSuite with Matchers {
}
test("Pack bits into byte using plus") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| byte output @$C000
| array input = [$F0, 1, 0, $41, $10, 1, $61, 0]
| void main () {
@ -129,7 +129,7 @@ class BitPackingSuite extends FunSuite with Matchers {
}
test("Reverse byte") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| word output_addr @$C000
| void main () {
| byte i
@ -151,7 +151,7 @@ class BitPackingSuite extends FunSuite with Matchers {
}
test("Reverse byte 2") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| byte output_real @$C000
| void main () {
| byte i
@ -172,7 +172,7 @@ class BitPackingSuite extends FunSuite with Matchers {
}
test("Reverse word") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| word output_addr @$C000
| void main () {
| byte i

View File

@ -1,6 +1,7 @@
package millfork.test
import millfork.test.emu.EmuBenchmarkRun
import millfork.Cpu
import millfork.test.emu.EmuCrossPlatformBenchmarkRun
import org.scalatest.{FunSuite, Matchers}
/**
@ -9,7 +10,7 @@ import org.scalatest.{FunSuite, Matchers}
class BooleanSuite extends FunSuite with Matchers {
test("Not") {
EmuBenchmarkRun(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| array input = [5,6,7]
@ -25,7 +26,7 @@ class BooleanSuite extends FunSuite with Matchers {
test("And") {
EmuBenchmarkRun(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| array input = [5,6,7]
@ -44,7 +45,7 @@ class BooleanSuite extends FunSuite with Matchers {
test("Or") {
EmuBenchmarkRun(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| array input = [5,6,7]

View File

@ -10,7 +10,7 @@ import org.scalatest.{FunSuite, Matchers}
class BreakContinueSuite extends FunSuite with Matchers {
test("Break from one-iteration loop 1") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| void main () {
@ -24,7 +24,7 @@ class BreakContinueSuite extends FunSuite with Matchers {
}
test("Break from one-iteration loop 2") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| void main () {
@ -39,7 +39,7 @@ class BreakContinueSuite extends FunSuite with Matchers {
}
test("Break from infinite loop 1") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| void main () {
@ -54,7 +54,7 @@ class BreakContinueSuite extends FunSuite with Matchers {
}
test("Break and continue from infinite loop 1") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| void main () {
@ -70,7 +70,7 @@ class BreakContinueSuite extends FunSuite with Matchers {
}
test("Nested break") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| void main () {
@ -87,7 +87,7 @@ class BreakContinueSuite extends FunSuite with Matchers {
}
test("Continue in for loop 1") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| byte counter @$c001

View File

@ -10,7 +10,7 @@ import org.scalatest.{FunSuite, Matchers}
class ByteDecimalMathSuite extends FunSuite with Matchers {
test("Decimal byte addition") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| byte a
@ -22,7 +22,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
}
test("Decimal byte addition 2") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| byte a
@ -33,8 +33,20 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
""".stripMargin)(_.readByte(0xc000) should equal(0x70))
}
test("In-place decimal byte addition") {
test("Decimal byte subtraction") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
"""
| byte output @$c000
| byte a
| void main () {
| a = $50
| output = a -' $35
| }
""".stripMargin)(_.readByte(0xc000) should equal(0x15))
}
test("In-place decimal byte addition") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| array output[3] @$c000
| byte a
@ -48,7 +60,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
}
test("In-place decimal byte addition 2") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| array output[3] @$c000
| void main () {
@ -67,8 +79,34 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
""".stripMargin)(_.readByte(0xc001) should equal(0x40))
}
test("Flag switching test") {
test("In-place decimal byte subtraction") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
"""
| byte output @$c000
| byte a
| void main () {
| output = $50
| output -'= $35
| }
""".stripMargin)(_.readByte(0xc000) should equal(0x15))
}
test("In-place decimal word subtraction") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
"""
| word output @$c000
| word a
| void main () {
| output = $1500
| output -'= $455
| a = $264
| output -'= a
| }
""".stripMargin)(_.readWord(0xc000) should equal(0x781))
}
test("Flag switching test") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| void main () {
@ -79,7 +117,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
}
test("Flag switching test 2") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| void main () {
@ -90,7 +128,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
}
test("Flag switching test 3") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| void main () {
@ -101,7 +139,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
}
test("Decimal left shift test") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80)(
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| void main () {
@ -116,7 +154,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
}
test("Decimal left shift test 2") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80)(
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| void main () {
@ -130,7 +168,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
}
test("Decimal left shift test 3") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80)(
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| word output @$c000
| void main () {
@ -234,7 +272,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
test("Decimal byte multiplication comprehensive suite") {
val numbers = List(0, 1, 2, 3, 6, 8, 10, 11, 12, 14, 15, 16, 20, 40, 73, 81, 82, 98, 99)
for (i <- numbers; j <- numbers) {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80)(
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| void main () {
@ -252,7 +290,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
test("Decimal comparison") {
// CMP#0 shouldn't be elided after a decimal operation.
// Currently no emulator used for testing can catch that.
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| void main () {

View File

@ -178,7 +178,7 @@ class ByteMathSuite extends FunSuite with Matchers {
}
test("Byte multiplication 2") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| import zp_reg
| byte output1 @$c001
@ -215,7 +215,7 @@ class ByteMathSuite extends FunSuite with Matchers {
| #if ARCH_6502
| if output1 != 20 { asm { lda $bfff }}
| if output2 != 27 { asm { lda $bfff }}
| #elseif ARCH_Z80
| #elseif ARCH_I80
| if output1 != 20 { asm { ld a,($bfff) }}
| if output2 != 27 { asm { ld a,($bfff) }}
| #else

View File

@ -10,7 +10,7 @@ import org.scalatest.{FunSuite, Matchers}
class CmosSuite extends FunSuite with Matchers {
test("Zero store 1") {
EmuCrossPlatformBenchmarkRun(Cpu.Cmos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Cmos, Cpu.Z80, Cpu.Intel8080)("""
| word output @$c000
| void main () {
| output = 1
@ -19,7 +19,7 @@ class CmosSuite extends FunSuite with Matchers {
""".stripMargin)(_.readWord(0xc000) should equal(0))
}
test("Zero store 2") {
EmuCrossPlatformBenchmarkRun(Cpu.Cmos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Cmos, Cpu.Z80, Cpu.Intel8080)("""
| byte output @$c000
| void main () {
| output = 1

View File

@ -10,7 +10,7 @@ import org.scalatest.{FunSuite, Matchers}
class ComparisonSuite extends FunSuite with Matchers {
test("Equality and inequality") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| void main () {
@ -28,7 +28,7 @@ class ComparisonSuite extends FunSuite with Matchers {
}
test("Less") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| void main () {
@ -41,7 +41,7 @@ class ComparisonSuite extends FunSuite with Matchers {
}
test("Compare to zero") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| void main () {
@ -76,7 +76,7 @@ class ComparisonSuite extends FunSuite with Matchers {
}
test("Does it even work") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| word output @$c000
| void main () {
@ -99,7 +99,7 @@ class ComparisonSuite extends FunSuite with Matchers {
| if 2222 == 3333 { output -= 1 }
| }
""".stripMargin
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(src)(_.readByte(0xc000) should equal(src.count(_ == '+')))
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(src)(_.readByte(0xc000) should equal(src.count(_ == '+')))
}
test("Word comparison == and !=") {
@ -122,7 +122,7 @@ class ComparisonSuite extends FunSuite with Matchers {
| if a != 0 { output += 1 }
| }
""".stripMargin
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(src)(_.readByte(0xc000) should equal(src.count(_ == '+')))
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(src)(_.readByte(0xc000) should equal(src.count(_ == '+')))
}
test("Word comparison <=") {
@ -143,7 +143,7 @@ class ComparisonSuite extends FunSuite with Matchers {
| if a <= c { output += 1 }
| }
""".stripMargin
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(src)(_.readByte(0xc000) should equal(src.count(_ == '+')))
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(src)(_.readByte(0xc000) should equal(src.count(_ == '+')))
}
test("Word comparison <") {
val src =
@ -162,7 +162,7 @@ class ComparisonSuite extends FunSuite with Matchers {
| if a < 257 { output += 1 }
| }
""".stripMargin
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(src)(_.readByte(0xc000) should equal(src.count(_ == '+')))
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(src)(_.readByte(0xc000) should equal(src.count(_ == '+')))
}
@ -183,7 +183,7 @@ class ComparisonSuite extends FunSuite with Matchers {
| if c > 0 { output += 1 }
| }
""".stripMargin
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(src)(_.readByte(0xc000) should equal(src.count(_ == '+')))
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(src)(_.readByte(0xc000) should equal(src.count(_ == '+')))
}
test("Word comparison >=") {
@ -206,7 +206,7 @@ class ComparisonSuite extends FunSuite with Matchers {
| if a >= 0 { output += 1 }
| }
""".stripMargin
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(src)(_.readByte(0xc000) should equal(src.count(_ == '+')))
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(src)(_.readByte(0xc000) should equal(src.count(_ == '+')))
}
test("Signed comparison >=") {
@ -265,7 +265,7 @@ class ComparisonSuite extends FunSuite with Matchers {
}
test("Multiple params for equality") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| void main () {
@ -281,7 +281,7 @@ class ComparisonSuite extends FunSuite with Matchers {
}
test("Multiple params for inequality") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| void main () {
@ -297,7 +297,7 @@ class ComparisonSuite extends FunSuite with Matchers {
}
test("Warnings") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| void main () {
@ -339,7 +339,7 @@ class ComparisonSuite extends FunSuite with Matchers {
| if c > 335444 { output += 1 }
| }
""".stripMargin
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(src)(_.readByte(0xc000) should equal(src.count(_ == '+')))
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(src)(_.readByte(0xc000) should equal(src.count(_ == '+')))
}
test("Mixed type comparison") {
@ -357,6 +357,6 @@ class ComparisonSuite extends FunSuite with Matchers {
| if x < z { output += 1 }
| }
""".stripMargin
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(src)(_.readByte(0xc000) should equal(1))
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(src)(_.readByte(0xc000) should equal(1))
}
}

View File

@ -10,7 +10,7 @@ import org.scalatest.{FunSuite, Matchers}
class EnumSuite extends FunSuite with Matchers {
test("Enum basic test") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80)(
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| enum ugly {
| a
@ -29,7 +29,7 @@ class EnumSuite extends FunSuite with Matchers {
| #if ARCH_6502
| sta $bfff
| rts
| #elseif ARCH_Z80
| #elseif ARCH_I80
| ld ($bfff),a
| ret
| #else
@ -40,7 +40,7 @@ class EnumSuite extends FunSuite with Matchers {
}
test("Enum arrays") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80)(
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| enum ugly {
| a
@ -56,7 +56,7 @@ class EnumSuite extends FunSuite with Matchers {
| #if ARCH_6502
| sta $bfff
| rts
| #elseif ARCH_Z80
| #elseif ARCH_I80
| ld ($bfff),a
| ret
| #else

View File

@ -10,7 +10,7 @@ import org.scalatest.{FunSuite, Matchers}
class ErasthotenesSuite extends FunSuite with Matchers {
test("Erasthotenes") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| const pointer sieve = $C000
| const byte sqrt = 128

View File

@ -1,6 +1,7 @@
package millfork.test
import millfork.test.emu.EmuBenchmarkRun
import millfork.Cpu
import millfork.test.emu.{EmuBenchmarkRun, EmuCrossPlatformBenchmarkRun}
import org.scalatest.{FunSuite, Matchers}
/**
@ -9,7 +10,7 @@ import org.scalatest.{FunSuite, Matchers}
class FarwordTest extends FunSuite with Matchers {
test("Farword assignment") {
EmuBenchmarkRun(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| farword output3 @$c000
| farword output2 @$c004
@ -28,7 +29,7 @@ class FarwordTest extends FunSuite with Matchers {
}
}
test("Farword assignment 2") {
EmuBenchmarkRun(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| farword output3 @$c000
| farword output2 @$c004
@ -52,7 +53,7 @@ class FarwordTest extends FunSuite with Matchers {
}
test("Farword assignment 3") {
EmuBenchmarkRun(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| farword output0 @$c000
| farword output1 @$c003
@ -69,7 +70,7 @@ class FarwordTest extends FunSuite with Matchers {
}
}
test("Farword addition") {
EmuBenchmarkRun(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| farword output @$c000
| void main () {
@ -89,7 +90,7 @@ class FarwordTest extends FunSuite with Matchers {
}
}
test("Farword addition 2") {
EmuBenchmarkRun(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| farword output @$c000
| void main () {
@ -103,7 +104,7 @@ class FarwordTest extends FunSuite with Matchers {
}
}
test("Farword subtraction") {
EmuBenchmarkRun(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| farword output @$c000
| void main () {
@ -123,7 +124,7 @@ class FarwordTest extends FunSuite with Matchers {
}
}
test("Farword subtraction 2") {
EmuBenchmarkRun(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| farword output @$c000
| void main () {
@ -137,7 +138,7 @@ class FarwordTest extends FunSuite with Matchers {
}
}
test("Farword subtraction 3") {
EmuBenchmarkRun(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| farword output @$c000
| void main () {
@ -157,7 +158,7 @@ class FarwordTest extends FunSuite with Matchers {
}
test("Farword AND") {
EmuBenchmarkRun(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| farword output @$c000
| void main () {
@ -177,7 +178,7 @@ class FarwordTest extends FunSuite with Matchers {
}
test("Farword INC/DEC") {
EmuBenchmarkRun(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| farword output0 @$c000
| farword output1 @$c004

View File

@ -11,8 +11,7 @@ import org.scalatest.{FunSuite, Matchers}
class ForArraySuite extends FunSuite with Matchers {
test("Basic for-array test") {
val m = EmuSuperOptimizedRun(
"""
val src = """
| byte output @$c000
| array input = for i,0,until,8 [i + i]
|
@ -37,7 +36,11 @@ class ForArraySuite extends FunSuite with Matchers {
| output = useless0[0] + useless1[0] + useless2[0] + useless3[0] + useless4[0] + useless5[0] + useless6[0] + useless7[0]
| output = input.length + input[5]
| }
""".stripMargin)
""".stripMargin
val m = EmuSuperOptimizedRun(src)
m.readByte(0xc000) should equal(18)
EmuCrossPlatformBenchmarkRun(Cpu.Cmos, Cpu.Z80, Cpu.Intel8080)(src) { m =>
m.readByte(0xc000) should equal(18)
}
}
}

View File

@ -118,7 +118,7 @@ class ForLoopSuite extends FunSuite with Matchers {
}
test("Various loops") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80)(
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| void init() {
| zero = 0
@ -228,7 +228,7 @@ class ForLoopSuite extends FunSuite with Matchers {
}
test("Edge cases - positive") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80)("""
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| void main() {
| byte i
| for i,0,until,256 { f() }

View File

@ -10,7 +10,7 @@ import org.scalatest.{FunSuite, Matchers}
class LongTest extends FunSuite with Matchers {
test("Long assignment") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| long output4 @$c000
| long output2 @$c004
@ -29,7 +29,7 @@ class LongTest extends FunSuite with Matchers {
}
}
test("Long assignment 2") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| long output4 @$c000
| long output2 @$c004
@ -52,7 +52,7 @@ class LongTest extends FunSuite with Matchers {
}
}
test("Long addition") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| long output @$c000
| void main () {
@ -72,7 +72,7 @@ class LongTest extends FunSuite with Matchers {
}
}
test("Long addition 2") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| long output @$c000
| void main () {
@ -86,7 +86,7 @@ class LongTest extends FunSuite with Matchers {
}
}
test("Long subtraction") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| long output @$c000
| void main () {
@ -106,7 +106,7 @@ class LongTest extends FunSuite with Matchers {
}
}
test("Long subtraction 2") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| long output @$c000
| void main () {
@ -120,7 +120,7 @@ class LongTest extends FunSuite with Matchers {
}
}
test("Long subtraction 3") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| long output @$c000
| void main () {
@ -140,7 +140,7 @@ class LongTest extends FunSuite with Matchers {
}
test("Long AND") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| long output @$c000
| void main () {
@ -160,7 +160,7 @@ class LongTest extends FunSuite with Matchers {
}
test("Long INC/DEC") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| long output0 @$c000
| long output1 @$c004

View File

@ -10,7 +10,7 @@ import org.scalatest.{FunSuite, Matchers}
class NonetSuite extends FunSuite with Matchers {
test("Nonet operations") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80)(
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)(
"""
| array output [5] @$c000
| void main () {

View File

@ -10,7 +10,7 @@ import org.scalatest.{FunSuite, Matchers}
class ReturnDispatchSuite extends FunSuite with Matchers {
test("Trivial test") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Cmos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Cmos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| void main () {
@ -28,7 +28,7 @@ class ReturnDispatchSuite extends FunSuite with Matchers {
}
}
test("Parameter test") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Cmos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Cmos, Cpu.Z80, Cpu.Intel8080)(
"""
| array output [200] @$c000
| sbyte param

View File

@ -1,8 +1,7 @@
package millfork.test
import millfork.assembly.mos.opt.{AlwaysGoodOptimizations, LaterOptimizations, VariableToRegisterOptimization}
import millfork.test.emu.{EmuBenchmarkRun, EmuRun, EmuUltraBenchmarkRun}
import millfork.{Cpu, OptimizationPresets}
import millfork.Cpu
import millfork.test.emu.{EmuBenchmarkRun, EmuCrossPlatformBenchmarkRun}
import org.scalatest.{FunSuite, Matchers}
/**
@ -11,7 +10,7 @@ import org.scalatest.{FunSuite, Matchers}
class SecondAssemblyOptimizationSuite extends FunSuite with Matchers {
test("Add-shift-add") {
EmuBenchmarkRun(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Cmos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| void main () {
@ -24,7 +23,7 @@ class SecondAssemblyOptimizationSuite extends FunSuite with Matchers {
}
test("And-shift-and") {
EmuBenchmarkRun(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Cmos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| void main () {
@ -37,7 +36,7 @@ class SecondAssemblyOptimizationSuite extends FunSuite with Matchers {
}
test("Add with limit") {
EmuBenchmarkRun(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Cmos, Cpu.Z80, Cpu.Intel8080)(
"""
| byte output @$c000
| const byte start = 5

View File

@ -1,6 +1,7 @@
package millfork.test
import millfork.test.emu.EmuBenchmarkRun
import millfork.Cpu
import millfork.test.emu.{EmuBenchmarkRun, EmuCrossPlatformBenchmarkRun}
import org.scalatest.{FunSuite, Matchers}
/**
@ -9,7 +10,7 @@ import org.scalatest.{FunSuite, Matchers}
class SeparateBytesSuite extends FunSuite with Matchers {
test("Separate assignment 1") {
EmuBenchmarkRun("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Cmos, Cpu.Z80, Cpu.Intel8080)("""
| word output @$c000
| void main () {
| output = 2:3
@ -18,7 +19,7 @@ class SeparateBytesSuite extends FunSuite with Matchers {
}
test("Separate assignment 2") {
EmuBenchmarkRun("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Cmos, Cpu.Z80, Cpu.Intel8080)("""
| byte output @$c000
| byte ignore @$c001
| void main () {
@ -30,7 +31,7 @@ class SeparateBytesSuite extends FunSuite with Matchers {
}
test("Separate assignment 3") {
EmuBenchmarkRun("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Cmos, Cpu.Z80, Cpu.Intel8080)("""
| byte output @$c000
| byte ignore @$c001
| void main () {
@ -43,7 +44,7 @@ class SeparateBytesSuite extends FunSuite with Matchers {
}
test("Separate assignment 4") {
EmuBenchmarkRun("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Cmos, Cpu.Z80, Cpu.Intel8080)("""
| array output [5] @$c000
| byte ignore @$c001
| void main () {
@ -58,7 +59,7 @@ class SeparateBytesSuite extends FunSuite with Matchers {
}
test("Separate assignment 5") {
EmuBenchmarkRun("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Cmos, Cpu.Z80, Cpu.Intel8080)("""
| array output [5] @$c000
| byte ignore @$c001
| void main () {
@ -73,7 +74,7 @@ class SeparateBytesSuite extends FunSuite with Matchers {
}
test("Magic split array") {
EmuBenchmarkRun("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Cmos, Cpu.Z80, Cpu.Intel8080)("""
| array hi [16] @$c000
| array lo [16] @$c010
| void main () {
@ -106,7 +107,7 @@ class SeparateBytesSuite extends FunSuite with Matchers {
}
test("Separate addition") {
EmuBenchmarkRun("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Cmos, Cpu.Z80, Cpu.Intel8080)("""
| word output @$c000
| void main () {
| byte h
@ -120,7 +121,7 @@ class SeparateBytesSuite extends FunSuite with Matchers {
}
test("Separate increase") {
EmuBenchmarkRun("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Cmos, Cpu.Z80, Cpu.Intel8080)("""
| word output @$c000
| void main () {
| byte h

View File

@ -9,7 +9,7 @@ import org.scalatest.{FunSuite, Matchers}
class ShiftSuite extends FunSuite with Matchers {
test("In-place shifting") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80)("""
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| array output [3] @$c000
| void main () {
| output[0] = 1
@ -20,7 +20,7 @@ class ShiftSuite extends FunSuite with Matchers {
}
test("Byte shifting") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| byte output @$c000
| void main () {
| byte a
@ -31,7 +31,7 @@ class ShiftSuite extends FunSuite with Matchers {
}
test("Word shifting") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| word output @$c000
| void main () {
| byte a
@ -50,10 +50,17 @@ class ShiftSuite extends FunSuite with Matchers {
| output <<= 2
| }
""".stripMargin)(_.readLong(0xc000) should equal(0x4040C04))
EmuCrossPlatformBenchmarkRun(Cpu.Z80, Cpu.Intel8080)("""
| long output @$c000
| void main () {
| output = $1010301
| output <<= 2
| }
""".stripMargin)(_.readLong(0xc000) should equal(0x4040C04))
}
test("Long shifting right") {
EmuBenchmarkRun("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| long output @$c000
| void main () {
| output = $4040C04
@ -63,7 +70,7 @@ class ShiftSuite extends FunSuite with Matchers {
}
test("Word shifting via pseudoregister") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| word output @$c000
| void main () {
| output = identity(three() << 7)
@ -74,7 +81,7 @@ class ShiftSuite extends FunSuite with Matchers {
}
test("Variable shifting") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| word output0 @$c000
| word output2 @$c002
| byte output4 @$c004

View File

@ -1,7 +1,7 @@
package millfork.test
import millfork.Cpu
import millfork.test.emu.{EmuCrossPlatformBenchmarkRun, EmuUnoptimizedCrossPlatformRun}
import millfork.test.emu.EmuCrossPlatformBenchmarkRun
import org.scalatest.{FunSuite, Matchers}
/**
@ -10,7 +10,7 @@ import org.scalatest.{FunSuite, Matchers}
class SignExtensionSuite extends FunSuite with Matchers {
test("Sbyte to Word") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| word output @$c000
| void main () {
| sbyte b
@ -22,7 +22,7 @@ class SignExtensionSuite extends FunSuite with Matchers {
}
}
test("Sbyte to Word 2") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| word output @$c000
| void main () {
| output = b()
@ -33,7 +33,7 @@ class SignExtensionSuite extends FunSuite with Matchers {
""".stripMargin){m => m.readWord(0xc000) should equal(0xffff)}
}
test("Sbyte to Long") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| long output @$c000
| void main () {
| output = 421
@ -46,7 +46,7 @@ class SignExtensionSuite extends FunSuite with Matchers {
}
test("Optimize pointless sign extension") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| array output [10] @$c000
| word w
| void main () {

View File

@ -10,7 +10,7 @@ import org.scalatest.{FunSuite, Matchers}
class StatementOptimizationSuite extends FunSuite with Matchers {
test("Statement optimization 1") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Intel8080)(
"""
| array output[10] @$c000
| void main() {

View File

@ -10,7 +10,7 @@ import org.scalatest.{FunSuite, Matchers}
class TypeSuite extends FunSuite with Matchers {
test("Word to word") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| word output @$c000
| void main () {
| output = word(0x203)

View File

@ -10,7 +10,7 @@ import org.scalatest.{FunSuite, Matchers}
class TypeWideningSuite extends FunSuite with Matchers {
test("Word after simple ops") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| word output @$c000
| void main () {
| output = random()

View File

@ -9,7 +9,7 @@ import org.scalatest.{FunSuite, Matchers}
class WordMathSuite extends FunSuite with Matchers {
test("Word addition") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| word output @$c000
| word a
| void main () {
@ -21,7 +21,7 @@ class WordMathSuite extends FunSuite with Matchers {
}
test("Word subtraction") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| word output @$c000
| word a
| void main () {
@ -33,7 +33,7 @@ class WordMathSuite extends FunSuite with Matchers {
}
test("Word subtraction 2") {
EmuCrossPlatformBenchmarkRun(Cpu.Cmos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Cmos, Cpu.Z80, Cpu.Intel8080)("""
| word output @$c000
| word a
| void main () {
@ -45,7 +45,7 @@ class WordMathSuite extends FunSuite with Matchers {
}
test("Byte-to-word addition") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| word output @$c000
| word pair
| void main () {
@ -58,7 +58,7 @@ class WordMathSuite extends FunSuite with Matchers {
}
test("Literal addition") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| word output @$c000
| void main () {
| output = 640
@ -68,7 +68,7 @@ class WordMathSuite extends FunSuite with Matchers {
}
test("Array element addition") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| word output @$c000
| word pair
| array b[2]
@ -85,7 +85,7 @@ class WordMathSuite extends FunSuite with Matchers {
}
test("nesdev.com example") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| byte output @$c000
| array map [256] @$c300
| array b[2]
@ -103,7 +103,7 @@ class WordMathSuite extends FunSuite with Matchers {
}
test("hi()/lo()") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| array output [7] @$c000
| void main () {
| output[0] = lo(33)
@ -135,7 +135,7 @@ class WordMathSuite extends FunSuite with Matchers {
}
test("Word addition 2") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| word output @$c000
| void main () {
| word v
@ -151,7 +151,7 @@ class WordMathSuite extends FunSuite with Matchers {
}
test("Word addition 3") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| word output @$c000
| void main () {
| byte c
@ -167,7 +167,7 @@ class WordMathSuite extends FunSuite with Matchers {
}
test("Word addition 4") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| word output @$c000
| void main () {
| word v
@ -187,7 +187,7 @@ class WordMathSuite extends FunSuite with Matchers {
}
test("Word bit ops 2") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| word output @$c000
| void main () {
| word v
@ -203,7 +203,7 @@ class WordMathSuite extends FunSuite with Matchers {
}
test("Word shift") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| word output @$c000
| void main () {
| word v
@ -221,7 +221,7 @@ class WordMathSuite extends FunSuite with Matchers {
}
test("Word shift 2") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| word output @$c000
| void main () {
| output = five()
@ -236,7 +236,7 @@ class WordMathSuite extends FunSuite with Matchers {
}
test("Word shift 3") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| word output @$c000
| void main () {
| output = five()
@ -251,7 +251,7 @@ class WordMathSuite extends FunSuite with Matchers {
}
test("Word shift 4") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| word output @$c000
| void main () {
| output = five()
@ -266,7 +266,7 @@ class WordMathSuite extends FunSuite with Matchers {
}
test("Word shift 5") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080)("""
| word output @$c000
| void main () {
| output = five()

View File

@ -1,6 +1,6 @@
package millfork.test
import millfork.test.emu.EmuUnoptimizedZ80Run
import millfork.test.emu.{EmuUnoptimizedIntel8080Run, EmuUnoptimizedZ80Run}
import org.scalatest.{FunSuite, Matchers}
/**
@ -9,7 +9,7 @@ import org.scalatest.{FunSuite, Matchers}
class Z80AssemblySuite extends FunSuite with Matchers {
test("Common I80 instructions") {
EmuUnoptimizedZ80Run(
EmuUnoptimizedIntel8080Run(
"""
| asm void main () {
| ret
@ -37,7 +37,6 @@ class Z80AssemblySuite extends FunSuite with Matchers {
| dec d
| ld d,$16
| rla
| jr main
| add hl,de
| ld a,(de)
| dec de
@ -46,14 +45,12 @@ class Z80AssemblySuite extends FunSuite with Matchers {
| ld e,$1e
| rra
|
| jr nz,main
| ld hl,$2121
| inc hl
| inc h
| dec h
| ld h,$26
| daa
| jr z,main
| add hl,hl
| dec hl
| inc l
@ -61,7 +58,6 @@ class Z80AssemblySuite extends FunSuite with Matchers {
| ld l,$2e
| cpl
|
| jr nc,main
| ld hl,$2121
| ld ($fffe),a
| inc sp
@ -69,7 +65,6 @@ class Z80AssemblySuite extends FunSuite with Matchers {
| dec (hl)
| ld h,$26
| scf
| jr c,main
| add hl,sp
| ld a,($fffe)
| dec sp
@ -280,16 +275,13 @@ class Z80AssemblySuite extends FunSuite with Matchers {
}
test("Intel 8080 instructions") {
EmuUnoptimizedZ80Run(
EmuUnoptimizedIntel8080Run(
"""
| asm void main () {
| ret
| ex af,af'
| djnz main
| ld ($fffe),hl
| ld hl,($fffe)
| out (1),a
| exx
| in a,(1)
| ret po
| jp po,main
@ -317,6 +309,13 @@ class Z80AssemblySuite extends FunSuite with Matchers {
| ret
|
| reti
|
| jr main
| jr nz,main
| jr z,main
| jr nc,main
| jr c,main
| ld (34),sp
|
| rlc b
| rlc c
@ -489,6 +488,10 @@ class Z80AssemblySuite extends FunSuite with Matchers {
| asm void main () {
| ret
|
| djnz main
| ex af,af'
| exx
|
| sll b
| sll c
| sll d
@ -533,7 +536,6 @@ class Z80AssemblySuite extends FunSuite with Matchers {
| adc hl,hl
| rld
| sbc hl,sp
| ld (34),sp
| in a,(c)
| out (c),a
| adc hl,sp

View File

@ -44,6 +44,25 @@ object EmuZ80BenchmarkRun {
}
}
object EmuIntel8080BenchmarkRun {
def apply(source: String)(verifier: MemoryBank => Unit): Unit = {
val (Timings(t0, _), m0) = EmuUnoptimizedIntel8080Run.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) {

View File

@ -10,6 +10,7 @@ object EmuUnoptimizedCrossPlatformRun {
def apply(platforms: Cpu.Value*)(source: String)(verifier: MemoryBank => Unit): Unit = {
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
if (platforms.contains(Cpu.Mos)) {
println(f"Running MOS")
verifier(mm)
@ -18,5 +19,9 @@ object EmuUnoptimizedCrossPlatformRun {
println(f"Running Z80")
verifier(mz)
}
if (platforms.contains(Cpu.Intel8080)) {
println(f"Running 8080")
verifier(mi)
}
}
}

View File

@ -8,4 +8,6 @@ import millfork.Cpu
*/
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)

View File

@ -34,6 +34,7 @@ class EmuZ80Run(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimizatio
val platform = EmuPlatform.get(cpu)
val extraFlags = Map(
CompilationFlag.InlineFunctions -> this.inline,
CompilationFlag.EmitIllegals -> (cpu == millfork.Cpu.Z80),
CompilationFlag.LenientTextEncoding -> true)
val options = CompilationOptions(platform, millfork.Cpu.defaultFlags(cpu).map(_ -> true).toMap ++ extraFlags, None, 0)
ErrorReporting.hasErrors = false
@ -110,7 +111,7 @@ class EmuZ80Run(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimizatio
(0x200 until 0x2000).takeWhile(memoryBank.occupied(_)).map(memoryBank.output).grouped(16).map(_.map(i => f"$i%02x").mkString(" ")).foreach(ErrorReporting.debug(_))
val timings = platform.cpu match {
case millfork.Cpu.Z80 =>
case millfork.Cpu.Z80 | millfork.Cpu.Intel8080 =>
val cpu = new Z80Core(Z80Memory(memoryBank), DummyIO)
cpu.reset()
cpu.setProgramCounter(0x1f0)