1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-12-23 23:30:22 +00:00

6809: Make some progress

This commit is contained in:
Karol Stasiak 2019-08-16 00:46:46 +02:00
parent 960d16fa18
commit 1d530d896a
17 changed files with 385 additions and 39 deletions

View File

@ -44,7 +44,10 @@ case class CompilationOptions(platform: Platform,
if (CpuFamily.forType(platform.cpu) != CpuFamily.I80) invalids ++= Set(
EmitExtended80Opcodes, EmitZ80Opcodes, EmitSharpOpcodes, EmitEZ80Opcodes,
UseIyForStack, UseShadowRegistersForInterrupts)
UseIyForStack, UseIxForScratch, UseIyForScratch, UseShadowRegistersForInterrupts)
if (CpuFamily.forType(platform.cpu) != CpuFamily.M6809) invalids ++= Set(
UseUForStack, UseYForStack)
invalids = invalids.filter(flags)
@ -177,6 +180,9 @@ case class CompilationOptions(platform: Platform,
}
case CpuFamily.I86 =>
case CpuFamily.M6809 =>
if (flags(UseUForStack) && flags(UseYForStack)) {
log.error("Cannot use both U and Y registers for stack variables simultaneously")
}
}
}
@ -225,6 +231,8 @@ case class CompilationOptions(platform: Platform,
"USES_ZPREG" -> toLong(platform.cpuFamily == CpuFamily.M6502 && zpRegisterSize > 0),
"USES_IX_STACK" -> toLong(flag(CompilationFlag.UseIxForStack)),
"USES_IY_STACK" -> toLong(flag(CompilationFlag.UseIyForStack)),
"USES_U_STACK" -> toLong(flag(CompilationFlag.UseUForStack)),
"USES_Y_STACK" -> toLong(flag(CompilationFlag.UseYForStack)),
"USES_SOFTWARE_STACK" -> toLong(flag(CompilationFlag.SoftwareStack)),
"USES_SHADOW_REGISTERS" -> toLong(flag(CompilationFlag.UseShadowRegistersForInterrupts)),
"ZPREG_SIZE" -> (if (platform.cpuFamily == CpuFamily.M6502) zpRegisterSize.toLong else 0)
@ -502,6 +510,8 @@ object CompilationFlag extends Enumeration {
UseIxForScratch, UseIyForScratch,
UseIntelSyntaxForInput,
UseIntelSyntaxForOutput,
// compilation options for 6809
UseUForStack, UseYForStack,
// optimization options:
OptimizeForSize, OptimizeForSpeed, OptimizeForSonicSpeed, OptimizeForDebugging,
DangerousOptimizations, InlineFunctions, InterproceduralOptimization,
@ -540,6 +550,8 @@ object CompilationFlag extends Enumeration {
"iy_stack" -> UseIyForStack,
"ix_scratch" -> UseIxForScratch,
"iy_scratch" -> UseIyForScratch,
"u_stack" -> UseUForStack,
"y_stack" -> UseYForStack,
"software_stack" -> SoftwareStack,
"use_shadow_registers_for_irq" -> UseShadowRegistersForInterrupts,
"output_intel_syntax" -> UseIntelSyntaxForOutput,

View File

@ -540,6 +540,12 @@ object Main {
flag("-fuse-iy-for-stack").action { c =>
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)
}.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)
}.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) {
c.changeFlag(CompilationFlag.UseIxForScratch, true).changeFlag(CompilationFlag.UseIxForStack, false)
@ -557,6 +563,9 @@ object Main {
flag("-fno-use-index-for-stack").action { c =>
c.changeFlag(CompilationFlag.UseIyForStack, false).changeFlag(CompilationFlag.UseIxForStack, false)
}.description("Don't use either IX or IY as base pointer for stack variables (Z80 only)")
flag("-fno-use-uy-for-stack").action { c =>
c.changeFlag(CompilationFlag.UseUForStack, false).changeFlag(CompilationFlag.UseYForStack, false)
}.description("Don't use either U or Y as base pointer for stack variables (6809 only)").hidden()
boolean("-fsoftware-stack", "-fno-software-stack").action { (c, v) =>
c.changeFlag(CompilationFlag.SoftwareStack, v)
}.description("Use software stack for stack variables (6502 only)")

View File

@ -6,6 +6,8 @@ import millfork.node.{M6809Register, Position}
* @author Karol Stasiak
*/
sealed trait MAddrMode {
def changesRegister(reg: M6809Register.Value): Boolean = false
def makeIndirect(position: Position): MAddrMode
}
@ -14,10 +16,14 @@ case object Inherent extends MAddrMode {
}
case object InherentA extends MAddrMode {
override def changesRegister(reg: M6809Register.Value): Boolean = reg == M6809Register.A || reg == M6809Register.D
def makeIndirect(position: Position): MAddrMode = ???
}
case object InherentB extends MAddrMode {
override def changesRegister(reg: M6809Register.Value): Boolean = reg == M6809Register.B || reg == M6809Register.D
def makeIndirect(position: Position): MAddrMode = ???
}
@ -70,10 +76,14 @@ case class DAccumulatorIndexed(base: M6809Register.Value, indirect: Boolean) ext
}
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)
}
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)
}

View File

@ -1,6 +1,8 @@
package millfork.assembly.m6809
import millfork.CompilationFlag
import millfork.assembly.{AbstractCode, Elidability, SourceLine}
import millfork.compiler.CompilationContext
import millfork.env.{Constant, Label, MemoryVariable, NumericConstant, StackVariable, Variable, VariableInMemory}
import millfork.node.{M6809Register, Position}
@ -33,6 +35,9 @@ object MLine {
def indexedS(opcode: MOpcode.Value, offset: Int = 0): MLine =
MLine(opcode, Indexed(M6809Register.S, indirect = false), NumericConstant(offset, 1))
def indexedX(opcode: MOpcode.Value, offset: Constant): MLine =
MLine(opcode, Indexed(M6809Register.X, indirect = false), offset)
def accessAndPullS(opcode: MOpcode.Value): MLine =
MLine(opcode, PostIncremented(M6809Register.S, 1, indirect = false), Constant.Zero)
@ -51,12 +56,21 @@ object MLine {
def absolute(opcode: MOpcode.Value, param: Constant): MLine = MLine(opcode, Absolute(false), param)
def userstack(opcode: MOpcode.Value, offset: Int): MLine = MLine(opcode, Indexed(M6809Register.U, indirect = false), Constant(offset))
//def userstack(opcode: MOpcode.Value, offset: Int): MLine = MLine(opcode, Indexed(M6809Register.U, indirect = false), Constant(offset))
def variable(opcode: MOpcode.Value, variable: Variable, offset: Int = 0): MLine = {
def variablestack(ctx: CompilationContext, opcode: MOpcode.Value, offset: Int): MLine = {
if (ctx.options.flag(CompilationFlag.UseUForStack)) MLine(opcode, Indexed(M6809Register.U, indirect = false), Constant(offset))
else if (ctx.options.flag(CompilationFlag.UseYForStack)) MLine(opcode, Indexed(M6809Register.Y, indirect = false), Constant(offset))
else MLine(opcode, Indexed(M6809Register.S, indirect = false), Constant(ctx.extraStackOffset + offset))
}
def variable(ctx: CompilationContext, opcode : MOpcode.Value, variable: Variable, offset: Int = 0): MLine = {
variable match {
case v: VariableInMemory => MLine.absolute(opcode, v.toAddress)
case v: StackVariable => MLine(opcode, Indexed(M6809Register.U, indirect = false), NumericConstant(v.baseOffset, 1))
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))
case _ => ???
}
}
@ -122,5 +136,37 @@ case class MLine(opcode: MOpcode.Value, addrMode: MAddrMode, parameter: Constant
}
s" $opcode$suffix"
}
def changesRegister(reg: M6809Register.Value): Boolean = {
import M6809Register._
def overlaps(other: M6809Register.Value): Boolean = {
if (reg == D && (other == A || other == B)) true
else if (other == D && (reg == A || reg == B)) true
else reg == other
}
import MOpcode._
(opcode, addrMode) match {
case (_, InherentA) => reg == A
case (_, InherentB) => reg == B
case (PULU, set:RegisterSet) => reg == U || set.contains(reg)
case (PULS, set:RegisterSet) => reg == S || set.contains(reg)
case (PSHS, _) => reg == U
case (PSHU, _) => reg == S
case (TFR, TwoRegisters(_, dest)) => overlaps(dest)
case (EXG, TwoRegisters(r1, r2)) => overlaps(r1) || overlaps(r2)
case (op, _) if MOpcode.ChangesAAlways(op) => overlaps(A) || addrMode.changesRegister(reg)
case (op, _) if MOpcode.ChangesBAlways(op) => overlaps(B) || addrMode.changesRegister(reg)
case (LDB, _) => overlaps(B) || addrMode.changesRegister(reg)
case (LDD, _) => overlaps(D) || addrMode.changesRegister(reg)
case (LDU | LEAU, _) => reg == U || addrMode.changesRegister(reg)
case (LDS | LEAS, _) => reg == S || addrMode.changesRegister(reg)
case (LDX | LEAX, _) => reg == X || addrMode.changesRegister(reg)
case (LDY | LEAY, _) => reg == Y || addrMode.changesRegister(reg)
case (MUL, _) => overlaps(D)
case (ABX, _) => reg == X
case (NOP | SWI | SWI2 | SWI3 | SYNC, _) => false
case _ => true // TODO
}
}
}

View File

@ -42,6 +42,9 @@ object MOpcode extends Enumeration {
val Prefixed: Set[MOpcode.Value] = PrefixedBy10 ++ PrefixedBy11
val CanHaveInherentAccumulator: Set[MOpcode.Value] = Set(ASL, ASR, CLR, COM, DEC, INC, LSR, NEG, ROL, ROR, TST)
val Branching: Set[MOpcode.Value] = Set(BRA, BRN, BHI, BLS, BCC, BCS, BNE, BEQ, BVC, BVS, BPL, BMI, BGE, BLT, BGT, BLE)
val ChangesAAlways: Set[MOpcode.Value] = Set(ADDA, ADCA, SUBA, SBCA, ANDA, ORA, EORA, SEX, DAA)
val ChangesBAlways: Set[MOpcode.Value] = Set(ADDB, ADCB, SUBB, SBCB, ANDB, ORB, EORB)
val ChangesDAlways: Set[MOpcode.Value] = Set(ADDD, SUBD, ANDB, ORB, EORB)
def lookup(opcode: String, position: Some[Position], log: Logger): (MOpcode.Value, Option[MAddrMode]) = {
val o = opcode.toUpperCase(Locale.ROOT)

View File

@ -0,0 +1,68 @@
package millfork.assembly.m6809.opt
import millfork.assembly.mos.State
import millfork.assembly.opt._
import millfork.env.Constant
//noinspection RedundantNewCaseClass
case class CpuStatus(a: Status[Int] = UnknownStatus,
b0: Status[Boolean] = UnknownStatus,
b7: Status[Boolean] = UnknownStatus,
memStack: Map[Int, Status[Int]] = Map(),
b: Status[Int] = UnknownStatus,
x: Status[Constant] = UnknownStatus,
y: Status[Constant] = UnknownStatus,
u: Status[Constant] = UnknownStatus,
z: Status[Boolean] = UnknownStatus,
n: Status[Boolean] = UnknownStatus,
c: Status[Boolean] = UnknownStatus,
v: Status[Boolean] = UnknownStatus
) {
override def toString: String = s"A=$a,B=$b,X=$x,Y=$y; Z=$z,N=$n,C=$c,V=$v; B7=$b7,B0=$b0"
def d: Status[Int] = (a, b) match {
case (SingleStatus(h), SingleStatus(l)) => SingleStatus(h.&(0xff).<<(8).+(l&0xff))
case (UnknownStatus, UnknownStatus) => UnknownStatus
case _ => AnyStatus
}
def nz: CpuStatus =
this.copy(n = AnyStatus, z = AnyStatus)
def nz(i: Long): CpuStatus =
this.copy(n = SingleStatus((i & 0x80) != 0), z = SingleStatus((i & 0xff) == 0))
def ~(that: CpuStatus) = new CpuStatus(
a = this.a ~ that.a,
b = this.b ~ that.b,
b7 = this.b7 ~ that.b7,
b0 = this.b0 ~ that.b0,
x = this.x ~ that.x,
y = this.y ~ that.y,
u = this.u ~ that.u,
memStack = (this.memStack.keySet | that.memStack.keySet).map(k => k -> (this.memStack.getOrElse(k, UnknownStatus) ~ that.memStack.getOrElse(k, UnknownStatus))).toMap,
z = this.z ~ that.z,
n = this.n ~ that.n,
c = this.c ~ that.c,
v = this.v ~ that.v
)
}
object CpuStatus {
val initialStatusStandard = CpuStatus(
a = AnyStatus,
b = AnyStatus,
b0 = AnyStatus,
b7 = AnyStatus,
x = AnyStatus,
y = AnyStatus,
u = AnyStatus,
c = AnyStatus,
v = AnyStatus,
z = AnyStatus,
n = AnyStatus,
)
}

View File

@ -0,0 +1,90 @@
package millfork.assembly.m6809.opt
import millfork.CompilationFlag
import millfork.assembly.OptimizationContext
import millfork.assembly.m6809.{MLine, MLine0}
import millfork.assembly.opt.{AnyStatus, FlowCache, SingleStatus, Status}
import millfork.env._
import millfork.node.{M6809Register, NiceFunctionProperty}
import scala.util.control.Breaks._
/**
* @author Karol Stasiak
*/
object ForwardFlowAnalysis {
val cache = new FlowCache[MLine, CpuStatus]("m6809 forward")
def analyze(f: NormalFunction, code: List[MLine], optimizationContext: OptimizationContext): List[CpuStatus] = {
cache.get(code).foreach(return _)
val compilationOptions = optimizationContext.options
val bpInU = compilationOptions.flag(CompilationFlag.UseUForStack)
val bpInY = compilationOptions.flag(CompilationFlag.UseYForStack)
val BP = if (bpInU) M6809Register.U else if (bpInY) M6809Register.Y else M6809Register.CC // CC is a nonsense sentinel value
val niceFunctionProperties = optimizationContext.niceFunctionProperties
def extractNiceConstant[T](callee: String)(matcher: NiceFunctionProperty => Option[T]): Status[T] = {
var result: Status[T] = AnyStatus
breakable {
niceFunctionProperties.foreach{ np =>
if (np._2 == callee) matcher(np._1) match {
case Some(x) =>
result = SingleStatus(x)
break
case _ =>
}
}
}
result
}
val initialStatus = CpuStatus.initialStatusStandard
val functionStartStatus = CpuStatus.initialStatusStandard
val emptyStatus = CpuStatus()
val flagArray = Array.fill[CpuStatus](code.length)(emptyStatus)
val codeArray = code.toArray
var changed = true
while (changed) {
changed = false
var currentStatus: CpuStatus = functionStartStatus
for (i <- codeArray.indices) {
import millfork.assembly.m6809.MOpcode._
if (flagArray(i) != currentStatus) {
changed = true
flagArray(i) = currentStatus
}
codeArray(i) match {
case MLine0(LABEL, _, MemoryAddressConstant(Label(l))) =>
val L = l
currentStatus = codeArray.indices.flatMap(j => codeArray(j) match {
case MLine0(_, _, MemoryAddressConstant(Label(L))) => Some(flagArray(j))
case _ => None
}).fold(currentStatus)(_ ~ _)
case MLine0(JSR, _, MemoryAddressConstant(th)) =>
currentStatus = initialStatus.copy(
memStack = currentStatus.memStack,
u = if (bpInU) currentStatus.u else AnyStatus,
y = if (bpInY) currentStatus.y else AnyStatus
)
case MLine0(JSR | BYTE, _, _) =>
currentStatus = initialStatus
case MLine0(NOP, _, _) =>
()
case MLine0(opcode, addrMode, _) =>
// TODO
currentStatus = initialStatus
}
}
// flagArray.zip(codeArray).foreach{
// case (fl, y) => if (y.isPrintable) println(f"$fl%-32s $y%-32s")
// }
// println("---------------------")
}
cache.put(code, flagArray.toList)
}
}

View File

@ -26,7 +26,8 @@ object M6809Buitins {
case (_, List(ldr@MLine0(LDB, Absolute(false), _))) if lc.last.opcode == LDB =>
lc ++ List(ldr.copy(opcode = opcode), lc.last.copy(opcode = STB))
case _ if lc.last.opcode == LDB =>
lc ++ List(MLine.pp(PSHS, M6809Register.B)) ++ rc ++ List(MLine.accessAndPullS(opcode))
// TODO: preserve X?
lc ++ List(MLine.pp(PSHS, M6809Register.B)) ++ rc ++ List(MLine.accessAndPullS(opcode), lc.last.copy(opcode = STB))
case _ =>
println(lc)
???

View File

@ -3,7 +3,7 @@ package millfork.compiler.m6809
import millfork.assembly.Elidability
import millfork.assembly.m6809.{Inherent, MLine, MOpcode, NonExistent}
import millfork.compiler.{AbstractCompiler, CompilationContext}
import millfork.env.{Constant, Label, MemoryAddressConstant}
import millfork.env.{Constant, Label, MemoryAddressConstant, NormalParamSignature}
/**
* @author Karol Stasiak
@ -11,9 +11,17 @@ import millfork.env.{Constant, Label, MemoryAddressConstant}
object M6809Compiler extends AbstractCompiler[MLine] {
override def compile(ctx: CompilationContext): List[MLine] = {
ctx.env.nameCheck(ctx.function.code)
import MOpcode._
val storeParamsFromRegisters = ctx.function.params match {
case NormalParamSignature(List(param)) if param.typ.size == 1 =>
List(MLine.absolute(STB, param.toAddress))
case NormalParamSignature(List(param)) if param.typ.size == 2 =>
List(MLine.absolute(STD, param.toAddress))
case _ => Nil
}
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
label :: chunk
// TODO: stackframe etc.
label :: (storeParamsFromRegisters ++ chunk)
}
}

View File

@ -4,7 +4,7 @@ import millfork.assembly.m6809.{DAccumulatorIndexed, Indexed, MLine, MOpcode, Tw
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._
import millfork.env.{Constant, ConstantBooleanType, ConstantPointy, FatBooleanType, MathOperator, MemoryVariable, NormalFunction, NormalParamSignature, NumericConstant, StackVariablePointy, Variable, VariablePointy}
import millfork.env.{AssemblyParamSignature, Constant, ConstantBooleanType, ConstantPointy, ExternFunction, FatBooleanType, M6809RegisterVariable, MathOperator, MemoryVariable, NormalFunction, NormalParamSignature, NumericConstant, StackVariablePointy, Variable, VariablePointy}
import scala.collection.GenTraversableOnce
@ -12,7 +12,7 @@ import scala.collection.GenTraversableOnce
* @author Karol Stasiak
*/
object MExpressionTarget extends Enumeration {
val A, B, D, X, Y, NOTHING = Value
val A, B, D, X, Y, U, NOTHING = Value
def toLd(r: Value): MOpcode.Value = r match {
case A => LDA
@ -20,18 +20,20 @@ object MExpressionTarget extends Enumeration {
case D => LDD
case X => LDX
case Y => LDY
case U => LDU
case _ => ???
}
def toLea(r: Value): MOpcode.Value = r match {
case X => LEAX
case Y => LEAY
case U => LEAU
case _ => ???
}
def size(r: Value): Int = r match {
case A | B => 1
case D | X | Y => 2
case D | X | Y | U => 2
case NOTHING => 0
}
@ -73,13 +75,13 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
case 1 =>
targetSize match {
case 0 => Nil
case 1 => List(MLine.variable(toLd(target), variable))
case 2 => List(MLine.variable(LDB, variable)) ++ zeroextendB(ctx, target, exprType.isSigned)
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(toLd(target), variable))
case 2 => List(MLine.variable(ctx, toLd(target), variable))
}
}
case LiteralExpression(c, _) =>
@ -89,6 +91,45 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
}
case DerefExpression(inner, offset, _) =>
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 =>
val (variableIndex, constIndex) = env.evalVariableAndConstantSubParts(index)
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)
})
case None =>
targetSize match {
case 0 => Nil
case 1 => List(MLine.absolute(toLd(target), constantOffset))
case 2 => List(MLine.absolute(LDB, constantOffset)) ++ zeroextendB(ctx, target, exprType.isSigned)
}
}
case v:VariablePointy =>
val (prepareIndex, offset): (List[MLine], Constant) = ctx.env.eval(index) match {
case Some(ix) => List(MLine.absolute(LDX, v.addr)) -> (ix * v.elementType.size).quickSimplify
case _ =>
v.indexType.size match {
case 1 =>
(compileToD(ctx, index) :+ MLine(LEAX, DAccumulatorIndexed(M6809Register.X, indirect = false), Constant.Zero)) -> 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)
})
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))
}
}
case e@SumExpression(expressions, decimal) =>
getArithmeticParamMaxSize(ctx, expressions.map(_._2)) match {
case 1 => M6809Buitins.compileByteSum(ctx, e, fromScratch = true) ++ targetifyB(ctx, target, isSigned = false)
@ -112,12 +153,12 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
case 1 => M6809Buitins.compileByteBitwise(ctx, params, fromScratch = true, ANDB, MathOperator.And, 0xff) ++ targetifyB(ctx, target, isSigned = false)
case 2 => M6809Buitins.compileWordBitwise(ctx, params, fromScratch = true, ANDA, ANDB, MathOperator.And, 0xffff) ++ targetifyB(ctx, target, isSigned = false)
}
case "|" => ???
case "|" =>
getArithmeticParamMaxSize(ctx, params) match {
case 1 => M6809Buitins.compileByteBitwise(ctx, params, fromScratch = true, ORB, MathOperator.Or, 0) ++ targetifyB(ctx, target, isSigned = false)
case 2 => M6809Buitins.compileWordBitwise(ctx, params, fromScratch = true, ORA, ORB, MathOperator.Or, 0) ++ targetifyB(ctx, target, isSigned = false)
}
case "^" => ???
case "^" =>
getArithmeticParamMaxSize(ctx, params) match {
case 1 => M6809Buitins.compileByteBitwise(ctx, params, fromScratch = true, EORB, MathOperator.Exor, 0) ++ targetifyB(ctx, target, isSigned = false)
case 2 => M6809Buitins.compileWordBitwise(ctx, params, fromScratch = true, EORA, EORB, MathOperator.Exor, 0) ++ targetifyB(ctx, target, isSigned = false)
@ -242,32 +283,71 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
case ">>>>=" => ???
case _ =>
val f = lookupFunction(ctx, fce)
f.params match {
case NormalParamSignature(Nil) => //ok
val prepareParams: List[MLine] = f.params match {
case NormalParamSignature(List(param)) if param.typ.size == 1 =>
compileToB(ctx, params.head)
case NormalParamSignature(List(param)) if param.typ.size == 2 =>
compileToD(ctx, params.head)
case NormalParamSignature(signature) =>
params.zip(signature).flatMap { case (paramExpr, paramVar) =>
val callCtx = callingContext(ctx, f.name, paramVar)
paramVar.typ.size match {
case 1 =>
compileToB(ctx, paramExpr) ++ storeB(callCtx, VariableExpression(paramVar.name + "`aa"))
case 2 =>
compileToD(ctx, paramExpr) ++ storeD(callCtx, VariableExpression(paramVar.name + "`aa"))
case _ =>
???
}
}
case AssemblyParamSignature(signature) =>
params.zip(signature).flatMap { case (e, a) =>
val compiled = a.variable match {
case M6809RegisterVariable(M6809Register.A, _) => compileToA(ctx, e)
case M6809RegisterVariable(M6809Register.B, _) => compileToB(ctx, e)
case M6809RegisterVariable(M6809Register.D, _) => compileToD(ctx, e)
case M6809RegisterVariable(M6809Register.X, _) => compileToX(ctx, e)
case M6809RegisterVariable(M6809Register.Y, _) => compileToY(ctx, e)
case M6809RegisterVariable(M6809Register.U, _) => compileToU(ctx, e)
case _ => ???
}
if (compiled.length > 1) ???
compiled
}
case _ => ???
}
f match {
val actualCall = f match {
case nf:NormalFunction =>
List(MLine.absolute(JSR, nf.toAddress))
case nf:ExternFunction =>
List(MLine.absolute(JSR, nf.toAddress))
case _ => ???
}
prepareParams ++ actualCall
}
case _ => ???
}
}
def compileToA(ctx: CompilationContext, expr: Expression): List[MLine] = compile(ctx, expr, MExpressionTarget.A)
def compileToB(ctx: CompilationContext, expr: Expression): List[MLine] = compile(ctx, expr, MExpressionTarget.B)
def compileToD(ctx: CompilationContext, expr: Expression): List[MLine] = compile(ctx, expr, MExpressionTarget.D)
def compileToX(ctx: CompilationContext, expr: Expression): List[MLine] = compile(ctx, expr, MExpressionTarget.X)
def compileToY(ctx: CompilationContext, expr: Expression): List[MLine] = compile(ctx, expr, MExpressionTarget.Y)
def compileToU(ctx: CompilationContext, expr: Expression): List[MLine] = compile(ctx, expr, MExpressionTarget.U)
def zeroextendB(ctx: CompilationContext, target: MExpressionTarget.Value, isSigned: Boolean): List[MLine] = {
val extendToA = if (isSigned) MLine.immediate(LDA, 0) else MLine.inherent(SEX)
val extendToA = if (isSigned) MLine.inherent(SEX) else MLine.immediate(LDA, 0)
target match {
case MExpressionTarget.D => List(extendToA)
case MExpressionTarget.X => List(extendToA, MLine.tfr(M6809Register.D, M6809Register.X))
case MExpressionTarget.Y => List(extendToA, MLine.tfr(M6809Register.D, M6809Register.Y))
case MExpressionTarget.U => List(extendToA, MLine.tfr(M6809Register.D, M6809Register.U))
case _ => ???
}
}
@ -281,27 +361,34 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
target match {
case VariableExpression(name) =>
val variable = ctx.env.get[Variable](name)
List(MLine.variable(STB, variable))
List(MLine.variable(ctx, STB, variable))
case DerefExpression(inner, offset, _) =>
compileToX(ctx, inner) :+ MLine(STB, Indexed(M6809Register.X, indirect = false), NumericConstant(offset, 2))
compileToX(ctx, inner) :+ MLine.indexedX(STB, NumericConstant(offset, 2))
case IndexedExpression(name, index) =>
ctx.env.getPointy(name) match {
case p: ConstantPointy =>
compileToX(ctx, index) :+ MLine(STB, Indexed(M6809Register.X, indirect = false), p.value)
val (variableIndex, constOffset) = ctx.env.evalVariableAndConstantSubParts(index)
val effectiveBase = (p.value + constOffset).quickSimplify
variableIndex match {
case Some(ix) =>
stashBIfNeeded(ctx, compileToX(ctx, ix)) :+ MLine.indexedX(STB, effectiveBase)
case None =>
List(MLine.absolute(STB, effectiveBase))
}
case v: VariablePointy =>
ctx.env.eval(index) match {
case Some(ix) => List(MLine.absolute(LDX, v.addr), MLine(STB, Indexed(M6809Register.X, indirect = false), ix * v.elementType.size))
case Some(ix) => List(MLine.absolute(LDX, v.addr), MLine.indexedX(STB, ix * v.elementType.size))
case _ =>
v.indexType.size match {
case 1 =>
stashBIfNeeded(ctx,
compileToD(ctx, index) :+ MLine(LEAX, DAccumulatorIndexed(M6809Register.X, indirect = false), Constant.Zero)) :+
MLine(STB, Indexed(M6809Register.X, indirect = false), Constant.Zero)
MLine.indexedX(STB, Constant.Zero)
}
}
case v: StackVariablePointy =>
ctx.env.eval(index) match {
case Some(ix) => List(MLine.userstack(LDX, v.offset), MLine(STB, Indexed(M6809Register.X, indirect = false), ix * v.elementType.size))
case Some(ix) => List(MLine.variablestack(ctx, LDX, v.offset), MLine.indexedX(STB, ix * v.elementType.size))
}
}
}
@ -311,7 +398,7 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
target match {
case VariableExpression(name) =>
val variable = ctx.env.get[Variable](name)
List(MLine.variable(STD, variable))
List(MLine.variable(ctx, STD, variable))
case DerefExpression(inner, offset, _) =>
compileToX(ctx, inner) :+ MLine(STD, Indexed(M6809Register.X, indirect = false), NumericConstant(offset, 2))
}
@ -321,14 +408,14 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
case MExpressionTarget.NOTHING => Nil
case MExpressionTarget.B => Nil
case MExpressionTarget.A => List(MLine.tfr(M6809Register.B, M6809Register.A))
case MExpressionTarget.D | MExpressionTarget.X | MExpressionTarget.Y => zeroextendB(ctx, target, isSigned)
case MExpressionTarget.D | MExpressionTarget.X | MExpressionTarget.Y | MExpressionTarget.U => zeroextendB(ctx, target, isSigned)
}
def targetifyA(ctx: CompilationContext, target: MExpressionTarget.Value, isSigned: Boolean): List[MLine] = target match {
case MExpressionTarget.NOTHING => Nil
case MExpressionTarget.A => Nil
case MExpressionTarget.B => List(MLine.tfr(M6809Register.A, M6809Register.B))
case MExpressionTarget.D | MExpressionTarget.X | MExpressionTarget.Y =>
case MExpressionTarget.D | MExpressionTarget.X | MExpressionTarget.Y | MExpressionTarget.U =>
List(MLine.tfr(M6809Register.A, M6809Register.B)) ++ zeroextendB(ctx, target, isSigned)
}
@ -337,6 +424,7 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
case MExpressionTarget.D => Nil
case MExpressionTarget.X => List(MLine.tfr(M6809Register.D, M6809Register.X))
case MExpressionTarget.Y => List(MLine.tfr(M6809Register.D, M6809Register.Y))
case MExpressionTarget.U => List(MLine.tfr(M6809Register.D, M6809Register.U))
}

View File

@ -81,6 +81,14 @@ sealed trait Constant {
}
}
def subwordReversed(index: Int): Constant = {
if (requiredSize <= index) Constant.Zero
else {
// TODO: check if ok
CompoundConstant(MathOperator.Or, CompoundConstant(MathOperator.Shl, subbyte(index), NumericConstant(8, 1)), subbyte(index + 1)).quickSimplify
}
}
def subconstant(offset: Int, length: Int): Constant = {
if (offset == 0 && length == requiredSize) {
this

View File

@ -142,7 +142,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
s.typ.size match {
case 0 => 0
case 1 => deepConstResolve(s.subbyte(0))
case 2 => deepConstResolve(s.subword(0)) // TODO: endianness?
case 2 => if (platform.isBigEndian) deepConstResolve(s.subwordReversed(0)) else deepConstResolve(s.subword(0)) // TODO: endianness?
case _ => ???
}
case CompoundConstant(operator, lc, rc) =>

View File

@ -90,12 +90,12 @@ class M6809Assembler(program: Program,
case MLine0(TFR, TwoRegisters(source, target), param)
if M6809Register.registerSize(source) == M6809Register.registerSize(target) && param.isProvablyZero =>
writeByte(bank, index, 0x1f)
writeByte(bank, index, registerCode(source) * 16 + registerCode(target))
writeByte(bank, index + 1, registerCode(source) * 16 + registerCode(target))
index + 2
case MLine0(EXG, TwoRegisters(source, target), param)
if M6809Register.registerSize(source) == M6809Register.registerSize(target) && param.isProvablyZero =>
writeByte(bank, index, 0x1e)
writeByte(bank, index, registerCode(source) * 16 + registerCode(target))
writeByte(bank, index + 1, registerCode(source) * 16 + registerCode(target))
index + 2
case l@MLine0(op, RegisterSet(set), param) if param.isProvablyZero && M6809Assembler.pushpull.contains(op) =>
writeByte(bank, index, M6809Assembler.pushpull(op))

View File

@ -29,6 +29,7 @@ case class M6809Parser(filename: String,
case "d" => ByM6809Register(M6809Register.D)
case "x" => ByM6809Register(M6809Register.X)
case "y" => ByM6809Register(M6809Register.Y)
case "u" => ByM6809Register(M6809Register.U)
case x => log.fatal(s"Unknown assembly parameter passing convention: `$x`")
}
override val asmParamDefinition: P[ParameterDeclaration] = for {

View File

@ -28,7 +28,7 @@ class ArraySuite extends FunSuite with Matchers with AppendedClues {
m.readByte(0xc000) should equal(5)
m.readByte(0xc001) should equal(6)
m.readByte(0xc002) should equal(7)
EmuCrossPlatformBenchmarkRun(Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(src) { m =>
EmuCrossPlatformBenchmarkRun(Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(src) { m =>
m.readByte(0xc000) should equal(5)
m.readByte(0xc001) should equal(6)
m.readByte(0xc002) should equal(7)
@ -53,7 +53,7 @@ class ArraySuite extends FunSuite with Matchers with AppendedClues {
m.readByte(0xc002) should equal(1)
m.readByte(0xc007) should equal(6)
}
EmuCrossPlatformBenchmarkRun(Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(src) { m =>
EmuCrossPlatformBenchmarkRun(Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(src) { m =>
m.readByte(0xc002) should equal(1)
m.readByte(0xc007) should equal(6)
}
@ -118,7 +118,7 @@ class ArraySuite extends FunSuite with Matchers with AppendedClues {
}
test("Array simple read") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
"""
| byte output @$c000
| array a[7]

View File

@ -63,7 +63,7 @@ class ByteMathSuite extends FunSuite with Matchers with AppendedClues {
}
test("In-place byte addition") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
"""
| array output[3] @$c000
| byte a
@ -77,7 +77,7 @@ class ByteMathSuite extends FunSuite with Matchers with AppendedClues {
}
test("LHS evaluation during in-place byte addition") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
"""
| array output[1] @$c000
| byte call_count @$c001
@ -97,7 +97,7 @@ class ByteMathSuite extends FunSuite with Matchers with AppendedClues {
}
test("Parameter order") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
"""
| byte output @$c000
| array arr[6]
@ -179,7 +179,7 @@ class ByteMathSuite extends FunSuite with Matchers with AppendedClues {
}
private def multiplyCase2(x: Int, y: Int): Unit = {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
s"""
| import zp_reg
| byte output @$$c000

View File

@ -22,6 +22,7 @@ class M6809Memory(memoryBank: MemoryBank, resetVector: Int) extends MemorySegmen
override def load(addr: Int): Int = {
if (!memoryBank.readable(addr)) {
println(s"Accessing memory for read at $$${addr.toHexString}")
???
}
memoryBank.readByte(addr)
@ -29,6 +30,7 @@ class M6809Memory(memoryBank: MemoryBank, resetVector: Int) extends MemorySegmen
override def store(addr: Int, `val`: Int): Unit = {
if (!memoryBank.writeable(addr)) {
println(s"Accessing memory for write at $$${addr.toHexString}")
???
}
memoryBank.output(addr) = `val`.toByte