mirror of
https://github.com/KarolS/millfork.git
synced 2024-10-31 14:04:58 +00:00
6809: tons of improvements:
* stack variables * large comparisons * pointer optimizations * fixed constant evaluation
This commit is contained in:
parent
b9bf433308
commit
a22571f60b
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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 = ???
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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)
|
||||
|
13
src/main/scala/millfork/env/Constant.scala
vendored
13
src/main/scala/millfork/env/Constant.scala
vendored
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user