diff --git a/include/m6809/m6809_math.mfk b/include/m6809/m6809_math.mfk new file mode 100644 index 00000000..5e6c4671 --- /dev/null +++ b/include/m6809/m6809_math.mfk @@ -0,0 +1,30 @@ + +#if not(ARCH_6809) +#warn m6809_math module should be used only on 6809-like targets +#endif + +noinline asm word __mul_u16u16u16(word register(x) x, word register(d) d) { + pshs d,x + exg d,x + lda ,s + mul + tfr d,x + ldd 1,s + mul + abx + tfr x,d + tfr b,a + ldb #0 + tfr d,x + puls d + lda 1,s + mul + leax d,x + tfr x,d + leas 2,s + rts +} + +noinline asm word __divmod_u16u16u16u16(word register(x) x, word register(d) d) { + +} \ No newline at end of file diff --git a/include/m6809/stdlib_6809.mfk b/include/m6809/stdlib_6809.mfk index a55a3e3c..52cf6102 100644 --- a/include/m6809/stdlib_6809.mfk +++ b/include/m6809/stdlib_6809.mfk @@ -4,6 +4,8 @@ #warn stdlib_6809 module should be only used on 6809-compatible targets #endif +import m6809/m6809_math + word nmi_routine_addr @$FFFC word reset_routine_addr @$FFFE word irq_routine_addr @$FFF8 diff --git a/src/main/scala/millfork/compiler/m6809/M6809ExpressionCompiler.scala b/src/main/scala/millfork/compiler/m6809/M6809ExpressionCompiler.scala index fedfc8dc..cdc2f573 100644 --- a/src/main/scala/millfork/compiler/m6809/M6809ExpressionCompiler.scala +++ b/src/main/scala/millfork/compiler/m6809/M6809ExpressionCompiler.scala @@ -3,7 +3,7 @@ package millfork.compiler.m6809 import millfork.CompilationFlag import millfork.assembly.m6809.{DAccumulatorIndexed, Immediate, Indexed, InherentB, MLine, MLine0, MOpcode, RegisterSet, 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.node.{DerefExpression, Expression, FunctionCallExpression, GeneratedConstantExpression, IndexedExpression, LhsExpression, LiteralExpression, M6809Register, SeparateBytesExpression, SumExpression, VariableExpression} import millfork.assembly.m6809.MOpcode._ import millfork.env.{AssemblyOrMacroParamSignature, BuiltInBooleanType, Constant, ConstantBooleanType, ConstantPointy, ExternFunction, FatBooleanType, FlagBooleanType, FunctionInMemory, FunctionPointerType, Label, M6809RegisterVariable, MacroFunction, MathOperator, MemoryAddressConstant, MemoryVariable, NonFatalCompilationException, NormalFunction, NormalParamSignature, NumericConstant, StackVariablePointy, ThingInMemory, Type, Variable, VariableInMemory, VariablePointy} @@ -139,6 +139,12 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] { case 1 => M6809Buitins.compileByteSum(ctx, e, fromScratch = true) ++ targetifyB(ctx, target, isSigned = false) case 2 => M6809Buitins.compileWordSum(ctx, e, fromScratch = true) ++ targetifyD(ctx, target) } + case SeparateBytesExpression(hi, lo) => + val h = compile(ctx, hi, MExpressionTarget.A) + val l = compile(ctx, lo, MExpressionTarget.B) + (if (l.exists(_.changesRegister(M6809Register.A))) { + if (h.exists(_.changesRegister(M6809Register.B))) h ++ stashAIfNeeded(ctx, l) else l ++ h + } else h ++ l) ++ targetifyD(ctx, target) case fce@FunctionCallExpression(functionName, params) => functionName match { case "not" => @@ -209,7 +215,11 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] { ctx.log.error("Invalid call syntax", fce.position) Nil } - case "*" => ??? + case "*" => + getArithmeticParamMaxSize(ctx, params) match { + 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 "/" => ??? case "%%" => ??? @@ -340,7 +350,12 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] { case _ => ??? } case "-'=" => ??? - case "*=" => ??? + case "*=" => + val (l, r, size) = assertArithmeticAssignmentLike(ctx, params) + size match { + 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 "/=" => ??? case "%%=" => ??? @@ -553,6 +568,11 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] { } } + def stashAIfNeeded(ctx: CompilationContext, lines: List[MLine]): List[MLine] = { + if (lines.exists(_.changesRegister(M6809Register.A))) MLine.pp(PSHS, M6809Register.A) :: (lines :+ MLine.pp(PULS, M6809Register.A)) + else lines + } + def stashBIfNeeded(ctx: CompilationContext, lines: List[MLine]): List[MLine] = { if (lines.exists(_.changesRegister(M6809Register.B))) MLine.pp(PSHS, M6809Register.B) :: (lines :+ MLine.pp(PULS, M6809Register.B)) else lines diff --git a/src/main/scala/millfork/compiler/m6809/M6809MulDiv.scala b/src/main/scala/millfork/compiler/m6809/M6809MulDiv.scala index 5d44aa7a..c92662a1 100644 --- a/src/main/scala/millfork/compiler/m6809/M6809MulDiv.scala +++ b/src/main/scala/millfork/compiler/m6809/M6809MulDiv.scala @@ -1,8 +1,108 @@ package millfork.compiler.m6809 +import millfork.assembly.m6809.{MLine, RegisterSet} +import millfork.compiler.CompilationContext +import millfork.env.{CompoundConstant, Constant, MathOperator, NumericConstant, ThingInMemory} +import millfork.node.{Expression, IndexedExpression, LiteralExpression, M6809Register, VariableExpression} +import millfork.assembly.m6809.MOpcode._ +import M6809Register._ + +import scala.collection.mutable.ListBuffer + /** * @author Karol Stasiak */ object M6809MulDiv { + def compileByteMultiplication(ctx: CompilationContext, params: List[Expression], updateDerefX: Boolean): List[MLine] = { + var constant = Constant.One + val variablePart = params.flatMap { p => + ctx.env.eval(p) match { + case Some(c) => + constant = CompoundConstant(MathOperator.Times, constant, c).quickSimplify + None + case None => Some(p) + } + } + if (!updateDerefX && variablePart.isEmpty) { + return List(MLine.immediate(LDB, constant)) + } + val result = ListBuffer[MLine]() + if (updateDerefX) { + result += MLine.indexedX(LDB, 0) + } else { + result ++= M6809ExpressionCompiler.compileToB(ctx, variablePart.head) + } + for (factor <- if (updateDerefX) variablePart else variablePart.tail) { + factor match { + case _: VariableExpression => + result ++= M6809ExpressionCompiler.stashBIfNeeded(ctx, M6809ExpressionCompiler.compileToA(ctx, factor)) + case _ => + // TODO: optimize? + result += MLine.tfr(B, A) + result ++= M6809ExpressionCompiler.stashAIfNeeded(ctx, M6809ExpressionCompiler.compileToB(ctx, factor)) + } + result += MLine.inherent(MUL) + } + constant.loByte.quickSimplify match { + case NumericConstant(0, _) => result += MLine.immediate(LDB, 0) + case NumericConstant(1, _) => () + case NumericConstant(2, _) => result += MLine.inherentB(ASL) + case NumericConstant(4, _) => result ++= List(MLine.inherentB(ASL), MLine.inherentB(ASL)) + case NumericConstant(8, _) => result ++= List(MLine.inherentB(ASL), MLine.inherentB(ASL), MLine.inherentB(ASL)) + case NumericConstant(16, _) => result ++= List(MLine.inherentB(ASL), MLine.inherentB(ASL), MLine.inherentB(ASL), MLine.inherentB(ASL)) + case NumericConstant(32, _) => result ++= List(MLine.inherentB(ASL), MLine.inherentB(ASL), MLine.inherentB(ASL), MLine.inherentB(ASL), MLine.inherentB(ASL)) + case NumericConstant(-1 | 255, _) => result += MLine.inherentB(NEG) + case NumericConstant(-2 | 254, _) => result ++= List(MLine.inherentB(ASL), MLine.inherentB(NEG)) + case _ => result ++= List(MLine.immediate(LDA, constant), MLine.inherent(MUL)) + } + if (updateDerefX) { + result += MLine.indexedX(STB, 0) + } + result.toList + } + + def compileWordMultiplication(ctx: CompilationContext, params: List[Expression], updateDerefX: Boolean): List[MLine] = { + var constant = Constant.One + val variablePart = params.flatMap { p => + ctx.env.eval(p) match { + case Some(c) => + constant = CompoundConstant(MathOperator.Times, constant, c).quickSimplify + None + case None => Some(p) + } + } + if (!updateDerefX && variablePart.isEmpty) { + return List(MLine.immediate(LDD, constant)) + } + val result = ListBuffer[MLine]() + if (updateDerefX) { + result += MLine.indexedX(LDD, 0) + result += MLine(PSHS, RegisterSet(Set(X)), Constant.Zero) + } else { + result ++= M6809ExpressionCompiler.compileToD(ctx, variablePart.head) + } + for (factor <- if (updateDerefX) variablePart else variablePart.tail) { + factor match { + case _: VariableExpression => + result ++= M6809ExpressionCompiler.stashDIfNeeded(ctx, M6809ExpressionCompiler.compileToX(ctx, factor)) + case _ => + // TODO: optimize? + result += MLine.tfr(D, X) + result ++= M6809ExpressionCompiler.stashXIfNeeded(ctx, M6809ExpressionCompiler.compileToD(ctx, factor)) + } + result += MLine.absolute(JSR, ctx.env.get[ThingInMemory]("__mul_u16u16u16")) + } + constant.loByte.quickSimplify match { + case NumericConstant(0, _) => result += MLine.immediate(LDD, 0) + case NumericConstant(1, _) => () + case NumericConstant(2, _) => result ++= List(MLine.inherentB(ASL), MLine.inherentA(ROL)) + case _ => result ++= List(MLine.immediate(LDX, constant), MLine.absolute(JSR, ctx.env.get[ThingInMemory]("__mul_u16u16u16"))) + } + if (updateDerefX) { + result += MLine(PULS, RegisterSet(Set(X)), Constant.Zero) + result += MLine.indexedX(STD, 0) + } + result.toList + } } diff --git a/src/test/scala/millfork/test/emu/EmuM6809Run.scala b/src/test/scala/millfork/test/emu/EmuM6809Run.scala index 7a19934d..dd184821 100644 --- a/src/test/scala/millfork/test/emu/EmuM6809Run.scala +++ b/src/test/scala/millfork/test/emu/EmuM6809Run.scala @@ -36,7 +36,7 @@ object EmuM6809Run { val PreprocessingResult(preprocessedSource, features, _) = Preprocessor.preprocessForTest(options, source) TestErrorReporting.log.debug(s"Features: $features") TestErrorReporting.log.info(s"Parsing $filename") - val parser = Z80Parser(filename, preprocessedSource, "", options, features, useIntelSyntax = false) + val parser = M6809Parser(filename, preprocessedSource, "", options, features) parser.toAst match { case Success(x, _) => Some(x) case f: Failure[_, _] => @@ -53,7 +53,7 @@ object EmuM6809Run { private def get(cpu: millfork.Cpu.Value, path: String): Program = synchronized { cache.getOrElseUpdate(cpu->path, preload(cpu, path)).getOrElse(throw new IllegalStateException()) } - def cachedMath(cpu: millfork.Cpu.Value): Program = get(cpu, "include/m6809_math.mfk") + def cachedMath(cpu: millfork.Cpu.Value): Program = get(cpu, "include/m6809/m6809_math.mfk") def cachedStdio(cpu: millfork.Cpu.Value): Program = get(cpu, "src/test/resources/include/dummy_stdio.mfk") } @@ -113,9 +113,8 @@ class EmuM6809Run(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimizat val withLibraries = { var tmp = unoptimized if(source.contains("import stdio")) - tmp += EmuRun.cachedStdio - if(!options.flag(CompilationFlag.DecimalMode) && (source.contains("+'") || source.contains("-'") || source.contains("<<'") || source.contains("*'"))) - tmp += EmuRun.cachedBcd + tmp += EmuM6809Run.cachedStdio(cpu) + tmp += EmuM6809Run.cachedMath(cpu) tmp } val program = nodeOptimizations.foldLeft(withLibraries.applyImportantAliases)((p, opt) => p.applyNodeOptimization(opt, options))