1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-11-01 05:05:32 +00:00

6809: Implement decimal operations

This commit is contained in:
Karol Stasiak 2020-06-21 02:25:02 +02:00
parent b387ece71d
commit e77811c67c
7 changed files with 370 additions and 52 deletions

View File

@ -500,6 +500,7 @@ object AbstractExpressionCompiler {
case FunctionCallExpression(">>", List(a1, a2)) =>
if (getExpressionTypeImpl(env, log, a2, loosely).size > 1) log.error("Shift amount too large", a2.position)
getExpressionTypeImpl(env, log, a1, loosely)
case FunctionCallExpression("*'", _) => b
case FunctionCallExpression("<<'", _) => b
case FunctionCallExpression(">>'", _) => b
case FunctionCallExpression(">>>>", _) => b

View File

@ -234,23 +234,36 @@ object M6809Buitins {
}
def compileWordSum(ctx: CompilationContext, expr: SumExpression, fromScratch: Boolean): List[MLine] = {
if (expr.decimal) ???
val (constant, variable) = split(ctx, expr)
val addendReads = variable
.map(addend => addend._1 -> M6809ExpressionCompiler.compileToD(ctx, addend._2))
.map(code => (if (code._1) 1 else 0, complexityD(code._2)) -> code).sortBy(_._1).map(_._2)
val result = ListBuffer[MLine]()
def decimalInvertD(): Unit = {
// TODO: check if it's ok:
val label = ctx.nextLabel("xx")
result += MLine.immediate(CMPD, 0)
result += MLine.shortBranch(BEQ, label)
result += MLine.immediate(EORA, 0xff)
result += MLine.immediate(EORB, 0xff)
result += MLine.immediate(ADDD, 0x999B)
result += MLine.label(label)
}
for ((neg, load) <- addendReads) {
if (result.isEmpty && fromScratch) {
result ++= load
if (neg) {
result += MLine.immediate(EORA, 0xff)
result += MLine.immediate(EORB, 0xff)
result += MLine.immediate(ADDD, 1)
if (expr.decimal) {
decimalInvertD()
} else {
result += MLine.immediate(EORA, 0xff)
result += MLine.immediate(EORB, 0xff)
result += MLine.immediate(ADDD, 1)
}
}
} else {
load match {
case List(l@MLine0(LDD, _, _)) =>
case List(l@MLine0(LDD, _, _)) if !expr.decimal=>
if (neg) {
result += l.copy(opcode = SUBD)
} else {
@ -258,17 +271,42 @@ object M6809Buitins {
}
case _ =>
if (neg) {
result += MLine.pp(PSHS, M6809Register.D)
result ++= load
// TODO: optimize
result += MLine.immediate(EORA, 0xff)
result += MLine.immediate(EORB, 0xff)
result += MLine.immediate(ADDD, 1)
result += MLine.accessAndPullSTwice(ADDD)
if (expr.decimal) {
result += MLine.exg(M6809Register.A, M6809Register.B)
result += MLine.pp(PSHS, M6809Register.D)
result ++= load
decimalInvertD()
result += MLine.exg(M6809Register.A, M6809Register.B)
result += MLine.accessAndPullS(ADDA)
result += MLine.inherent(DAA)
result += MLine.exg(M6809Register.A, M6809Register.B)
result += MLine.accessAndPullS(ADCA)
result += MLine.inherent(DAA)
} else {
result += MLine.pp(PSHS, M6809Register.D)
result ++= load
// TODO: optimize
result += MLine.immediate(EORA, 0xff)
result += MLine.immediate(EORB, 0xff)
result += MLine.immediate(ADDD, 1)
result += MLine.accessAndPullSTwice(ADDD)
}
} else {
result += MLine.pp(PSHS, M6809Register.D)
result ++= load
result += MLine.accessAndPullSTwice(ADDD)
if (expr.decimal) {
result += MLine.exg(M6809Register.A, M6809Register.B)
result += MLine.pp(PSHS, M6809Register.D)
result ++= load
result += MLine.exg(M6809Register.A, M6809Register.B)
result += MLine.accessAndPullS(ADDA)
result += MLine.inherent(DAA)
result += MLine.exg(M6809Register.A, M6809Register.B)
result += MLine.accessAndPullS(ADCA)
result += MLine.inherent(DAA)
} else {
result += MLine.pp(PSHS, M6809Register.D)
result ++= load
result += MLine.accessAndPullSTwice(ADDD)
}
}
}
}
@ -276,6 +314,13 @@ object M6809Buitins {
if (!constant.isProvablyZero) {
if (result.isEmpty) {
result += MLine.immediate(LDD, constant)
} else if (expr.decimal) {
result += MLine.exg(M6809Register.A, M6809Register.B)
result += MLine.immediate(ADDA, constant.loByte)
result += MLine.inherent(DAA)
result += MLine.exg(M6809Register.A, M6809Register.B)
result += MLine.immediate(ADCA, constant.hiByte)
result += MLine.inherent(DAA)
} else {
result += MLine.immediate(ADDD, constant)
}

View File

@ -1,12 +1,14 @@
package millfork.compiler.m6809
import millfork.assembly.m6809.MLine
import millfork.compiler.CompilationContext
import millfork.node.Expression
import millfork.assembly.m6809.{Immediate, MLine, MLine0}
import millfork.compiler.{AbstractExpressionCompiler, CompilationContext}
import millfork.node.{Expression, LhsExpression}
import millfork.assembly.m6809.MOpcode._
import millfork.env.NumericConstant
import millfork.env.{Constant, NumericConstant}
import millfork.node.M6809Register._
import scala.collection.mutable.ListBuffer
/**
* @author Karol Stasiak
*/
@ -28,14 +30,14 @@ object M6809DecimalBuiltins {
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.label(labelRepeat),
MLine.pp(PSHS, A),
MLine.accessAndPullS(ADDA),
MLine.inherent(DAA),
MLine.inherentB(DEC),
MLine.shortBranch(BRA, labelRepeat),
MLine.shortBranch(BNE, labelRepeat),
MLine.label(labelSkip)
)
}
@ -45,4 +47,230 @@ object M6809DecimalBuiltins {
}
load ++ loop ++ store
}
def compileLongDecimalShiftLeft(ctx: CompilationContext, lhs: LhsExpression, rhs: Expression): List[MLine] = {
val result = new ListBuffer[MLine]()
val byteCount = AbstractExpressionCompiler.getExpressionType(ctx, lhs).size
val targetAddr = M6809ExpressionCompiler.compileAddressToX(ctx, lhs) match {
case List(MLine0(LDX, Immediate, addr)) =>
Some(addr)
case xs =>
result ++= xs
None
}
val once = List.tabulate(byteCount){ i =>
val innerResult = new ListBuffer[MLine]()
targetAddr match {
case Some(addr) =>
innerResult += MLine.absolute(LDA, addr + (byteCount - 1 - i))
innerResult += MLine.absolute(if (i == 0) ADDA else ADCA, addr + (byteCount - 1 - i))
case None =>
innerResult += MLine.indexedX(LDA, byteCount - 1 - i)
innerResult += MLine.indexedX(if (i == 0) ADDA else ADCA, byteCount - 1 - i)
}
// TODO: use these if volatile:
// innerResult += MLine.pp(PSHS, A)
// innerResult += MLine.accessAndPullS(if (i == 0) ADDA else ADCA)
innerResult += MLine.inherent(DAA)
targetAddr match {
case Some(addr) =>
innerResult += MLine.absolute(STA, addr + (byteCount - 1 - i))
case None =>
innerResult += MLine.indexedX(STA, byteCount - 1 - i)
}
innerResult.toSeq
}.flatten
ctx.env.eval(rhs) match {
case Some(NumericConstant(0, _)) =>
// TODO: volatile?
case Some(NumericConstant(1, _)) =>
result ++= once
case _ =>
val labelSkip = ctx.nextLabel("ss")
val labelRepeat = ctx.nextLabel("sr")
result ++= M6809ExpressionCompiler.compileToB(ctx, rhs)
result += MLine.immediate(CMPB, 0)
result += MLine.shortBranch(BEQ, labelSkip)
result += MLine.label(labelRepeat)
result ++= once
result += MLine.inherentB(DEC)
result += MLine.shortBranch(BNE, labelRepeat)
result += MLine.label(labelSkip)
}
result.toList
}
def compileInPlaceByteMultiplication(ctx: CompilationContext, target: LhsExpression, multiplicand: Expression): List[MLine] = {
val multiplier = ctx.env.eval(multiplicand) match {
case Some(NumericConstant(v, _)) =>
if (v.&(0xf0) > 0x90 || v.&(0xf) > 9)
ctx.log.error("Invalid decimal constant", multiplicand.position)
(v.&(0xf0).>>(4) * 10 + v.&(0xf)).toInt min 99
case _ =>
ctx.log.error("Cannot multiply by a non-constant amount", multiplicand.position)
return Nil
}
val result = new ListBuffer[MLine]()
val targetAddr: Option[Constant] = M6809ExpressionCompiler.compileAddressToX(ctx, target) match {
case List(MLine(LDX, Immediate, addr, _, _)) =>
result += MLine.absolute(LDB, addr)
Some(addr)
case xs =>
result ++= xs
result += MLine.indexedX(LDB, 0)
None
}
multiplier match {
case 0 =>
result += MLine.inherentA(CLR)
case 1 =>
result += MLine.tfr(B, A)
case x =>
result += MLine.tfr(B, A)
result += MLine.pp(PSHS, D)
val add1 = List()
// TODO: rethink this:
val ways = waysStolenFromTheZ80Implementation
for(way <- ways(x)) way match {
case 1 =>
result += MLine.indexedS(ADDA, 1)
result += MLine.inherent(DAA)
result += MLine.indexedS(STA, 0)
case q if q < 10 =>
for(i<-0 until (q-1)) {
result += MLine.indexedS(ADDA, 0)
result += MLine.inherent(DAA)
}
result += MLine.indexedS(STA, 0)
case q if q >= 10 =>
result += MLine.inherentA(ASL)
result += MLine.inherentA(ASL)
result += MLine.inherentA(ASL)
result += MLine.inherentA(ASL)
for(i<-0 until (q-10)) {
result += MLine.indexedS(ADDA, 0)
result += MLine.inherent(DAA)
}
result += MLine.indexedS(STA, 0)
}
result += MLine.indexedS(LEAS, 2)
}
targetAddr match {
case Some(addr) =>
result += MLine.absolute(STA, addr)
case None =>
result += MLine.indexedX(STA, 0)
}
result.toList
}
private lazy val waysStolenFromTheZ80Implementation: Map[Int, List[Int]] = Map(
2 -> List(2), 3 -> List(3), 4 -> List(2,2), 5 -> List(2,2,1), 6 -> List(3,2), 7 -> List(3,2,1), 8 -> List(2,2,2), 9 -> List(3,3), 10 -> List(10),
11 -> List(11), 12 -> List(12), 13 -> List(13), 14 -> List(3,2,1,2), 15 -> List(3,5), 16 -> List(2,2,2,2), 17 -> List(2,2,2,2,1), 18 -> List(3,3,2), 19 -> List(3,3,2,1), 20 -> List(2,10),
21 -> List(2,10,1), 22 -> List(11,2), 23 -> List(11,2,1), 24 -> List(12,2), 25 -> List(12,2,1), 26 -> List(2,13), 27 -> List(3,3,3), 28 -> List(3,2,1,2,2), 29 -> List(3,2,1,2,2,1), 30 -> List(3,10),
31 -> List(3,10,1), 32 -> List(2,2,2,2,2), 33 -> List(11,3), 34 -> List(11,3,1), 35 -> List(11,3,1,1), 36 -> List(3,12), 37 -> List(3,12,1), 38 -> List(3,3,2,1,2), 39 -> List(3,13), 40 -> List(2,2,10),
41 -> List(2,2,10,1), 42 -> List(2,10,1,2), 43 -> List(2,10,1,2,1), 44 -> List(11,2,2), 45 -> List(11,2,2,1), 46 -> List(11,2,1,2), 47 -> List(11,2,1,2,1), 48 -> List(12,2,2), 49 -> List(12,2,2,1), 50 -> List(2,2,1,10),
51 -> List(2,2,1,10,1), 52 -> List(2,2,13), 53 -> List(2,2,13,1), 54 -> List(3,3,3,2), 55 -> List(11,5), 56 -> List(3,2,1,2,2,2), 57 -> List(3,3,2,1,3), 58 -> List(3,2,1,2,2,1,2), 59 -> List(3,2,1,2,2,1,2,1), 60 -> List(3,2,10),
61 -> List(3,2,10,1), 62 -> List(3,10,1,2), 63 -> List(2,10,1,3), 64 -> List(2,2,2,2,2,2), 65 -> List(2,2,2,2,2,2,1), 66 -> List(11,3,2), 67 -> List(11,3,2,1), 68 -> List(11,3,1,2), 69 -> List(11,2,1,3), 70 -> List(3,2,1,10),
71 -> List(3,2,1,10,1), 72 -> List(3,12,2), 73 -> List(3,12,2,1), 74 -> List(3,12,1,2), 75 -> List(12,2,1,3), 76 -> List(3,3,2,1,2,2), 77 -> List(3,2,1,11), 78 -> List(3,2,13), 79 -> List(3,2,13,1), 80 -> List(2,2,2,10),
81 -> List(2,2,2,10,1), 82 -> List(2,2,10,1,2), 83 -> List(2,2,10,1,2,1), 84 -> List(2,10,1,2,2), 85 -> List(2,10,1,2,2,1), 86 -> List(2,10,1,2,1,2), 87 -> List(2,10,1,2,1,2,1), 88 -> List(11,2,2,2), 89 -> List(11,2,2,2,1), 90 -> List(3,3,10),
91 -> List(3,3,10,1), 92 -> List(11,2,1,2,2), 93 -> List(3,10,1,3), 94 -> List(3,10,1,3,1), 95 -> List(3,3,2,1,5), 96 -> List(12,2,2,2), 97 -> List(12,2,2,2,1), 98 -> List(12,2,2,1,2), 99 -> List(11,3,3),
)
private def shiftOrRotateAccumulatorRight(ctx: CompilationContext, rotate: Boolean, preserveCarry: Boolean): List[MLine] = {
val skipHiDigit = ctx.nextLabel("ds")
val skipLoDigit = ctx.nextLabel("ds")
val result = new ListBuffer[MLine]()
result += (if (rotate) MLine.inherentA(ROR) else MLine.inherentA(LSR))
if (preserveCarry) result += MLine.pp(PSHS, CC)
result += MLine.shortBranch(BPL, skipHiDigit)
result += MLine.immediate(SUBA, 0x30)
result += MLine.label(skipHiDigit)
result += MLine.immediate(BITA, 8)
result += MLine.shortBranch(BEQ, skipLoDigit)
result += MLine.immediate(SUBA, 0x3)
result += MLine.label(skipLoDigit)
if (preserveCarry) result += MLine.pp(PULS, CC)
result.toList
}
def compileByteDecimalShiftRight(ctx: CompilationContext, lhs: Option[Expression], rhs: Expression): List[MLine] = {
val result = new ListBuffer[MLine]()
lhs match {
case None => result += MLine.indexedX(LDA, 0)
case Some(l) => result ++= M6809ExpressionCompiler.compileToA(ctx, l)
}
val once = shiftOrRotateAccumulatorRight(ctx, rotate = false, preserveCarry = false)
ctx.env.eval(rhs) match {
case Some(NumericConstant(0, _)) =>
case Some(NumericConstant(1, _)) =>
result ++= once
case _ =>
val labelSkip = ctx.nextLabel("ss")
val labelRepeat = ctx.nextLabel("sr")
result ++= M6809ExpressionCompiler.stashAIfNeeded(ctx, M6809ExpressionCompiler.compileToB(ctx, rhs))
result += MLine.immediate(CMPB, 0)
result += MLine.shortBranch(BEQ, labelSkip)
result += MLine.label(labelRepeat)
result ++= once
result += MLine.inherentB(DEC)
result += MLine.shortBranch(BNE, labelRepeat)
result += MLine.label(labelSkip)
}
lhs match {
case None => result += MLine.indexedX(STA, 0)
case _ =>
}
result.toList
}
def compileLongDecimalShiftRight(ctx: CompilationContext, lhs: LhsExpression, rhs: Expression): List[MLine] = {
val result = new ListBuffer[MLine]()
val byteCount = AbstractExpressionCompiler.getExpressionType(ctx, lhs).size
val targetAddr = M6809ExpressionCompiler.compileAddressToX(ctx, lhs) match {
case List(MLine0(LDX, Immediate, addr)) =>
Some(addr)
case xs =>
result ++= xs
None
}
val once = List.tabulate(byteCount){ i =>
val innerResult = new ListBuffer[MLine]()
targetAddr match {
case Some(addr) =>
innerResult += MLine.absolute(LDA, addr + i)
case None =>
innerResult += MLine.indexedX(LDA, i)
}
innerResult ++= shiftOrRotateAccumulatorRight(ctx, rotate = i != 0, preserveCarry = i != byteCount - 1)
targetAddr match {
case Some(addr) =>
innerResult += MLine.absolute(STA, addr + i)
case None =>
innerResult += MLine.indexedX(STA, i)
}
innerResult.toSeq
}.flatten
ctx.env.eval(rhs) match {
case Some(NumericConstant(0, _)) =>
// TODO: volatile?
case Some(NumericConstant(1, _)) =>
result ++= once
case _ =>
val labelSkip = ctx.nextLabel("ss")
val labelRepeat = ctx.nextLabel("sr")
result ++= M6809ExpressionCompiler.compileToB(ctx, rhs)
result += MLine.immediate(CMPB, 0)
result += MLine.shortBranch(BEQ, labelSkip)
result += MLine.label(labelRepeat)
result ++= once
result += MLine.inherentB(DEC)
result += MLine.shortBranch(BNE, labelRepeat)
result += MLine.label(labelSkip)
}
result.toList
}
}

View File

@ -222,7 +222,6 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
case 1 => M6809MulDiv.compileByteMultiplication(ctx, params, updateDerefX = false) ++ targetifyB(ctx, target, isSigned = false)
case 2 => M6809MulDiv.compileWordMultiplication(ctx, params, updateDerefX = false) ++ targetifyD(ctx, target)
}
case "*'" => ctx.log.error("Decimal multiplication not implemented yet", fce.position); Nil
case "/" =>
assertArithmeticBinary(ctx, params) match {
case (l, r, 1) => M6809MulDiv.compileByteDivision(ctx, Some(l), r, mod=false) ++ targetifyB(ctx, target, isSigned = false)
@ -353,7 +352,12 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
case (l, r, 2) => ???
case (l, r, _) => ???
}
case ">>'" => ???
case ">>'" =>
assertArithmeticBinary(ctx, params) match {
case (l, r, 1) => M6809DecimalBuiltins.compileByteDecimalShiftRight(ctx, Some(l), r) ++ targetifyA(ctx, target, isSigned = false)
case (l, r, 2) => ???
case (l, r, _) => ???
}
case "+=" =>
val (l, r, size) = assertArithmeticAssignmentLike(ctx, params)
size match {
@ -399,7 +403,10 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
case 1 => compileAddressToX(ctx, l) ++ M6809MulDiv.compileByteMultiplication(ctx, List(r), updateDerefX = true)
case 2 => compileAddressToX(ctx, l) ++ M6809MulDiv.compileWordMultiplication(ctx, List(r), updateDerefX = true)
}
case "*'=" => ctx.log.error("Decimal multiplication not implemented yet", fce.position); Nil
case "*'=" =>
assertAllArithmeticBytes("Long multiplication not supported", ctx, params)
val (l, r, 1) = assertArithmeticAssignmentLike(ctx, params)
M6809DecimalBuiltins.compileInPlaceByteMultiplication(ctx, l, r)
case "/=" =>
val (l, r, size) = assertArithmeticAssignmentLike(ctx, params)
size match {
@ -449,7 +456,7 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
size match {
case 1 =>
compileAddressToX(ctx, l) ++ M6809DecimalBuiltins.compileByteDecimalShiftLeft(ctx, None, r)
case 2 => ???
case _ => M6809DecimalBuiltins.compileLongDecimalShiftLeft(ctx, l, r)
}
case ">>=" =>
val (l, r, size) = assertArithmeticAssignmentLike(ctx, params)
@ -459,7 +466,13 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
case 2 => handleInPlaceModification(ctx, l, 2, M6809Buitins.compileWordShiftForD(ctx, r, left = false))
case _ => M6809LargeBuiltins.compileShiftInPlace(ctx, size, l, r, left = false)
}
case ">>'=" => ???
case ">>'=" =>
val (l, r, size) = assertArithmeticAssignmentLike(ctx, params)
size match {
case 1 =>
compileAddressToX(ctx, l) ++ M6809DecimalBuiltins.compileByteDecimalShiftRight(ctx, None, r)
case _ => M6809DecimalBuiltins.compileLongDecimalShiftRight(ctx, l, r)
}
case ">>>>=" => ???
case _ =>
env.maybeGet[Type](fce.functionName) match {
@ -532,7 +545,7 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
}
val storeResult = f.returnType.size match {
case 1 => targetifyB(ctx, target, f.returnType.isSigned)
case 2 => targetifyD(ctx, target)
case 2 => targetifyDWithNarrowing(ctx, target)
case _ =>
if (target == MExpressionTarget.NOTHING) {
Nil

View File

@ -63,12 +63,16 @@ object M6809LargeBuiltins {
}
// TODO: use loop for very large structures
// TODO: use D to speed up certain loads
targetInit ++ byteLoads.zipWithIndex.flatMap{ case (loadByte, ix) =>
M6809ExpressionCompiler.stashXIfNeeded(ctx, loadByte) :+ ( targetAddr match {
case Some(addr) => MLine.absolute(STB, addr + (byteCount - 1 - ix))
case None => MLine.indexedX(STB, byteCount - 1 - ix)
} )
}
targetInit ++ (targetAddr match {
case Some(addr) =>
byteLoads.zipWithIndex.flatMap { case (loadByte, ix) =>
loadByte :+ MLine.absolute(STB, addr + (byteCount - 1 - ix))
}
case None =>
byteLoads.zipWithIndex.flatMap { case (loadByte, ix) =>
M6809ExpressionCompiler.stashXIfNeeded(ctx, loadByte) :+ MLine.indexedX(STB, byteCount - 1 - ix)
}
})
}
def convertToLda(ldb: List[MLine]): List[MLine] = {
@ -145,19 +149,41 @@ object M6809LargeBuiltins {
case (ADDB | SUBB | ADDA | SUBA, Some(0)) if i == firstNonzeroByte =>
firstNonzeroByte = i + 1
case (SUBA, _) => ???
case (SUBA, _) =>
targetAddr match {
case Some(addr) =>
if (i == firstNonzeroByte) {
result ++= ldb
} else {
result ++= M6809ExpressionCompiler.stashCarryIfNeeded(ctx, ldb)
}
result += MLine.pp(PSHS, M6809Register.B)
result += MLine.immediate(LDA, if (i == firstNonzeroByte) 0x9a else 0x99)
result += MLine.accessAndPullS(SUBA)
result += MLine.absolute(if (i == firstNonzeroByte) ADDA else ADCA, addr + (sizeInBytes - 1 - i))
result += MLine.inherent(DAA)
result += MLine.absolute(STA, addr + (sizeInBytes - 1 - i))
case None =>
result ++= M6809ExpressionCompiler.stashXIfNeeded(ctx, ldb)
result += MLine.pp(PSHS, M6809Register.B)
result += MLine.immediate(LDA, if (i == firstNonzeroByte) 0x9a else 0x99)
result += MLine.accessAndPullS(SUBA)
result += MLine.indexedX(if (i == firstNonzeroByte) ADDA else ADCA, sizeInBytes - 1 - i)
result += MLine.inherent(DAA)
result += MLine.indexedX(STA, sizeInBytes - 1 - i)
}
case (ADDA, _) if i == firstNonzeroByte =>
val lda = convertToLda(ldb)
targetAddr match {
case Some(addr) =>
result ++= lda
result += MLine.absolute(ADCA, addr + (sizeInBytes - 1 - i))
result += MLine.absolute(ADDA, addr + (sizeInBytes - 1 - i))
result += MLine.inherent(DAA)
result += MLine.absolute(STA, addr + (sizeInBytes - 1 - i))
case None =>
result ++= M6809ExpressionCompiler.stashXIfNeeded(ctx, lda)
result += MLine.indexedX(ADCA, sizeInBytes - 1 - i)
result += MLine.indexedX(ADDA, sizeInBytes - 1 - i)
result += MLine.inherent(DAA)
result += MLine.indexedX(STA, sizeInBytes - 1 - i)
}

View File

@ -209,7 +209,7 @@ object Z80DecimalBuiltIns {
case Some(NumericConstant(v, _)) =>
if (v.&(0xf0) > 0x90 || v.&(0xf) > 9)
ctx.log.error("Invalid decimal constant", r.position)
(v.&(0xf0).>>(4) * 10 + v.&(0xf)).toInt
(v.&(0xf0).>>(4) * 10 + v.&(0xf)).toInt min 99
case _ =>
ctx.log.error("Cannot multiply by a non-constant amount", r.position)
return Nil

View File

@ -2,12 +2,12 @@ package millfork.test
import millfork.Cpu
import millfork.test.emu.{EmuCrossPlatformBenchmarkRun, EmuUnoptimizedCrossPlatformRun, EmuUnoptimizedRun, ShouldNotCompile}
import org.scalatest.{FunSuite, Matchers}
import org.scalatest.{AppendedClues, FunSuite, Matchers}
/**
* @author Karol Stasiak
*/
class ByteDecimalMathSuite extends FunSuite with Matchers {
class ByteDecimalMathSuite extends FunSuite with Matchers with AppendedClues {
test("Decimal byte addition") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Ricoh, Cpu.Intel8086, Cpu.Motorola6809)(
@ -120,7 +120,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
}
test("Decimal word 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)(
"""
| word output @$c000
| void main () {
@ -136,7 +136,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
}
test("Decimal word 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)(
"""
| word output @$c000
| void main () {
@ -152,7 +152,8 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
}
test("In-place decimal word subtraction") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Ricoh, Cpu.Intel8086)(
// TODO: enable 6809 after the DAA bug in the emulator is fixed
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Ricoh, Cpu.Intel8086/*, Cpu.Motorola6809*/)(
"""
| word output @$c000
| word a
@ -166,7 +167,8 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
}
test("In-place decimal long subtraction") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Ricoh, Cpu.Intel8086)(
// TODO: enable 6809 after the DAA bug in the emulator is fixed
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Ricoh, Cpu.Intel8086/*, Cpu.Motorola6809*/)(
"""
| long output @$c000
| word a
@ -243,7 +245,8 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
}
test("Decimal left shift test 3") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Ricoh, Cpu.Intel8086)(
// TODO: enable 6809 after the DAA bug in the emulator is fixed
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Ricoh, Cpu.Intel8086/*, Cpu.Motorola6809*/)(
"""
| word output @$c000
| void main () {
@ -257,7 +260,8 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
}
test("Decimal left shift test 4") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Ricoh, Cpu.Intel8086)(
// TODO: enable 6809 after the DAA bug in the emulator is fixed
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Ricoh, Cpu.Intel8086/*, Cpu.Motorola6809*/)(
"""
| long output @$c000
| void main () {
@ -271,7 +275,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
}
test("Decimal right 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 () {
@ -286,7 +290,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
}
test("Decimal right 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 () {
@ -300,7 +304,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
}
test("Decimal right shift test 3") {
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)(
"""
| word output @$c000
| void main () {
@ -335,7 +339,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
test("Decimal word right-shift comprehensive suite") {
for (i <- List(0, 1, 10, 100, 1000, 2000, 500, 200, 280, 300, 5234, 7723, 7344, 9, 16, 605, 1111, 2222, 3333, 9999, 8888, 8100)) {
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)(
"""
| word output @$c000
| void main () {
@ -351,7 +355,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, 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 () {
@ -361,7 +365,8 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
| void init() { output = $#i }
| void run () { output *'= $#j }
""".stripMargin.replace("#i", i.toString).replace("#j", j.toString)) { m =>
toDecimal(m.readByte(0xc000)) should equal((i * j) % 100)
val actualHex = m.readByte(0xc000)
toDecimal(actualHex) should equal((i * j) % 100) withClue s"$i×$j = should be ${i*j} was ${actualHex.toHexString}"
}
}
}
@ -392,7 +397,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, 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 () {