diff --git a/src/main/scala/millfork/compiler/m6809/M6809Buitins.scala b/src/main/scala/millfork/compiler/m6809/M6809Buitins.scala index 279ac573..7b4f4c73 100644 --- a/src/main/scala/millfork/compiler/m6809/M6809Buitins.scala +++ b/src/main/scala/millfork/compiler/m6809/M6809Buitins.scala @@ -88,7 +88,7 @@ object M6809Buitins { case (false, false) => MathOperator.Plus case (true, false) => MathOperator.Minus case (false, true) => MathOperator.DecimalPlus - case (false, true) => MathOperator.DecimalMinus + case (true, true) => MathOperator.DecimalMinus }, constant, c ).quickSimplify @@ -133,27 +133,51 @@ object M6809Buitins { val result = ListBuffer[MLine]() for ((neg, load) <- addendReads) { if (result.isEmpty && fromScratch) { - result ++= load - if (neg) result += MLine.inherentB(NEG) + if (expr.decimal) { + if (load.nonEmpty && load.last.opcode == LDB) { + result ++= load.init + result += load.last.copy(opcode = LDA) + } else { + result ++= load + result += MLine.tfr(M6809Register.B, M6809Register.A) + } + if (neg) ??? + } else { + result ++= load + if (neg) result += MLine.inherentB(NEG) + } } else { load match { case List(l@MLine0(LDB, _, _)) => if (neg) { - result += l.copy(opcode = sub) - if (expr.decimal) ??? + if (expr.decimal) { + result += MLine.pp(PSHS, M6809Register.A) + result += MLine.immediate(LDA, 0x9a) + result += l.copy(opcode = SUBA) + result += MLine.accessAndPullS(ADDA) + result += MLine.inherent(DAA) + } else { + result += l.copy(opcode = sub) + } } else { result += l.copy(opcode = add) if (expr.decimal) result += MLine.inherent(DAA) } case _ => if (expr.decimal) { - result += MLine.pp(PSHS, M6809Register.A) - result ++= load - result += MLine.pp(PULS, M6809Register.A) if (neg) { - ??? - if (expr.decimal) ??? + result += MLine.pp(PSHS, M6809Register.A) + result ++= load + result += MLine.pp(PSHS, M6809Register.B) + result += MLine.immediate(LDA, 0x9a) + result += MLine.accessAndPullS(SUBA) + result += MLine.accessAndPullS(ADDA) + result += MLine.inherent(DAA) } else { + result += MLine.pp(PSHS, M6809Register.A) + result ++= load + result += MLine.pp(PULS, M6809Register.A) + result += MLine.pp(PSHS, M6809Register.B) result += MLine.accessAndPullS(ADDA) result += MLine.inherent(DAA) } diff --git a/src/main/scala/millfork/compiler/m6809/M6809DecimalBuiltins.scala b/src/main/scala/millfork/compiler/m6809/M6809DecimalBuiltins.scala new file mode 100644 index 00000000..e1f06d81 --- /dev/null +++ b/src/main/scala/millfork/compiler/m6809/M6809DecimalBuiltins.scala @@ -0,0 +1,48 @@ +package millfork.compiler.m6809 + +import millfork.assembly.m6809.MLine +import millfork.compiler.CompilationContext +import millfork.node.Expression +import millfork.assembly.m6809.MOpcode._ +import millfork.env.NumericConstant +import millfork.node.M6809Register._ + +/** + * @author Karol Stasiak + */ +object M6809DecimalBuiltins { + + def compileByteDecimalShiftLeft(ctx: CompilationContext, lhs: Option[Expression], rhs: Expression): List[MLine] = { + val load = lhs match { + case None => List(MLine.indexedX(LDA, 0)) + case Some(l) => M6809ExpressionCompiler.compileToA(ctx, l) + } + val loop = ctx.env.eval(rhs) match { + case Some(NumericConstant(0, _)) => Nil + case Some(NumericConstant(1, _)) => List( + MLine.pp(PSHS, A), + MLine.accessAndPullS(ADDA), + MLine.inherent(DAA) + ) + case _ => + val labelSkip = ctx.nextLabel("ss") + val labelRepeat = ctx.nextLabel("sr") + M6809ExpressionCompiler.stashAIfNeeded(ctx, M6809ExpressionCompiler.compileToB(ctx, rhs)) ++ List( + MLine.label(labelRepeat), + MLine.immediate(CMPB, 0), + MLine.shortBranch(BEQ, labelSkip), + MLine.pp(PSHS, A), + MLine.accessAndPullS(ADDA), + MLine.inherent(DAA), + MLine.inherentB(DEC), + MLine.shortBranch(BRA, labelRepeat), + MLine.label(labelSkip) + ) + } + val store = lhs match { + case None => List(MLine.indexedX(STA, 0)) + case Some(l) => Nil + } + load ++ loop ++ store + } +} diff --git a/src/main/scala/millfork/compiler/m6809/M6809ExpressionCompiler.scala b/src/main/scala/millfork/compiler/m6809/M6809ExpressionCompiler.scala index babed652..9c502070 100644 --- a/src/main/scala/millfork/compiler/m6809/M6809ExpressionCompiler.scala +++ b/src/main/scala/millfork/compiler/m6809/M6809ExpressionCompiler.scala @@ -345,7 +345,12 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] { M6809Buitins.compileWordShiftForD(ctx, params(1), left = false) ++ targetifyB(ctx, target, isSigned = false) } - case "<<'" => ??? + case "<<'" => + assertArithmeticBinary(ctx, params) match { + case (l, r, 1) => M6809DecimalBuiltins.compileByteDecimalShiftLeft(ctx, Some(l), r) ++ targetifyA(ctx, target, isSigned = false) + case (l, r, 2) => ??? + case (l, r, _) => ??? + } case ">>'" => ??? case "+=" => val (l, r, size) = assertArithmeticAssignmentLike(ctx, params) @@ -354,7 +359,22 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] { case 2 => M6809Buitins.perform16BitInPlace(ctx, l, r, ADDD, commutative = true) case _ => ctx.log.error("Long addition not implemented yet", fce.position); Nil } - case "+'=" => ??? + case "+'=" => + val (l, r, size) = assertArithmeticAssignmentLike(ctx, params) + size match { + case 1 => + val lc = compileAddressToX(ctx, l) + val rc = compileToA(ctx, r) + val add = List(MLine.indexedX(ADDA, 0), MLine.inherent(DAA), MLine.indexedX(STA, 0)) + (lc.exists(_.changesRegister(M6809Register.A)), rc.exists(_.changesRegister(M6809Register.X))) match { + case (false, false) => rc ++ lc ++ add + case (false, true) => rc ++ lc ++ add + case (true, false) => lc ++ rc ++ add + case (true, true) => rc ++ stashAIfNeeded(ctx, lc) ++ add + } + case 2 => ??? + case _ => ??? + } case "-=" => val (l, r, size) = assertArithmeticAssignmentLike(ctx, params) size match { @@ -362,7 +382,17 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] { case 2 => M6809Buitins.perform16BitInPlace(ctx, l, r, SUBD, commutative = false) case _ => ??? } - case "-'=" => ??? + case "-'=" => + val (l, r, size) = assertArithmeticAssignmentLike(ctx, params) + size match { + case 1 => + val lc = compileAddressToX(ctx, l) + val rc = compileToB(ctx, r) + lc ++ List(MLine.pp(PSHS, M6809Register.B)) ++ + rc ++ List(MLine.pp(PSHS, M6809Register.B), MLine.immediate(LDA, 0x9a), MLine.accessAndPullS(SUBA), MLine.accessAndPullS(ADDA), MLine.inherent(DAA), MLine.indexedX(STA, 0)) + case 2 => ??? + case _ => ??? + } case "*=" => val (l, r, size) = assertArithmeticAssignmentLike(ctx, params) size match { @@ -412,7 +442,13 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] { case 2 => handleInPlaceModification(ctx, l, 2, M6809Buitins.compileWordShiftForD(ctx, r, left = true)) } - case "<<'=" => ??? + case "<<'=" => + val (l, r, size) = assertArithmeticAssignmentLike(ctx, params) + size match { + case 1 => + compileAddressToX(ctx, l) ++ M6809DecimalBuiltins.compileByteDecimalShiftLeft(ctx, None, r) + case 2 => ??? + } case ">>=" => val (l, r, size) = assertArithmeticAssignmentLike(ctx, params) // TODO: optimize shifts directly in memory diff --git a/src/test/scala/millfork/test/ByteDecimalMathSuite.scala b/src/test/scala/millfork/test/ByteDecimalMathSuite.scala index 86c771e5..5bccdd50 100644 --- a/src/test/scala/millfork/test/ByteDecimalMathSuite.scala +++ b/src/test/scala/millfork/test/ByteDecimalMathSuite.scala @@ -10,7 +10,7 @@ import org.scalatest.{FunSuite, Matchers} class ByteDecimalMathSuite extends FunSuite with Matchers { test("Decimal byte addition") { - EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Ricoh, Cpu.Intel8086)( + EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Ricoh, Cpu.Intel8086, Cpu.Motorola6809)( """ | 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, Cpu.Intel8080, Cpu.Sharp, Cpu.Ricoh, Cpu.Intel8086)( + EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Ricoh, Cpu.Intel8086, Cpu.Motorola6809)( """ | byte output @$c000 | byte a @@ -62,7 +62,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers { } test("Decimal byte subtraction") { - EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Ricoh, Cpu.Intel8086)( + EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Ricoh, Cpu.Intel8086, Cpu.Motorola6809)( """ | byte output @$c000 | byte a @@ -74,7 +74,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers { } test("In-place decimal byte addition") { - EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Ricoh, Cpu.Intel8086)( + EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Ricoh, Cpu.Intel8086, Cpu.Motorola6809)( """ | array output[3] @$c000 | byte a @@ -88,7 +88,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers { } test("In-place decimal byte addition 2") { - EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Ricoh, Cpu.Intel8086)( + EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Ricoh, Cpu.Intel8086, Cpu.Motorola6809)( """ | array output[3] @$c000 | void main () { @@ -108,7 +108,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers { } test("In-place decimal byte subtraction") { - EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Ricoh, Cpu.Intel8086)( + EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Ricoh, Cpu.Intel8086, Cpu.Motorola6809)( """ | byte output @$c000 | byte a @@ -181,7 +181,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers { } test("Flag switching test") { - EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Ricoh, Cpu.Intel8086)( + EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Ricoh, Cpu.Intel8086, Cpu.Motorola6809)( """ | byte output @$c000 | void main () { @@ -192,7 +192,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers { } test("Flag switching test 2") { - EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Ricoh, Cpu.Intel8086)( + EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Ricoh, Cpu.Intel8086, Cpu.Motorola6809)( """ | byte output @$c000 | void main () { @@ -203,7 +203,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers { } test("Flag switching test 3") { - EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Ricoh, Cpu.Intel8086)( + EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Ricoh, Cpu.Intel8086, Cpu.Motorola6809)( """ | byte output @$c000 | void main () { @@ -214,7 +214,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers { } test("Decimal left shift test") { - EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Ricoh, Cpu.Intel8086)( + EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Ricoh, Cpu.Intel8086, Cpu.Motorola6809)( """ | byte output @$c000 | void main () { @@ -229,7 +229,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers { } test("Decimal left shift test 2") { - EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Ricoh, Cpu.Intel8086)( + EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Ricoh, Cpu.Intel8086, Cpu.Motorola6809)( """ | byte output @$c000 | void main () { diff --git a/src/test/scala/millfork/test/emu/M6809Memory.scala b/src/test/scala/millfork/test/emu/M6809Memory.scala index 99274395..31f7a1b2 100644 --- a/src/test/scala/millfork/test/emu/M6809Memory.scala +++ b/src/test/scala/millfork/test/emu/M6809Memory.scala @@ -22,6 +22,8 @@ class M6809Memory(memoryBank: MemoryBank, resetVector: Int) extends MemorySegmen override def load(addr: Int): Int = { if (!memoryBank.readable(addr)) { + val start = addr & 0xff00 + (0 until 0x100).grouped(16).map(range => (start + range.head).toHexString + range.map(i => memoryBank.output(start + i)).map(v => f" $v%02X").mkString("")).foreach(println) println(s"Accessing memory for read at $$${addr.toHexString}") ??? }