diff --git a/src/main/scala/millfork/assembly/m6809/MLine.scala b/src/main/scala/millfork/assembly/m6809/MLine.scala index 6db7a0c9..ea5eec99 100644 --- a/src/main/scala/millfork/assembly/m6809/MLine.scala +++ b/src/main/scala/millfork/assembly/m6809/MLine.scala @@ -32,6 +32,10 @@ object MLine { def longBranch(opcode: MOpcode.Value, label: String): MLine = longBranch(opcode, Label(label)) + def shortBranch(opcode: MOpcode.Value, label: Label): MLine = MLine(opcode, Relative, label.toAddress) + + def shortBranch(opcode: MOpcode.Value, label: String): MLine = shortBranch(opcode, Label(label)) + def tfr(source: M6809Register.Value, target: M6809Register.Value): MLine = MLine(TFR, TwoRegisters(source, target), Constant.Zero) def pp(opcode: MOpcode.Value, registers: M6809Register.Value*): MLine = MLine(opcode, RegisterSet(registers.toSet), Constant.Zero) @@ -42,6 +46,9 @@ object MLine { def indexedX(opcode: MOpcode.Value, offset: Constant): MLine = MLine(opcode, Indexed(M6809Register.X, indirect = false), offset) + def indexedX(opcode: MOpcode.Value, offset: Int): MLine = + MLine(opcode, Indexed(M6809Register.X, indirect = false), Constant(offset)) + def accessAndPullS(opcode: MOpcode.Value): MLine = MLine(opcode, PostIncremented(M6809Register.S, 1, indirect = false), Constant.Zero) @@ -74,9 +81,10 @@ object MLine { variable match { case v: VariableInMemory => MLine.absolute(opcode, v.toAddress) case v: StackVariable => - if (ctx.options.flag(CompilationFlag.UseUForStack)) MLine(opcode, Indexed(M6809Register.U, indirect = false), NumericConstant(v.baseOffset, 1)) - else if (ctx.options.flag(CompilationFlag.UseYForStack)) MLine(opcode, Indexed(M6809Register.Y, indirect = false), NumericConstant(v.baseOffset, 1)) - else MLine(opcode, Indexed(M6809Register.S, indirect = false), NumericConstant(v.baseOffset + ctx.extraStackOffset, 1)) + val size = variable.typ.size + if (ctx.options.flag(CompilationFlag.UseUForStack)) MLine(opcode, Indexed(M6809Register.U, indirect = false), NumericConstant(v.baseOffset, size)) + else if (ctx.options.flag(CompilationFlag.UseYForStack)) MLine(opcode, Indexed(M6809Register.Y, indirect = false), NumericConstant(v.baseOffset, size)) + else MLine(opcode, Indexed(M6809Register.S, indirect = false), NumericConstant(v.baseOffset + ctx.extraStackOffset, size)) case _ => ??? } } diff --git a/src/main/scala/millfork/compiler/m6809/M6809Buitins.scala b/src/main/scala/millfork/compiler/m6809/M6809Buitins.scala index 82efb1e7..ad2d4363 100644 --- a/src/main/scala/millfork/compiler/m6809/M6809Buitins.scala +++ b/src/main/scala/millfork/compiler/m6809/M6809Buitins.scala @@ -54,6 +54,28 @@ object M6809Buitins { } } + def perform16BitInPlace(ctx: CompilationContext, l: LhsExpression, r: Expression, opcodeA: MOpcode.Value, opcodeB: MOpcode.Value, commutative: Boolean): List[MLine] = { + val lc = M6809ExpressionCompiler.compileToD(ctx, l) + val rc = M6809ExpressionCompiler.compileToD(ctx, r) + (lc, rc) match { + case (List(ldl@MLine0(LDD, Absolute(false), _)), _) => + rc ++ List(ldl.copy(opcode = opcodeA), ldl.copy(opcode = opcodeB, parameter = ldl.parameter + 1), ldl.copy(opcode = STD)) + case (_, List(ldr@MLine0(LDD, Absolute(false), _))) if lc.last.opcode == LDD => + lc ++ List(ldr.copy(opcode = opcodeA), ldr.copy(opcode = opcodeB, parameter = ldr.parameter + 1), lc.last.copy(opcode = STD)) + case (_, List(ldr@MLine0(LDD, Immediate, _))) if lc.last.opcode == LDD => + lc ++ List(ldr.copy(opcode = opcodeA, parameter = ldr.parameter.hiByte), ldr.copy(opcode = opcodeB, parameter = ldr.parameter.loByte), lc.last.copy(opcode = STD)) + case _ if lc.last.opcode == LDD && commutative => + // TODO: preserve X? + lc ++ List(MLine.pp(PSHS, M6809Register.D)) ++ rc ++ List(MLine.accessAndPullS(opcodeA), MLine.accessAndPullS(opcodeB), lc.last.copy(opcode = STD)) + case _ if lc.last.opcode == LDD => + // TODO: preserve X? + rc ++ List(MLine.pp(PSHS, M6809Register.D)) ++ lc ++ List(MLine.accessAndPullS(opcodeA), MLine.accessAndPullS(opcodeB), lc.last.copy(opcode = STD)) + case _ => + println(lc) + ??? + } + } + def split(ctx: CompilationContext, expr: SumExpression): (Constant, List[(Boolean, Expression)]) = { var constant = Constant.Zero @@ -283,7 +305,18 @@ object M6809Buitins { ctx.env.eval(rhs) match { case Some(NumericConstant(0, _)) => Nil case Some(NumericConstant(n, _)) => List.fill(n.toInt)(MLine.inherentB(op)) - case _ => ??? + case _ => + val loop = ctx.nextLabel("sr") + val skip = ctx.nextLabel("ss") + M6809ExpressionCompiler.stashBIfNeeded(ctx, M6809ExpressionCompiler.compileToX(ctx, rhs)) ++ List( + MLine.label(loop), + MLine.indexedX(LEAX, -1), + MLine.immediate(CMPX, -1), + MLine.shortBranch(BEQ, skip), + MLine.inherentB(op), + MLine.shortBranch(BRA, loop), + MLine.label(skip) + ) } } @@ -291,8 +324,21 @@ object M6809Buitins { val op = if (left) List(MLine.inherentB(ASL), MLine.inherentA(ROL)) else List(MLine.inherentA(LSR), MLine.inherentB(ROR)) ctx.env.eval(rhs) match { case Some(NumericConstant(0, _)) => Nil + case Some(NumericConstant(8, _)) => + if (left) List(MLine.tfr(M6809Register.B, M6809Register.A), MLine.immediate(LDB, 0)) + else List(MLine.tfr(M6809Register.A, M6809Register.B), MLine.immediate(LDA, 0)) case Some(NumericConstant(n, _)) => List.fill(n.toInt)(op).flatten - case _ => ??? + case _ => + val loop = ctx.nextLabel("sr") + val skip = ctx.nextLabel("ss") + M6809ExpressionCompiler.stashDIfNeeded(ctx, M6809ExpressionCompiler.compileToX(ctx, rhs)) ++ List( + MLine.label(loop), + MLine.indexedX(LEAX, -1), + MLine.immediate(CMPX, -1), + MLine.shortBranch(BEQ, skip))++op++List( + MLine.shortBranch(BRA, loop), + MLine.label(skip) + ) } } diff --git a/src/main/scala/millfork/compiler/m6809/M6809Comparisons.scala b/src/main/scala/millfork/compiler/m6809/M6809Comparisons.scala index a34497e6..bf706cd7 100644 --- a/src/main/scala/millfork/compiler/m6809/M6809Comparisons.scala +++ b/src/main/scala/millfork/compiler/m6809/M6809Comparisons.scala @@ -11,7 +11,7 @@ import millfork.assembly.m6809.MOpcode._ object M6809Comparisons { def isTrivial(lc: List[MLine]): Boolean = lc match { - case List(MLine0(LDB, _, _)) => true + case List(MLine0(LDB | LDD, _, _)) => true case _ => false } @@ -25,7 +25,7 @@ object M6809Comparisons { case ComparisonType.GreaterOrEqualUnsigned => BCC case ComparisonType.LessUnsigned => BCS case ComparisonType.GreaterUnsigned => BHI - case ComparisonType.LessOrEqualSigned => BLS + case ComparisonType.LessOrEqualUnsigned => BLS case ComparisonType.GreaterSigned => BGT case ComparisonType.GreaterOrEqualSigned => BGE case ComparisonType.LessSigned => BLT @@ -45,4 +45,34 @@ object M6809Comparisons { } } + def compile16BitComparison(ctx: CompilationContext, comparisonType: ComparisonType.Value, l: Expression, r: Expression, branches: BranchSpec): scala.List[MLine] = { + val jump = branches match { + case BranchIfFalse(label) => return compile16BitComparison(ctx, ComparisonType.negate(comparisonType), l, r, branches.flip) + case BranchIfTrue(label) => List(MLine.longBranch( + comparisonType match { + case ComparisonType.Equal => BEQ + case ComparisonType.NotEqual => BNE + case ComparisonType.GreaterOrEqualUnsigned => BCC + case ComparisonType.LessUnsigned => BCS + case ComparisonType.GreaterUnsigned => BHI + case ComparisonType.LessOrEqualUnsigned => BLS + case ComparisonType.GreaterSigned => BGT + case ComparisonType.GreaterOrEqualSigned => BGE + case ComparisonType.LessSigned => BLT + case ComparisonType.LessOrEqualSigned => BLE + }, + label + )) + case _ => Nil + } + val lc = M6809ExpressionCompiler.compileToD(ctx, l) + val rc = M6809ExpressionCompiler.compileToD(ctx, r) + if (isTrivial(lc) && !isTrivial(rc)) return compile16BitComparison(ctx, ComparisonType.flip(comparisonType), r, l, branches) + if (isTrivial(rc)) { + lc ++ rc.map(_.copy(opcode = CMPD)) ++ jump + } else { + rc ++ List(MLine.pp(PSHS, M6809Register.D)) ++ lc ++ List(MLine.accessAndPullSTwice(CMPD)) ++ jump + } + } + } diff --git a/src/main/scala/millfork/compiler/m6809/M6809ExpressionCompiler.scala b/src/main/scala/millfork/compiler/m6809/M6809ExpressionCompiler.scala index 3347971a..d417116c 100644 --- a/src/main/scala/millfork/compiler/m6809/M6809ExpressionCompiler.scala +++ b/src/main/scala/millfork/compiler/m6809/M6809ExpressionCompiler.scala @@ -1,6 +1,6 @@ package millfork.compiler.m6809 -import millfork.assembly.m6809.{DAccumulatorIndexed, Indexed, MLine, MOpcode, TwoRegisters} +import millfork.assembly.m6809.{DAccumulatorIndexed, Immediate, Indexed, MLine, MLine0, MOpcode, TwoRegisters} import millfork.compiler.{AbstractExpressionCompiler, BranchIfFalse, BranchIfTrue, BranchSpec, ComparisonType, CompilationContext, NoBranching} import millfork.node.{DerefExpression, Expression, FunctionCallExpression, GeneratedConstantExpression, IndexedExpression, LhsExpression, LiteralExpression, M6809Register, SumExpression, VariableExpression} import millfork.assembly.m6809.MOpcode._ @@ -252,7 +252,7 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] { compileTransitiveRelation(ctx, "==", params, target, branches) { (l, r) => size match { case 1 => M6809Comparisons.compile8BitComparison(ctx, ComparisonType.Equal, l, r, branches) - case 2 => ctx.log.error("Word equality comparison not implemented yet", fce.position); Nil + case 2 => M6809Comparisons.compile16BitComparison(ctx, ComparisonType.Equal, l, r, branches) case _ => ??? } } @@ -261,7 +261,7 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] { compileTransitiveRelation(ctx, "!=", params, target, branches) { (l, r) => size match { case 1 => M6809Comparisons.compile8BitComparison(ctx, ComparisonType.NotEqual, l, r, branches) - case 2 => ctx.log.error("Word inequality comparison not implemented yet", fce.position); Nil + case 2 => M6809Comparisons.compile16BitComparison(ctx, ComparisonType.NotEqual, l, r, branches) case _ => ??? } } @@ -270,6 +270,7 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] { compileTransitiveRelation(ctx, "<", params, target, branches) { (l, r) => size match { case 1 => M6809Comparisons.compile8BitComparison(ctx, if (signed) ComparisonType.LessSigned else ComparisonType.LessUnsigned, l, r, branches) + case 2 => M6809Comparisons.compile16BitComparison(ctx, if (signed) ComparisonType.LessSigned else ComparisonType.LessUnsigned, l, r, branches) case _ => ??? } } @@ -278,6 +279,7 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] { compileTransitiveRelation(ctx, ">", params, target, branches) { (l, r) => size match { case 1 => M6809Comparisons.compile8BitComparison(ctx, if (signed) ComparisonType.GreaterSigned else ComparisonType.GreaterUnsigned, l, r, branches) + case 2 => M6809Comparisons.compile16BitComparison(ctx, if (signed) ComparisonType.GreaterSigned else ComparisonType.GreaterUnsigned, l, r, branches) case _ => ??? } } @@ -286,6 +288,7 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] { compileTransitiveRelation(ctx, "<=", params, target, branches) { (l, r) => size match { case 1 => M6809Comparisons.compile8BitComparison(ctx, if (signed) ComparisonType.LessOrEqualSigned else ComparisonType.LessOrEqualUnsigned, l, r, branches) + case 2 => M6809Comparisons.compile16BitComparison(ctx, if (signed) ComparisonType.LessOrEqualSigned else ComparisonType.LessOrEqualUnsigned, l, r, branches) case _ => ??? } } @@ -294,6 +297,7 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] { compileTransitiveRelation(ctx, ">=", params, target, branches) { (l, r) => size match { case 1 => M6809Comparisons.compile8BitComparison(ctx, if (signed) ComparisonType.GreaterOrEqualSigned else ComparisonType.GreaterOrEqualUnsigned, l, r, branches) + case 2 => M6809Comparisons.compile16BitComparison(ctx, if (signed) ComparisonType.GreaterOrEqualSigned else ComparisonType.GreaterOrEqualUnsigned, l, r, branches) case _ => ??? } } @@ -302,13 +306,13 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] { case 1 => compileToB(ctx, params(0)) ++ M6809Buitins.compileByteShiftForB(ctx, params(1), left = true) ++ targetifyB(ctx, target, isSigned = false) case 2 => compileToD(ctx, params(0)) ++ M6809Buitins.compileWordShiftForD(ctx, params(1), left = true) ++ targetifyD(ctx, target) } - case ">>" => ??? + case ">>" => getArithmeticParamMaxSize(ctx, params) match { case 1 => compileToB(ctx, params(0)) ++ M6809Buitins.compileByteShiftForB(ctx, params(1), left = false) ++ targetifyB(ctx, target, isSigned = false) case 2 => compileToD(ctx, params(0)) ++ M6809Buitins.compileWordShiftForD(ctx, params(1), left = false) ++ targetifyD(ctx, target) } case ">>>>" => - // TODO: this words, but is really suboptimal + // TODO: this works, but is really suboptimal getArithmeticParamMaxSize(ctx, params) match { case 1 | 2 => compileToD(ctx, params(0)) ++ List(MLine.immediate(ANDA, 1)) ++ @@ -341,46 +345,39 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] { val (l, r, size) = assertArithmeticAssignmentLike(ctx, params) size match { case 1 => M6809Buitins.perform8BitInPlace(ctx, l, r, ANDB) + case 2 => M6809Buitins.perform16BitInPlace(ctx, l, r, ANDB, commutative = true) case _ => ??? } case "|=" => val (l, r, size) = assertArithmeticAssignmentLike(ctx, params) size match { case 1 => M6809Buitins.perform8BitInPlace(ctx, l, r, ORB) + case 2 => M6809Buitins.perform16BitInPlace(ctx, l, r, ORB, commutative = true) case _ => ??? } case "^=" => val (l, r, size) = assertArithmeticAssignmentLike(ctx, params) size match { case 1 => M6809Buitins.perform8BitInPlace(ctx, l, r, EORB) + case 2 => M6809Buitins.perform16BitInPlace(ctx, l, r, EORB, commutative = true) case _ => ??? } case "<<=" => val (l, r, size) = assertArithmeticAssignmentLike(ctx, params) // TODO: optimize shifts directly in memory size match { - case 1 => compileAddressToX(ctx, l) ++ - List(MLine.indexedX(LDB, Constant.Zero)) ++ - M6809Buitins.compileByteShiftForB(ctx, r, left = true) ++ - List(MLine.indexedX(STB, Constant.Zero)) - case 2 => compileAddressToX(ctx, l) ++ - List(MLine.indexedX(LDD, Constant.Zero)) ++ - M6809Buitins.compileWordShiftForD(ctx, r, left = true) ++ - List(MLine.indexedX(STD, Constant.Zero)) + case 1 => + handleInPlaceModification(ctx, l, 1, M6809Buitins.compileByteShiftForB(ctx, r, left = true)) + case 2 => + handleInPlaceModification(ctx, l, 2, M6809Buitins.compileWordShiftForD(ctx, r, left = true)) } case "<<'=" => ??? case ">>=" => val (l, r, size) = assertArithmeticAssignmentLike(ctx, params) // TODO: optimize shifts directly in memory size match { - case 1 => compileAddressToX(ctx, l) ++ - List(MLine.indexedX(LDB, Constant.Zero)) ++ - M6809Buitins.compileByteShiftForB(ctx, r, left = false) ++ - List(MLine.indexedX(STB, Constant.Zero)) - case 2 => compileAddressToX(ctx, l) ++ - List(MLine.indexedX(LDD, Constant.Zero)) ++ - M6809Buitins.compileWordShiftForD(ctx, r, left = false) ++ - List(MLine.indexedX(STD, Constant.Zero)) + case 1 => handleInPlaceModification(ctx, l, 1, M6809Buitins.compileByteShiftForB(ctx, r, left = false)) + case 2 => handleInPlaceModification(ctx, l, 2, M6809Buitins.compileWordShiftForD(ctx, r, left = false)) } case ">>'=" => ??? case ">>>>=" => ??? @@ -547,6 +544,11 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] { else lines } + def stashXIfNeeded(ctx: CompilationContext, lines: List[MLine]): List[MLine] = { + if (lines.exists(_.changesRegister(M6809Register.X))) MLine.pp(PSHS, M6809Register.X) :: (lines :+ MLine.pp(PULS, M6809Register.X)) + else lines + } + def storeB(ctx: CompilationContext, target: LhsExpression): List[MLine] = { target match { case VariableExpression(name) => @@ -642,6 +644,29 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] { } } + def handleInPlaceModification(ctx: CompilationContext, l: LhsExpression, size: Int, r: List[MLine]): List[MLine] = { + compileAddressToX(ctx, l) match { + case List(MLine0(LDX, Immediate, addr)) => + size match { + case 1 => List(MLine.absolute(LDB, addr)) ++ r ++ List(MLine.absolute(STB, addr)) + case 2 => List(MLine.absolute(LDD, addr)) ++ r ++ List(MLine.absolute(STD, addr)) + } + case lc => + size match { + case 1 => + lc ++ + List(MLine.indexedX(LDB, Constant.Zero)) ++ + stashXIfNeeded(ctx, r) ++ + List(MLine.indexedX(STB, Constant.Zero)) + case 2 => + lc ++ + List(MLine.indexedX(LDD, Constant.Zero)) ++ + stashXIfNeeded(ctx, r) ++ + List(MLine.indexedX(LDD, Constant.Zero)) + } + } + } + private def compileTransitiveRelation(ctx: CompilationContext, operator: String,