1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-07-01 12:29:29 +00:00

6809: Improved support for large types

This commit is contained in:
Karol Stasiak 2020-06-18 20:29:31 +02:00
parent 88b2bbd434
commit b387ece71d
10 changed files with 401 additions and 64 deletions

View File

@ -38,6 +38,8 @@ object MLine {
def tfr(source: M6809Register.Value, target: M6809Register.Value): MLine = MLine(TFR, TwoRegisters(source, target), Constant.Zero)
def exg(source: M6809Register.Value, target: M6809Register.Value): MLine = MLine(EXG, TwoRegisters(source, target), Constant.Zero)
def pp(opcode: MOpcode.Value, registers: M6809Register.Value*): MLine = MLine(opcode, RegisterSet(registers.toSet), Constant.Zero)
def indexedS(opcode: MOpcode.Value, offset: Int = 0): MLine =
@ -79,12 +81,12 @@ object MLine {
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: VariableInMemory => MLine.absolute(opcode, v.toAddress + offset)
case v: StackVariable =>
val size = variable.typ.size
if (ctx.options.flag(CompilationFlag.UseUForStack)) MLine(opcode, Indexed(M6809Register.U, indirect = false), NumericConstant(v.baseOffset, size))
else if (ctx.options.flag(CompilationFlag.UseYForStack)) MLine(opcode, Indexed(M6809Register.Y, indirect = false), NumericConstant(v.baseOffset, size))
else MLine(opcode, Indexed(M6809Register.S, indirect = false), NumericConstant(v.baseOffset + ctx.extraStackOffset, size))
if (ctx.options.flag(CompilationFlag.UseUForStack)) MLine(opcode, Indexed(M6809Register.U, indirect = false), NumericConstant(v.baseOffset + offset, size))
else if (ctx.options.flag(CompilationFlag.UseYForStack)) MLine(opcode, Indexed(M6809Register.Y, indirect = false), NumericConstant(v.baseOffset + offset, size))
else MLine(opcode, Indexed(M6809Register.S, indirect = false), NumericConstant(v.baseOffset + ctx.extraStackOffset + offset, size))
case _ => ???
}
}
@ -177,9 +179,9 @@ case class MLine(opcode: MOpcode.Value, addrMode: MAddrMode, parameter: Constant
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 (LDA, _) => overlaps(A) || addrMode.changesRegister(reg)
case (LDB, _) => overlaps(B) || addrMode.changesRegister(reg)
case (LDD, _) => overlaps(D) || addrMode.changesRegister(reg)
case (LDA | ANDA | ADDA | ADCA | SUBA | SBCA | EORA | ORA | BITA, _) => overlaps(A) || addrMode.changesRegister(reg)
case (LDB | ANDB | ADDB | ADCB | SUBB | SBCB | EORB | ORB | BITB, _) => overlaps(B) || addrMode.changesRegister(reg)
case (LDD | ADDD | SUBD, _) => 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)
@ -187,10 +189,17 @@ case class MLine(opcode: MOpcode.Value, addrMode: MAddrMode, parameter: Constant
case (MUL, _) => overlaps(D)
case (ABX, _) => reg == X
case (NOP | SWI | SWI2 | SWI3 | SYNC, _) => false
case _ => true // TODO
case (STA | STB | STD | STS | STU | STX | STY, _) => false
case (SEX | DAA, _) => overlaps(A)
case (JSR | SWI | SWI2 | SWI3, _) => true
case _ => addrMode.changesRegister(reg)
}
}
def changesCarryFlag: Boolean = !MOpcode.PreservesC(opcode)
def readsRegister(reg: M6809Register.Value): Boolean = {
import M6809Register._
def overlaps(other: M6809Register.Value): Boolean = {

View File

@ -46,7 +46,6 @@ object MOpcode extends Enumeration {
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)
val ChangesCFAlways: Set[MOpcode.Value] = Set(ADDD, SUBD, ANDB, ORB, EORB)
val ReadsAAlways: Set[MOpcode.Value] = Set(ADDD, SUBD, ANDB, ORB, EORB)
val AccessesWordInMemory: Set[MOpcode.Value] = Set(ADDD, SUBD, LDD, STD, LDX, LDY, LDU, LDS, STX, STY, STU, STS, CMPD, CMPX, CMPY, CMPU, CMPS)
val AllLinear: Set[MOpcode.Value] = Set(
@ -78,6 +77,15 @@ object MOpcode extends Enumeration {
CMPA, CMPB, CMPD, CMPX, CMPY, CMPU, CMPS,
MUL,
)
val PreservesC: Set[MOpcode.Value] = Set(
ANDA, ANDB, BITA, BITB, DEC, EXG, INC,
LDA, LDB, LDD, LDX, LDY, LDU, LDS,
LEAS, LEAX, LEAY, LEAU,
NOP, ORA, ORB,
PSHS, PSHU, PULS, PULU,
STA, STB, STD, STX, STY, STS, STU,
TFR, TST
)
// The following are incomplete:
val ChangesN: Set[MOpcode.Value] = Set(
CWAI, ORCC, ANDCC,

View File

@ -1,11 +1,13 @@
package millfork.compiler.m6809
import java.util.concurrent.AbstractExecutorService
import millfork.CompilationFlag
import millfork.assembly.m6809.{DAccumulatorIndexed, Immediate, Indexed, InherentB, MLine, MLine0, MOpcode, RegisterSet, TwoRegisters}
import millfork.compiler.{AbstractExpressionCompiler, BranchIfFalse, BranchIfTrue, BranchSpec, ComparisonType, CompilationContext, NoBranching}
import millfork.node.{DerefExpression, Expression, FunctionCallExpression, GeneratedConstantExpression, IndexedExpression, LhsExpression, LiteralExpression, M6809Register, SeparateBytesExpression, SumExpression, VariableExpression}
import millfork.assembly.m6809.MOpcode._
import millfork.env.{AssemblyOrMacroParamSignature, BuiltInBooleanType, Constant, ConstantBooleanType, ConstantPointy, ExternFunction, FatBooleanType, FlagBooleanType, FunctionInMemory, FunctionPointerType, Label, M6809RegisterVariable, MacroFunction, MathOperator, MemoryAddressConstant, MemoryVariable, NonFatalCompilationException, NormalFunction, NormalParamSignature, NumericConstant, StackVariablePointy, ThingInMemory, Type, Variable, VariableInMemory, VariablePointy}
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 scala.collection.GenTraversableOnce
@ -357,7 +359,7 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
size match {
case 1 => M6809Buitins.perform8BitInPlace(ctx, l, r, ADDB)
case 2 => M6809Buitins.perform16BitInPlace(ctx, l, r, ADDD, commutative = true)
case _ => ctx.log.error("Long addition not implemented yet", fce.position); Nil
case _ => M6809LargeBuiltins.modifyInPlaceViaX(ctx, l, r, ADDB)
}
case "+'=" =>
val (l, r, size) = assertArithmeticAssignmentLike(ctx, params)
@ -372,15 +374,14 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
case (true, false) => lc ++ rc ++ add
case (true, true) => rc ++ stashAIfNeeded(ctx, lc) ++ add
}
case 2 => ???
case _ => ???
case _ => M6809LargeBuiltins.modifyInPlaceViaX(ctx, l, r, ADDA)
}
case "-=" =>
val (l, r, size) = assertArithmeticAssignmentLike(ctx, params)
size match {
case 1 => M6809Buitins.perform8BitInPlace(ctx, l, r, SUBB)
case 2 => M6809Buitins.perform16BitInPlace(ctx, l, r, SUBD, commutative = false)
case _ => ???
case _ => M6809LargeBuiltins.modifyInPlaceViaX(ctx, l, r, SUBB)
}
case "-'=" =>
val (l, r, size) = assertArithmeticAssignmentLike(ctx, params)
@ -390,8 +391,7 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
val rc = compileToB(ctx, r)
lc ++ List(MLine.pp(PSHS, M6809Register.B)) ++
rc ++ List(MLine.pp(PSHS, M6809Register.B), MLine.immediate(LDA, 0x9a), MLine.accessAndPullS(SUBA), MLine.accessAndPullS(ADDA), MLine.inherent(DAA), MLine.indexedX(STA, 0))
case 2 => ???
case _ => ???
case _ => M6809LargeBuiltins.modifyInPlaceViaX(ctx, l, r, SUBA)
}
case "*=" =>
val (l, r, size) = assertArithmeticAssignmentLike(ctx, params)
@ -417,21 +417,21 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
size match {
case 1 => M6809Buitins.perform8BitInPlace(ctx, l, r, ANDB)
case 2 => M6809Buitins.perform16BitInPlace(ctx, l, r, ANDA, ANDB, commutative = true)
case _ => ???
case _ => M6809LargeBuiltins.modifyInPlaceViaX(ctx, l, r, ANDB)
}
case "|=" =>
val (l, r, size) = assertArithmeticAssignmentLike(ctx, params)
size match {
case 1 => M6809Buitins.perform8BitInPlace(ctx, l, r, ORB)
case 2 => M6809Buitins.perform16BitInPlace(ctx, l, r, ORA, ORB, commutative = true)
case _ => ???
case _ => M6809LargeBuiltins.modifyInPlaceViaX(ctx, l, r, ORB)
}
case "^=" =>
val (l, r, size) = assertArithmeticAssignmentLike(ctx, params)
size match {
case 1 => M6809Buitins.perform8BitInPlace(ctx, l, r, EORB)
case 2 => M6809Buitins.perform16BitInPlace(ctx, l, r, EORA, EORB, commutative = true)
case _ => ???
case _ => M6809LargeBuiltins.modifyInPlaceViaX(ctx, l, r, EORB)
}
case "<<=" =>
val (l, r, size) = assertArithmeticAssignmentLike(ctx, params)
@ -441,6 +441,8 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
handleInPlaceModification(ctx, l, 1, M6809Buitins.compileByteShiftForB(ctx, r, left = true))
case 2 =>
handleInPlaceModification(ctx, l, 2, M6809Buitins.compileWordShiftForD(ctx, r, left = true))
case _ =>
M6809LargeBuiltins.compileShiftInPlace(ctx, size, l, r, left = true)
}
case "<<'=" =>
val (l, r, size) = assertArithmeticAssignmentLike(ctx, params)
@ -455,6 +457,7 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
size match {
case 1 => handleInPlaceModification(ctx, l, 1, M6809Buitins.compileByteShiftForB(ctx, r, left = false))
case 2 => handleInPlaceModification(ctx, l, 2, M6809Buitins.compileWordShiftForD(ctx, r, left = false))
case _ => M6809LargeBuiltins.compileShiftInPlace(ctx, size, l, r, left = false)
}
case ">>'=" => ???
case ">>>>=" => ???
@ -499,7 +502,7 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
case 2 =>
compileToD(ctx, paramExpr) ++ storeD(callCtx, VariableExpression(paramVar.name + "`aa"))
case _ =>
???
M6809LargeBuiltins.storeLarge(callCtx, VariableExpression(paramVar.name + "`aa"), paramExpr)
}
}
case AssemblyOrMacroParamSignature(signature) =>
@ -647,6 +650,11 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
else lines
}
def stashCarryIfNeeded(ctx: CompilationContext, lines: List[MLine]): List[MLine] = {
if (lines.exists(_.changesCarryFlag)) MLine.pp(PSHS, M6809Register.CC) :: (lines :+ MLine.pp(PULS, M6809Register.CC))
else lines
}
def storeA(ctx: CompilationContext, target: LhsExpression): List[MLine] = store8(ctx, target, stashAIfNeeded, STA)
def storeB(ctx: CompilationContext, target: LhsExpression): List[MLine] = store8(ctx, target, stashBIfNeeded, STB)
@ -839,4 +847,74 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
}
false
}
def compileToByteReads(ctx: CompilationContext, source: Expression, targetSize: Int): List[List[MLine]] = {
val sourceType = AbstractExpressionCompiler.getExpressionType(ctx, source)
ctx.env.eval(source) match {
case Some(const) =>
List.tabulate(targetSize)(i => List(MLine.immediate(LDB, const.subbyteBe(targetSize - 1 - i, targetSize))))
case None =>
sourceType.size match {
case 0 => ???
case 1 =>
List.tabulate(targetSize)(i =>
if (sourceType.isSigned) {
if (i == 0) compileToB(ctx, source) :+ MLine.tfr(M6809Register.B, M6809Register.A)
else if (i == 1) List(
MLine.tfr(M6809Register.A, M6809Register.B),
MLine.inherent(SEX),
MLine.tfr(M6809Register.B, M6809Register.A)
)
else List(MLine.tfr(M6809Register.A, M6809Register.B))
} else {
if (i == 0) compileToB(ctx, source)
else List(MLine.immediate(LDB, 0))
}
)
case 2 =>
List.tabulate(targetSize)(i =>
if (sourceType.isSigned) {
if (i == 0) compileToD(ctx, source)
else if (i == 1) List(MLine.tfr(M6809Register.A, M6809Register.B))
else if (i == 2) {
if (targetSize > 3) List(
MLine.tfr(M6809Register.A, M6809Register.B),
MLine.inherent(SEX),
MLine.tfr(M6809Register.B, M6809Register.A)
) else List(
MLine.tfr(M6809Register.A, M6809Register.B),
MLine.inherent(SEX)
)
} else List(MLine.tfr(M6809Register.A, M6809Register.B))
} else {
if (i == 0) compileToD(ctx, source)
else if (i == 1) List(MLine.tfr(M6809Register.A, M6809Register.B))
else List(MLine.immediate(LDB, 0))
}
)
case _ =>
source match {
case LiteralExpression(value, size) =>
val const = NumericConstant(value, size)
List.tabulate(targetSize)(i => List(MLine.immediate(LDB, const.subbyte(i))))
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)))
case e:FunctionCallExpression =>
ctx.env.maybeGet[NormalFunction](e.functionName) match {
case Some(function) =>
val load = M6809ExpressionCompiler.compile(ctx, e, MExpressionTarget.NOTHING)
val v = ctx.env.get[VariableInMemory](function.name + ".return")
List.tabulate(targetSize) { i =>
if (i == 0) load :+ MLine.variable(ctx, LDB, v, v.typ.size - 1 - i)
else List(if (i < v.typ.size) MLine.variable(ctx, LDB, v, v.typ.size - 1 - i) else MLine.immediate(LDB, 0))
}
case _ => ???
}
}
}
}
}
}

View File

@ -0,0 +1,238 @@
package millfork.compiler.m6809
import millfork.assembly.m6809.{Immediate, MLine, MLine0, MOpcode, TwoRegisters}
import millfork.compiler.{AbstractExpressionCompiler, CompilationContext}
import millfork.node.{Expression, LhsExpression, M6809Register}
import millfork.assembly.m6809.MOpcode._
import millfork.env.{Constant, NumericConstant}
import scala.collection.GenTraversableOnce
import scala.collection.mutable.ListBuffer
/**
* @author Karol Stasiak
*/
object M6809LargeBuiltins {
def compileShiftInPlace(ctx: CompilationContext, size: Int, target: LhsExpression, shiftValue: Expression, left: Boolean): List[MLine] = {
val (targetAddr, targetInit): (Option[Constant], List[MLine]) = M6809ExpressionCompiler.compileAddressToX(ctx, target) match {
case List(MLine(LDX, Immediate, addr, _, _)) => Some(addr) -> Nil
case xs => None -> xs
}
val oneShift = if (left) {
targetAddr match {
case Some(addr) =>
List.tabulate(size)(i => MLine.absolute(if (i == 0) ASL else ROL, addr + (size - 1 - i)))
case None =>
List.tabulate(size)(i => MLine.indexedX(if (i == 0) ASL else ROL, size - 1 - i))
}
} else {
targetAddr match {
case Some(addr) =>
List.tabulate(size)(i => MLine.absolute(if (i == 0) LSR else ROR, addr + i))
case None =>
List.tabulate(size)(i => MLine.indexedX(if (i == 0) LSR else ROR, i))
}
}
targetInit ++ (M6809ExpressionCompiler.compileToB(ctx, shiftValue) match {
case List(MLine0(LDB, Immediate, NumericConstant(n, _))) if n >= 0 && (n - 1) * size < 4 =>
List.fill(n.toInt)(oneShift).flatten
case xs@List(MLine0(LDB, Immediate, c)) if c.isProvablyGreaterOrEqualThan(1) =>
val label = ctx.nextLabel("sr")
xs ++ List(MLine.label(label)) ++ oneShift ++ List(MLine.inherentB(DEC), MLine.shortBranch(BNE, label))
case xs =>
val loop = ctx.nextLabel("sr")
val skip = ctx.nextLabel("ss")
M6809ExpressionCompiler.stashXIfNeeded(ctx, xs) ++ List(
MLine.label(loop),
MLine.inherentB(DEC),
MLine.immediate(CMPB, -1),
MLine.shortBranch(BEQ, skip)) ++ oneShift ++ List(
MLine.shortBranch(BRA, loop),
MLine.label(skip)
)
})
}
def storeLarge(ctx: CompilationContext, target: LhsExpression, source: Expression): List[MLine] = {
val byteCount = AbstractExpressionCompiler.getExpressionType(ctx, target).size
val byteLoads = M6809ExpressionCompiler.compileToByteReads(ctx, source, byteCount)
val (targetAddr, targetInit): (Option[Constant], List[MLine]) = M6809ExpressionCompiler.compileAddressToX(ctx, target) match {
case List(MLine(LDX, Immediate, addr, _, _)) => Some(addr) -> Nil
case xs => None -> xs
}
// TODO: use loop for very large structures
// TODO: use D to speed up certain loads
targetInit ++ byteLoads.zipWithIndex.flatMap{ case (loadByte, ix) =>
M6809ExpressionCompiler.stashXIfNeeded(ctx, loadByte) :+ ( targetAddr match {
case Some(addr) => MLine.absolute(STB, addr + (byteCount - 1 - ix))
case None => MLine.indexedX(STB, byteCount - 1 - ix)
} )
}
}
def convertToLda(ldb: List[MLine]): List[MLine] = {
ldb match {
case List(l@MLine0(LDB, _, _)) => List(l.copy(opcode = LDA))
case List(l@MLine0(TFR, TwoRegisters(M6809Register.A, M6809Register.B), _)) => List(l.copy(addrMode = TwoRegisters(M6809Register.B, M6809Register.A)))
case _ => MLine.exg(M6809Register.A, M6809Register.B) :: (ldb :+ MLine.exg(M6809Register.A, M6809Register.B))
}
}
def compileInc(ctx: CompilationContext, target: LhsExpression): List[MLine] = {
val sizeInBytes = AbstractExpressionCompiler.getExpressionType(ctx, target).size
val result = new ListBuffer[MLine]()
val targetAddr: Option[Constant] = M6809ExpressionCompiler.compileAddressToX(ctx, target) match {
case List(MLine(LDX, Immediate, addr, _, _)) => Some(addr)
case xs =>
result ++= xs
None
}
val skipLabel = ctx.nextLabel("in")
for (i <- 0 until sizeInBytes) {
targetAddr match {
case Some(addr) =>
result += MLine.absolute(INC, addr + (sizeInBytes - 1 - i))
case None =>
result += MLine.indexedX(INC, sizeInBytes - 1 - i)
}
if (i != sizeInBytes - 1) {
result += MLine.shortBranch(BNE, skipLabel)
}
}
result += MLine.label(skipLabel)
result.toList
}
def modifyInPlaceViaX(ctx: CompilationContext, target: LhsExpression, argument: Expression, opcode: MOpcode.Value): List[MLine] = {
if (opcode == ADDB) ctx.env.eval(argument) match {
case Some(NumericConstant(1, _)) =>
return compileInc(ctx, target)
case _ =>
}
val sizeInBytes = AbstractExpressionCompiler.getExpressionType(ctx, target).size
val byteLoads = M6809ExpressionCompiler.compileToByteReads(ctx, argument, sizeInBytes)
val result = new ListBuffer[MLine]()
val targetAddr: Option[Constant] = M6809ExpressionCompiler.compileAddressToX(ctx, target) match {
case List(MLine(LDX, Immediate, addr, _, _)) => Some(addr)
case xs =>
result ++= xs
ctx.log.error("Invalid left-hand-side expression", target.position)
None
}
var firstNonzeroByte = 0
for (i <- 0 until sizeInBytes) {
val ldb = byteLoads(i)
val magicConstant =
ldb match {
case List(MLine0(LDB, Immediate, NumericConstant(x, _))) => Some(x.toInt & 0xff)
case _ => None
}
(opcode, magicConstant) match {
case (ORB | EORB, Some(0)) =>
// nothing
case (ANDB, Some(0xff)) =>
// nothing
case (EORB, Some(0xff)) =>
targetAddr match {
case Some(addr) =>
result += MLine.absolute(COM, addr + (sizeInBytes - 1 - i))
case None =>
result += MLine.indexedX(COM, sizeInBytes - 1 - i)
}
case (ADDB | SUBB | ADDA | SUBA, Some(0)) if i == firstNonzeroByte =>
firstNonzeroByte = i + 1
case (SUBA, _) => ???
case (ADDA, _) if i == firstNonzeroByte =>
val lda = convertToLda(ldb)
targetAddr match {
case Some(addr) =>
result ++= lda
result += MLine.absolute(ADCA, addr + (sizeInBytes - 1 - i))
result += MLine.inherent(DAA)
result += MLine.absolute(STA, addr + (sizeInBytes - 1 - i))
case None =>
result ++= M6809ExpressionCompiler.stashXIfNeeded(ctx, lda)
result += MLine.indexedX(ADCA, sizeInBytes - 1 - i)
result += MLine.inherent(DAA)
result += MLine.indexedX(STA, sizeInBytes - 1 - i)
}
case (ADDA, _) if i != firstNonzeroByte =>
val lda = convertToLda(ldb)
targetAddr match {
case Some(addr) =>
result ++= M6809ExpressionCompiler.stashCarryIfNeeded(ctx, lda)
result += MLine.absolute(ADCA, addr + (sizeInBytes - 1 - i))
result += MLine.inherent(DAA)
result += MLine.absolute(STA, addr + (sizeInBytes - 1 - i))
case None =>
result ++= M6809ExpressionCompiler.stashCarryIfNeeded(ctx, M6809ExpressionCompiler.stashXIfNeeded(ctx, lda))
result += MLine.indexedX(ADCA, sizeInBytes - 1 - i)
result += MLine.inherent(DAA)
result += MLine.indexedX(STA, sizeInBytes - 1 - i)
}
case (SUBB, _) if i == firstNonzeroByte =>
targetAddr match {
case Some(addr) =>
result ++= ldb
result += MLine.pp(PSHS, M6809Register.B)
result += MLine.absolute(LDB, addr + (sizeInBytes - 1 - i))
result += MLine.accessAndPullS(SUBB)
result += MLine.absolute(STB, addr + (sizeInBytes - 1 - i))
case None =>
result ++= M6809ExpressionCompiler.stashXIfNeeded(ctx, ldb)
result += MLine.pp(PSHS, M6809Register.B)
result += MLine.indexedX(LDB, sizeInBytes - 1 - i)
result += MLine.accessAndPullS(SUBB)
result += MLine.indexedX(STB, sizeInBytes - 1 - i)
}
case (SUBB, _) if i != firstNonzeroByte =>
targetAddr match {
case Some(addr) =>
result ++= M6809ExpressionCompiler.stashCarryIfNeeded(ctx, ldb)
result += MLine.pp(PSHS, M6809Register.B)
result += MLine.absolute(LDB, addr + (sizeInBytes - 1 - i))
result += MLine.accessAndPullS(SBCB)
result += MLine.absolute(STB, addr + (sizeInBytes - 1 - i))
case None =>
result ++= M6809ExpressionCompiler.stashCarryIfNeeded(ctx, M6809ExpressionCompiler.stashXIfNeeded(ctx, ldb))
result += MLine.pp(PSHS, M6809Register.B)
result += MLine.indexedX(LDB, sizeInBytes - 1 - i)
result += MLine.accessAndPullS(SBCB)
result += MLine.indexedX(STB, sizeInBytes - 1 - i)
}
case (ADDB, _) if i != firstNonzeroByte =>
targetAddr match {
case Some(addr) =>
result ++= M6809ExpressionCompiler.stashCarryIfNeeded(ctx, ldb)
result += MLine.absolute(ADCB, addr + (sizeInBytes - 1 - i))
result += MLine.absolute(STB, addr + (sizeInBytes - 1 - i))
case None =>
result ++= M6809ExpressionCompiler.stashCarryIfNeeded(ctx, M6809ExpressionCompiler.stashXIfNeeded(ctx, ldb))
result += MLine.indexedX(ADCB, sizeInBytes - 1 - i)
result += MLine.indexedX(STB, sizeInBytes - 1 - i)
}
case _ =>
targetAddr match {
case Some(addr) =>
result ++= ldb
result += MLine.absolute(opcode, addr + (sizeInBytes - 1 - i))
result += MLine.absolute(STB, addr + (sizeInBytes - 1 - i))
case None =>
result ++= M6809ExpressionCompiler.stashXIfNeeded(ctx, ldb)
result += MLine.indexedX(opcode, sizeInBytes - 1 - i)
result += MLine.indexedX(STB, sizeInBytes - 1 - i)
}
}
}
result.toList
}
}

View File

@ -33,6 +33,12 @@ object M6809StatementCompiler extends AbstractStatementCompiler[MLine] {
M6809ExpressionCompiler.compile(ctx, e, MExpressionTarget.NOTHING)
case 1 => M6809ExpressionCompiler.compileToB(ctx, e)
case 2 => M6809ExpressionCompiler.compileToD(ctx, e)
case _ =>
if (ctx.function.hasElidedReturnVariable) {
Nil
} else {
M6809LargeBuiltins.storeLarge(ctx, VariableExpression(ctx.function.name + ".return"), e)
}
}
}
(eval ++ rts) -> Nil
@ -65,6 +71,7 @@ object M6809StatementCompiler extends AbstractStatementCompiler[MLine] {
case _ => M6809ExpressionCompiler.compileToB(ctx, source) ++ M6809ExpressionCompiler.storeB(ctx, destination)
}
case 2 => M6809ExpressionCompiler.compileToD(ctx, source) ++ M6809ExpressionCompiler.storeD(ctx, destination)
case _ => M6809LargeBuiltins.storeLarge(ctx, destination, source)
}) -> Nil
case ExpressionStatement(expression) =>
M6809ExpressionCompiler.compile(ctx, expression, MExpressionTarget.NOTHING) -> Nil

View File

@ -34,6 +34,10 @@ class MemoryBank(val index: Int, val isBigEndian: Boolean) {
if (isBigEndian) readByte(addr + 3) + (readByte(addr + 2) << 8) + (readByte(addr + 1) << 16) + (readByte(addr) << 24)
else readByte(addr) + (readByte(addr + 1) << 8) + (readByte(addr + 2) << 16) + (readByte(addr + 3) << 24)
def readLongLong(addr: Int): Long =
if (isBigEndian) readLong(addr).toLong.<<(32) + readLong(addr + 4).&(1L.<<(32).-(1))
else readLong(addr + 4).toLong.<<(32) + readLong(addr).&(1L.<<(32).-(1))
def readWord(addrHi: Int, addrLo: Int): Int = readByte(addrLo) + (readByte(addrHi) << 8)
val output: Array[Byte] = Array.fill[Byte](1 << 16)(0)

View File

@ -10,7 +10,7 @@ import org.scalatest.{FunSuite, Matchers}
class FarwordTest extends FunSuite with Matchers {
test("Int24 assignment") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
"""
| int24 output3 @$c000
| int24 output2 @$c004
@ -29,7 +29,7 @@ class FarwordTest extends FunSuite with Matchers {
}
}
test("Int24 assignment 2") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
"""
| int24 output3 @$c000
| int24 output2 @$c004
@ -48,12 +48,12 @@ class FarwordTest extends FunSuite with Matchers {
""".stripMargin) { m =>
m.readMedium(0xc000) should equal(0x23344)
m.readMedium(0xc004) should equal(0x7788)
m.readMedium(0xc008) should equal(0x55)
m.readWord(0xc008) should equal(0x55)
}
}
test("Int24 assignment 3") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
"""
| int24 output0 @$c000
| int24 output1 @$c003
@ -70,7 +70,7 @@ class FarwordTest extends FunSuite with Matchers {
}
}
test("Int24 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)(
"""
| int24 output @$c000
| void main () {
@ -90,7 +90,7 @@ class FarwordTest extends FunSuite with Matchers {
}
}
test("Int24 addition 2") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
"""
| int24 output @$c000
| void main () {
@ -104,7 +104,7 @@ class FarwordTest extends FunSuite with Matchers {
}
}
test("Int24 subtraction") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
"""
| int24 output @$c000
| void main () {
@ -124,7 +124,7 @@ class FarwordTest extends FunSuite with Matchers {
}
}
test("Int24 subtraction 2") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
"""
| int24 output @$c000
| void main () {
@ -138,7 +138,7 @@ class FarwordTest extends FunSuite with Matchers {
}
}
test("Int24 subtraction 3") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
"""
| int24 output @$c000
| void main () {
@ -158,7 +158,7 @@ class FarwordTest extends FunSuite with Matchers {
}
test("Int24 AND") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
"""
| int24 output @$c000
| void main () {
@ -178,7 +178,7 @@ class FarwordTest extends FunSuite with Matchers {
}
test("Int24 INC/DEC") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
"""
| int24 output0 @$c000
| int24 output1 @$c004

View File

@ -28,7 +28,7 @@ class LongTest extends FunSuite with Matchers {
}
test("Long assignment") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
"""
| long output4 @$c000
| long output2 @$c004
@ -47,7 +47,7 @@ class LongTest extends FunSuite with Matchers {
}
}
test("Long assignment 2") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
"""
| long output4 @$c000
| long output2 @$c004
@ -66,11 +66,11 @@ class LongTest extends FunSuite with Matchers {
""".stripMargin) { m =>
m.readLong(0xc000) should equal(0x11223344)
m.readLong(0xc004) should equal(0x7788)
m.readLong(0xc008) should equal(0x55)
m.readWord(0xc008) should equal(0x55)
}
}
test("Long 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)(
"""
| long output @$c000
| void main () {
@ -90,7 +90,7 @@ class LongTest extends FunSuite with Matchers {
}
}
test("Long addition 2") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
"""
| long output @$c000
| void main () {
@ -104,7 +104,7 @@ class LongTest extends FunSuite with Matchers {
}
}
test("Long addition 3") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
"""
| long output @$c000
| void main () {
@ -138,7 +138,7 @@ class LongTest extends FunSuite with Matchers {
}
}
test("Long subtraction") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
"""
| long output @$c000
| void main () {
@ -158,7 +158,7 @@ class LongTest extends FunSuite with Matchers {
}
}
test("Long subtraction 2") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
"""
| long output @$c000
| void main () {
@ -172,7 +172,7 @@ class LongTest extends FunSuite with Matchers {
}
}
test("Long subtraction 3") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
"""
| long output @$c000
| void main () {
@ -192,7 +192,7 @@ class LongTest extends FunSuite with Matchers {
}
test("Long AND") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
"""
| long output @$c000
| void main () {
@ -212,7 +212,7 @@ class LongTest extends FunSuite with Matchers {
}
test("Long INC/DEC") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
"""
| long output0 @$c000
| long output1 @$c004
@ -252,7 +252,7 @@ class LongTest extends FunSuite with Matchers {
}
test("Returning long") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
"""
| long output @$c000
| void main () {
@ -267,7 +267,7 @@ class LongTest extends FunSuite with Matchers {
}
test("Various combinations involving promotions") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
"""
| long output0 @$c000
| long output1 @$c004
@ -329,7 +329,7 @@ class LongTest extends FunSuite with Matchers {
}
test("Larger than long") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
"""
| int64 output0 @$c000
| int64 output1 @$c008
@ -364,18 +364,11 @@ class LongTest extends FunSuite with Matchers {
| return param
| }
""".stripMargin) { m =>
m.readLong(0xc000) should equal(0x91929394)
m.readLong(0xc008) should equal(0x929394)
m.readLong(0xc010) should equal(0x9394)
m.readLong(0xc018) should equal(0x94)
m.readLong(0xc004) should equal(0)
m.readLong(0xc00c) should equal(0)
m.readLong(0xc014) should equal(0)
m.readLong(0xc01c) should equal(0)
m.readLong(0xc020) should equal(0x91929394)
m.readLong(0xc024) should equal(0x01010101)
m.readLongLong(0xc000) should equal(0x91929394L)
m.readLongLong(0xc008) should equal(0x929394L)
m.readLongLong(0xc010) should equal(0x9394L)
m.readLongLong(0xc018) should equal(0x94L)
m.readLongLong(0xc020) should equal(0x0101010191929394L)
}
}
}

View File

@ -33,7 +33,7 @@ class SignExtensionSuite extends FunSuite with Matchers {
""".stripMargin){m => m.readWord(0xc000) should equal(0xfffe)}
}
test("Sbyte to Long") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)("""
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)("""
| long output @$c000
| void main () {
| output = 421
@ -46,7 +46,7 @@ class SignExtensionSuite extends FunSuite with Matchers {
}
test("Optimize pointless sign extension") {
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 [10] @$c000
| word w
| void main () {
@ -66,7 +66,7 @@ class SignExtensionSuite extends FunSuite with Matchers {
| return 5
| }
""".stripMargin){m =>
m.readWord(0xc000) should equal(440)
m.readWord(0xc001, 0xc000) should equal(440)
}
}
@ -111,7 +111,7 @@ class SignExtensionSuite extends FunSuite with Matchers {
}
test("Check multilayered conversions of signed and unsigned types") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80)(
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(
"""
|long output @$c000
|noinline sbyte f() = $FE
@ -140,7 +140,7 @@ class SignExtensionSuite extends FunSuite with Matchers {
}
test("Signed16 to int32 extension") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80)(
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(
"""
|int32 output @$c000
|
@ -156,7 +156,7 @@ class SignExtensionSuite extends FunSuite with Matchers {
}
test("Signed16 to int32 extension 2") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80)(
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(
"""
|int32 output @$c000
|

View File

@ -50,7 +50,7 @@ object Settings {
/**
* Should the Motorola 6809 tests be enabled?
* Motorola 6809 emulation is not yet implemented, so keep this false for the time being.
* Motorola 6809 emulation is currently under development and more and more tests are ran against it.
*/
val enableMotorola6809Tests: Boolean = true