1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-06-25 19:29:49 +00:00

Better support for big-endian systems

This commit is contained in:
Karol Stasiak 2019-07-29 22:51:08 +02:00
parent dd4cb17a80
commit b68e4b67c8
20 changed files with 196 additions and 76 deletions

View File

@ -109,14 +109,16 @@ An array is initialized with either:
* (only byte arrays) a format, followed by an array initializer:
* `@word` (=`@word_le`): for every term of the array initializer, emit two bytes, first being the low byte of the value, second being the high byte:
`@word [$1122]` is equivalent to `[$22, $11]`
* `@word_le`: for every term of the array initializer, emit two bytes, first being the low byte of the value, second being the high byte:
`@word_le [$1122]` is equivalent to `[$22, $11]`
* `@word_be` like the above, but opposite:
`@word_be [$1122]` is equivalent to `[$11, $22]`
* `@long` (=`@long_le`), `@long_be`: similar, but with four bytes
`@long [$11223344]` is equivalent to `[$44, $33, $22, $11]`
* `@word`: equivalent to `@word_le` on little-endian architectures and `@word_be` on big-endian architectures
* `@long`, `@long_le`, `@long_be`: similar, but with four bytes
`@long_le [$11223344]` is equivalent to `[$44, $33, $22, $11]`
`@long_be [$11223344]` is equivalent to `[$11, $22, $33, $44]`
* `@struct`: every term of the initializer is interpreted as a struct constructor (see below)

View File

@ -21,6 +21,8 @@ case class CompilationOptions(platform: Platform,
def log: Logger = jobContext.log
@inline
def nextLabel: LabelGenerator = jobContext.nextLabel
@inline
def isBigEndian: Boolean = platform.isBigEndian
val flags: Map[CompilationFlag.Value, Boolean] = CompilationFlag.values.map { f =>
f -> commandLineFlags.getOrElse(f, platform.flagOverrides.getOrElse(f, Cpu.defaultFlags(platform.cpu)(f)))

View File

@ -47,10 +47,12 @@ object MLine {
def immediate(opcode: MOpcode.Value, param: Constant): MLine = MLine(opcode, Immediate, param)
def immediate(opcode: MOpcode.Value, param: Int): MLine = MLine(opcode, Immediate, NumericConstant(param, Constant.minimumSize(param)))
def immediate(opcode: MOpcode.Value, param: Int): MLine = MLine(opcode, Immediate, Constant(param))
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 variable(opcode: MOpcode.Value, variable: Variable, offset: Int = 0): MLine = {
variable match {
case v: VariableInMemory => MLine.absolute(opcode, v.toAddress)

View File

@ -25,7 +25,7 @@ abstract class MacroExpander[T <: AbstractCode] {
def h(s: String) = if (s == paramName) target.asInstanceOf[VariableExpression].name else s
(stmt match {
case RawBytesStatement(contents) => RawBytesStatement(contents.replaceVariable(paramName, target))
case RawBytesStatement(contents, be) => RawBytesStatement(contents.replaceVariable(paramName, target), be)
case ExpressionStatement(e) => ExpressionStatement(e.replaceVariable(paramName, target))
case ReturnStatement(e) => ReturnStatement(e.map(f))
case ReturnDispatchStatement(i, ps, bs) => ReturnDispatchStatement(i.replaceVariable(paramName, target), ps.map(fx), bs.map {

View File

@ -1,10 +1,10 @@
package millfork.compiler.m6809
import millfork.assembly.m6809.{Indexed, MLine, MOpcode, TwoRegisters}
import millfork.assembly.m6809.{DAccumulatorIndexed, Indexed, MLine, MOpcode, TwoRegisters}
import millfork.compiler.{AbstractExpressionCompiler, BranchIfFalse, BranchIfTrue, BranchSpec, ComparisonType, CompilationContext, NoBranching}
import millfork.node.{DerefExpression, Expression, FunctionCallExpression, GeneratedConstantExpression, IndexedExpression, LhsExpression, LiteralExpression, M6809Register, SumExpression, VariableExpression}
import millfork.assembly.m6809.MOpcode._
import millfork.env.{ConstantBooleanType, ConstantPointy, FatBooleanType, MathOperator, MemoryVariable, NormalFunction, NormalParamSignature, NumericConstant, Variable}
import millfork.env.{Constant, ConstantBooleanType, ConstantPointy, FatBooleanType, MathOperator, MemoryVariable, NormalFunction, NormalParamSignature, NumericConstant, StackVariablePointy, Variable, VariablePointy}
import scala.collection.GenTraversableOnce
@ -272,6 +272,11 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
}
}
def stashBIfNeeded(ctx: CompilationContext, lines: List[MLine]): List[MLine] = {
// TODO: only push if needed
MLine.pp(PSHS, M6809Register.B) :: (lines :+ MLine.pp(PULS, M6809Register.B))
}
def storeB(ctx: CompilationContext, target: LhsExpression): List[MLine] = {
target match {
case VariableExpression(name) =>
@ -283,6 +288,21 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
ctx.env.getPointy(name) match {
case p: ConstantPointy =>
compileToX(ctx, index) :+ MLine(STB, Indexed(M6809Register.X, indirect = false), p.value)
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 _ =>
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)
}
}
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))
}
}
}
}

View File

@ -17,6 +17,18 @@ object M6809StatementCompiler extends AbstractStatementCompiler[MLine] {
// TODO: clean stack
// TODO: RTI
List(MLine.inherent(RTS)) -> Nil
case ReturnStatement(Some(e)) =>
// TODO: clean stack
// TODO: RTI
val rts = List(MLine.inherent(RTS))
val eval = ctx.function.returnType.size match {
case 0 =>
ctx.log.error("Cannot return anything from a void function", statement.position)
M6809ExpressionCompiler.compile(ctx, e, MExpressionTarget.NOTHING)
case 1 => M6809ExpressionCompiler.compileToB(ctx, e)
case 2 => M6809ExpressionCompiler.compileToD(ctx, e)
}
(eval ++ rts) -> Nil
case M6809AssemblyStatement(opcode, addrMode, expression, elidability) =>
ctx.env.evalForAsm(expression) match {
case Some(e) => List(MLine(opcode, addrMode, e, elidability)) -> Nil
@ -62,7 +74,8 @@ object M6809StatementCompiler extends AbstractStatementCompiler[MLine] {
override def branchChunk(opcode: BranchingOpcodeMapping, labelName: String): List[MLine] = ???
override def compileExpressionForBranching(ctx: CompilationContext, expr: Expression, branching: BranchSpec): List[MLine] = ???
override def compileExpressionForBranching(ctx: CompilationContext, expr: Expression, branching: BranchSpec): List[MLine] =
M6809ExpressionCompiler.compile(ctx, expr, MExpressionTarget.NOTHING, branching)
override def replaceLabel(ctx: CompilationContext, line: MLine, from: String, to: String): MLine = ???

View File

@ -179,7 +179,7 @@ object MosStatementCompiler extends AbstractStatementCompiler[AssemblyLine] {
case _ => a
}
List(AssemblyLine(o, actualAddrMode, c, e)) -> Nil
case RawBytesStatement(contents) =>
case RawBytesStatement(contents, _) =>
env.extractArrayContents(contents).map { expr =>
env.eval(expr) match {
case Some(c) => AssemblyLine(BYTE, RawByte, c, elidability = Elidability.Fixed)

View File

@ -206,7 +206,7 @@ object Z80StatementCompiler extends AbstractStatementCompiler[ZLine] {
}
case ExpressionStatement(e) =>
Z80ExpressionCompiler.compile(ctx, e, ZExpressionTarget.NOTHING) -> Nil
case RawBytesStatement(contents) =>
case RawBytesStatement(contents, _) =>
env.extractArrayContents(contents).map { expr =>
env.eval(expr) match {
case Some(c) => ZLine(BYTE, NoRegisters, c, elidability = Elidability.Fixed)

View File

@ -69,6 +69,8 @@ sealed trait Constant {
}
}
def subbyteBe(index: Int, totalSize: Int): Constant = subbyte(totalSize - 1 - index)
def subword(index: Int): Constant = {
if (requiredSize <= index) Constant.Zero
else {
@ -146,7 +148,20 @@ case class StructureConstant(typ: StructType, fields: List[Constant]) extends Co
for ((fv, (ft, _)) <- fields.zip(typ.mutableFieldsWithTypes)) {
val fs = ft.size
if (index < offset + fs) {
return fv.subbyte(index - offset)
val indexInField = index - offset
return fv.subbyte(indexInField)
}
offset += fs
}
Constant.Zero
}
override def subbyteBe(index: Int, totalSize: Int): Constant = {
var offset = 0
for ((fv, (ft, _)) <- fields.zip(typ.mutableFieldsWithTypes)) {
val fs = ft.size
if (index < offset + fs) {
val indexInField = index - offset
return fv.subbyteBe(indexInField, fs)
}
offset += fs
}

View File

@ -1169,7 +1169,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
}
if (maybeGet[Thing](name).isEmpty) {
println("registering text literal")
root.registerArray(ArrayDeclarationStatement(name, None, None, "byte", None, const = true, Some(LiteralContents(literal.characters)), None).pos(literal.position), options)
root.registerArray(ArrayDeclarationStatement(name, None, None, "byte", None, const = true, Some(LiteralContents(literal.characters)), None, options.isBigEndian).pos(literal.position), options)
}
name
}
@ -1341,11 +1341,11 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
case CombinedContents(xs) => xs.flatMap(extractArrayContents)
case pc@ProcessedContents("struct", xs: CombinedContents) =>
checkIfArrayContentsAreSimple(xs)
xs.getAllExpressions.flatMap(x => extractStructArrayContents(x, None))
xs.getAllExpressions(options.isBigEndian).flatMap(x => extractStructArrayContents(x, None))
case pc@ProcessedContents("struct", _) =>
log.error(s"Invalid struct array contents", pc.position)
Nil
case pc@ProcessedContents(f, xs) => pc.getAllExpressions
case pc@ProcessedContents(f, xs) => pc.getAllExpressions(options.isBigEndian)
case ForLoopContents(v, start, end, direction, body) =>
(eval(start), eval(end)) match {
case (Some(NumericConstant(s, sz1)), Some(NumericConstant(e, sz2))) =>
@ -1412,7 +1412,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
case VariableExpression(name) =>
maybeGet[Type](name) match {
case Some(typ@EnumType(_, Some(count))) =>
typ -> NumericConstant(count, 1)
typ -> NumericConstant(count, Constant.minimumSize(count))
case Some(typ) =>
log.error(s"Type $name cannot be used as an array index", l.position)
w -> Constant.Zero
@ -1666,6 +1666,9 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
val b = get[VariableType]("byte")
val w = get[VariableType]("word")
if (typ.name == "__reg$type") {
if (options.isBigEndian) {
throw new IllegalArgumentException("__reg$type on 6809???")
}
return (".lo", 0, b) ::
(".hi", 1, b) ::
(".loword", 0, w) ::
@ -1678,10 +1681,23 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
}
typ match {
case _: PlainType => typ.size match {
case 2 => List(
case 2 => if (options.isBigEndian) List(
(".lo", 1, b),
(".hi", 0, b)
) else List(
(".lo", 0, b),
(".hi", 1, b))
case 3 => List(
case 3 => if (options.isBigEndian) List(
(".loword", 1, w),
(".loword.lo", 2, b),
(".loword.hi", 1, b),
(".hiword", 0, w),
(".hiword.lo", 1, b),
(".hiword.hi", 0, b),
(".b0", 2, b),
(".b1", 1, b),
(".b2", 0, b)
) else List(
(".loword", 0, w),
(".loword.lo", 0, b),
(".loword.hi", 1, b),
@ -1691,7 +1707,18 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
(".b0", 0, b),
(".b1", 1, b),
(".b2", 2, b))
case 4 => List(
case 4 => if (options.isBigEndian) List(
(".loword", 2, w),
(".hiword", 0, w),
(".loword.lo", 3, b),
(".loword.hi", 2, b),
(".hiword.lo", 1, b),
(".hiword.hi", 0, b),
(".b0", 3, b),
(".b1", 2, b),
(".b2", 1, b),
(".b3", 0, b)
) else List(
(".loword", 0, w),
(".hiword", 2, w),
(".loword.lo", 0, b),
@ -1701,22 +1728,36 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
(".b0", 0, b),
(".b1", 1, b),
(".b2", 2, b),
(".b3", 3, b))
(".b3", 3, b)
)
case sz if sz > 4 =>
(".lo", 0, b) ::
(".loword", 0, w) ::
(".loword.lo", 0, b) ::
(".loword.hi", 1, b) ::
List.tabulate(sz){ i => (".b" + i, i, b) }
if (options.isBigEndian) {
(".lo", sz - 1, b) ::
(".loword", sz - 2, w) ::
(".loword.lo", sz - 1, b) ::
(".loword.hi", sz - 2, b) ::
List.tabulate(sz){ i => (".b" + i, sz - 1 - i, b) }
} else {
(".lo", 0, b) ::
(".loword", 0, w) ::
(".loword.lo", 0, b) ::
(".loword.hi", 1, b) ::
List.tabulate(sz){ i => (".b" + i, i, b) }
}
case _ => Nil
}
case p: PointerType =>
List(
(".raw", 0, p),
(".raw.lo", 0, b),
(".raw.hi", 1, b),
(".lo", 0, b),
(".hi", 1, b))
case p: PointerType => if (options.isBigEndian) List(
(".raw", 0, p),
(".raw.lo", 1, b),
(".raw.hi", 0, b),
(".lo", 1, b),
(".hi", 0, b)
) else List(
(".raw", 0, p),
(".raw.lo", 0, b),
(".raw.hi", 1, b),
(".lo", 0, b),
(".hi", 1, b))
case s: StructType =>
val builder = new ListBuffer[(String, Int, VariableType)]
var offset = 0

View File

@ -352,19 +352,19 @@ case class VariableDeclarationStatement(name: String,
}
trait ArrayContents extends Node {
def getAllExpressions: List[Expression]
def getAllExpressions(bigEndian: Boolean): List[Expression]
def replaceVariable(variableToReplace: String, expression: Expression): ArrayContents
}
case class LiteralContents(contents: List[Expression]) extends ArrayContents {
override def getAllExpressions: List[Expression] = contents
override def getAllExpressions(bigEndian: Boolean): List[Expression] = contents
override def replaceVariable(variable: String, expression: Expression): ArrayContents =
LiteralContents(contents.map(_.replaceVariable(variable, expression)))
}
case class ForLoopContents(variable: String, start: Expression, end: Expression, direction: ForDirection.Value, body: ArrayContents) extends ArrayContents {
override def getAllExpressions: List[Expression] = start :: end :: body.getAllExpressions.map(_.replaceVariable(variable, LiteralExpression(0, 1)))
override def getAllExpressions(bigEndian: Boolean): List[Expression] = start :: end :: body.getAllExpressions(bigEndian).map(_.replaceVariable(variable, LiteralExpression(0, 1)))
override def replaceVariable(variableToReplace: String, expression: Expression): ArrayContents =
if (variableToReplace == variable) this else ForLoopContents(
@ -376,39 +376,44 @@ case class ForLoopContents(variable: String, start: Expression, end: Expression,
}
case class CombinedContents(contents: List[ArrayContents]) extends ArrayContents {
override def getAllExpressions: List[Expression] = contents.flatMap(_.getAllExpressions)
override def getAllExpressions(bigEndian: Boolean): List[Expression] = contents.flatMap(_.getAllExpressions(bigEndian))
override def replaceVariable(variableToReplace: String, expression: Expression): ArrayContents =
CombinedContents(contents.map(_.replaceVariable(variableToReplace, expression)))
}
case class ProcessedContents(processor: String, values: ArrayContents) extends ArrayContents {
override def getAllExpressions: List[Expression] = processor match {
case "word" | "word_le" =>
values.getAllExpressions.flatMap(expr => List(
private def normalizeProcessor(bigEndian: Boolean): String = processor match {
case "word" => if (bigEndian) "word_be" else "word_le"
case "long" => if (bigEndian) "long_be" else "long_le"
case x => x
}
override def getAllExpressions(bigEndian: Boolean): List[Expression] = normalizeProcessor(bigEndian) match {
case "word_le" =>
values.getAllExpressions(bigEndian).flatMap(expr => List(
FunctionCallExpression("lo", List(expr)).pos(expr.position),
FunctionCallExpression("hi", List(expr)).pos(expr.position)
))
case "word_be" =>
values.getAllExpressions.flatMap(expr => List(
values.getAllExpressions(bigEndian).flatMap(expr => List(
FunctionCallExpression("hi", List(expr)).pos(expr.position),
FunctionCallExpression("lo", List(expr)).pos(expr.position)
))
case "long" | "long_le" =>
values.getAllExpressions.flatMap(expr => List(
case "long_le" =>
values.getAllExpressions(bigEndian).flatMap(expr => List(
FunctionCallExpression("lo", List(expr)).pos(expr.position),
FunctionCallExpression("lo", List(FunctionCallExpression(">>", List(expr, LiteralExpression(8, 1))).pos(expr.position))).pos(expr.position),
FunctionCallExpression("lo", List(FunctionCallExpression(">>", List(expr, LiteralExpression(16, 1))).pos(expr.position))).pos(expr.position),
FunctionCallExpression("lo", List(FunctionCallExpression(">>", List(expr, LiteralExpression(24, 1))).pos(expr.position))).pos(expr.position)
))
case "long_be" =>
values.getAllExpressions.flatMap(expr => List(
values.getAllExpressions(bigEndian).flatMap(expr => List(
FunctionCallExpression("lo", List(FunctionCallExpression(">>", List(expr, LiteralExpression(24, 1))).pos(expr.position))).pos(expr.position),
FunctionCallExpression("lo", List(FunctionCallExpression(">>", List(expr, LiteralExpression(16, 1))).pos(expr.position))).pos(expr.position),
FunctionCallExpression("lo", List(FunctionCallExpression(">>", List(expr, LiteralExpression(8, 1))).pos(expr.position))).pos(expr.position),
FunctionCallExpression("lo", List(expr)).pos(expr.position)
))
case "struct" => values.getAllExpressions // not used for emitting actual arrays
case "struct" => values.getAllExpressions(bigEndian) // not used for emitting actual arrays
}
override def replaceVariable(variableToReplace: String, expression: Expression): ArrayContents =
@ -438,8 +443,9 @@ case class ArrayDeclarationStatement(name: String,
address: Option[Expression],
const: Boolean,
elements: Option[ArrayContents],
alignment: Option[MemoryAlignment]) extends BankedDeclarationStatement {
override def getAllExpressions: List[Expression] = List(length, address).flatten ++ elements.fold(List[Expression]())(_.getAllExpressions)
alignment: Option[MemoryAlignment],
bigEndian: Boolean) extends BankedDeclarationStatement {
override def getAllExpressions: List[Expression] = List(length, address).flatten ++ elements.fold(List[Expression]())(_.getAllExpressions(bigEndian))
override def withChangedBank(bank: String): BankedDeclarationStatement = copy(bank = Some(bank))
}
@ -473,8 +479,8 @@ case class FunctionDeclarationStatement(name: String,
sealed trait ExecutableStatement extends Statement
case class RawBytesStatement(contents: ArrayContents) extends ExecutableStatement {
override def getAllExpressions: List[Expression] = contents.getAllExpressions
case class RawBytesStatement(contents: ArrayContents, bigEndian: Boolean) extends ExecutableStatement {
override def getAllExpressions: List[Expression] = contents.getAllExpressions(bigEndian)
}
sealed trait CompoundStatement extends ExecutableStatement {

View File

@ -100,7 +100,7 @@ object UnusedFunctions extends NodeOptimization {
def getAllCalledFunctions(expressions: List[Node]): List[String] = expressions.flatMap {
case s: VariableDeclarationStatement => getAllCalledFunctions(s.address.toList) ++ getAllCalledFunctions(s.initialValue.toList)
case s: ArrayDeclarationStatement => getAllCalledFunctions(s.address.toList) ++ getAllCalledFunctions(s.elements.toList)
case s: ArrayContents => getAllCalledFunctions(s.getAllExpressions)
case s: ArrayContents => getAllCalledFunctions(s.getAllExpressions(false)) // endianness doesn't matter here at all
case s: FunctionDeclarationStatement => getAllCalledFunctions(s.address.toList) ++ getAllCalledFunctions(s.statements.getOrElse(Nil))
case Assignment(target, expr) => getAllCalledFunctions(target :: expr :: Nil)
case s: ReturnDispatchStatement =>

View File

@ -52,7 +52,7 @@ object UnusedGlobalVariables extends NodeOptimization {
def getAllReadVariables(expressions: List[Node]): List[String] = expressions.flatMap {
case s: VariableDeclarationStatement => getAllReadVariables(s.address.toList) ++ getAllReadVariables(s.initialValue.toList) ++ (if (s.stack) List("__sp", "__stack") else Nil)
case s: ArrayDeclarationStatement => getAllReadVariables(s.address.toList) ++ getAllReadVariables(s.elements.toList)
case s: ArrayContents => getAllReadVariables(s.getAllExpressions)
case s: ArrayContents => getAllReadVariables(s.getAllExpressions(false)) // endianness doesn't matter here at all
case s: FunctionDeclarationStatement => getAllReadVariables(s.address.toList) ++ getAllReadVariables(s.statements.getOrElse(Nil))
case Assignment(VariableExpression(_), expr) => getAllReadVariables(expr :: Nil)
case ExpressionStatement(FunctionCallExpression(op, VariableExpression(_) :: params)) if op.endsWith("=") => getAllReadVariables(params)

View File

@ -30,7 +30,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
var initializedVariablesSize: Int = 0
protected val log: Logger = rootEnv.log
val mem = new CompiledMemory(platform.bankNumbers.toList)
val mem = new CompiledMemory(platform.bankNumbers.toList, platform.isBigEndian)
val labelMap: mutable.Map[String, (Int, Int)] = mutable.Map()
private val bytesToWriteLater = mutable.ListBuffer[(String, Int, Constant)]()
private val wordsToWriteLater = mutable.ListBuffer[(String, Int, Constant)]()
@ -139,7 +139,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))
case 2 => deepConstResolve(s.subword(0)) // TODO: endianness?
case _ => ???
}
case CompoundConstant(operator, lc, rc) =>
@ -189,6 +189,8 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
def deduplicate(options: CompilationOptions, compiledFunctions: mutable.Map[String, CompiledFunction[T]]): Unit
protected def subbyte(c: Constant, index: Int, totalSize: Int): Constant = if (platform.isBigEndian) c.subbyteBe(index, totalSize) else c.subbyte(index)
def assemble(callGraph: CallGraph, unfilteredOptimizations: Seq[AssemblyOptimization[T]], options: CompilationOptions): AssemblerOutput = {
mem.programName = options.outputFileName.getOrElse("MILLFORK")
val platform = options.platform
@ -291,7 +293,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
env.eval(item) match {
case Some(c) =>
for(i <- 0 until elementType.size) {
writeByte(bank, index, c.subbyte(i))
writeByte(bank, index, subbyte(c, i, elementType.size))
bank0.occupied(index) = true
bank0.initialized(index) = true
bank0.writeable(index) = true
@ -302,7 +304,8 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
}
}
items.flatMap(expr => env.eval(expr) match {
case Some(c) => List.tabulate(elementType.size)(i => c.subbyte(i).quickSimplify.toString)
case Some(c) =>
List.tabulate(elementType.size)(i => subbyte(c, i, elementType.size).quickSimplify.toString)
case None => List.fill(elementType.size)("<? unknown constant ?>")
}).grouped(16).foreach { group =>
assembly.append(" " + bytePseudoopcode + " " + group.mkString(", "))
@ -382,9 +385,12 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
val c = thing.toAddress
writeByte(bank, index, 0x2c.toByte) // BIT abs
index += 1
if (platform.isBigEndian) {
throw new IllegalStateException("LUnix cannot run on big-endian architectures")
}
for (i <- 0 until typ.size) {
writeByte(bank, index, c.subbyte(i))
assembly.append(" " + bytePseudoopcode + " " + c.subbyte(i).quickSimplify)
writeByte(bank, index, subbyte(c, i, typ.size))
assembly.append(" " + bytePseudoopcode + " " + subbyte(c, i, typ.size).quickSimplify)
index += 1
}
initializedVariablesSize += typ.size
@ -431,14 +437,14 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
env.eval(item) match {
case Some(c) =>
for (i <- 0 until elementType.size) {
writeByte(bank, index, c.subbyte(i))
writeByte(bank, index, subbyte(c, i, elementType.size))
index += 1
}
case None => log.error(s"Non-constant contents of array `$name`", item.position)
}
}
items.flatMap(expr => env.eval(expr) match {
case Some(c) => List.tabulate(elementType.size)(i => c.subbyte(i).quickSimplify.toString)
case Some(c) => List.tabulate(elementType.size)(i => subbyte(c, i, elementType.size).quickSimplify.toString)
case None => List.fill(elementType.size)("<? unknown constant ?>")
}).grouped(16).foreach { group =>
assembly.append(" " + bytePseudoopcode + " " + group.mkString(", "))
@ -464,8 +470,8 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
env.eval(value) match {
case Some(c) =>
for (i <- 0 until typ.size) {
writeByte(bank, index, c.subbyte(i))
assembly.append(" " + bytePseudoopcode + " " + c.subbyte(i).quickSimplify)
writeByte(bank, index, subbyte(c, i, typ.size))
assembly.append(" " + bytePseudoopcode + " " + subbyte(c, i, typ.size).quickSimplify)
index += 1
}
case None =>

View File

@ -69,7 +69,7 @@ abstract class AbstractInliningCalculator[T <: AbstractCode] {
case ReturnDispatchStatement(index, params, branches) =>
getAllCalledFunctions(List(index)) ++ getAllCalledFunctions(params) ++ getAllCalledFunctions(branches.map(b => b.function))
case s: ArrayDeclarationStatement => getAllCalledFunctions(s.address.toList) ++ getAllCalledFunctions(s.elements.toList)
case s: ArrayContents => getAllCalledFunctions(s.getAllExpressions)
case s: ArrayContents => getAllCalledFunctions(s.getAllExpressions(false)) // endianness doesn't matter here at all
case s: FunctionDeclarationStatement => getAllCalledFunctions(s.address.toList) ++ getAllCalledFunctions(s.statements.getOrElse(Nil))
case Assignment(VariableExpression(_), expr) => getAllCalledFunctions(expr :: Nil)
case MosAssemblyStatement(Opcode.JSR, _, VariableExpression(name), Elidability.Elidable) => (name -> false) :: Nil

View File

@ -5,19 +5,25 @@ import scala.collection.mutable
/**
* @author Karol Stasiak
*/
class CompiledMemory(bankNames: List[(String, Int)]) {
class CompiledMemory(bankNames: List[(String, Int)], bigEndian: Boolean) {
var programName = "MILLFORK"
val banks: mutable.Map[String, MemoryBank] = mutable.Map(bankNames.map(p => p._1 -> new MemoryBank(p._2)): _*)
val banks: mutable.Map[String, MemoryBank] = mutable.Map(bankNames.map(p => p._1 -> new MemoryBank(p._2, bigEndian)): _*)
}
class MemoryBank(val index: Int) {
class MemoryBank(val index: Int, val isBigEndian: Boolean) {
def readByte(addr: Int): Int = output(addr) & 0xff
def readWord(addr: Int): Int = readByte(addr) + (readByte(addr + 1) << 8)
def readWord(addr: Int): Int =
if (isBigEndian) readByte(addr + 1) + (readByte(addr) << 8)
else readByte(addr) + (readByte(addr + 1) << 8)
def readMedium(addr: Int): Int = readByte(addr) + (readByte(addr + 1) << 8) + (readByte(addr + 2) << 16)
def readMedium(addr: Int): Int =
if (isBigEndian) readByte(addr + 2) + (readByte(addr + 1) << 8) + (readByte(addr) << 16)
else readByte(addr) + (readByte(addr + 1) << 8) + (readByte(addr + 2) << 16)
def readLong(addr: Int): Int = readByte(addr) + (readByte(addr + 1) << 8) + (readByte(addr + 2) << 16) + (readByte(addr + 3) << 24)
def readLong(addr: Int): Int =
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 readWord(addrHi: Int, addrLo: Int): Int = readByte(addrLo) + (readByte(addrHi) << 8)

View File

@ -215,7 +215,7 @@ abstract class MfParser[T](fileId: String, input: String, currentDirectory: Stri
def arrayContents: P[ArrayContents] = arrayProcessedContents | arrayListContents | arrayLoopContents | arrayFileContents | arrayStringContents
def arrayContentsForAsm: P[RawBytesStatement] = (arrayListContents | arrayStringContents).map(RawBytesStatement)
def arrayContentsForAsm: P[RawBytesStatement] = (arrayListContents | arrayStringContents).map(c => RawBytesStatement(c, options.isBigEndian))
val aliasDefinition: P[Seq[AliasDefinitionStatement]] = for {
p <- position()
@ -252,7 +252,7 @@ abstract class MfParser[T](fileId: String, input: String, currentDirectory: Stri
alignment <- alignmentDeclaration(fastAlignmentForFunctions).? ~/ HWS
addr <- ("@" ~/ HWS ~/ mfExpression(1, false)).? ~/ HWS
contents <- ("=" ~/ HWS ~/ arrayContents).? ~/ HWS
} yield Seq(ArrayDeclarationStatement(name, bank, length, elementType.getOrElse("byte"), addr, const.isDefined, contents, alignment).pos(p))
} yield Seq(ArrayDeclarationStatement(name, bank, length, elementType.getOrElse("byte"), addr, const.isDefined, contents, alignment, options.isBigEndian).pos(p))
def tightMfExpression(allowIntelHex: Boolean, allowTopLevelIndexing: Boolean): P[Expression] = {
val a = if (allowIntelHex) atomWithIntel else atom

View File

@ -140,7 +140,7 @@ class BasicSymonTest extends FunSuite with Matchers {
| }
| }
""".stripMargin) { m =>
m.readWord(0xc000) should equal(4)
m.readByte(0xc000) should equal(4)
}
}

View File

@ -40,7 +40,7 @@ class StructSuite extends FunSuite with Matchers {
}
test("Nested structs") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Intel8080, Cpu.Intel8086)("""
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Intel8080, Cpu.Intel8086, Cpu.Motorola6809)("""
| struct inner { word x, word y }
| struct s {
| word w
@ -53,7 +53,11 @@ class StructSuite extends FunSuite with Matchers {
| output.b = 5
| output.w.hi = output.b
| output.p = output.w.addr
| #if BIG_ENDIAN
| output.p[1] = 6
| #else
| output.p[0] = 6
| #endif
| output.i.x.lo = 55
| output.i.x.hi = s.p.offset
| output.i.y = 777
@ -62,14 +66,13 @@ class StructSuite extends FunSuite with Matchers {
m.readWord(0xc000) should equal(0x506)
m.readByte(0xc002) should equal(5)
m.readWord(0xc003) should equal(0xc000)
m.readByte(0xc005) should equal(55)
m.readByte(0xc006) should equal(3)
m.readWord(0xc005) should equal(3 * 256 + 55)
m.readWord(0xc007) should equal(777)
}
}
test("Basic union support") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Intel8080, Cpu.Intel8086)("""
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Intel8080, Cpu.Intel8086, Cpu.Motorola6809)("""
| struct point { byte x, byte y }
| union point_or_word { point p, word w }
| word output @$c000
@ -80,7 +83,11 @@ class StructSuite extends FunSuite with Matchers {
| output = u.w
| }
""".stripMargin) { m =>
m.readWord(0xc000) should equal(0x201)
if (m.isBigEndian) {
m.readWord(0xc000) should equal(0x102)
} else {
m.readWord(0xc000) should equal(0x201)
}
}
}

View File

@ -74,7 +74,7 @@ class EmuI86Run(nodeOptimizations: List[NodeOptimization], assemblyOptimizations
}
def apply2(source: String): (Timings, MemoryBank) = {
if (!Settings.enableIntel8086Tests) return Timings(-1, -1) -> new MemoryBank(0)
if (!Settings.enableIntel8086Tests) return Timings(-1, -1) -> new MemoryBank(0, false)
Console.out.flush()
Console.err.flush()
val log = TestErrorReporting.log