1
0
mirror of https://github.com/KarolS/millfork.git synced 2025-08-14 13:26:05 +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)) => case FunctionCallExpression(">>", List(a1, a2)) =>
if (getExpressionTypeImpl(env, log, a2, loosely).size > 1) log.error("Shift amount too large", a2.position) if (getExpressionTypeImpl(env, log, a2, loosely).size > 1) log.error("Shift amount too large", a2.position)
getExpressionTypeImpl(env, log, a1, loosely) getExpressionTypeImpl(env, log, a1, loosely)
case FunctionCallExpression("*'", _) => b
case FunctionCallExpression("<<'", _) => b case FunctionCallExpression("<<'", _) => b
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] = { def compileWordSum(ctx: CompilationContext, expr: SumExpression, fromScratch: Boolean): List[MLine] = {
if (expr.decimal) ???
val (constant, variable) = split(ctx, expr) val (constant, variable) = split(ctx, expr)
val addendReads = variable val addendReads = variable
.map(addend => addend._1 -> M6809ExpressionCompiler.compileToD(ctx, addend._2)) .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) .map(code => (if (code._1) 1 else 0, complexityD(code._2)) -> code).sortBy(_._1).map(_._2)
val result = ListBuffer[MLine]() 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) { for ((neg, load) <- addendReads) {
if (result.isEmpty && fromScratch) { if (result.isEmpty && fromScratch) {
result ++= load result ++= load
if (neg) { if (neg) {
if (expr.decimal) {
decimalInvertD()
} else {
result += MLine.immediate(EORA, 0xff) result += MLine.immediate(EORA, 0xff)
result += MLine.immediate(EORB, 0xff) result += MLine.immediate(EORB, 0xff)
result += MLine.immediate(ADDD, 1) result += MLine.immediate(ADDD, 1)
} }
}
} else { } else {
load match { load match {
case List(l@MLine0(LDD, _, _)) => case List(l@MLine0(LDD, _, _)) if !expr.decimal=>
if (neg) { if (neg) {
result += l.copy(opcode = SUBD) result += l.copy(opcode = SUBD)
} else { } else {
@@ -258,6 +271,18 @@ object M6809Buitins {
} }
case _ => case _ =>
if (neg) { if (neg) {
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 += MLine.pp(PSHS, M6809Register.D)
result ++= load result ++= load
// TODO: optimize // TODO: optimize
@@ -265,6 +290,18 @@ object M6809Buitins {
result += MLine.immediate(EORB, 0xff) result += MLine.immediate(EORB, 0xff)
result += MLine.immediate(ADDD, 1) result += MLine.immediate(ADDD, 1)
result += MLine.accessAndPullSTwice(ADDD) result += MLine.accessAndPullSTwice(ADDD)
}
} else {
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 { } else {
result += MLine.pp(PSHS, M6809Register.D) result += MLine.pp(PSHS, M6809Register.D)
result ++= load result ++= load
@@ -273,9 +310,17 @@ object M6809Buitins {
} }
} }
} }
}
if (!constant.isProvablyZero) { if (!constant.isProvablyZero) {
if (result.isEmpty) { if (result.isEmpty) {
result += MLine.immediate(LDD, constant) 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 { } else {
result += MLine.immediate(ADDD, constant) result += MLine.immediate(ADDD, constant)
} }

View File

@@ -1,12 +1,14 @@
package millfork.compiler.m6809 package millfork.compiler.m6809
import millfork.assembly.m6809.MLine import millfork.assembly.m6809.{Immediate, MLine, MLine0}
import millfork.compiler.CompilationContext import millfork.compiler.{AbstractExpressionCompiler, CompilationContext}
import millfork.node.Expression import millfork.node.{Expression, LhsExpression}
import millfork.assembly.m6809.MOpcode._ import millfork.assembly.m6809.MOpcode._
import millfork.env.NumericConstant import millfork.env.{Constant, NumericConstant}
import millfork.node.M6809Register._ import millfork.node.M6809Register._
import scala.collection.mutable.ListBuffer
/** /**
* @author Karol Stasiak * @author Karol Stasiak
*/ */
@@ -28,14 +30,14 @@ object M6809DecimalBuiltins {
val labelSkip = ctx.nextLabel("ss") val labelSkip = ctx.nextLabel("ss")
val labelRepeat = ctx.nextLabel("sr") val labelRepeat = ctx.nextLabel("sr")
M6809ExpressionCompiler.stashAIfNeeded(ctx, M6809ExpressionCompiler.compileToB(ctx, rhs)) ++ List( M6809ExpressionCompiler.stashAIfNeeded(ctx, M6809ExpressionCompiler.compileToB(ctx, rhs)) ++ List(
MLine.label(labelRepeat),
MLine.immediate(CMPB, 0), MLine.immediate(CMPB, 0),
MLine.shortBranch(BEQ, labelSkip), MLine.shortBranch(BEQ, labelSkip),
MLine.label(labelRepeat),
MLine.pp(PSHS, A), MLine.pp(PSHS, A),
MLine.accessAndPullS(ADDA), MLine.accessAndPullS(ADDA),
MLine.inherent(DAA), MLine.inherent(DAA),
MLine.inherentB(DEC), MLine.inherentB(DEC),
MLine.shortBranch(BRA, labelRepeat), MLine.shortBranch(BNE, labelRepeat),
MLine.label(labelSkip) MLine.label(labelSkip)
) )
} }
@@ -45,4 +47,230 @@ object M6809DecimalBuiltins {
} }
load ++ loop ++ store 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 1 => M6809MulDiv.compileByteMultiplication(ctx, params, updateDerefX = false) ++ targetifyB(ctx, target, isSigned = false)
case 2 => M6809MulDiv.compileWordMultiplication(ctx, params, updateDerefX = false) ++ targetifyD(ctx, target) case 2 => M6809MulDiv.compileWordMultiplication(ctx, params, updateDerefX = false) ++ targetifyD(ctx, target)
} }
case "*'" => ctx.log.error("Decimal multiplication not implemented yet", fce.position); Nil
case "/" => case "/" =>
assertArithmeticBinary(ctx, params) match { assertArithmeticBinary(ctx, params) match {
case (l, r, 1) => M6809MulDiv.compileByteDivision(ctx, Some(l), r, mod=false) ++ targetifyB(ctx, target, isSigned = false) 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, 2) => ???
case (l, r, _) => ??? 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 "+=" => case "+=" =>
val (l, r, size) = assertArithmeticAssignmentLike(ctx, params) val (l, r, size) = assertArithmeticAssignmentLike(ctx, params)
size match { size match {
@@ -399,7 +403,10 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
case 1 => compileAddressToX(ctx, l) ++ M6809MulDiv.compileByteMultiplication(ctx, List(r), updateDerefX = true) 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 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 "/=" => case "/=" =>
val (l, r, size) = assertArithmeticAssignmentLike(ctx, params) val (l, r, size) = assertArithmeticAssignmentLike(ctx, params)
size match { size match {
@@ -449,7 +456,7 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
size match { size match {
case 1 => case 1 =>
compileAddressToX(ctx, l) ++ M6809DecimalBuiltins.compileByteDecimalShiftLeft(ctx, None, r) compileAddressToX(ctx, l) ++ M6809DecimalBuiltins.compileByteDecimalShiftLeft(ctx, None, r)
case 2 => ??? case _ => M6809DecimalBuiltins.compileLongDecimalShiftLeft(ctx, l, r)
} }
case ">>=" => case ">>=" =>
val (l, r, size) = assertArithmeticAssignmentLike(ctx, params) 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 2 => handleInPlaceModification(ctx, l, 2, M6809Buitins.compileWordShiftForD(ctx, r, left = false))
case _ => M6809LargeBuiltins.compileShiftInPlace(ctx, size, l, 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 ">>>>=" => ???
case _ => case _ =>
env.maybeGet[Type](fce.functionName) match { env.maybeGet[Type](fce.functionName) match {
@@ -532,7 +545,7 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
} }
val storeResult = f.returnType.size match { val storeResult = f.returnType.size match {
case 1 => targetifyB(ctx, target, f.returnType.isSigned) case 1 => targetifyB(ctx, target, f.returnType.isSigned)
case 2 => targetifyD(ctx, target) case 2 => targetifyDWithNarrowing(ctx, target)
case _ => case _ =>
if (target == MExpressionTarget.NOTHING) { if (target == MExpressionTarget.NOTHING) {
Nil Nil

View File

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

View File

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

View File

@@ -2,12 +2,12 @@ package millfork.test
import millfork.Cpu import millfork.Cpu
import millfork.test.emu.{EmuCrossPlatformBenchmarkRun, EmuUnoptimizedCrossPlatformRun, EmuUnoptimizedRun, ShouldNotCompile} import millfork.test.emu.{EmuCrossPlatformBenchmarkRun, EmuUnoptimizedCrossPlatformRun, EmuUnoptimizedRun, ShouldNotCompile}
import org.scalatest.{FunSuite, Matchers} import org.scalatest.{AppendedClues, FunSuite, Matchers}
/** /**
* @author Karol Stasiak * @author Karol Stasiak
*/ */
class ByteDecimalMathSuite extends FunSuite with Matchers { class ByteDecimalMathSuite extends FunSuite with Matchers with AppendedClues {
test("Decimal byte addition") { test("Decimal byte addition") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Ricoh, Cpu.Intel8086, Cpu.Motorola6809)( 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") { 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 | word output @$c000
| void main () { | void main () {
@@ -136,7 +136,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
} }
test("Decimal word subtraction") { 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 | word output @$c000
| void main () { | void main () {
@@ -152,7 +152,8 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
} }
test("In-place decimal word subtraction") { 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 output @$c000
| word a | word a
@@ -166,7 +167,8 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
} }
test("In-place decimal long subtraction") { 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 | long output @$c000
| word a | word a
@@ -243,7 +245,8 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
} }
test("Decimal left shift test 3") { 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 | word output @$c000
| void main () { | void main () {
@@ -257,7 +260,8 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
} }
test("Decimal left shift test 4") { 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 | long output @$c000
| void main () { | void main () {
@@ -271,7 +275,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
} }
test("Decimal right shift test") { 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 | byte output @$c000
| void main () { | void main () {
@@ -286,7 +290,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
} }
test("Decimal right shift test 2") { 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 | byte output @$c000
| void main () { | void main () {
@@ -300,7 +304,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
} }
test("Decimal right shift test 3") { 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 | word output @$c000
| void main () { | void main () {
@@ -335,7 +339,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
test("Decimal word right-shift comprehensive suite") { 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)) { 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 | word output @$c000
| void main () { | void main () {
@@ -351,7 +355,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
test("Decimal byte multiplication comprehensive suite") { 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) 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) { 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 | byte output @$c000
| void main () { | void main () {
@@ -361,7 +365,8 @@ class ByteDecimalMathSuite extends FunSuite with Matchers {
| void init() { output = $#i } | void init() { output = $#i }
| void run () { output *'= $#j } | void run () { output *'= $#j }
""".stripMargin.replace("#i", i.toString).replace("#j", j.toString)) { m => """.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") { test("Decimal comparison") {
// CMP#0 shouldn't be elided after a decimal operation. // CMP#0 shouldn't be elided after a decimal operation.
// Currently no emulator used for testing can catch that. // 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 | byte output @$c000
| void main () { | void main () {