mirror of
https://github.com/KarolS/millfork.git
synced 2025-03-24 10:33:53 +00:00
Z80: Decimal subtraction on 8080, fixes for adding longs returned from functions
This commit is contained in:
parent
6b02c5178a
commit
9b5b39181a
@ -129,13 +129,24 @@ object ZBuiltIns {
|
||||
result += ZLine.register(INC, ZRegister.A)
|
||||
}
|
||||
} else {
|
||||
// TODO: optimize
|
||||
result += ZLine.ld8(ZRegister.D, ZRegister.A)
|
||||
result ++= Z80ExpressionCompiler.stashDEIfChanged(ctx, Z80ExpressionCompiler.compileToA(ctx, expr))
|
||||
result += ZLine.ld8(ZRegister.E, ZRegister.A)
|
||||
result += ZLine.ld8(ZRegister.A, ZRegister.D)
|
||||
result += ZLine.register(SUB, ZRegister.E)
|
||||
if (decimal) {
|
||||
if (!decimal || ctx.options.flag(CompilationFlag.EmitExtended80Opcodes)) {
|
||||
// TODO: optimize
|
||||
result += ZLine.ld8(ZRegister.D, ZRegister.A)
|
||||
result ++= Z80ExpressionCompiler.stashDEIfChanged(ctx, Z80ExpressionCompiler.compileToA(ctx, expr))
|
||||
result += ZLine.ld8(ZRegister.E, ZRegister.A)
|
||||
result += ZLine.ld8(ZRegister.A, ZRegister.D)
|
||||
result += ZLine.register(SUB, ZRegister.E)
|
||||
if (decimal) {
|
||||
result += ZLine.implied(DAA)
|
||||
}
|
||||
} else {
|
||||
// -' on Intel 8080
|
||||
result += ZLine.ld8(ZRegister.D, ZRegister.A)
|
||||
result ++= Z80ExpressionCompiler.stashDEIfChanged(ctx, Z80ExpressionCompiler.compileToA(ctx, expr))
|
||||
result += ZLine.ld8(ZRegister.E, ZRegister.A)
|
||||
result += ZLine.ldImm8(ZRegister.A, 0x9a)
|
||||
result += ZLine.register(SUB, ZRegister.E)
|
||||
result += ZLine.register(ADD, ZRegister.D)
|
||||
result += ZLine.implied(DAA)
|
||||
}
|
||||
}
|
||||
@ -151,8 +162,17 @@ object ZBuiltIns {
|
||||
if (hasConst) {
|
||||
const match {
|
||||
case CompoundConstant(MathOperator.DecimalMinus | MathOperator.Minus, NumericConstant(0, _), c) =>
|
||||
result += ZLine.imm8(SUB, c.loByte)
|
||||
if (decimal) {
|
||||
if (!decimal || ctx.options.flag(CompilationFlag.EmitExtended80Opcodes)) {
|
||||
result += ZLine.imm8(SUB, c.loByte)
|
||||
if (decimal) {
|
||||
result += ZLine.implied(DAA)
|
||||
}
|
||||
} else {
|
||||
import ZRegister._
|
||||
result += ZLine.ld8(E, A)
|
||||
result += ZLine.ldImm8(A, 0x9a)
|
||||
result += ZLine.imm8(SUB, c.loByte)
|
||||
result += ZLine.register(ADD, E)
|
||||
result += ZLine.implied(DAA)
|
||||
}
|
||||
case NumericConstant(n, _) if n < 0 && !decimal =>
|
||||
@ -183,11 +203,11 @@ object ZBuiltIns {
|
||||
result += ZLine.ld8(ZRegister.D, ZRegister.H)
|
||||
result ++= Z80ExpressionCompiler.stashDEIfChanged(ctx, Z80ExpressionCompiler.compileToHL(ctx, expr))
|
||||
result += ZLine.ld8(ZRegister.A, ZRegister.L)
|
||||
result += ZLine.registers(ADD, ZRegister.A, ZRegister.E)
|
||||
result += ZLine.register(ADD, ZRegister.E)
|
||||
result += ZLine.implied(DAA)
|
||||
result += ZLine.ld8(ZRegister.L, ZRegister.A)
|
||||
result += ZLine.ld8(ZRegister.A, ZRegister.H)
|
||||
result += ZLine.registers(ADC, ZRegister.A, ZRegister.D)
|
||||
result += ZLine.register(ADC, ZRegister.D)
|
||||
result += ZLine.implied(DAA)
|
||||
result += ZLine.ld8(ZRegister.H, ZRegister.A)
|
||||
}
|
||||
@ -198,7 +218,36 @@ object ZBuiltIns {
|
||||
case (true, expr) =>
|
||||
ctx.env.eval(expr) match {
|
||||
case None =>
|
||||
ctx.log.error("Decimal subtraction not supported on Intel 8080-like CPUs.", expr.position)
|
||||
if (result.isEmpty) {
|
||||
???
|
||||
} else if (ctx.options.flag(CompilationFlag.EmitExtended80Opcodes)) {
|
||||
result += ZLine.ld8(ZRegister.E, ZRegister.L)
|
||||
result += ZLine.ld8(ZRegister.D, ZRegister.H)
|
||||
result ++= Z80ExpressionCompiler.stashDEIfChanged(ctx, Z80ExpressionCompiler.compileToHL(ctx, expr))
|
||||
result += ZLine.ld8(ZRegister.A, ZRegister.E)
|
||||
result += ZLine.registers(SUB, ZRegister.A, ZRegister.L)
|
||||
result += ZLine.implied(DAA)
|
||||
result += ZLine.ld8(ZRegister.L, ZRegister.A)
|
||||
result += ZLine.ld8(ZRegister.A, ZRegister.D)
|
||||
result += ZLine.registers(SBC, ZRegister.A, ZRegister.H)
|
||||
result += ZLine.implied(DAA)
|
||||
result += ZLine.ld8(ZRegister.H, ZRegister.A)
|
||||
} else {
|
||||
result += ZLine.ld8(ZRegister.E, ZRegister.L)
|
||||
result += ZLine.ld8(ZRegister.D, ZRegister.H)
|
||||
result ++= Z80ExpressionCompiler.stashDEIfChanged(ctx, Z80ExpressionCompiler.compileToHL(ctx, expr))
|
||||
result += ZLine.ldImm8(ZRegister.A, 0x9A)
|
||||
result += ZLine.register(SUB, ZRegister.L)
|
||||
result += ZLine.register(ADD, ZRegister.E)
|
||||
result += ZLine.implied(DAA)
|
||||
result += ZLine.ld8(ZRegister.L, ZRegister.A)
|
||||
result += ZLine.ldImm8(ZRegister.A, 0x99)
|
||||
result += ZLine.imm8(ADC, 0)
|
||||
result += ZLine.register(SUB, ZRegister.H)
|
||||
result += ZLine.register(ADD, ZRegister.D)
|
||||
result += ZLine.implied(DAA)
|
||||
result += ZLine.ld8(ZRegister.H, ZRegister.A)
|
||||
}
|
||||
case Some(c) =>
|
||||
hasConst = true
|
||||
const = CompoundConstant(MathOperator.DecimalMinus, const, c).quickSimplify
|
||||
@ -309,12 +358,23 @@ object ZBuiltIns {
|
||||
ZLine.ld8(lv, ZRegister.A))
|
||||
}
|
||||
case SUB if decimal =>
|
||||
setup ++ List(
|
||||
ZLine.ld8(ZRegister.E, ZRegister.A),
|
||||
ZLine.ld8(ZRegister.A, lv),
|
||||
ZLine.register(SUB, ZRegister.E),
|
||||
ZLine.implied(DAA),
|
||||
ZLine.ld8(lv, ZRegister.A))
|
||||
if (ctx.options.flag(CompilationFlag.EmitExtended80Opcodes)) {
|
||||
setup ++ List(
|
||||
ZLine.ld8(ZRegister.E, ZRegister.A),
|
||||
ZLine.ld8(ZRegister.A, lv),
|
||||
ZLine.register(SUB, ZRegister.E),
|
||||
ZLine.implied(DAA),
|
||||
ZLine.ld8(lv, ZRegister.A))
|
||||
} else {
|
||||
setup ++ List(
|
||||
ZLine.ld8(ZRegister.E, ZRegister.A),
|
||||
ZLine.ld8(ZRegister.D, lv),
|
||||
ZLine.ldImm8(ZRegister.A, 0x9a),
|
||||
ZLine.register(SUB, ZRegister.E),
|
||||
ZLine.register(ADD, ZRegister.D),
|
||||
ZLine.implied(DAA),
|
||||
ZLine.ld8(lv, ZRegister.A))
|
||||
}
|
||||
case SUB if !decimal=>
|
||||
constantRight match {
|
||||
case Some(NumericConstant(1, _)) =>
|
||||
@ -447,14 +507,50 @@ object ZBuiltIns {
|
||||
}
|
||||
}
|
||||
val store = Z80ExpressionCompiler.compileByteStores(ctx, lhs, size, includeStep = false)
|
||||
val loadLeft = Z80ExpressionCompiler.compileByteReads(ctx, lhs, size, ZExpressionTarget.HL)
|
||||
val loadRight = Z80ExpressionCompiler.compileByteReads(ctx, rhs, size, ZExpressionTarget.BC)
|
||||
List.tabulate(size) {i =>
|
||||
val rightIsBig = loadRight.exists(_.exists(l => l.changesRegister(ZRegister.HL) || l.changesRegister(ZRegister.DE)))
|
||||
val (leftStasher, calcStasher, loadLeft) = if (rightIsBig) {
|
||||
(
|
||||
((e: List[ZLine]) => Z80ExpressionCompiler.stashHLIfChanged(ctx, e)),
|
||||
((e: List[ZLine]) => Z80ExpressionCompiler.stashDEIfChanged(ctx, e)),
|
||||
Z80ExpressionCompiler.compileByteReads(ctx, lhs, size, ZExpressionTarget.BC)
|
||||
)
|
||||
} else {
|
||||
(
|
||||
((e: List[ZLine]) => Z80ExpressionCompiler.stashBCIfChanged(ctx, e)),
|
||||
((e: List[ZLine]) => e),
|
||||
Z80ExpressionCompiler.compileByteReads(ctx, lhs, size, ZExpressionTarget.HL)
|
||||
)
|
||||
}
|
||||
List.tabulate(size) { i =>
|
||||
import ZRegister._
|
||||
// TODO: stash things correctly?
|
||||
val firstPhase = loadRight(i) ++ List(ZLine.ld8(ZRegister.E, ZRegister.A)) ++
|
||||
(Z80ExpressionCompiler.stashBCIfChanged(ctx, loadLeft(i)) :+ ZLine.register(if (i==0) opcodeFirst else opcodeLater, ZRegister.E))
|
||||
val secondPhase = if (decimal) firstPhase :+ ZLine.implied(ZOpcode.DAA) else firstPhase
|
||||
secondPhase ++ store(i)
|
||||
if (opcodeFirst == ZOpcode.SUB && decimal && !ctx.options.flag(CompilationFlag.EmitExtended80Opcodes)) {
|
||||
// TODO: check if carry is ok
|
||||
if (i == 0) {
|
||||
loadRight(i) ++ calcStasher(List(ZLine.ld8(ZRegister.E, ZRegister.A)) ++
|
||||
(leftStasher(loadLeft(i)) ++ List(
|
||||
ZLine.ld8(D, A),
|
||||
ZLine.ldImm8(A, 0x9A),
|
||||
ZLine.register(SUB, E),
|
||||
ZLine.register(ADD, D),
|
||||
ZLine.implied(DAA)) ++ store(i)))
|
||||
} else {
|
||||
loadRight(i) ++ calcStasher(List(ZLine.ld8(ZRegister.E, ZRegister.A)) ++
|
||||
(leftStasher(loadLeft(i)) ++ List(
|
||||
ZLine.ld8(D, A),
|
||||
ZLine.ldImm8(A, 0x99),
|
||||
ZLine.imm8(ADC, 0),
|
||||
ZLine.register(SUB, E),
|
||||
ZLine.register(ADD, D),
|
||||
ZLine.implied(DAA)) ++ store(i)))
|
||||
}
|
||||
} else {
|
||||
val firstPhase = loadRight(i) ++ calcStasher(List(ZLine.ld8(ZRegister.E, ZRegister.A)) ++
|
||||
(leftStasher(loadLeft(i)) :+ ZLine.register(if (i == 0) opcodeFirst else opcodeLater, ZRegister.E)))
|
||||
val secondPhase = if (decimal) firstPhase :+ ZLine.implied(ZOpcode.DAA) else firstPhase
|
||||
secondPhase ++ store(i)
|
||||
}
|
||||
}.flatten
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
|
||||
}
|
||||
|
||||
test("Decimal byte subtraction") {
|
||||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Sharp)(
|
||||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp)(
|
||||
"""
|
||||
| byte output @$c000
|
||||
| byte a
|
||||
@ -80,7 +80,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
|
||||
}
|
||||
|
||||
test("In-place decimal byte subtraction") {
|
||||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Sharp)(
|
||||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp)(
|
||||
"""
|
||||
| byte output @$c000
|
||||
| byte a
|
||||
@ -92,7 +92,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
|
||||
}
|
||||
|
||||
test("In-place decimal word subtraction") {
|
||||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Sharp)(
|
||||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp)(
|
||||
"""
|
||||
| word output @$c000
|
||||
| word a
|
||||
@ -105,6 +105,21 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
|
||||
""".stripMargin)(_.readWord(0xc000) should equal(0x781))
|
||||
}
|
||||
|
||||
test("In-place decimal long subtraction") {
|
||||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp)(
|
||||
"""
|
||||
| long output @$c000
|
||||
| word a
|
||||
| void main () {
|
||||
| output = $22334455
|
||||
| output -'= f()
|
||||
| }
|
||||
| noinline long f() {
|
||||
| return $20304050
|
||||
| }
|
||||
""".stripMargin)(_.readLong(0xc000) should equal(0x2030405))
|
||||
}
|
||||
|
||||
test("Flag switching test") {
|
||||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp)(
|
||||
"""
|
||||
|
@ -85,6 +85,40 @@ class LongTest extends FunSuite with Matchers {
|
||||
m.readLong(0xc000) should equal(0x58008)
|
||||
}
|
||||
}
|
||||
test("Long addition 3") {
|
||||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp)(
|
||||
"""
|
||||
| long output @$c000
|
||||
| void main () {
|
||||
| output = 0
|
||||
| output += f()
|
||||
| output += $8000
|
||||
| output += $8
|
||||
| }
|
||||
| long f() {
|
||||
| return $50000
|
||||
| }
|
||||
""".stripMargin) { m =>
|
||||
m.readLong(0xc000) should equal(0x58008)
|
||||
}
|
||||
}
|
||||
test("Extralong addition") {
|
||||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp)(
|
||||
"""
|
||||
| int128 output @$c000
|
||||
| void main () {
|
||||
| output = 0
|
||||
| output += f()
|
||||
| output += $8000
|
||||
| output += $8
|
||||
| }
|
||||
| int128 f() {
|
||||
| return $50000
|
||||
| }
|
||||
""".stripMargin) { m =>
|
||||
m.readLong(0xc000) should equal(0x58008)
|
||||
}
|
||||
}
|
||||
test("Long subtraction") {
|
||||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp)(
|
||||
"""
|
||||
|
@ -113,7 +113,13 @@ class EmuZ80Run(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimizatio
|
||||
memoryBank.output(0x1f3) = 0x76.toByte
|
||||
|
||||
(0x200 until 0x2000).takeWhile(memoryBank.occupied(_)).map(memoryBank.output).grouped(16).map(_.map(i => f"$i%02x").mkString(" ")).foreach(log.debug(_))
|
||||
|
||||
val resetN = source.contains("-'") && !options.flag(CompilationFlag.EmitExtended80Opcodes)
|
||||
val resetNMethod = {
|
||||
val clazz = classOf[Z80Core]
|
||||
val method = clazz.getDeclaredMethod("resetN")
|
||||
method.setAccessible(true)
|
||||
method
|
||||
}
|
||||
val timings = platform.cpu match {
|
||||
case millfork.Cpu.Z80 | millfork.Cpu.Intel8080 =>
|
||||
val cpu = new Z80Core(Z80Memory(memoryBank), DummyIO)
|
||||
@ -122,6 +128,9 @@ class EmuZ80Run(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimizatio
|
||||
cpu.resetTStates()
|
||||
while (!cpu.getHalt) {
|
||||
cpu.executeOneInstruction()
|
||||
if (resetN) {
|
||||
resetNMethod.invoke(cpu)
|
||||
}
|
||||
// dump(cpu)
|
||||
cpu.getTStates should be < TooManyCycles
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user