1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-06-26 11:29:28 +00:00

6809: tons of improvements:

* stack variables
* large comparisons
* pointer optimizations
* fixed constant evaluation
This commit is contained in:
Karol Stasiak 2020-07-09 01:50:18 +02:00
parent b9bf433308
commit a22571f60b
14 changed files with 324 additions and 46 deletions

View File

@ -187,6 +187,14 @@ Allow using the IY register for other purposes.
Compiling to 8086 is based on translating from a mix of 8085 and Z80 instructions to 8086.
See [the 8086 support disclaimer](./../lang/x86disclaimer.md).
#### 6809-related
* `-fuse-u-for-stack`, `-fuse-y-for-stack`
Which of Z80 index registers should be used as the base pointer for accessing stack variables, if any.
`.ini` equivalent: `u_stack` and `y_stack`. Default: none.
**Warning: Currently, picking one of those two options is required!**
The compiler doesn't support accessing the stack variables via the S stack pointer register yet.
## Optimization options
* `-O0` Disable all optimizations except unused global symbol removal.

View File

@ -114,6 +114,13 @@ This list cannot contain module template instantiations.
* `iy_scratch` allow using the IY register for other purposes, default is `false`
* `u_stack` use the U register to access stack variables, default is `false`. Applicable only to 6809-based targets.
* `y_stack` use the Y register to access stack variables, default is `false`. Applicable only to 6809-based targets.
**Warning: Currently, picking either `u_stack` or `y_stack` is required,
unless you want to always specify this option in the compiler's command line!**
The compiler doesn't support accessing the stack variables via the S stack pointer register yet.
* `software_stack` use software stack for stack variables, default is `false`. Applicable only to 6502-based targets.
* `output_intel_syntax` use Intel syntax instead of Zilog syntax, default is `true` for Intel 8080/8085 and `false` otherwise

View File

@ -190,6 +190,9 @@ case class CompilationOptions(platform: Platform,
if (flags(UseUForStack) && flags(UseYForStack)) {
log.error("Cannot use both U and Y registers for stack variables simultaneously")
}
if (!flags(UseUForStack) && !flags(UseYForStack)) {
log.error("You need to use either the U register or the Y register as the base pointer. This might be relaxed in the future.")
}
}
}

View File

@ -651,10 +651,10 @@ object Main {
c.changeFlag(CompilationFlag.UseIyForStack, true).changeFlag(CompilationFlag.UseIxForStack, false)
}.description("Use IY as base pointer for stack variables (Z80 only)")
flag("-fuse-u-for-stack").action { c =>
c.changeFlag(CompilationFlag.UseIxForStack, true).changeFlag(CompilationFlag.UseUForStack, false)
c.changeFlag(CompilationFlag.UseUForStack, true).changeFlag(CompilationFlag.UseYForStack, false)
}.description("Use U as base pointer for stack variables (6809 only)").hidden()
flag("-fuse-y-for-stack").action { c =>
c.changeFlag(CompilationFlag.UseIyForStack, true).changeFlag(CompilationFlag.UseYForStack, false)
c.changeFlag(CompilationFlag.UseYForStack, true).changeFlag(CompilationFlag.UseUForStack, false)
}.description("Use Y as base pointer for stack variables (6809 only)").hidden()
boolean("-fuse-ix-for-scratch", "-fno-use-ix-for-scratch").action { (c, v) =>
if (v) {

View File

@ -9,26 +9,41 @@ sealed trait MAddrMode {
def changesRegister(reg: M6809Register.Value): Boolean = false
def makeIndirect(position: Position): MAddrMode
def isDeferenceable: Boolean
def dereference(): MAddrMode
}
case object Inherent extends MAddrMode {
def makeIndirect(position: Position): MAddrMode = ???
def isDeferenceable: Boolean = false
def dereference(): MAddrMode = ???
}
case object InherentA extends MAddrMode {
override def changesRegister(reg: M6809Register.Value): Boolean = reg == M6809Register.A || reg == M6809Register.D
def makeIndirect(position: Position): MAddrMode = ???
def isDeferenceable: Boolean = false
def dereference(): MAddrMode = ???
}
case object InherentB extends MAddrMode {
override def changesRegister(reg: M6809Register.Value): Boolean = reg == M6809Register.B || reg == M6809Register.D
def makeIndirect(position: Position): MAddrMode = ???
def isDeferenceable: Boolean = false
def dereference(): MAddrMode = ???
}
case class TwoRegisters(source: M6809Register.Value, target: M6809Register.Value) extends MAddrMode {
def makeIndirect(position: Position): MAddrMode = ???
def isDeferenceable: Boolean = false
def dereference(): MAddrMode = ???
}
case class RegisterSet(registers: Set[M6809Register.Value]) extends MAddrMode {
@ -42,6 +57,9 @@ case class RegisterSet(registers: Set[M6809Register.Value]) extends MAddrMode {
case _ => registers(register)
}
}
def isDeferenceable: Boolean = false
def dereference(): MAddrMode = ???
}
object RegisterSet {
@ -57,56 +75,88 @@ object RegisterSet {
case class Absolute(indirect: Boolean) extends MAddrMode {
def makeIndirect(position: Position): MAddrMode = copy(indirect = true)
def isDeferenceable: Boolean = !indirect
def dereference(): MAddrMode = copy(indirect = true)
}
case class Indexed(base: M6809Register.Value, indirect: Boolean) extends MAddrMode {
def makeIndirect(position: Position): MAddrMode = copy(indirect = true)
def isDeferenceable: Boolean = !indirect
def dereference(): MAddrMode = copy(indirect = true)
}
case class AAccumulatorIndexed(base: M6809Register.Value, indirect: Boolean) extends MAddrMode {
def makeIndirect(position: Position): MAddrMode = copy(indirect = true)
def isDeferenceable: Boolean = !indirect
def dereference(): MAddrMode = copy(indirect = true)
}
case class BAccumulatorIndexed(base: M6809Register.Value, indirect: Boolean) extends MAddrMode {
def makeIndirect(position: Position): MAddrMode = copy(indirect = true)
def isDeferenceable: Boolean = !indirect
def dereference(): MAddrMode = copy(indirect = true)
}
case class DAccumulatorIndexed(base: M6809Register.Value, indirect: Boolean) extends MAddrMode {
def makeIndirect(position: Position): MAddrMode = copy(indirect = true)
def isDeferenceable: Boolean = !indirect
def dereference(): MAddrMode = copy(indirect = true)
}
case class PostIncremented(base: M6809Register.Value, amount: Int, indirect: Boolean) extends MAddrMode {
override def changesRegister(reg: M6809Register.Value): Boolean = reg == base
def makeIndirect(position: Position): MAddrMode = copy(indirect = true)
def isDeferenceable: Boolean = false
def dereference(): MAddrMode = ???
}
case class PreDecremented(base: M6809Register.Value, amount: Int, indirect: Boolean) extends MAddrMode {
override def changesRegister(reg: M6809Register.Value): Boolean = reg == base
def makeIndirect(position: Position): MAddrMode = copy(indirect = true)
def isDeferenceable: Boolean = false
def dereference(): MAddrMode = ???
}
case object Relative extends MAddrMode {
def makeIndirect(position: Position): MAddrMode = ???
def isDeferenceable: Boolean = false
def dereference(): MAddrMode = ???
}
case object LongRelative extends MAddrMode {
def makeIndirect(position: Position): MAddrMode = ???
def isDeferenceable: Boolean = false
def dereference(): MAddrMode = ???
}
case object Immediate extends MAddrMode {
def makeIndirect(position: Position): MAddrMode = ???
def isDeferenceable: Boolean = true
def dereference(): MAddrMode = Absolute(false)
}
case object DirectPage extends MAddrMode {
def makeIndirect(position: Position): MAddrMode = ???
def isDeferenceable: Boolean = false
def dereference(): MAddrMode = ???
}
case object NonExistent extends MAddrMode {
def makeIndirect(position: Position): MAddrMode = ???
def isDeferenceable: Boolean = false
def dereference(): MAddrMode = ???
}
case object RawByte extends MAddrMode {
def makeIndirect(position: Position): MAddrMode = ???
def isDeferenceable: Boolean = false
def dereference(): MAddrMode = ???
}

View File

@ -51,6 +51,12 @@ object MLine {
def indexedX(opcode: MOpcode.Value, offset: Int): MLine =
MLine(opcode, Indexed(M6809Register.X, indirect = false), Constant(offset))
def indexedU(opcode: MOpcode.Value, offset: Int): MLine =
MLine(opcode, Indexed(M6809Register.U, indirect = false), Constant(offset))
def indexedY(opcode: MOpcode.Value, offset: Int): MLine =
MLine(opcode, Indexed(M6809Register.Y, indirect = false), Constant(offset))
def accessAndPullS(opcode: MOpcode.Value): MLine =
MLine(opcode, PostIncremented(M6809Register.S, 1, indirect = false), Constant.Zero)

View File

@ -49,8 +49,7 @@ object M6809Buitins {
// TODO: preserve X?
rc ++ List(MLine.pp(PSHS, M6809Register.D)) ++ lc ++ List(MLine.accessAndPullSTwice(opcode), lc.last.copy(opcode = STD))
case _ =>
println(lc)
???
rc ++ List(MLine.pp(PSHS, M6809Register.D)) ++ lc ++ List(MLine.accessAndPullSTwice(opcode)) ++ M6809ExpressionCompiler.storeD(ctx, l)
}
}

View File

@ -1,5 +1,6 @@
package millfork.compiler.m6809
import millfork.CompilationFlag
import millfork.assembly.Elidability
import millfork.assembly.m6809.{Inherent, MLine, MOpcode, NonExistent}
import millfork.compiler.{AbstractCompiler, CompilationContext}
@ -10,8 +11,26 @@ import millfork.env.{Constant, Label, MemoryAddressConstant, NormalParamSignatur
*/
object M6809Compiler extends AbstractCompiler[MLine] {
override def compile(ctx: CompilationContext): List[MLine] = {
ctx.env.nameCheck(ctx.function.code)
import MOpcode._
val prologue = if (ctx.function.stackVariablesSize == 0) Nil else {
import millfork.node.M6809Register.{U, S, Y}
if (ctx.options.flag(CompilationFlag.UseUForStack)) {
List(
MLine.pp(PSHS, U),
MLine.indexedS(LEAS, -ctx.function.stackVariablesSize),
MLine.tfr(S, U))
} else if (ctx.options.flag(CompilationFlag.UseYForStack)) {
List(
MLine.pp(PSHS, Y),
MLine.indexedS(LEAS, -ctx.function.stackVariablesSize),
MLine.tfr(S, Y))
} else {
List(MLine.indexedS(LEAS, -ctx.function.stackVariablesSize))
}
}
ctx.env.nameCheck(ctx.function.code)
val storeParamsFromRegisters = ctx.function.params match {
case NormalParamSignature(List(param)) if param.typ.size == 1 =>
List(MLine.absolute(STB, param.toAddress))
@ -22,6 +41,6 @@ object M6809Compiler extends AbstractCompiler[MLine] {
val label = MLine.label(Label(ctx.function.name)).copy(elidability = Elidability.Fixed)
val chunk = packHalves(M6809StatementCompiler.compile(ctx, new M6809StatementPreprocessor(ctx, ctx.function.code)()))
// TODO: stackframe etc.
label :: (storeParamsFromRegisters ++ chunk)
label :: (storeParamsFromRegisters ++ prologue ++ chunk)
}
}

View File

@ -7,7 +7,7 @@ import millfork.assembly.m6809.{DAccumulatorIndexed, Immediate, Indexed, Inheren
import millfork.compiler.{AbstractExpressionCompiler, BranchIfFalse, BranchIfTrue, BranchSpec, ComparisonType, CompilationContext, NoBranching}
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, StructureConstant, ThingInMemory, Type, Variable, VariableInMemory, VariablePointy}
import millfork.env.{AssemblyOrMacroParamSignature, BuiltInBooleanType, Constant, ConstantBooleanType, ConstantPointy, ExternFunction, FatBooleanType, FlagBooleanType, FunctionInMemory, FunctionPointerType, Label, M6809RegisterVariable, MacroFunction, MathOperator, MemoryAddressConstant, MemoryVariable, NonFatalCompilationException, NormalFunction, NormalParamSignature, NumericConstant, StackOffsetThing, StackVariable, StackVariablePointy, StructureConstant, Thing, ThingInMemory, Type, Variable, VariableInMemory, VariableLikeThing, VariablePointy}
import scala.collection.GenTraversableOnce
@ -73,18 +73,29 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
}
expr match {
case VariableExpression(name) =>
val variable = env.get[Variable](name)
exprType.size match {
case 1 =>
targetSize match {
case 0 => Nil
case 1 => List(MLine.variable(ctx, toLd(target), variable))
case 2 => List(MLine.variable(ctx, LDB, variable)) ++ zeroextendB(ctx, target, exprType.isSigned)
env.get[VariableLikeThing](name) match {
case variable: Variable =>
exprType.size match {
case 1 =>
targetSize match {
case 0 => Nil
case 1 => List(MLine.variable(ctx, toLd(target), variable))
case 2 => List(MLine.variable(ctx, LDB, variable)) ++ zeroextendB(ctx, target, exprType.isSigned)
}
case 2 =>
targetSize match {
case 0 => Nil
case 2 => List(MLine.variable(ctx, toLd(target), variable))
}
}
case 2 =>
targetSize match {
case 0 => Nil
case 2 => List(MLine.variable(ctx, toLd(target), variable))
case sot: StackOffsetThing =>
sot.subbyte match {
case None =>
if (target == MExpressionTarget.X) calculateStackAddressToX(ctx, sot.offset)
else calculateStackAddressToD(ctx, sot.offset) ++ targetifyD(ctx, target)
case Some(0) => calculateStackAddressToD(ctx, sot.offset) ++ targetifyB(ctx, target, isSigned = false)
case Some(1) => calculateStackAddressToD(ctx, sot.offset) ++ targetifyA(ctx, target, isSigned = false)
case _ => throw new IllegalArgumentException
}
}
case LiteralExpression(c, _) =>
@ -93,7 +104,12 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
case _ => List(MLine.immediate(MExpressionTarget.toLd(target), NumericConstant(c, MExpressionTarget.size(target))))
}
case DerefExpression(inner, offset, _) =>
compileToX(ctx, inner) :+ MLine(toLd(target), Indexed(M6809Register.X, indirect = false), NumericConstant(offset, 2))
compileToX(ctx, inner) match {
case List(l@MLine0(LDX, addrMode, _)) if addrMode.isDeferenceable =>
List(l.copy(opcode = toLd(target), addrMode = addrMode.dereference()))
case _ =>
compileToX(ctx, inner) :+ MLine(toLd(target), Indexed(M6809Register.X, indirect = false), NumericConstant(offset, 2))
}
case IndexedExpression(name, index) =>
env.getPointy(name) match {
case c: ConstantPointy =>
@ -101,12 +117,18 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
val constantOffset = (c.value + constIndex).quickSimplify
variableIndex match {
case (Some(ix)) =>
compileToX(ctx, ix) ++ (
targetSize match {
case 0 => Nil
case 1 => List(MLine.indexedX(toLd(target), constantOffset))
case 2 => List(MLine.indexedX(LDB, constantOffset)) ++ zeroextendB(ctx, target, exprType.isSigned)
})
val prepareIndex = compileToX(ctx, ix)
targetSize match {
case 0 => prepareIndex
case 1 =>
prepareIndex match {
case List(l@MLine0(LDX, addrMode, _)) if addrMode.isDeferenceable && constantOffset.isProvablyZero =>
List(l.copy(opcode = toLd(target), addrMode = addrMode.dereference()))
case _ =>
prepareIndex ++ List(MLine.indexedX(toLd(target), constantOffset))
}
case 2 => prepareIndex ++ List(MLine.indexedX(LDB, constantOffset)) ++ zeroextendB(ctx, target, exprType.isSigned)++targetifyD(ctx, target)
}
case None =>
targetSize match {
case 0 => Nil
@ -126,11 +148,19 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
)) -> Constant.Zero
}
}
prepareIndex ++ (targetSize match {
case 0 => Nil
case 1 => List(MLine.indexedX(toLd(target), offset))
case 2 => List(MLine.indexedX(LDB, offset)) ++ zeroextendB(ctx, target, exprType.isSigned)
})
targetSize match {
case 0 => prepareIndex
case 1 =>
prepareIndex match {
case List(l@MLine0(LDX, addrMode, _)) if addrMode.isDeferenceable && offset.isProvablyZero =>
List(l.copy(opcode = toLd(target), addrMode = addrMode.dereference()))
case _ =>
prepareIndex :+ MLine.indexedX(toLd(target), offset)
}
case 2 =>
val toD = prepareIndex ++ List(MLine.indexedX(LDB, offset)) ++ zeroextendB(ctx, target, exprType.isSigned)
toD ++ targetifyD(ctx, target)
}
case v:StackVariablePointy =>
ctx.env.eval(index) match {
case Some(ix) => List(MLine.variablestack(ctx, LDX, v.offset), MLine.indexedX(LDB, ix * v.elementType.size))
@ -280,7 +310,7 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
size match {
case 1 => M6809Comparisons.compile8BitComparison(ctx, ComparisonType.Equal, l, r, branches)
case 2 => M6809Comparisons.compile16BitComparison(ctx, ComparisonType.Equal, l, r, branches)
case _ => ???
case _ => M6809LargeBuiltins.compileComparison(ctx, ComparisonType.Equal, l, r, branches)
}
}
case "!=" =>
@ -289,7 +319,7 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
size match {
case 1 => M6809Comparisons.compile8BitComparison(ctx, ComparisonType.NotEqual, l, r, branches)
case 2 => M6809Comparisons.compile16BitComparison(ctx, ComparisonType.NotEqual, l, r, branches)
case _ => ???
case _ => M6809LargeBuiltins.compileComparison(ctx, ComparisonType.NotEqual, l, r, branches)
}
}
case "<" =>
@ -298,7 +328,7 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
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 _ => ???
case _ => M6809LargeBuiltins.compileComparison(ctx, if (signed) ComparisonType.LessSigned else ComparisonType.LessUnsigned, l, r, branches)
}
}
case ">" =>
@ -307,7 +337,7 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
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 _ => ???
case _ => M6809LargeBuiltins.compileComparison(ctx, if (signed) ComparisonType.GreaterSigned else ComparisonType.GreaterUnsigned, l, r, branches)
}
}
case "<=" =>
@ -316,7 +346,7 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
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 _ => ???
case _ => M6809LargeBuiltins.compileComparison(ctx, if (signed) ComparisonType.LessOrEqualSigned else ComparisonType.LessOrEqualUnsigned, l, r, branches)
}
}
case ">=" =>
@ -325,7 +355,7 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
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 _ => ???
case _ => M6809LargeBuiltins.compileComparison(ctx, if (signed) ComparisonType.GreaterOrEqualSigned else ComparisonType.GreaterOrEqualUnsigned, l, r, branches)
}
}
case "<<" =>
@ -766,8 +796,13 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
def compileAddressToX(ctx: CompilationContext, expr: LhsExpression): List[MLine] = {
expr match {
case VariableExpression(name) =>
val variable = ctx.env.get[VariableInMemory](name)
List(MLine.immediate(MOpcode.LDX, variable.toAddress))
ctx.env.get[Thing](name) match {
case variable: VariableInMemory =>
List(MLine.immediate(MOpcode.LDX, variable.toAddress))
case variable: StackVariable =>
List(MLine.variable(ctx, LEAX, variable))
}
case DerefExpression(inner, offset, _) =>
compileToX(ctx, inner) :+ MLine.indexedX(MOpcode.LEAX, Constant(offset))
case IndexedExpression(aname, index) =>
@ -913,8 +948,12 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
case GeneratedConstantExpression(const, _) =>
List.tabulate(targetSize)(i => List(MLine.immediate(LDB, const.subbyteBe(targetSize - 1 - i, targetSize))))
case VariableExpression(name) =>
val v = ctx.env.get[Variable](name)
List.tabulate(targetSize)(i => List(if (i < v.typ.size) MLine.variable(ctx, LDB, v, v.typ.size - 1 - i) else MLine.immediate(LDB, 0)))
ctx.env.get[VariableLikeThing](name) match {
case v: Variable =>
List.tabulate(targetSize)(i => List(if (i < v.typ.size) MLine.variable(ctx, LDB, v, v.typ.size - 1 - i) else MLine.immediate(LDB, 0)))
case sot: StackOffsetThing =>
List(calculateStackAddressToD(ctx, sot.offset), List(MLine.tfr(M6809Register.A, M6809Register.B)))
}
case e:FunctionCallExpression =>
ctx.env.maybeGet[NormalFunction](e.functionName) match {
case Some(function) =>
@ -930,4 +969,26 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
}
}
}
def calculateStackAddressToD(ctx: CompilationContext, baseOffset: Int): List[MLine] = {
import M6809Register._
if (ctx.options.flag(CompilationFlag.UseUForStack)) {
List(MLine.tfr(U, D), MLine.immediate(ADDD, baseOffset))
} else if (ctx.options.flag(CompilationFlag.UseYForStack)) {
List(MLine.tfr(Y, D), MLine.immediate(ADDD, baseOffset))
} else {
List(MLine.tfr(S, D), MLine.immediate(ADDD, baseOffset + ctx.extraStackOffset))
}
}
def calculateStackAddressToX(ctx: CompilationContext, baseOffset: Int): List[MLine] = {
import M6809Register._
if (ctx.options.flag(CompilationFlag.UseUForStack)) {
List(MLine.indexedU(LEAX, baseOffset))
} else if (ctx.options.flag(CompilationFlag.UseYForStack)) {
List(MLine.indexedY(LEAX, baseOffset))
} else {
List(MLine.indexedS(LEAX, baseOffset + ctx.extraStackOffset))
}
}
}

View File

@ -1,7 +1,7 @@
package millfork.compiler.m6809
import millfork.assembly.m6809.{Immediate, MLine, MLine0, MOpcode, TwoRegisters}
import millfork.compiler.{AbstractExpressionCompiler, CompilationContext}
import millfork.compiler.{AbstractExpressionCompiler, BranchIfFalse, BranchIfTrue, BranchSpec, ComparisonType, CompilationContext, NoBranching}
import millfork.node.{Expression, LhsExpression, M6809Register}
import millfork.assembly.m6809.MOpcode._
import millfork.env.{Constant, NumericConstant}
@ -83,6 +83,13 @@ object M6809LargeBuiltins {
}
}
def isSingleLdb(code: List[MLine]): Boolean = code.length == 1 && code.head.opcode == LDB
def replaceLdb(code: List[MLine], op: MOpcode.Value): List[MLine] = {
if (code.last.opcode != LDB) ???
code.init :+ code.last.copy(opcode = op)
}
def compileInc(ctx: CompilationContext, target: LhsExpression): List[MLine] = {
val sizeInBytes = AbstractExpressionCompiler.getExpressionType(ctx, target).size
val result = new ListBuffer[MLine]()
@ -120,6 +127,7 @@ object M6809LargeBuiltins {
val result = new ListBuffer[MLine]()
val targetAddr: Option[Constant] = M6809ExpressionCompiler.compileAddressToX(ctx, target) match {
case List(MLine(LDX, Immediate, addr, _, _)) => Some(addr)
case List(MLine(LEAX, _, _, _, _)) => None
case xs =>
result ++= xs
ctx.log.error("Invalid left-hand-side expression", target.position)
@ -273,4 +281,91 @@ object M6809LargeBuiltins {
result.toList
}
def compileComparison(ctx: CompilationContext, typ: ComparisonType.Value, l: Expression, r: Expression, branches: BranchSpec): List[MLine] = {
typ match {
case ComparisonType.GreaterSigned | ComparisonType.GreaterUnsigned | ComparisonType.LessOrEqualSigned | ComparisonType.LessOrEqualUnsigned =>
return compileComparison(ctx, ComparisonType.flip(typ), r, l, branches)
case _ =>
}
val targetLabel = branches match {
case BranchIfTrue(label) => Some(label)
case BranchIfFalse(label) => return compileComparison(ctx, ComparisonType.negate(typ), l, r, BranchIfTrue(label))
case NoBranching => None
}
val ltype = AbstractExpressionCompiler.getExpressionType(ctx, l)
val rtype = AbstractExpressionCompiler.getExpressionType(ctx, r)
val size = ltype.size max rtype.size
val lReads = M6809ExpressionCompiler.compileToByteReads(ctx, l, size)
val rReads = M6809ExpressionCompiler.compileToByteReads(ctx, r, size)
if (!lReads.forall(isSingleLdb) && !rReads.forall(isSingleLdb)) {
ctx.log.error("Too complex comparison", l.position.orElse(r.position))
return Nil
}
val result = ListBuffer[MLine]()
typ match {
case ComparisonType.Equal =>
val skipLabel = ctx.nextLabel("co")
for(i <- 0 until size) {
(lReads(i), rReads(i)) match {
case (List(MLine0(LDB, Immediate, NumericConstant(a, _))), List(MLine0(LDB, Immediate, NumericConstant(b, _)))) if a == b =>
if (a != b) {
targetLabel.foreach(l => result += MLine.shortBranch(BRA, skipLabel))
}
case (l, r) =>
if (isSingleLdb(l)) {
result ++= r ++ replaceLdb(l, CMPB)
} else if (isSingleLdb(r)) {
result ++= l ++ replaceLdb(r, CMPB)
} else ???
}
if (i != size - 1) {
targetLabel.foreach(l => result += MLine.longBranch(BNE, skipLabel))
}
}
targetLabel.foreach(l => result += MLine.longBranch(BEQ, l))
result += MLine.label(skipLabel)
case ComparisonType.NotEqual =>
for(i <- 0 until size) {
(lReads(i), rReads(i)) match {
case (List(MLine0(LDB, Immediate, NumericConstant(a, _))), List(MLine0(LDB, Immediate, NumericConstant(b, _)))) =>
if (a != b) {
targetLabel.foreach(l => result += MLine.longBranch(BRA, l))
}
case (l, r) =>
if (isSingleLdb(l)) {
result ++= r ++ replaceLdb(l, CMPB)
} else if (isSingleLdb(r)) {
result ++= l ++ replaceLdb(r, CMPB)
} else ???
}
if (result.nonEmpty) {
targetLabel.foreach(l => result += MLine.longBranch(BNE, l))
}
}
case _ =>
for(i <- 0 until size) {
val l = lReads(i)
val r = rReads(i)
if (isSingleLdb(r)) {
result ++= M6809ExpressionCompiler.stashCarryIfNeeded(ctx, l)
result ++= replaceLdb(r, if (i == 0) SUBB else SBCB)
} else {
result ++= M6809ExpressionCompiler.stashCarryIfNeeded(ctx, r)
result += MLine.pp(PSHS, M6809Register.B)
result ++= M6809ExpressionCompiler.stashCarryIfNeeded(ctx, l)
result += MLine.accessAndPullS(if (i == 0) SUBB else SBCB)
}
}
val j = typ match {
case ComparisonType.GreaterOrEqualSigned => MOpcode.BGE
case ComparisonType.GreaterOrEqualUnsigned => MOpcode.BCC
case ComparisonType.LessSigned => MOpcode.BLT
case ComparisonType.LessUnsigned => MOpcode.BCS
}
targetLabel.foreach(l => result += MLine.longBranch(j, l))
}
result.toList
}
}

View File

@ -1,9 +1,10 @@
package millfork.compiler.m6809
import millfork.{CompilationFlag, CompilationOptions}
import millfork.assembly.{BranchingOpcodeMapping, Elidability}
import millfork.assembly.m6809.{Inherent, MLine, MOpcode, NonExistent}
import millfork.compiler.{AbstractCompiler, AbstractExpressionCompiler, AbstractStatementCompiler, BranchSpec, CompilationContext}
import millfork.node.{Assignment, BlackHoleExpression, BreakStatement, ContinueStatement, DoWhileStatement, ExecutableStatement, Expression, ExpressionStatement, ForEachStatement, ForStatement, FunctionCallExpression, GotoStatement, IfStatement, LabelStatement, LiteralExpression, M6809AssemblyStatement, MemsetStatement, ReturnDispatchStatement, ReturnStatement, VariableExpression, WhileStatement}
import millfork.node.{Assignment, BlackHoleExpression, BreakStatement, ContinueStatement, DoWhileStatement, EmptyStatement, ExecutableStatement, Expression, ExpressionStatement, ForEachStatement, ForStatement, FunctionCallExpression, GotoStatement, IfStatement, LabelStatement, LiteralExpression, M6809AssemblyStatement, MemsetStatement, ReturnDispatchStatement, ReturnStatement, VariableExpression, WhileStatement}
import millfork.assembly.m6809.MOpcode._
import millfork.env.{BooleanType, ConstantBooleanType, FatBooleanType, Label, MemoryAddressConstant, StructureConstant, ThingInMemory}
@ -13,11 +14,25 @@ import millfork.env.{BooleanType, ConstantBooleanType, FatBooleanType, Label, Me
object M6809StatementCompiler extends AbstractStatementCompiler[MLine] {
def compile(ctx: CompilationContext, statement: ExecutableStatement): (List[MLine], List[MLine]) = {
val env = ctx.env
val epilogue = if (ctx.function.stackVariablesSize == 0) Nil else {
import millfork.node.M6809Register.{U, Y}
if (ctx.options.flag(CompilationFlag.UseUForStack)) {
List(
MLine.indexedS(LEAS, ctx.function.stackVariablesSize),
MLine.pp(PULS, U))
} else if (ctx.options.flag(CompilationFlag.UseYForStack)) {
List(
MLine.indexedS(LEAS, ctx.function.stackVariablesSize),
MLine.pp(PULS, Y))
} else {
List(MLine.indexedS(LEAS, ctx.function.stackVariablesSize))
}
}
val code: (List[MLine], List[MLine]) = statement match {
case ReturnStatement(None) =>
// TODO: clean stack
// TODO: RTI
List(MLine.inherent(RTS)) -> Nil
(epilogue :+ MLine.inherent(RTS)) -> Nil
case ReturnStatement(Some(e)) =>
// TODO: clean stack
// TODO: RTI
@ -41,7 +56,7 @@ object M6809StatementCompiler extends AbstractStatementCompiler[MLine] {
}
}
}
(eval ++ rts) -> Nil
(eval ++ epilogue ++ rts) -> Nil
case M6809AssemblyStatement(opcode, addrMode, expression, elidability) =>
ctx.env.evalForAsm(expression, opcode) match {
case Some(e) => List(MLine(opcode, addrMode, e, elidability)) -> Nil
@ -109,6 +124,8 @@ object M6809StatementCompiler extends AbstractStatementCompiler[MLine] {
}
case s: ReturnDispatchStatement =>
M6809ReturnDispatch.compile(ctx, s) -> Nil
case EmptyStatement(_) =>
Nil -> Nil
case _ =>
println(statement)
ctx.log.error("Not implemented yet", statement.position)

View File

@ -1,5 +1,6 @@
package millfork.env
import millfork.CompilationOptions
import millfork.DecimalUtils._
import millfork.node.{ResolvedFieldDesc, SumExpression}
import millfork.output.DivisibleAlignment
@ -95,13 +96,23 @@ sealed trait Constant {
}
}
def subconstant(offset: Int, length: Int): Constant = {
def subconstant(options: CompilationOptions, offset: Int, length: Int): Constant = {
if (offset == 0 && length == requiredSize) {
this
} else if (options.platform.isBigEndian && length == 1) {
// TODO: is this ok?
subbyteBe(offset, requiredSize)
} else if (length == 1) {
subbyte(offset)
} else if (offset >= requiredSize) {
Constant.Zero
} else if (options.platform.isBigEndian) {
// TODO: is this ok?
(0 until length).map { i =>
val index = i + offset
val shift = 8 * (length - i)
CompoundConstant(MathOperator.Shl, subbyteBe(index, requiredSize), NumericConstant(shift, 1)).quickSimplify
}.reduceLeft((l, r) => CompoundConstant(MathOperator.Or, l, r).quickSimplify).quickSimplify
} else {
((length - 1) to 0 by (-1)).map { i =>
val index = i + offset

View File

@ -1844,7 +1844,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
addThing(ConstantThing(prefix + name, constantValue, typ), stmt.position)
for(Subvariable(suffix, offset, t, arraySize) <- getSubvariables(typ)) {
if (arraySize.isDefined) ??? // TODO
addThing(ConstantThing(prefix + name + suffix, constantValue.subconstant(offset, t.size), t), stmt.position)
addThing(ConstantThing(prefix + name + suffix, constantValue.subconstant(options, offset, t.size), t), stmt.position)
}
} else {
if (stmt.stack && stmt.global) log.error(s"`$name` is static or global and cannot be on stack", position)

View File

@ -32,6 +32,7 @@ object EmuM6809Run {
TestErrorReporting.log.info(s"Loading $filename for $cpu")
val source = Files.readAllLines(Paths.get(filename), StandardCharsets.US_ASCII).asScala.mkString("\n")
val options = CompilationOptions(EmuPlatform.get(cpu), Map(
CompilationFlag.UseUForStack -> true,
CompilationFlag.LenientTextEncoding -> true
), None, 0, Map(), EmuPlatform.textCodecRepository, JobContext(TestErrorReporting.log, new LabelGenerator))
val PreprocessingResult(preprocessedSource, features, _) = Preprocessor.preprocessForTest(options, source)
@ -90,6 +91,7 @@ class EmuM6809Run(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimizat
CompilationFlag.EmitIllegals -> this.emitIllegals,
CompilationFlag.InlineFunctions -> this.inline,
CompilationFlag.OptimizeStdlib -> this.inline,
CompilationFlag.UseUForStack -> true,
CompilationFlag.InterproceduralOptimization -> true,
CompilationFlag.CompactReturnDispatchParams -> true,
CompilationFlag.SubroutineExtraction -> optimizeForSize,