mirror of
https://github.com/KarolS/millfork.git
synced 2025-01-15 09:29:49 +00:00
Internal support for pointers to volatile objects; add volatile fields (closes #112)
This commit is contained in:
parent
73beafd65e
commit
431a25d325
@ -332,7 +332,7 @@ object AbstractExpressionCompiler {
|
||||
env.getPointy(name).elementType
|
||||
case DerefDebuggingExpression(_, 1) => b
|
||||
case DerefDebuggingExpression(_, 2) => w
|
||||
case DerefExpression(_, _, typ) => typ
|
||||
case DerefExpression(_, _, _, typ) => typ
|
||||
case IndirectFieldExpression(inner, firstIndices, fieldPath) =>
|
||||
var currentType = inner match {
|
||||
case VariableExpression(arrName) =>
|
||||
|
@ -175,7 +175,7 @@ abstract class AbstractStatementPreprocessor(protected val ctx: CompilationConte
|
||||
Assignment(DerefExpression(
|
||||
FunctionCallExpression("pointer", List(VariableExpression(target.name).pos(pos))).pos(pos) #+#
|
||||
FunctionCallExpression("<<", List(optimizeExpr(target.index, cv), LiteralExpression(1, 1))).pos(pos),
|
||||
0, env.getPointy(target.name).elementType).pos(pos), optimizeExpr(arg, cv)).pos(pos) -> cv
|
||||
0, false, env.getPointy(target.name).elementType).pos(pos), optimizeExpr(arg, cv)).pos(pos) -> cv
|
||||
case Assignment(target:IndexedExpression, arg) =>
|
||||
cv = search(arg, cv)
|
||||
cv = search(target, cv)
|
||||
@ -347,7 +347,7 @@ abstract class AbstractStatementPreprocessor(protected val ctx: CompilationConte
|
||||
case HalfWordExpression(arg, _) => search(arg, cv)
|
||||
case IndexedExpression(_, arg) => search(arg, cv)
|
||||
case DerefDebuggingExpression(arg, _) => search(arg, cv)
|
||||
case DerefExpression(arg, _, _) => search(arg, cv)
|
||||
case DerefExpression(arg, _, _, _) => search(arg, cv)
|
||||
case _ => cv // TODO
|
||||
}
|
||||
}
|
||||
@ -435,7 +435,7 @@ abstract class AbstractStatementPreprocessor(protected val ctx: CompilationConte
|
||||
false
|
||||
}
|
||||
if (zero) {
|
||||
DerefExpression(result, 0, targetType)
|
||||
DerefExpression(result, 0, false, targetType)
|
||||
} else {
|
||||
val indexType = AbstractExpressionCompiler.getExpressionType(env, env.log, index)
|
||||
val (newResult, constantOffset) = result match {
|
||||
@ -449,11 +449,11 @@ abstract class AbstractStatementPreprocessor(protected val ctx: CompilationConte
|
||||
if (constantOffset + (targetType.alignedSize * n) <= 127) {
|
||||
DerefExpression(
|
||||
("pointer." + targetType.name) <| newResult,
|
||||
constantOffset + targetType.alignedSize * n.toInt, targetType)
|
||||
constantOffset + targetType.alignedSize * n.toInt, false, targetType)
|
||||
} else {
|
||||
DerefExpression(
|
||||
("pointer." + targetType.name) <| result,
|
||||
targetType.alignedSize * n.toInt, targetType)
|
||||
targetType.alignedSize * n.toInt, false, targetType)
|
||||
}
|
||||
case _ =>
|
||||
val small = smallArraySizeInBytes.isDefined || (indexType.size == 1 && !indexType.isSigned)
|
||||
@ -468,12 +468,12 @@ abstract class AbstractStatementPreprocessor(protected val ctx: CompilationConte
|
||||
}
|
||||
DerefExpression(("pointer." + targetType.name) <| (
|
||||
("pointer" <| newResult) #+# scaledIndexWithOffset
|
||||
), 0, targetType)
|
||||
), 0, false, targetType)
|
||||
case _ =>
|
||||
val scaledIndex: Expression = scaleIndexForArrayAccess(index, targetType, smallArraySizeInBytes)
|
||||
DerefExpression(("pointer." + targetType.name) <| (
|
||||
("pointer" <| result) #+# optimizeExpr(scaledIndex, Map())
|
||||
), 0, targetType)
|
||||
), 0, false, targetType)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -492,18 +492,18 @@ abstract class AbstractStatementPreprocessor(protected val ctx: CompilationConte
|
||||
case Some(NumericConstant(n, _)) if n >= 0 && (targetType.alignedSize * n) <= 127 =>
|
||||
x match {
|
||||
case _: PointerType =>
|
||||
DerefExpression(result, targetType.alignedSize * n.toInt, targetType)
|
||||
DerefExpression(result, targetType.alignedSize * n.toInt, false, targetType)
|
||||
case _ =>
|
||||
DerefExpression(
|
||||
("pointer." + targetType.name) <| result,
|
||||
targetType.alignedSize * n.toInt, targetType)
|
||||
targetType.alignedSize * n.toInt, false, targetType)
|
||||
}
|
||||
case _ =>
|
||||
val scaledIndex: Expression = scaleIndexForArrayAccess(index, targetType, arraySizeInBytes)
|
||||
// TODO: re-cast pointer type
|
||||
DerefExpression(("pointer." + targetType.name) <| (
|
||||
result #+# optimizeExpr(scaledIndex, Map())
|
||||
), 0, targetType)
|
||||
), 0, false, targetType)
|
||||
}
|
||||
case _ =>
|
||||
ctx.log.error("Not a pointer type on the left-hand side of `[`", pos)
|
||||
@ -519,9 +519,9 @@ abstract class AbstractStatementPreprocessor(protected val ctx: CompilationConte
|
||||
for ((dot, fieldName, indices) <- fieldPath) {
|
||||
if (dot && ok) {
|
||||
val pointer = result match {
|
||||
case DerefExpression(inner, 0, _) =>
|
||||
case DerefExpression(inner, 0, _, _) =>
|
||||
optimizeExpr(inner, currentVarValues).pos(pos)
|
||||
case DerefExpression(inner, offset, targetType) =>
|
||||
case DerefExpression(inner, offset, _, targetType) =>
|
||||
if (offset == 0) {
|
||||
("pointer." + targetType.name) <| ("pointer" <| optimizeExpr(inner, currentVarValues).pos(pos))
|
||||
} else {
|
||||
@ -597,7 +597,7 @@ abstract class AbstractStatementPreprocessor(protected val ctx: CompilationConte
|
||||
currentArraySizeInBytes = None
|
||||
pointerWrap match {
|
||||
case 0 =>
|
||||
DerefExpression(inner, fieldOffset, fieldType)
|
||||
DerefExpression(inner, fieldOffset, subvariable.isVolatile, fieldType)
|
||||
case 1 =>
|
||||
if (fieldOffset == 0) {
|
||||
("pointer." + fieldType.name) <| ("pointer" <| inner)
|
||||
@ -648,9 +648,9 @@ abstract class AbstractStatementPreprocessor(protected val ctx: CompilationConte
|
||||
}
|
||||
result
|
||||
case DerefDebuggingExpression(inner, 1) =>
|
||||
DerefExpression(optimizeExpr(inner, currentVarValues, optimizeSum = true), 0, env.get[VariableType]("byte")).pos(pos)
|
||||
DerefExpression(optimizeExpr(inner, currentVarValues, optimizeSum = true), 0, false, env.get[VariableType]("byte")).pos(pos)
|
||||
case DerefDebuggingExpression(inner, 2) =>
|
||||
DerefExpression(optimizeExpr(inner, currentVarValues, optimizeSum = true), 0, env.get[VariableType]("word")).pos(pos)
|
||||
DerefExpression(optimizeExpr(inner, currentVarValues, optimizeSum = true), 0, false, env.get[VariableType]("word")).pos(pos)
|
||||
case e@TextLiteralExpression(characters) =>
|
||||
val name = ctx.env.getTextLiteralArrayName(e)
|
||||
VariableExpression(name).pos(pos)
|
||||
@ -731,11 +731,11 @@ abstract class AbstractStatementPreprocessor(protected val ctx: CompilationConte
|
||||
if (pointy.isArray) {
|
||||
DerefExpression(
|
||||
"pointer" <| VariableExpression(name).pos(pos),
|
||||
o.toInt, pointy.elementType).pos(pos)
|
||||
o.toInt, false, pointy.elementType).pos(pos)
|
||||
} else {
|
||||
DerefExpression(
|
||||
VariableExpression(name).pos(pos),
|
||||
o.toInt, pointy.elementType).pos(pos)
|
||||
o.toInt, false, pointy.elementType).pos(pos)
|
||||
}
|
||||
case _ =>
|
||||
val arraySizeInBytes = pointy match {
|
||||
@ -769,7 +769,7 @@ abstract class AbstractStatementPreprocessor(protected val ctx: CompilationConte
|
||||
}
|
||||
DerefExpression(
|
||||
("pointer" <| VariableExpression(name).pos(pos)) #+# optimizeExpr(scaledIndex, Map()),
|
||||
0, pointy.elementType).pos(pos)
|
||||
0, false, pointy.elementType).pos(pos)
|
||||
}
|
||||
}
|
||||
case _ => expr // TODO
|
||||
|
@ -2,6 +2,7 @@ package millfork.compiler.m6809
|
||||
|
||||
import java.util.concurrent.AbstractExecutorService
|
||||
import millfork.CompilationFlag
|
||||
import millfork.assembly.Elidability
|
||||
import millfork.assembly.m6809.{Absolute, 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}
|
||||
@ -117,17 +118,18 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
|
||||
case MExpressionTarget.NOTHING => Nil
|
||||
case _ => List(MLine.immediate(MExpressionTarget.toLd(target), NumericConstant(c, MExpressionTarget.size(target))))
|
||||
}
|
||||
case DerefExpression(inner, offset, _) =>
|
||||
case DerefExpression(inner, offset, vol, _) =>
|
||||
val (i, o) = if (offset == 0) {
|
||||
extractConstantOffset(ctx, inner)
|
||||
} else (inner, offset)
|
||||
val el = if (vol) Elidability.Volatile else Elidability.Elidable
|
||||
compileToX(ctx, i) match {
|
||||
case List(l@MLine0(LDX, Immediate, _)) =>
|
||||
List(l.copy(opcode = toLd(target), addrMode = Absolute(false), parameter = l.parameter + o))
|
||||
List(l.copy(opcode = toLd(target), addrMode = Absolute(false), parameter = l.parameter + o, elidability = el))
|
||||
case List(l@MLine0(LDX, addrMode, _)) if addrMode.isDeferenceable && o == 0 =>
|
||||
List(l.copy(opcode = toLd(target), addrMode = addrMode.dereference()))
|
||||
List(l.copy(opcode = toLd(target), addrMode = addrMode.dereference(), elidability = el))
|
||||
case other =>
|
||||
other :+ MLine(toLd(target), Indexed(M6809Register.X, indirect = false), NumericConstant(o, 2))
|
||||
other :+ MLine(toLd(target), Indexed(M6809Register.X, indirect = false), NumericConstant(o, 2), elidability = el)
|
||||
}
|
||||
case IndexedExpression(name, index) =>
|
||||
env.getPointy(name) match {
|
||||
@ -782,8 +784,8 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
|
||||
case VariableExpression(name) =>
|
||||
val variable = ctx.env.get[Variable](name)
|
||||
List(MLine.variable(ctx, store, variable))
|
||||
case DerefExpression(inner, offset, _) =>
|
||||
stashIfNeeded(ctx, compileToX(ctx, inner)) :+ MLine.indexedX(store, NumericConstant(offset, 2))
|
||||
case DerefExpression(inner, offset, vol, _) =>
|
||||
stashIfNeeded(ctx, compileToX(ctx, inner)) :+ MLine.indexedX(store, NumericConstant(offset, 2)).copy(elidability = if(vol) Elidability.Volatile else Elidability.Elidable)
|
||||
case IndexedExpression(name, index) =>
|
||||
ctx.env.getPointy(name) match {
|
||||
case p: ConstantPointy =>
|
||||
@ -837,14 +839,15 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
|
||||
val sh = storeA(ctx, hi)
|
||||
val sl = storeB(ctx, lo)
|
||||
stashBIfNeeded(ctx, sh) ++ sl // TODO: optimize
|
||||
case DerefExpression(inner, offset, _) =>
|
||||
case DerefExpression(inner, offset, vol, _) =>
|
||||
val el = if(vol) Elidability.Volatile else Elidability.Elidable
|
||||
compileToX(ctx, inner) match {
|
||||
case List(MLine0(LDX, Immediate, constAddr)) =>
|
||||
List(MLine(STD, Absolute(false), constAddr + offset))
|
||||
List(MLine(STD, Absolute(false), constAddr + offset, elidability = el))
|
||||
case List(MLine0(LDX, Absolute(false), constAddr)) if offset == 0 =>
|
||||
List(MLine(STD, Absolute(true), constAddr))
|
||||
List(MLine(STD, Absolute(true), constAddr, elidability = el))
|
||||
case xs =>
|
||||
stashDIfNeeded(ctx, xs) :+ MLine(STD, Indexed(M6809Register.X, indirect = false), NumericConstant(offset, 2))
|
||||
stashDIfNeeded(ctx, xs) :+ MLine(STD, Indexed(M6809Register.X, indirect = false), NumericConstant(offset, 2), elidability = el)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -893,8 +896,8 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
|
||||
List(MLine.variable(ctx, LEAX, variable))
|
||||
}
|
||||
|
||||
case DerefExpression(inner, offset, _) =>
|
||||
compileToX(ctx, inner) :+ MLine.indexedX(MOpcode.LEAX, Constant(offset))
|
||||
case DerefExpression(inner, offset, vol, _) =>
|
||||
compileToX(ctx, inner) :+ MLine.indexedX(MOpcode.LEAX, Constant(offset)).copy(elidability = if(vol) Elidability.Volatile else Elidability.Elidable)
|
||||
case IndexedExpression(aname, index) =>
|
||||
ctx.env.getPointy(aname) match {
|
||||
case p: VariablePointy => compileToD(ctx, index #*# p.elementType.alignedSize) ++ List(MLine.absolute(ADDD, p.addr), MLine.tfr(M6809Register.D, M6809Register.X))
|
||||
@ -1046,9 +1049,10 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
|
||||
List(calculateStackAddressToD(ctx, sot.offset), List(MLine.tfr(M6809Register.A, M6809Register.B)))
|
||||
}
|
||||
case e:DerefExpression =>
|
||||
val el = if(e.isVolatile) Elidability.Volatile else Elidability.Elidable
|
||||
List.tabulate(targetSize)(i =>
|
||||
if (i == 0) compileAddressToX(ctx, e) :+ MLine.indexedX(LDB, 0)
|
||||
else List(MLine.indexedX(LDB, i))
|
||||
if (i == 0) compileAddressToX(ctx, e) :+ MLine.indexedX(LDB, 0).copy(elidability = el)
|
||||
else List(MLine.indexedX(LDB, i).copy(elidability = el))
|
||||
)
|
||||
case e:FunctionCallExpression =>
|
||||
ctx.env.maybeGet[NormalFunction](e.functionName) match {
|
||||
|
@ -336,6 +336,7 @@ object BuiltIns {
|
||||
val reg = ctx.env.get[VariableInMemory]("__reg")
|
||||
lhs match {
|
||||
case dx: DerefExpression =>
|
||||
val el = if(dx.isVolatile) Elidability.Volatile else Elidability.Elidable
|
||||
if (ctx.options.zpRegisterSize < 4) {
|
||||
ctx.log.error("Unsupported shift operation. Consider increasing the size of the zeropage register or simplifying the left hand side expression.", lhs.position)
|
||||
return MosExpressionCompiler.compileToAX(ctx, lhs) ++ MosExpressionCompiler.compileToAX(ctx, rhs)
|
||||
@ -348,19 +349,19 @@ object BuiltIns {
|
||||
val loadToR2 =
|
||||
List(
|
||||
AssemblyLine.immediate(LDY, offset),
|
||||
AssemblyLine.indexedY(LDA, ptr),
|
||||
AssemblyLine.indexedY(LDA, ptr).copy(elidability = el),
|
||||
AssemblyLine.zeropage(STA, reg, 2),
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine.indexedY(LDA, ptr),
|
||||
AssemblyLine.indexedY(LDA, ptr).copy(elidability = el),
|
||||
AssemblyLine.zeropage(STA, reg, 3))
|
||||
val storeFromR2 =
|
||||
List(
|
||||
AssemblyLine.immediate(LDY, offset),
|
||||
AssemblyLine.zeropage(LDA, reg, 2),
|
||||
AssemblyLine.indexedY(STA, ptr),
|
||||
AssemblyLine.indexedY(STA, ptr).copy(elidability = el),
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine.zeropage(LDA, reg, 3),
|
||||
AssemblyLine.indexedY(STA, ptr))
|
||||
AssemblyLine.indexedY(STA, ptr).copy(elidability = el))
|
||||
val shiftR2 =
|
||||
if (aslRatherThanLsr) List(AssemblyLine.zeropage(ASL, reg, 2), AssemblyLine.zeropage(ROL, reg, 3))
|
||||
else List(AssemblyLine.zeropage(LSR, reg, 3), AssemblyLine.zeropage(ROR, reg, 2))
|
||||
@ -369,23 +370,23 @@ object BuiltIns {
|
||||
case Some(1) if aslRatherThanLsr =>
|
||||
List(
|
||||
AssemblyLine.immediate(LDY, offset),
|
||||
AssemblyLine.indexedY(LDA, ptr),
|
||||
AssemblyLine.indexedY(LDA, ptr).copy(elidability = el),
|
||||
AssemblyLine.implied(ASL),
|
||||
AssemblyLine.indexedY(STA, ptr),
|
||||
AssemblyLine.indexedY(STA, ptr).copy(elidability = el),
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine.indexedY(LDA, ptr),
|
||||
AssemblyLine.indexedY(LDA, ptr).copy(elidability = el),
|
||||
AssemblyLine.implied(ROL),
|
||||
AssemblyLine.indexedY(STA, ptr))
|
||||
AssemblyLine.indexedY(STA, ptr).copy(elidability = el))
|
||||
case Some(1) if !aslRatherThanLsr =>
|
||||
List(
|
||||
AssemblyLine.immediate(LDY, offset + 1),
|
||||
AssemblyLine.indexedY(LDA, ptr),
|
||||
AssemblyLine.indexedY(LDA, ptr).copy(elidability = el),
|
||||
AssemblyLine.implied(LSR),
|
||||
AssemblyLine.indexedY(STA, ptr),
|
||||
AssemblyLine.indexedY(STA, ptr).copy(elidability = el),
|
||||
AssemblyLine.implied(DEY),
|
||||
AssemblyLine.indexedY(LDA, ptr),
|
||||
AssemblyLine.indexedY(LDA, ptr).copy(elidability = el),
|
||||
AssemblyLine.implied(ROR),
|
||||
AssemblyLine.indexedY(STA, ptr))
|
||||
AssemblyLine.indexedY(STA, ptr).copy(elidability = el))
|
||||
case Some(n) if n >= 1 && n <= 7 => // TODO: pick optimal
|
||||
loadToR2 ++ List.fill(n)(shiftR2).flatten ++ storeFromR2
|
||||
case _ =>
|
||||
@ -412,9 +413,9 @@ object BuiltIns {
|
||||
AssemblyLine.implied(CLC),
|
||||
AssemblyLine.immediate(LDY, 0),
|
||||
AssemblyLine.label(innerLoopLabel),
|
||||
AssemblyLine.indexedY(LDA, reg),
|
||||
AssemblyLine.indexedY(LDA, reg).copy(elidability = el),
|
||||
AssemblyLine.implied(ROL),
|
||||
AssemblyLine.indexedY(STA, reg),
|
||||
AssemblyLine.indexedY(STA, reg).copy(elidability = el),
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine.immediate(CPY, size),
|
||||
AssemblyLine.relative(BNE, innerLoopLabel))
|
||||
@ -423,9 +424,9 @@ object BuiltIns {
|
||||
AssemblyLine.implied(CLC),
|
||||
AssemblyLine.immediate(LDY, size - 1),
|
||||
AssemblyLine.label(innerLoopLabel),
|
||||
AssemblyLine.indexedY(LDA, reg),
|
||||
AssemblyLine.indexedY(LDA, reg).copy(elidability = el),
|
||||
AssemblyLine.implied(ROR),
|
||||
AssemblyLine.indexedY(STA, reg),
|
||||
AssemblyLine.indexedY(STA, reg).copy(elidability = el),
|
||||
AssemblyLine.implied(DEY),
|
||||
AssemblyLine.relative(BPL, innerLoopLabel))
|
||||
}
|
||||
@ -436,7 +437,7 @@ object BuiltIns {
|
||||
AssemblyLine.immediate(LDY, size - 1),
|
||||
AssemblyLine.label(innerLoopLabel),
|
||||
AssemblyLine.immediate(LDA, 0),
|
||||
AssemblyLine.indexedY(STA, reg),
|
||||
AssemblyLine.indexedY(STA, reg).copy(elidability = el),
|
||||
AssemblyLine.implied(DEY),
|
||||
AssemblyLine.relative(BPL, innerLoopLabel))
|
||||
case Some(1) => singleShift
|
||||
@ -1195,6 +1196,7 @@ object BuiltIns {
|
||||
def compileInPlaceWordMultiplication(ctx: CompilationContext, v: LhsExpression, addend: Expression): List[AssemblyLine] = {
|
||||
v match {
|
||||
case dx: DerefExpression =>
|
||||
val el = if(dx.isVolatile) Elidability.Volatile else Elidability.Elidable
|
||||
// this is ugly, needs a rewrite
|
||||
return handleWordOrLongInPlaceModificationViaDeref(ctx, dx, addend, fromMsb = false){(ptr, reg, offset, r) =>
|
||||
val constR = r match {
|
||||
@ -1210,27 +1212,27 @@ object BuiltIns {
|
||||
case Some(0) => List(
|
||||
AssemblyLine.immediate(LDA, 0),
|
||||
AssemblyLine.immediate(LDY, offset),
|
||||
AssemblyLine.indexedY(STA, ptr),
|
||||
AssemblyLine.indexedY(STA, ptr).copy(elidability = el),
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine.indexedY(STA, ptr))
|
||||
AssemblyLine.indexedY(STA, ptr).copy(elidability = el))
|
||||
case Some(2) => List(
|
||||
AssemblyLine.immediate(LDA, 0),
|
||||
AssemblyLine.immediate(LDY, offset),
|
||||
AssemblyLine.indexedY(LDA, ptr),
|
||||
AssemblyLine.indexedY(LDA, ptr).copy(elidability = el),
|
||||
AssemblyLine.implied(ASL),
|
||||
AssemblyLine.indexedY(STA, ptr),
|
||||
AssemblyLine.indexedY(STA, ptr).copy(elidability = el),
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine.indexedY(LDA, ptr),
|
||||
AssemblyLine.indexedY(LDA, ptr).copy(elidability = el),
|
||||
AssemblyLine.implied(ROL),
|
||||
AssemblyLine.indexedY(STA, ptr))
|
||||
AssemblyLine.indexedY(STA, ptr).copy(elidability = el))
|
||||
// TODO: other powers of two
|
||||
case _ if reg.toAddress == ptr => List(
|
||||
AssemblyLine.implied(PHA),
|
||||
AssemblyLine.immediate(LDY, offset),
|
||||
AssemblyLine.indexedY(LDA, reg),
|
||||
AssemblyLine.indexedY(LDA, reg).copy(elidability = el),
|
||||
AssemblyLine.zeropage(STA, reg, 2),
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine.indexedY(LDA, reg),
|
||||
AssemblyLine.indexedY(LDA, reg).copy(elidability = el),
|
||||
AssemblyLine.zeropage(STA, reg, 3),
|
||||
AssemblyLine.implied(PLA),
|
||||
AssemblyLine.implied(TAY),
|
||||
@ -1248,26 +1250,26 @@ object BuiltIns {
|
||||
AssemblyLine.zeropage(STA, reg, 1),
|
||||
AssemblyLine.immediate(LDY, offset),
|
||||
AssemblyLine.zeropage(LDA, reg, 2),
|
||||
AssemblyLine.indexedY(STA, reg),
|
||||
AssemblyLine.indexedY(STA, reg).copy(elidability = el),
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine.implied(TXA),
|
||||
AssemblyLine.indexedY(STA, reg),
|
||||
AssemblyLine.indexedY(STA, reg).copy(elidability = el),
|
||||
)
|
||||
case _ => List(
|
||||
AssemblyLine.zeropage(STA, reg),
|
||||
AssemblyLine.zeropage(STX, reg, 1),
|
||||
AssemblyLine.immediate(LDY, offset),
|
||||
AssemblyLine.indexedY(LDA, ptr),
|
||||
AssemblyLine.indexedY(LDA, ptr).copy(elidability = el),
|
||||
AssemblyLine.zeropage(STA, reg, 2),
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine.indexedY(LDA, ptr),
|
||||
AssemblyLine.indexedY(LDA, ptr).copy(elidability = el),
|
||||
AssemblyLine.zeropage(STA, reg, 3),
|
||||
AssemblyLine.absolute(JSR, ctx.env.get[ThingInMemory]("__mul_u16u16u16")),
|
||||
AssemblyLine.immediate(LDY, offset),
|
||||
AssemblyLine.indexedY(STA, ptr),
|
||||
AssemblyLine.indexedY(STA, ptr).copy(elidability = el),
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine.implied(TXA),
|
||||
AssemblyLine.indexedY(STA, ptr),
|
||||
AssemblyLine.indexedY(STA, ptr).copy(elidability = el),
|
||||
)
|
||||
}
|
||||
}(Left({size => ???}))
|
||||
@ -1585,6 +1587,7 @@ object BuiltIns {
|
||||
}
|
||||
lhs match {
|
||||
case dx: DerefExpression =>
|
||||
val el = if(dx.isVolatile) Elidability.Volatile else Elidability.Elidable
|
||||
if (subtract && ctx.options.zpRegisterSize < 3) {
|
||||
ctx.log.error("Too complex left hand side. Consider increasing the size of the zeropage register.", lhs.position)
|
||||
return compileInPlaceWordOrLongAddition(ctx, lhs, addend, subtract = false, decimal = false)
|
||||
@ -1593,14 +1596,14 @@ object BuiltIns {
|
||||
AssemblyLine.immediate(LDY, offset),
|
||||
AssemblyLine.implied(SEC),
|
||||
AssemblyLine.zeropage(STA, reg, 2),
|
||||
AssemblyLine.indexedY(LDA, ptr),
|
||||
AssemblyLine.indexedY(LDA, ptr).copy(elidability = el),
|
||||
AssemblyLine.zeropage(SBC, reg, 2),
|
||||
AssemblyLine.indexedY(STA, ptr),
|
||||
AssemblyLine.indexedY(STA, ptr).copy(elidability = el),
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine.zeropage(STX, reg, 2),
|
||||
AssemblyLine.indexedY(LDA, ptr),
|
||||
AssemblyLine.indexedY(LDA, ptr).copy(elidability = el),
|
||||
AssemblyLine.zeropage(SBC, reg, 2),
|
||||
AssemblyLine.indexedY(STA, ptr),
|
||||
AssemblyLine.indexedY(STA, ptr).copy(elidability = el),
|
||||
)))(Right({(iy, r, last) =>
|
||||
val reg = ctx.env.get[VariableInMemory]("__reg")
|
||||
val result = ListBuffer[AssemblyLine]()
|
||||
@ -1611,7 +1614,7 @@ object BuiltIns {
|
||||
}
|
||||
result += AssemblyLine.immediate(LDY, iy)
|
||||
result += AssemblyLine.zeropage(STA, reg, 2)
|
||||
result += AssemblyLine.indexedY(LDA, reg)
|
||||
result += AssemblyLine.indexedY(LDA, reg).copy(elidability = el)
|
||||
if (iy == 0) {
|
||||
result += AssemblyLine.implied(SEC)
|
||||
}
|
||||
@ -1627,12 +1630,12 @@ object BuiltIns {
|
||||
})) else handleWordOrLongInPlaceModificationViaDeref(ctx, dx, addend, fromMsb = false)((ptr, _, offset, _) => wrapInSedCldIfNeeded(decimal, List(
|
||||
AssemblyLine.immediate(LDY, offset),
|
||||
AssemblyLine.implied(CLC),
|
||||
AssemblyLine.indexedY(ADC, ptr),
|
||||
AssemblyLine.indexedY(STA, ptr),
|
||||
AssemblyLine.indexedY(ADC, ptr).copy(elidability = el),
|
||||
AssemblyLine.indexedY(STA, ptr).copy(elidability = el),
|
||||
AssemblyLine.implied(TXA),
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine.indexedY(ADC, ptr),
|
||||
AssemblyLine.indexedY(STA, ptr),
|
||||
AssemblyLine.indexedY(ADC, ptr).copy(elidability = el),
|
||||
AssemblyLine.indexedY(STA, ptr).copy(elidability = el),
|
||||
)))(Right({(iy, r, last) =>
|
||||
val reg = ctx.env.get[VariableInMemory]("__reg")
|
||||
val result = ListBuffer[AssemblyLine]()
|
||||
@ -2004,14 +2007,16 @@ object BuiltIns {
|
||||
|
||||
def compileInPlaceWordOrLongBitOp(ctx: CompilationContext, lhs: LhsExpression, param: Expression, operation: Opcode.Value): List[AssemblyLine] = {
|
||||
lhs match {
|
||||
case dx: DerefExpression => return handleWordOrLongInPlaceModificationViaDeref(ctx, dx, param, fromMsb = false)((ptr, _, offset, _) => List(
|
||||
case dx: DerefExpression =>
|
||||
val el = if(dx.isVolatile) Elidability.Volatile else Elidability.Elidable
|
||||
return handleWordOrLongInPlaceModificationViaDeref(ctx, dx, param, fromMsb = false)((ptr, _, offset, _) => List(
|
||||
AssemblyLine.immediate(LDY, offset),
|
||||
AssemblyLine.indexedY(operation, ptr),
|
||||
AssemblyLine.indexedY(STA, ptr),
|
||||
AssemblyLine.indexedY(operation, ptr).copy(elidability = el),
|
||||
AssemblyLine.indexedY(STA, ptr).copy(elidability = el),
|
||||
AssemblyLine.implied(TXA),
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine.indexedY(operation, ptr),
|
||||
AssemblyLine.indexedY(STA, ptr),
|
||||
AssemblyLine.indexedY(operation, ptr).copy(elidability = el),
|
||||
AssemblyLine.indexedY(STA, ptr).copy(elidability = el),
|
||||
))(Right({ (iy, r, last) =>
|
||||
val reg = ctx.env.get[VariableInMemory]("__reg")
|
||||
r ++ List(
|
||||
|
@ -431,21 +431,22 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
||||
ctx.log.error("Invalid index for writing", indexExpr.position)
|
||||
Nil
|
||||
}
|
||||
case DerefExpression(inner, offset, targetType) =>
|
||||
case DerefExpression(inner, offset, isVolatile, targetType) =>
|
||||
val el = if(isVolatile) Elidability.Volatile else Elidability.Elidable
|
||||
val (prepare, addr, am, fast) = getPhysicalPointerForDeref(ctx, inner)
|
||||
if (targetType.size == 1) {
|
||||
fast match {
|
||||
case Some((fastBase, fastAddrMode, fastIndex)) =>
|
||||
return preserveRegisterIfNeeded(ctx, MosRegister.A, fastIndex(offset)) ++ List(AssemblyLine(STA, fastAddrMode, fastBase))
|
||||
return preserveRegisterIfNeeded(ctx, MosRegister.A, fastIndex(offset)) ++ List(AssemblyLine(STA, fastAddrMode, fastBase, elidability = el))
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
val lo = preserveRegisterIfNeeded(ctx, MosRegister.A, prepare) ++ List(AssemblyLine.immediate(LDY, offset), AssemblyLine(STA, am, addr))
|
||||
val lo = preserveRegisterIfNeeded(ctx, MosRegister.A, prepare) ++ List(AssemblyLine.immediate(LDY, offset), AssemblyLine(STA, am, addr, elidability = el))
|
||||
if (targetType.size == 1) {
|
||||
lo
|
||||
} else {
|
||||
lo ++ List(AssemblyLine.immediate(LDA, 0)) ++
|
||||
List.tabulate(targetType.size - 1)(i => List(AssemblyLine.implied(INY), AssemblyLine(STA, am, addr))).flatten
|
||||
List.tabulate(targetType.size - 1)(i => List(AssemblyLine.implied(INY), AssemblyLine(STA, am, addr, elidability = el))).flatten
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -563,13 +564,13 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
||||
def getPhysicalPointerForDeref(ctx: CompilationContext, pointerExpression: Expression): (List[AssemblyLine], Constant, AddrMode.Value, Option[(Constant, AddrMode.Value, Int => List[AssemblyLine])]) = {
|
||||
pointerExpression match {
|
||||
case VariableExpression(name) =>
|
||||
val p = ctx.env.get[ThingInMemory](name)
|
||||
val p = ctx.env.maybeGet[ThingInMemory](name)
|
||||
p match {
|
||||
case array: MfArray => return (Nil, p.toAddress, AddrMode.AbsoluteY,
|
||||
if (array.sizeInBytes <= 256) Some((p.toAddress, AbsoluteY, (i: Int) => List(AssemblyLine.immediate(LDY, i)))) else None)
|
||||
case Some(array: MfArray) => return (Nil, array.toAddress, AddrMode.AbsoluteY,
|
||||
if (array.sizeInBytes <= 256) Some((array.toAddress, AbsoluteY, (i: Int) => List(AssemblyLine.immediate(LDY, i)))) else None)
|
||||
case Some(q) => if (q.zeropage) return (Nil, q.toAddress, AddrMode.IndexedY, None)
|
||||
case _ =>
|
||||
}
|
||||
if (p.zeropage) return (Nil, p.toAddress, AddrMode.IndexedY, None)
|
||||
case _ =>
|
||||
}
|
||||
ctx.env.eval(pointerExpression) match {
|
||||
@ -1145,43 +1146,44 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
||||
result ++ List(AssemblyLine.implied(PHA), AssemblyLine.implied(XBA), AssemblyLine.implied(PLA)) ++ signExtendA(ctx) ++ List(AssemblyLine.implied(XBA))
|
||||
}
|
||||
}
|
||||
case DerefExpression(inner, offset, targetType) =>
|
||||
case DerefExpression(inner, offset, isVolatile, targetType) =>
|
||||
val el = if(isVolatile) Elidability.Volatile else Elidability.Elidable
|
||||
val (prepare, addr, am, fast) = getPhysicalPointerForDeref(ctx, inner)
|
||||
(fast, targetType.size, am) match {
|
||||
case (Some((fastBase, fastAddrMode, fastIndex)), 1, _) =>
|
||||
fastIndex(offset) ++ List(AssemblyLine(LDA, fastAddrMode, fastBase)) ++ expressionStorageFromA(ctx, exprTypeAndVariable, expr.position, exprType.isSigned)
|
||||
fastIndex(offset) ++ List(AssemblyLine(LDA, fastAddrMode, fastBase, elidability = el)) ++ expressionStorageFromA(ctx, exprTypeAndVariable, expr.position, exprType.isSigned)
|
||||
case (_, 1, AbsoluteY) =>
|
||||
prepare ++ List(AssemblyLine.absolute(LDA, addr + offset)) ++ expressionStorageFromA(ctx, exprTypeAndVariable, expr.position, exprType.isSigned)
|
||||
prepare ++ List(AssemblyLine.absolute(LDA, addr + offset).copy(elidability = el)) ++ expressionStorageFromA(ctx, exprTypeAndVariable, expr.position, exprType.isSigned)
|
||||
case (_, 1, _) =>
|
||||
prepare ++ List(AssemblyLine.immediate(LDY, offset), AssemblyLine(LDA, am, addr)) ++ expressionStorageFromA(ctx, exprTypeAndVariable, expr.position, exprType.isSigned)
|
||||
prepare ++ List(AssemblyLine.immediate(LDY, offset), AssemblyLine(LDA, am, addr, elidability = el)) ++ expressionStorageFromA(ctx, exprTypeAndVariable, expr.position, exprType.isSigned)
|
||||
case (Some((fastBase, AbsoluteY, fastIndex)), 2, _) =>
|
||||
fastIndex(offset) ++ List(
|
||||
AssemblyLine.absoluteY(LDA, fastBase),
|
||||
AssemblyLine.absoluteY(LDA, fastBase).copy(elidability = el),
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine.absoluteY(LDX, fastBase)) ++
|
||||
AssemblyLine.absoluteY(LDX, fastBase).copy(elidability = el)) ++
|
||||
expressionStorageFromAX(ctx, exprTypeAndVariable, expr.position)
|
||||
case (Some((fastBase, fastAddrMode, fastIndex)), 2, _) =>
|
||||
fastIndex(offset) ++ List(
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine(LDA, fastAddrMode, fastBase),
|
||||
AssemblyLine(LDA, fastAddrMode, fastBase).copy(elidability = el),
|
||||
AssemblyLine.implied(TAX),
|
||||
AssemblyLine.implied(DEY),
|
||||
AssemblyLine(LDA, fastAddrMode, fastBase)) ++
|
||||
AssemblyLine(LDA, fastAddrMode, fastBase).copy(elidability = el)) ++
|
||||
expressionStorageFromAX(ctx, exprTypeAndVariable, expr.position)
|
||||
case (_, 2, AbsoluteY) =>
|
||||
prepare ++
|
||||
List(
|
||||
AssemblyLine.absolute(LDA, addr + offset),
|
||||
AssemblyLine.absolute(LDX, addr + offset + 1)) ++
|
||||
AssemblyLine.absolute(LDA, addr + offset).copy(elidability = el),
|
||||
AssemblyLine.absolute(LDX, addr + offset + 1).copy(elidability = el)) ++
|
||||
expressionStorageFromAX(ctx, exprTypeAndVariable, expr.position)
|
||||
case (_, 2, _) =>
|
||||
prepare ++
|
||||
List(
|
||||
AssemblyLine.immediate(LDY, offset+1),
|
||||
AssemblyLine(LDA, am, addr),
|
||||
AssemblyLine(LDA, am, addr, elidability = el),
|
||||
AssemblyLine.implied(TAX),
|
||||
AssemblyLine.implied(DEY),
|
||||
AssemblyLine(LDA, am, addr)) ++
|
||||
AssemblyLine(LDA, am, addr, elidability = el)) ++
|
||||
expressionStorageFromAX(ctx, exprTypeAndVariable, expr.position)
|
||||
case _ =>
|
||||
exprTypeAndVariable match {
|
||||
@ -2229,7 +2231,8 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
||||
case SeparateBytesExpression(_, _) =>
|
||||
ctx.log.error("Invalid left-hand-side use of `:`")
|
||||
Nil
|
||||
case DerefExpression(inner, offset, targetType) =>
|
||||
case DerefExpression(inner, offset, isVolatile, targetType) =>
|
||||
val el = if(isVolatile) Elidability.Volatile else Elidability.Elidable
|
||||
val (prepare, addr, am, fastTarget) = getPhysicalPointerForDeref(ctx, inner)
|
||||
env.eval(source) match {
|
||||
case Some(constant) =>
|
||||
@ -2237,7 +2240,7 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
||||
case AbsoluteY =>
|
||||
prepare ++ (0 until targetType.size).flatMap(i => List(
|
||||
AssemblyLine.immediate(LDA, constant.subbyte(i)),
|
||||
AssemblyLine.absolute(STA, addr + offset + i)))
|
||||
AssemblyLine.absolute(STA, addr + offset + i).copy(elidability = el)))
|
||||
case _ =>
|
||||
fastTarget match {
|
||||
case Some((constAddr, fastAddrMode, initializeY)) =>
|
||||
@ -2245,13 +2248,13 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
||||
val load = List(AssemblyLine.immediate(LDA, constant.subbyte(i)))
|
||||
load ++ (if (i == 0) List(AssemblyLine(STA, fastAddrMode, constAddr)) else List(
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine(STA, fastAddrMode, constAddr)))
|
||||
AssemblyLine(STA, fastAddrMode, constAddr, elidability = el)))
|
||||
}
|
||||
case _ =>
|
||||
prepare ++ (0 until targetType.size).flatMap(i => List(
|
||||
if (i == 0) AssemblyLine.immediate(LDY, offset) else AssemblyLine.implied(INY),
|
||||
AssemblyLine.immediate(LDA, constant.subbyte(i)),
|
||||
AssemblyLine(STA, am, addr)))
|
||||
AssemblyLine(STA, am, addr, elidability = el)))
|
||||
}
|
||||
}
|
||||
case None =>
|
||||
@ -2262,7 +2265,7 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
||||
case (1, AbsoluteY) =>
|
||||
prepare ++
|
||||
AssemblyLine.variable(ctx, LDA, variable) :+
|
||||
AssemblyLine.absolute(STA, addr + offset)
|
||||
AssemblyLine.absolute(STA, addr + offset).copy(elidability = el)
|
||||
case (1, _) if fastTarget.isEmpty =>
|
||||
prepare ++
|
||||
AssemblyLine.variable(ctx, LDA, variable) ++ List(
|
||||
@ -2272,7 +2275,7 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
||||
prepare ++ (0 until targetType.size).flatMap { i =>
|
||||
val load = loadSingleByteAssumingAPreserved(ctx, sourceType, variable, i)
|
||||
load ++ List(
|
||||
AssemblyLine.absolute(STA, addr + offset + i))
|
||||
AssemblyLine.absolute(STA, addr + offset + i).copy(elidability = el))
|
||||
}
|
||||
case (_, _) =>
|
||||
fastTarget match {
|
||||
@ -2281,37 +2284,38 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
||||
val load = loadSingleByteAssumingAPreserved(ctx, sourceType, variable, i)
|
||||
load ++ (if (i == 0) List(AssemblyLine(STA, fastAddrMode, constAddr)) else List(
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine(STA, fastAddrMode, constAddr)))
|
||||
AssemblyLine(STA, fastAddrMode, constAddr, elidability = el)))
|
||||
}
|
||||
case _ =>
|
||||
prepare ++ (0 until targetType.size).flatMap { i =>
|
||||
val load = loadSingleByteAssumingAPreserved(ctx, sourceType, variable, i)
|
||||
load ++ List(
|
||||
if (i == 0) AssemblyLine.immediate(LDY, offset) else AssemblyLine.implied(INY),
|
||||
AssemblyLine(STA, am, addr))
|
||||
AssemblyLine(STA, am, addr).copy(elidability = el))
|
||||
}
|
||||
}
|
||||
case _ =>
|
||||
ctx.log.error("Cannot assign to a large object indirectly", target.position)
|
||||
Nil
|
||||
}
|
||||
case DerefExpression(innerSource, sourceOffset, _) =>
|
||||
case DerefExpression(innerSource, sourceOffset, sourceVolatile, _) =>
|
||||
val sEl = if (sourceVolatile) Elidability.Volatile else Elidability.Elidable
|
||||
val (prepareSource, addrSource, amSource, fastSource) = getPhysicalPointerForDeref(ctx, innerSource)
|
||||
(am, amSource) match {
|
||||
case (AbsoluteY, AbsoluteY) =>
|
||||
prepare ++ prepareSource ++ (0 until targetType.size).flatMap { i =>
|
||||
loadSingleByteAssumingAPreserved(ctx, sourceType, addrSource + sourceOffset, i) :+ AssemblyLine.absolute(STA, addr + offset + i)
|
||||
loadSingleByteAssumingAPreserved(ctx, sourceType, addrSource + sourceOffset, i, sEl) :+ AssemblyLine.absolute(STA, addr + offset + i).copy(elidability = el)
|
||||
}
|
||||
case (AbsoluteY, _) =>
|
||||
prepare ++ prepareSource ++ (0 until targetType.size).flatMap { i =>
|
||||
loadSingleByteIndexedCountingYAssumingAPreserved(ctx, sourceType, amSource, addrSource, sourceOffset, i) :+
|
||||
AssemblyLine.absolute(STA, addr + offset + i)
|
||||
loadSingleByteIndexedCountingYAssumingAPreserved(ctx, sourceType, amSource, addrSource, sourceOffset, i, sEl) :+
|
||||
AssemblyLine.absolute(STA, addr + offset + i).copy(elidability = el)
|
||||
}
|
||||
case (_, AbsoluteY) =>
|
||||
prepare ++ prepareSource ++ (0 until targetType.size).flatMap { i =>
|
||||
(if (i == 0) AssemblyLine.immediate(LDY, sourceOffset) else AssemblyLine.implied(INY)) ::
|
||||
(loadSingleByteAssumingAPreserved(ctx, sourceType, addrSource + sourceOffset, i) :+
|
||||
AssemblyLine(STA, am, addr))
|
||||
(loadSingleByteAssumingAPreserved(ctx, sourceType, addrSource + sourceOffset, i, sEl) :+
|
||||
AssemblyLine(STA, am, addr, elidability = el))
|
||||
}
|
||||
case (IndexedY, IndexedY) =>
|
||||
val reg = env.get[ThingInMemory]("__reg.loword")
|
||||
@ -2327,8 +2331,8 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
||||
AssemblyLine.zeropage(LDA, reg, 1),
|
||||
AssemblyLine.zeropage(STA, reg, 3)) ++ prepareSource ++ (0 until targetType.size).flatMap { i =>
|
||||
(if (i == 0) AssemblyLine.immediate(LDY, sourceOffset) else AssemblyLine.implied(INY)) ::
|
||||
(loadSingleByteIndexedAssumingAPreserved(ctx, sourceType, IndexedY, reg.toAddress, i) :+
|
||||
AssemblyLine.indexedY(STA, reg, 2))
|
||||
(loadSingleByteIndexedAssumingAPreserved(ctx, sourceType, IndexedY, reg.toAddress, i, elidability = sEl) :+
|
||||
AssemblyLine.indexedY(STA, reg, 2).copy(elidability = el))
|
||||
}
|
||||
case (false, true) =>
|
||||
prepareSource ++ List(
|
||||
@ -2337,8 +2341,8 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
||||
AssemblyLine.zeropage(LDA, reg, 1),
|
||||
AssemblyLine.zeropage(STA, reg, 3)) ++ prepare ++ (0 until targetType.size).flatMap { i =>
|
||||
(if (i == 0) AssemblyLine.immediate(LDY, sourceOffset) else AssemblyLine.implied(INY)) ::
|
||||
(loadSingleByteIndexedAssumingAPreserved(ctx, sourceType, IndexedY, reg.toAddress + 2, i) :+
|
||||
AssemblyLine.indexedY(STA, reg))
|
||||
(loadSingleByteIndexedAssumingAPreserved(ctx, sourceType, IndexedY, reg.toAddress + 2, i, elidability = sEl) :+
|
||||
AssemblyLine.indexedY(STA, reg).copy(elidability = el))
|
||||
}
|
||||
case _ =>
|
||||
prepare ++ List(
|
||||
@ -2351,15 +2355,15 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
||||
AssemblyLine.implied(PLA),
|
||||
AssemblyLine.zeropage(STA, reg, 3)) ++ (0 until targetType.size).flatMap { i =>
|
||||
(if (i == 0) AssemblyLine.immediate(LDY, sourceOffset) else AssemblyLine.implied(INY)) ::
|
||||
(loadSingleByteIndexedAssumingAPreserved(ctx, sourceType, IndexedY, reg.toAddress, i) :+
|
||||
AssemblyLine.indexedY(STA, reg, 2))
|
||||
(loadSingleByteIndexedAssumingAPreserved(ctx, sourceType, IndexedY, reg.toAddress, i, sEl) :+
|
||||
AssemblyLine.indexedY(STA, reg, 2).copy(elidability = el))
|
||||
}
|
||||
}
|
||||
case (MemoryAddressConstant(thT: MemoryVariable), MemoryAddressConstant(thS: MemoryVariable)) if thT.name != thS.name =>
|
||||
prepare ++ prepareSource ++ (0 until targetType.size).flatMap { i =>
|
||||
(if (i == 0) AssemblyLine.immediate(LDY, sourceOffset) else AssemblyLine.implied(INY)) ::
|
||||
(loadSingleByteIndexedAssumingAPreserved(ctx, sourceType, IndexedY, thS.toAddress, i) :+
|
||||
AssemblyLine.indexedY(STA, thT))
|
||||
(loadSingleByteIndexedAssumingAPreserved(ctx, sourceType, IndexedY, thS.toAddress, i, sEl) :+
|
||||
AssemblyLine.indexedY(STA, thT).copy(elidability = el))
|
||||
}
|
||||
case _ =>
|
||||
???
|
||||
@ -2376,17 +2380,17 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
||||
// TODO: optimize if prepare is empty
|
||||
if (prepare.isEmpty) {
|
||||
compile(ctx, source, someTuple, BranchSpec.None) ++ List(
|
||||
AssemblyLine.absolute(STA, addr + offset),
|
||||
AssemblyLine.absolute(STX, addr + offset + 1))
|
||||
AssemblyLine.absolute(STA, addr + offset).copy(elidability = el),
|
||||
AssemblyLine.absolute(STX, addr + offset + 1).copy(elidability = el))
|
||||
} else {
|
||||
compile(ctx, source, someTuple, BranchSpec.None) ++ List(
|
||||
AssemblyLine.implied(PHA),
|
||||
AssemblyLine.implied(TXA),
|
||||
AssemblyLine.implied(PHA)) ++ prepare ++ List(
|
||||
AssemblyLine.implied(PLA),
|
||||
AssemblyLine.absolute(STA, addr + offset + 1),
|
||||
AssemblyLine.absolute(STA, addr + offset + 1).copy(elidability = el),
|
||||
AssemblyLine.implied(PLA),
|
||||
AssemblyLine.absolute(STA, addr + offset))
|
||||
AssemblyLine.absolute(STA, addr + offset).copy(elidability = el))
|
||||
}
|
||||
case (2, _) =>
|
||||
val someTuple = Some(targetType, RegisterVariable(MosRegister.AX, targetType))
|
||||
@ -2395,18 +2399,18 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
||||
compile(ctx, source, someTuple, BranchSpec.None) ++
|
||||
preserveRegisterIfNeeded(ctx, MosRegister.AX, initializeY(offset)) ++
|
||||
List(
|
||||
AssemblyLine(STA, fastAddrMode, baseOffset),
|
||||
AssemblyLine(STA, fastAddrMode, baseOffset, elidability = el),
|
||||
AssemblyLine.implied(TXA),
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine(STA, fastAddrMode, baseOffset))
|
||||
AssemblyLine(STA, fastAddrMode, baseOffset, elidability = el))
|
||||
case _ =>
|
||||
if (prepare.isEmpty) {
|
||||
compile(ctx, source, someTuple, BranchSpec.None) ++ List(
|
||||
AssemblyLine.immediate(LDY, offset),
|
||||
AssemblyLine.indexedY(STA, addr),
|
||||
AssemblyLine.indexedY(STA, addr).copy(elidability = el),
|
||||
AssemblyLine.implied(TXA),
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine.indexedY(STA, addr))
|
||||
AssemblyLine.indexedY(STA, addr).copy(elidability = el))
|
||||
} else {
|
||||
compile(ctx, source, someTuple, BranchSpec.None) ++ List(
|
||||
AssemblyLine.implied(PHA),
|
||||
@ -2414,10 +2418,10 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
||||
AssemblyLine.implied(PHA)) ++ prepare ++ List(
|
||||
AssemblyLine.immediate(LDY, offset+1),
|
||||
AssemblyLine.implied(PLA),
|
||||
AssemblyLine.indexedY(STA, addr),
|
||||
AssemblyLine.indexedY(STA, addr).copy(elidability = el),
|
||||
AssemblyLine.implied(PLA),
|
||||
AssemblyLine.implied(DEY),
|
||||
AssemblyLine.indexedY(STA, addr))
|
||||
AssemblyLine.indexedY(STA, addr).copy(elidability = el))
|
||||
}
|
||||
}
|
||||
case _ =>
|
||||
@ -2443,25 +2447,25 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
||||
else AssemblyLine.variable(ctx, LDA, variable, i)
|
||||
}
|
||||
|
||||
private def loadSingleByteAssumingAPreserved(ctx: CompilationContext, sourceType: Type, varAddr: Constant, i: Int) = {
|
||||
private def loadSingleByteAssumingAPreserved(ctx: CompilationContext, sourceType: Type, varAddr: Constant, i: Int, elidability: Elidability.Value) = {
|
||||
if (i == sourceType.size) {
|
||||
if (sourceType.isSigned) signExtendA(ctx) else List(AssemblyLine.immediate(LDA, 0))
|
||||
} else if (i > sourceType.size) Nil
|
||||
else List(AssemblyLine.absolute(LDA, varAddr + i))
|
||||
else List(AssemblyLine(LDA, Absolute, varAddr + i, elidability))
|
||||
}
|
||||
|
||||
private def loadSingleByteIndexedAssumingAPreserved(ctx: CompilationContext, sourceType: Type, addrMode: AddrMode.Value, baseAddr: Constant, i: Int) = {
|
||||
private def loadSingleByteIndexedAssumingAPreserved(ctx: CompilationContext, sourceType: Type, addrMode: AddrMode.Value, baseAddr: Constant, i: Int, elidability: Elidability.Value) = {
|
||||
if (i == sourceType.size) {
|
||||
if (sourceType.isSigned) signExtendA(ctx) else List(AssemblyLine.immediate(LDA, 0))
|
||||
} else if (i > sourceType.size) Nil
|
||||
else List(AssemblyLine(LDA, addrMode, baseAddr))
|
||||
else List(AssemblyLine(LDA, addrMode, baseAddr, elidability))
|
||||
}
|
||||
|
||||
private def loadSingleByteIndexedCountingYAssumingAPreserved(ctx: CompilationContext, sourceType: Type, addrMode: AddrMode.Value, baseAddr: Constant, sourceOffset:Int, i: Int) = {
|
||||
private def loadSingleByteIndexedCountingYAssumingAPreserved(ctx: CompilationContext, sourceType: Type, addrMode: AddrMode.Value, baseAddr: Constant, sourceOffset:Int, i: Int, elidability: Elidability.Value) = {
|
||||
if (i == sourceType.size) {
|
||||
if (sourceType.isSigned) signExtendA(ctx) else List(AssemblyLine.immediate(LDA, 0))
|
||||
} else if (i > sourceType.size) Nil
|
||||
else List(if(i==0) AssemblyLine.immediate(LDY, sourceOffset) else AssemblyLine.implied(INY), AssemblyLine(LDA, addrMode, baseAddr))
|
||||
else List(if(i==0) AssemblyLine.immediate(LDY, sourceOffset) else AssemblyLine.implied(INY), AssemblyLine(LDA, addrMode, baseAddr, elidability))
|
||||
}
|
||||
|
||||
def arrayBoundsCheck(ctx: CompilationContext, pointy: Pointy, register: MosRegister.Value, index: Expression): List[AssemblyLine] = {
|
||||
|
@ -623,70 +623,71 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
|
||||
case ZExpressionTarget.DE => xxx(ZRegister.D, ZRegister.E, allowRedirect = true)
|
||||
case ZExpressionTarget.BC => xxx(ZRegister.B, ZRegister.C, allowRedirect = true)
|
||||
}
|
||||
case e@DerefExpression(inner, offset, targetType) =>
|
||||
case e@DerefExpression(inner, offset, isVolatile, targetType) =>
|
||||
val el = if (isVolatile) Elidability.Volatile else Elidability.Elidable
|
||||
compileDerefPointer(ctx, e) ++ (targetType.size match {
|
||||
case 1 => target match {
|
||||
case ZExpressionTarget.A => List(ZLine.ld8(ZRegister.A, ZRegister.MEM_HL))
|
||||
case ZExpressionTarget.A => List(ZLine.ld8(ZRegister.A, ZRegister.MEM_HL).copy(elidability = el))
|
||||
case ZExpressionTarget.DEHL =>
|
||||
if (targetType.isSigned) {
|
||||
List(ZLine.ld8(ZRegister.A, ZRegister.MEM_HL), ZLine.ld8(ZRegister.L, ZRegister.A)) ++
|
||||
List(ZLine.ld8(ZRegister.A, ZRegister.MEM_HL).copy(elidability = el), ZLine.ld8(ZRegister.L, ZRegister.A)) ++
|
||||
signExtendHighestByte(ctx, ZRegister.A) ++
|
||||
List(ZLine.ld8(ZRegister.H, ZRegister.A), ZLine.ld8(ZRegister.E, ZRegister.A), ZLine.ld8(ZRegister.D, ZRegister.A))
|
||||
} else {
|
||||
List(ZLine.ld8(ZRegister.L, ZRegister.MEM_HL), ZLine.ldImm8(ZRegister.H, 0), ZLine.ldImm8(ZRegister.E, 0), ZLine.ldImm8(ZRegister.D, 0))
|
||||
List(ZLine.ld8(ZRegister.L, ZRegister.MEM_HL).copy(elidability = el), ZLine.ldImm8(ZRegister.H, 0), ZLine.ldImm8(ZRegister.E, 0), ZLine.ldImm8(ZRegister.D, 0))
|
||||
}
|
||||
case ZExpressionTarget.HL =>
|
||||
if (targetType.isSigned) {
|
||||
List(ZLine.ld8(ZRegister.A, ZRegister.MEM_HL), ZLine.ld8(ZRegister.L, ZRegister.A)) ++ signExtendHighestByte(ctx, ZRegister.H)
|
||||
List(ZLine.ld8(ZRegister.A, ZRegister.MEM_HL).copy(elidability = el), ZLine.ld8(ZRegister.L, ZRegister.A)) ++ signExtendHighestByte(ctx, ZRegister.H)
|
||||
} else {
|
||||
List(ZLine.ld8(ZRegister.L, ZRegister.MEM_HL), ZLine.ldImm8(ZRegister.H, 0))
|
||||
List(ZLine.ld8(ZRegister.L, ZRegister.MEM_HL).copy(elidability = el), ZLine.ldImm8(ZRegister.H, 0))
|
||||
}
|
||||
case ZExpressionTarget.BC =>
|
||||
if (targetType.isSigned) {
|
||||
List(ZLine.ld8(ZRegister.A, ZRegister.MEM_HL), ZLine.ld8(ZRegister.C, ZRegister.A)) ++ signExtendHighestByte(ctx, ZRegister.B)
|
||||
List(ZLine.ld8(ZRegister.A, ZRegister.MEM_HL).copy(elidability = el), ZLine.ld8(ZRegister.C, ZRegister.A)) ++ signExtendHighestByte(ctx, ZRegister.B)
|
||||
} else {
|
||||
List(ZLine.ld8(ZRegister.C, ZRegister.MEM_HL), ZLine.ldImm8(ZRegister.B, 0))
|
||||
List(ZLine.ld8(ZRegister.C, ZRegister.MEM_HL).copy(elidability = el), ZLine.ldImm8(ZRegister.B, 0))
|
||||
}
|
||||
case ZExpressionTarget.DE =>
|
||||
if (targetType.isSigned) {
|
||||
List(ZLine.ld8(ZRegister.A, ZRegister.MEM_HL), ZLine.ld8(ZRegister.E, ZRegister.A)) ++ signExtendHighestByte(ctx, ZRegister.D)
|
||||
List(ZLine.ld8(ZRegister.A, ZRegister.MEM_HL).copy(elidability = el), ZLine.ld8(ZRegister.E, ZRegister.A)) ++ signExtendHighestByte(ctx, ZRegister.D)
|
||||
} else {
|
||||
List(ZLine.ld8(ZRegister.E, ZRegister.MEM_HL), ZLine.ldImm8(ZRegister.D, 0))
|
||||
List(ZLine.ld8(ZRegister.E, ZRegister.MEM_HL).copy(elidability = el), ZLine.ldImm8(ZRegister.D, 0))
|
||||
}
|
||||
case ZExpressionTarget.NOTHING => Nil
|
||||
}
|
||||
case 2 => target match {
|
||||
case ZExpressionTarget.DEHL =>
|
||||
List(
|
||||
ZLine.ld8(ZRegister.A, ZRegister.MEM_HL),
|
||||
ZLine.ld8(ZRegister.A, ZRegister.MEM_HL).copy(elidability = el),
|
||||
ZLine.register(INC_16, ZRegister.HL),
|
||||
ZLine.ld8(ZRegister.H, ZRegister.MEM_HL),
|
||||
ZLine.ld8(ZRegister.H, ZRegister.MEM_HL).copy(elidability = el),
|
||||
ZLine.ld8(ZRegister.L, ZRegister.A),
|
||||
ZLine.ldImm8(ZRegister.E, 0),
|
||||
ZLine.ldImm8(ZRegister.D, 0)) // TODO
|
||||
case ZExpressionTarget.EHL =>
|
||||
List(
|
||||
ZLine.ld8(ZRegister.A, ZRegister.MEM_HL),
|
||||
ZLine.ld8(ZRegister.A, ZRegister.MEM_HL).copy(elidability = el),
|
||||
ZLine.register(INC_16, ZRegister.HL),
|
||||
ZLine.ld8(ZRegister.H, ZRegister.MEM_HL),
|
||||
ZLine.ld8(ZRegister.H, ZRegister.MEM_HL).copy(elidability = el),
|
||||
ZLine.ld8(ZRegister.L, ZRegister.A),
|
||||
ZLine.ldImm8(ZRegister.E, 0)) // TODO
|
||||
case ZExpressionTarget.HL =>
|
||||
List(
|
||||
ZLine.ld8(ZRegister.A, ZRegister.MEM_HL),
|
||||
ZLine.ld8(ZRegister.A, ZRegister.MEM_HL).copy(elidability = el),
|
||||
ZLine.register(INC_16, ZRegister.HL),
|
||||
ZLine.ld8(ZRegister.H, ZRegister.MEM_HL),
|
||||
ZLine.ld8(ZRegister.H, ZRegister.MEM_HL).copy(elidability = el),
|
||||
ZLine.ld8(ZRegister.L, ZRegister.A))
|
||||
case ZExpressionTarget.BC =>
|
||||
List(
|
||||
ZLine.ld8(ZRegister.C, ZRegister.MEM_HL),
|
||||
ZLine.ld8(ZRegister.C, ZRegister.MEM_HL).copy(elidability = el),
|
||||
ZLine.register(INC_16, ZRegister.HL),
|
||||
ZLine.ld8(ZRegister.B, ZRegister.MEM_HL))
|
||||
ZLine.ld8(ZRegister.B, ZRegister.MEM_HL).copy(elidability = el))
|
||||
case ZExpressionTarget.DE =>
|
||||
List(
|
||||
ZLine.ld8(ZRegister.E, ZRegister.MEM_HL),
|
||||
ZLine.ld8(ZRegister.E, ZRegister.MEM_HL).copy(elidability = el),
|
||||
ZLine.register(INC_16, ZRegister.HL),
|
||||
ZLine.ld8(ZRegister.D, ZRegister.MEM_HL))
|
||||
ZLine.ld8(ZRegister.D, ZRegister.MEM_HL).copy(elidability = el))
|
||||
case ZExpressionTarget.NOTHING => Nil
|
||||
}
|
||||
case 3 => target match {
|
||||
@ -694,20 +695,20 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
|
||||
case ZExpressionTarget.EHL | ZExpressionTarget.DEHL =>
|
||||
if (ctx.options.flag(CompilationFlag.EmitIntel8080Opcodes)) {
|
||||
List(
|
||||
ZLine.ld8(ZRegister.E, ZRegister.MEM_HL),
|
||||
ZLine.ld8(ZRegister.E, ZRegister.MEM_HL).copy(elidability = el),
|
||||
ZLine.register(INC_16, ZRegister.HL),
|
||||
ZLine.ld8(ZRegister.D, ZRegister.MEM_HL),
|
||||
ZLine.ld8(ZRegister.D, ZRegister.MEM_HL).copy(elidability = el),
|
||||
ZLine.register(INC_16, ZRegister.HL),
|
||||
ZLine.ld8(ZRegister.L, ZRegister.MEM_HL),
|
||||
ZLine.ld8(ZRegister.L, ZRegister.MEM_HL).copy(elidability = el),
|
||||
ZLine.ldImm8(ZRegister.H, 0),
|
||||
ZLine.implied(EX_DE_HL)) // TODO
|
||||
} else {
|
||||
List(
|
||||
ZLine.ld8(ZRegister.C, ZRegister.MEM_HL),
|
||||
ZLine.ld8(ZRegister.C, ZRegister.MEM_HL).copy(elidability = el),
|
||||
ZLine.register(INC_16, ZRegister.HL),
|
||||
ZLine.ld8(ZRegister.B, ZRegister.MEM_HL),
|
||||
ZLine.ld8(ZRegister.B, ZRegister.MEM_HL).copy(elidability = el),
|
||||
ZLine.register(INC_16, ZRegister.HL),
|
||||
ZLine.ld8(ZRegister.E, ZRegister.MEM_HL),
|
||||
ZLine.ld8(ZRegister.E, ZRegister.MEM_HL).copy(elidability = el),
|
||||
ZLine.ld8(ZRegister.L, ZRegister.C),
|
||||
ZLine.ld8(ZRegister.H, ZRegister.B),
|
||||
ZLine.ldImm8(ZRegister.D, 0)) // TODO
|
||||
@ -718,24 +719,24 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
|
||||
case ZExpressionTarget.DEHL =>
|
||||
if (ctx.options.flag(CompilationFlag.EmitIntel8080Opcodes)) {
|
||||
List(
|
||||
ZLine.ld8(ZRegister.E, ZRegister.MEM_HL),
|
||||
ZLine.ld8(ZRegister.E, ZRegister.MEM_HL).copy(elidability = el),
|
||||
ZLine.register(INC_16, ZRegister.HL),
|
||||
ZLine.ld8(ZRegister.D, ZRegister.MEM_HL),
|
||||
ZLine.ld8(ZRegister.D, ZRegister.MEM_HL).copy(elidability = el),
|
||||
ZLine.register(INC_16, ZRegister.HL),
|
||||
ZLine.ld8(ZRegister.A, ZRegister.MEM_HL),
|
||||
ZLine.ld8(ZRegister.A, ZRegister.MEM_HL).copy(elidability = el),
|
||||
ZLine.register(INC_16, ZRegister.HL),
|
||||
ZLine.ld8(ZRegister.H, ZRegister.MEM_HL),
|
||||
ZLine.ld8(ZRegister.H, ZRegister.MEM_HL).copy(elidability = el),
|
||||
ZLine.ld8(ZRegister.L, ZRegister.A),
|
||||
ZLine.implied(EX_DE_HL)) // TODO
|
||||
} else {
|
||||
List(
|
||||
ZLine.ld8(ZRegister.C, ZRegister.MEM_HL),
|
||||
ZLine.ld8(ZRegister.C, ZRegister.MEM_HL).copy(elidability = el),
|
||||
ZLine.register(INC_16, ZRegister.HL),
|
||||
ZLine.ld8(ZRegister.B, ZRegister.MEM_HL),
|
||||
ZLine.ld8(ZRegister.B, ZRegister.MEM_HL).copy(elidability = el),
|
||||
ZLine.register(INC_16, ZRegister.HL),
|
||||
ZLine.ld8(ZRegister.E, ZRegister.MEM_HL),
|
||||
ZLine.ld8(ZRegister.E, ZRegister.MEM_HL).copy(elidability = el),
|
||||
ZLine.register(INC_16, ZRegister.HL),
|
||||
ZLine.ld8(ZRegister.D, ZRegister.MEM_HL),
|
||||
ZLine.ld8(ZRegister.D, ZRegister.MEM_HL).copy(elidability = el),
|
||||
ZLine.ld8(ZRegister.L, ZRegister.C),
|
||||
ZLine.ld8(ZRegister.H, ZRegister.B)) // TODO
|
||||
}
|
||||
@ -1590,11 +1591,15 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
|
||||
prepareA ++ fillUpperBytes
|
||||
}
|
||||
|
||||
private def signExtendHighestByte(ctx: CompilationContext, sourceHiRegister: ZRegister.Value, targetHiRegister: ZRegister.Value = ZRegister.A, signedSource: Boolean = true): List[ZLine] = {
|
||||
private def signExtendHighestByte(ctx: CompilationContext,
|
||||
sourceHiRegister: ZRegister.Value,
|
||||
targetHiRegister: ZRegister.Value = ZRegister.A,
|
||||
signedSource: Boolean = true,
|
||||
elidability: Elidability.Value = Elidability.Elidable): List[ZLine] = {
|
||||
if (!signedSource) {
|
||||
return List(ZLine.ldImm8(targetHiRegister, 0))
|
||||
}
|
||||
val prefix = if (sourceHiRegister == ZRegister.A) Nil else List(ZLine.ld8(ZRegister.A, sourceHiRegister))
|
||||
val prefix = if (sourceHiRegister == ZRegister.A) Nil else List(ZLine.ld8(ZRegister.A, sourceHiRegister).copy(elidability = elidability))
|
||||
val label = ctx.nextLabel("sx")
|
||||
val resultInA = if (ctx.options.flag(CompilationFlag.EmitIntel8080Opcodes)) {
|
||||
prefix ++ List(
|
||||
@ -1613,7 +1618,7 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
|
||||
} else {
|
||||
throw new IllegalStateException()
|
||||
}
|
||||
if (targetHiRegister == ZRegister.A) resultInA else resultInA :+ ZLine.ld8(targetHiRegister, ZRegister.A)
|
||||
if (targetHiRegister == ZRegister.A) resultInA else resultInA :+ ZLine.ld8(targetHiRegister, ZRegister.A).copy(elidability = elidability)
|
||||
}
|
||||
|
||||
def signExtendViaIX(ctx: CompilationContext, targetOffset: Int, hiRegister: ZRegister.Value, bytes: Int, signedSource: Boolean): List[ZLine] = {
|
||||
@ -1868,17 +1873,18 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
|
||||
List(ZLine.ld8(ZRegister.E, ZRegister.A)) ++ stashDEIfChanged(ctx, code) :+ ZLine.ld8(ZRegister.MEM_HL, ZRegister.E)
|
||||
} else code :+ ZLine.ld8(ZRegister.MEM_HL, ZRegister.A)
|
||||
}
|
||||
case e@DerefExpression(_, _, targetType) =>
|
||||
val lo = stashAFIfChanged(ctx, compileDerefPointer(ctx, e)) :+ ZLine.ld8(ZRegister.MEM_HL, ZRegister.A)
|
||||
case e@DerefExpression(_, _, vol, targetType) =>
|
||||
val el = if (vol) Elidability.Volatile else Elidability.Elidable
|
||||
val lo = stashAFIfChanged(ctx, compileDerefPointer(ctx, e)) :+ ZLine.ld8(ZRegister.MEM_HL, ZRegister.A).copy(elidability = el)
|
||||
if (targetType.size == 1) lo
|
||||
else if (targetType.size == 2) {
|
||||
lo ++ List(ZLine.register(INC_16, ZRegister.HL)) ++
|
||||
signExtendHighestByte(ctx, ZRegister.A, signedSource = signedSource) ++
|
||||
List(ZLine.ld8(ZRegister.MEM_HL, ZRegister.A))
|
||||
List(ZLine.ld8(ZRegister.MEM_HL, ZRegister.A).copy(elidability = el))
|
||||
} else {
|
||||
lo ++ signExtendHighestByte(ctx, ZRegister.A, signedSource = signedSource) ++ List.tabulate(targetType.size - 1)(_ => List(
|
||||
ZLine.register(INC_16, ZRegister.HL),
|
||||
ZLine.ld8(ZRegister.MEM_HL, ZRegister.A)
|
||||
ZLine.ld8(ZRegister.MEM_HL, ZRegister.A).copy(elidability = el)
|
||||
)).flatten
|
||||
}
|
||||
//TODO
|
||||
@ -1889,10 +1895,11 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
|
||||
def storeConstantWord(ctx: CompilationContext, target: LhsExpression, source: Constant, signedSource: Boolean): List[ZLine] = {
|
||||
target match {
|
||||
case e: DerefExpression =>
|
||||
val el = if(e.isVolatile) Elidability.Volatile else Elidability.Elidable
|
||||
compileDerefPointer(ctx, e) ++ List(
|
||||
ZLine.ldImm8(ZRegister.MEM_HL, source.loByte),
|
||||
ZLine.ldImm8(ZRegister.MEM_HL, source.loByte).copy(elidability = el),
|
||||
ZLine.register(INC_16, ZRegister.HL),
|
||||
ZLine.ldImm8(ZRegister.MEM_HL, source.hiByte))
|
||||
ZLine.ldImm8(ZRegister.MEM_HL, source.hiByte).copy(elidability = el))
|
||||
case _ => ZLine.ldImm16(ZRegister.HL, source) :: storeHL(ctx, target, signedSource)
|
||||
}
|
||||
}
|
||||
@ -1958,6 +1965,7 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
|
||||
Z80ExpressionCompiler.stashHLIfChanged(ctx, ZLine.ld8(ZRegister.A, ZRegister.L) :: storeA(ctx, lo, signedSource)) ++
|
||||
(ZLine.ld8(ZRegister.A, ZRegister.H) :: storeA(ctx, hi, signedSource))
|
||||
case e:DerefExpression =>
|
||||
val el = if(e.isVolatile) Elidability.Volatile else Elidability.Elidable
|
||||
if (ctx.options.flag(CompilationFlag.EmitIntel8085Opcodes) && ctx.options.flag(CompilationFlag.EmitIllegals)) {
|
||||
List(ZLine.register(PUSH, ZRegister.HL)) ++ fixTsx(ctx, compileDerefPointer(ctx, e)) ++ List(
|
||||
ZLine.register(POP, ZRegister.DE),
|
||||
@ -1968,20 +1976,20 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
|
||||
List(ZLine.register(INC_16, DE)) ++
|
||||
List.fill(e.targetType.size - 2)(List(
|
||||
ZLine.register(INC_16, DE),
|
||||
ZLine.ld8(MEM_DE, A)
|
||||
ZLine.ld8(MEM_DE, A).copy(elidability = el)
|
||||
)).flatten
|
||||
else Nil)
|
||||
} else {
|
||||
List(ZLine.register(PUSH, ZRegister.HL)) ++ fixTsx(ctx, compileDerefPointer(ctx, e)) ++ List(
|
||||
ZLine.register(POP, ZRegister.BC),
|
||||
ZLine.ld8(ZRegister.MEM_HL, ZRegister.C),
|
||||
ZLine.ld8(ZRegister.MEM_HL, ZRegister.C).copy(elidability = el),
|
||||
ZLine.register(INC_16, ZRegister.HL),
|
||||
ZLine.ld8(ZRegister.MEM_HL, ZRegister.B)) ++
|
||||
ZLine.ld8(ZRegister.MEM_HL, ZRegister.B).copy(elidability = el)) ++
|
||||
(if (e.targetType.size > 2)
|
||||
signExtendHighestByte(ctx, B) ++
|
||||
List.fill(e.targetType.size - 2)(List(
|
||||
ZLine.register(INC_16, HL),
|
||||
ZLine.ld8(MEM_HL, A)
|
||||
ZLine.ld8(MEM_HL, A).copy(elidability = el)
|
||||
)).flatten
|
||||
else Nil)
|
||||
}
|
||||
@ -2298,16 +2306,17 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
|
||||
case _ => List(ZLine.ldImm8(ZRegister.A, 0)) // TODO: signed large types?
|
||||
}
|
||||
}
|
||||
case e@DerefExpression(_, _, _) =>
|
||||
case e: DerefExpression =>
|
||||
val el = if(e.isVolatile) Elidability.Volatile else Elidability.Elidable
|
||||
import ZRegister._
|
||||
val prepareHL = compileDerefPointer(ctx, e)
|
||||
List.tabulate(size) { i =>
|
||||
if (i == 0) {
|
||||
prepareHL :+ ZLine.ld8(A, MEM_HL)
|
||||
prepareHL :+ ZLine.ld8(A, MEM_HL).copy(elidability = el)
|
||||
} else if (i < e.targetType.size) {
|
||||
List(ZLine.register(INC_16, HL), ZLine.ld8(A, MEM_HL))
|
||||
List(ZLine.register(INC_16, HL), ZLine.ld8(A, MEM_HL).copy(elidability = el))
|
||||
} else if (e.targetType.isSigned) {
|
||||
signExtendHighestByte(ctx, ZRegister.MEM_HL)
|
||||
signExtendHighestByte(ctx, ZRegister.MEM_HL, elidability = el)
|
||||
} else {
|
||||
List(ZLine.ldImm8(A, 0))
|
||||
}
|
||||
@ -2383,15 +2392,16 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
|
||||
Nil
|
||||
}
|
||||
}
|
||||
case de@DerefExpression(inner, offset, targetType) =>
|
||||
case de@DerefExpression(inner, offset, isVolatile, targetType) =>
|
||||
val el = if(isVolatile) Elidability.Volatile else Elidability.Elidable
|
||||
import ZRegister._
|
||||
val prepareHL = compileDerefPointer(ctx, de)
|
||||
List.tabulate(size) { i =>
|
||||
if (i == 0) {
|
||||
prepareHL :+ ZLine.ld8(MEM_HL, A)
|
||||
prepareHL :+ ZLine.ld8(MEM_HL, A).copy(elidability = el)
|
||||
} else if (i < targetType.size) {
|
||||
if (includeStep) List(ZLine.register(INC_16, HL), ZLine.ld8(MEM_HL, A))
|
||||
else List(ZLine.ld8(MEM_HL, A))
|
||||
if (includeStep) List(ZLine.register(INC_16, HL), ZLine.ld8(MEM_HL, A).copy(elidability = el))
|
||||
else List(ZLine.ld8(MEM_HL, A).copy(elidability = el))
|
||||
} else Nil
|
||||
}
|
||||
case _ =>
|
||||
|
@ -5,6 +5,7 @@ import millfork.compiler.CompilationContext
|
||||
import millfork.node._
|
||||
import ZOpcode._
|
||||
import millfork.CompilationFlag
|
||||
import millfork.assembly.Elidability
|
||||
import millfork.env._
|
||||
import millfork.error.ConsoleLogger
|
||||
|
||||
@ -485,24 +486,25 @@ object ZBuiltIns {
|
||||
|
||||
def performLongInPlace(ctx: CompilationContext, lhs: LhsExpression, rhs: Expression, opcodeFirst: ZOpcode.Value, opcodeLater: ZOpcode.Value, size: Int, decimal: Boolean = false): List[ZLine] = {
|
||||
lhs match {
|
||||
case dx@DerefExpression(inner, offset, targetType) =>
|
||||
case dx@DerefExpression(inner, offset, isVolatile, targetType) =>
|
||||
val el = if(isVolatile) Elidability.Volatile else Elidability.Elidable
|
||||
val env = ctx.env
|
||||
if (targetType.size == 2) {
|
||||
if (opcodeFirst == ADD && !decimal && ctx.options.flag(CompilationFlag.EmitZ80Opcodes)) {
|
||||
val l = Z80ExpressionCompiler.compileToBC(ctx, inner #+# offset)
|
||||
val r = Z80ExpressionCompiler.compileToDE(ctx, rhs)
|
||||
val s = List(
|
||||
ZLine.ld8(ZRegister.A, ZRegister.MEM_BC),
|
||||
ZLine.ld8(ZRegister.A, ZRegister.MEM_BC).copy(elidability = el),
|
||||
ZLine.ld8(ZRegister.L, ZRegister.A),
|
||||
ZLine.register(INC_16, ZRegister.BC),
|
||||
ZLine.ld8(ZRegister.A, ZRegister.MEM_BC),
|
||||
ZLine.ld8(ZRegister.A, ZRegister.MEM_BC).copy(elidability = el),
|
||||
ZLine.ld8(ZRegister.H, ZRegister.A),
|
||||
ZLine.registers(ADD_16, ZRegister.HL, ZRegister.DE),
|
||||
ZLine.ld8(ZRegister.A, ZRegister.H),
|
||||
ZLine.ld8(ZRegister.MEM_BC, ZRegister.A),
|
||||
ZLine.ld8(ZRegister.MEM_BC, ZRegister.A).copy(elidability = el),
|
||||
ZLine.register(DEC_16, ZRegister.BC),
|
||||
ZLine.ld8(ZRegister.A, ZRegister.L),
|
||||
ZLine.ld8(ZRegister.MEM_BC, ZRegister.A),
|
||||
ZLine.ld8(ZRegister.MEM_BC, ZRegister.A).copy(elidability = el),
|
||||
)
|
||||
if (!r.exists(Z80ExpressionCompiler.changesBC)) {
|
||||
return l ++ r ++ s
|
||||
@ -517,15 +519,15 @@ object ZBuiltIns {
|
||||
val s = if (opcodeFirst == SUB && decimal) {
|
||||
if (ctx.options.flag(CompilationFlag.EmitExtended80Opcodes)) {
|
||||
List(
|
||||
ZLine.ld8(ZRegister.A, ZRegister.MEM_HL),
|
||||
ZLine.ld8(ZRegister.A, ZRegister.MEM_HL).copy(elidability = el),
|
||||
ZLine.register(SUB, ZRegister.E),
|
||||
ZLine.implied(DAA),
|
||||
ZLine.ld8(ZRegister.MEM_HL, ZRegister.A),
|
||||
ZLine.ld8(ZRegister.MEM_HL, ZRegister.A).copy(elidability = el),
|
||||
ZLine.register(INC_16, ZRegister.HL),
|
||||
ZLine.ld8(ZRegister.A, ZRegister.MEM_HL),
|
||||
ZLine.ld8(ZRegister.A, ZRegister.MEM_HL).copy(elidability = el),
|
||||
ZLine.register(SBC, ZRegister.D),
|
||||
ZLine.implied(DAA),
|
||||
ZLine.ld8(ZRegister.MEM_HL, ZRegister.A),
|
||||
ZLine.ld8(ZRegister.MEM_HL, ZRegister.A).copy(elidability = el),
|
||||
)
|
||||
} else {
|
||||
ctx.log.error("Decimal subtraction from such a complex LHS is not yet supported", dx.position)
|
||||
@ -533,25 +535,25 @@ object ZBuiltIns {
|
||||
}
|
||||
} else if (opcodeFirst == ADD && decimal) {
|
||||
List(
|
||||
ZLine.ld8(ZRegister.A, ZRegister.MEM_HL),
|
||||
ZLine.ld8(ZRegister.A, ZRegister.MEM_HL).copy(elidability = el),
|
||||
ZLine.register(ADD, ZRegister.E),
|
||||
ZLine.implied(DAA),
|
||||
ZLine.ld8(ZRegister.MEM_HL, ZRegister.A),
|
||||
ZLine.ld8(ZRegister.MEM_HL, ZRegister.A).copy(elidability = el),
|
||||
ZLine.register(INC_16, ZRegister.HL),
|
||||
ZLine.ld8(ZRegister.A, ZRegister.MEM_HL),
|
||||
ZLine.ld8(ZRegister.A, ZRegister.MEM_HL).copy(elidability = el),
|
||||
ZLine.register(ADC, ZRegister.D),
|
||||
ZLine.implied(DAA),
|
||||
ZLine.ld8(ZRegister.MEM_HL, ZRegister.A),
|
||||
ZLine.ld8(ZRegister.MEM_HL, ZRegister.A).copy(elidability = el),
|
||||
)
|
||||
} else {
|
||||
List(
|
||||
ZLine.ld8(ZRegister.A, ZRegister.MEM_HL),
|
||||
ZLine.ld8(ZRegister.A, ZRegister.MEM_HL).copy(elidability = el),
|
||||
ZLine.register(opcodeFirst, ZRegister.E),
|
||||
ZLine.ld8(ZRegister.MEM_HL, ZRegister.A),
|
||||
ZLine.ld8(ZRegister.MEM_HL, ZRegister.A).copy(elidability = el),
|
||||
ZLine.register(INC_16, ZRegister.HL),
|
||||
ZLine.ld8(ZRegister.A, ZRegister.MEM_HL),
|
||||
ZLine.ld8(ZRegister.A, ZRegister.MEM_HL).copy(elidability = el),
|
||||
ZLine.register(opcodeLater, ZRegister.D),
|
||||
ZLine.ld8(ZRegister.MEM_HL, ZRegister.A),
|
||||
ZLine.ld8(ZRegister.MEM_HL, ZRegister.A).copy(elidability = el),
|
||||
)
|
||||
}
|
||||
if (!r.exists(Z80ExpressionCompiler.changesHL)) {
|
||||
@ -575,17 +577,17 @@ object ZBuiltIns {
|
||||
result ++= sourceBytes(i)
|
||||
result += ZLine.ld8(ZRegister.E, ZRegister.A)
|
||||
if (i != 0) result += ZLine.register(POP, ZRegister.AF)
|
||||
result += ZLine.ld8(ZRegister.A, ZRegister.MEM_HL)
|
||||
result += ZLine.ld8(ZRegister.A, ZRegister.MEM_HL).copy(elidability = el)
|
||||
result += ZLine.register(if (i == 0) opcodeFirst else opcodeLater, ZRegister.E)
|
||||
result += ZLine.ld8(ZRegister.MEM_HL, ZRegister.A)
|
||||
result += ZLine.ld8(ZRegister.MEM_HL, ZRegister.A).copy(elidability = el)
|
||||
if (i != size - 1) result += ZLine.register(INC_16, ZRegister.HL)
|
||||
}
|
||||
} else {
|
||||
for (i <- 0 until size) {
|
||||
result ++= sourceBytes(i)
|
||||
result += ZLine.register(if (i==0) opcodeFirst else opcodeLater, ZRegister.MEM_HL)
|
||||
result += ZLine.register(if (i==0) opcodeFirst else opcodeLater, ZRegister.MEM_HL).copy(elidability = el)
|
||||
if (decimal) result += ZLine.implied(DAA)
|
||||
result += ZLine.ld8(ZRegister.MEM_HL, ZRegister.A)
|
||||
result += ZLine.ld8(ZRegister.MEM_HL, ZRegister.A).copy(elidability = el)
|
||||
if (i != size -1) result += ZLine.register(INC_16, ZRegister.HL)
|
||||
}
|
||||
}
|
||||
|
206
src/main/scala/millfork/env/Environment.scala
vendored
206
src/main/scala/millfork/env/Environment.scala
vendored
@ -11,6 +11,7 @@ import millfork.node._
|
||||
import millfork.output._
|
||||
import org.apache.commons.lang3.StringUtils
|
||||
|
||||
import java.nio.file.Files
|
||||
import scala.collection.mutable
|
||||
import scala.collection.mutable.ListBuffer
|
||||
|
||||
@ -549,8 +550,8 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
|
||||
BranchingOpcodeMapping(Opcode.BPL, IfFlagClear(ZFlag.S), MOpcode.BPL),
|
||||
BranchingOpcodeMapping(Opcode.BMI, IfFlagSet(ZFlag.S), MOpcode.BMI)),
|
||||
None)
|
||||
val byte_and_pointer$ = StructType("byte_and_pointer$", List(FieldDesc("byte", "zp", None), FieldDesc("pointer", "branch", None)), NoAlignment)
|
||||
val hudson_transfer$ = StructType("hudson_transfer$", List(FieldDesc("word", "a", None), FieldDesc("word", "b", None), FieldDesc("word", "c", None)), NoAlignment)
|
||||
val byte_and_pointer$ = StructType("byte_and_pointer$", List(FieldDesc("byte", "zp", false, None), FieldDesc("pointer", "branch", false, None)), NoAlignment)
|
||||
val hudson_transfer$ = StructType("hudson_transfer$", List(FieldDesc("word", "a", false, None), FieldDesc("word", "b", false, None), FieldDesc("word", "c", false, None)), NoAlignment)
|
||||
addThing(byte_and_pointer$, None)
|
||||
addThing(hudson_transfer$, None)
|
||||
Environment.constOnlyBuiltinFunction.foreach(n => addThing(ConstOnlyCallable(n), None))
|
||||
@ -1155,7 +1156,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
|
||||
case s: CompoundVariableType =>
|
||||
if (s.mutableAlignment ne null) return s.mutableAlignment
|
||||
var alignment = s.baseAlignment
|
||||
for( ResolvedFieldDesc(fieldType, _, _) <- s.mutableFieldsWithTypes) {
|
||||
for( ResolvedFieldDesc(fieldType, _, _, _) <- s.mutableFieldsWithTypes) {
|
||||
val a = getTypeAlignment(fieldType, path + name)
|
||||
if (a eq null) return null
|
||||
alignment = alignment & a
|
||||
@ -1175,7 +1176,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
|
||||
else {
|
||||
val newPath = path + name
|
||||
var sum = 0
|
||||
for( ResolvedFieldDesc(fieldType, _, indexTypeAndCount) <- s.mutableFieldsWithTypes) {
|
||||
for( ResolvedFieldDesc(fieldType, _, _, indexTypeAndCount) <- s.mutableFieldsWithTypes) {
|
||||
val fieldSize = getTypeSize(fieldType, newPath) * indexTypeAndCount.fold(1)(_._2)
|
||||
if (fieldSize < 0) return -1
|
||||
sum = fieldType.alignment.roundSizeUp(sum)
|
||||
@ -1188,7 +1189,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
|
||||
}
|
||||
val b = get[Type]("byte")
|
||||
var offset = 0
|
||||
for( ResolvedFieldDesc(fieldType, fieldName, indexTypeAndCount) <- s.mutableFieldsWithTypes) {
|
||||
for( ResolvedFieldDesc(fieldType, fieldName, _, indexTypeAndCount) <- s.mutableFieldsWithTypes) {
|
||||
offset = fieldType.alignment.roundSizeUp(offset)
|
||||
addThing(ConstantThing(s"$name.$fieldName.offset", NumericConstant(offset, 1), b), None)
|
||||
offset += getTypeSize(fieldType, newPath) * indexTypeAndCount.fold(1)(_._2)
|
||||
@ -1201,7 +1202,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
|
||||
else {
|
||||
val newPath = path + name
|
||||
var max = 0
|
||||
for( ResolvedFieldDesc(fieldType, _, indexTypeAndCount) <- s.mutableFieldsWithTypes) {
|
||||
for( ResolvedFieldDesc(fieldType, _, _, indexTypeAndCount) <- s.mutableFieldsWithTypes) {
|
||||
val fieldSize = getTypeSize(fieldType, newPath) * indexTypeAndCount.fold(1)(_._2)
|
||||
if (fieldSize < 0) return -1
|
||||
max = max max fieldSize
|
||||
@ -1211,7 +1212,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
|
||||
log.error(s"Union `$name` is larger than 255 bytes")
|
||||
}
|
||||
val b = get[Type]("byte")
|
||||
for (ResolvedFieldDesc(fieldType, fieldName, _) <- s.mutableFieldsWithTypes) {
|
||||
for (ResolvedFieldDesc(fieldType, fieldName, _, _) <- s.mutableFieldsWithTypes) {
|
||||
addThing(ConstantThing(s"$name.$fieldName.offset", NumericConstant(0, 1), b), None)
|
||||
}
|
||||
max
|
||||
@ -1613,9 +1614,9 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
|
||||
addThing(v, stmt.position)
|
||||
registerAddressConstant(v, stmt.position, options, Some(typ))
|
||||
val addr = v.toAddress
|
||||
for(Subvariable(suffix, offset, t, arraySize) <- getSubvariables(typ)) {
|
||||
for(Subvariable(suffix, offset, vol, t, arraySize) <- getSubvariables(typ)) {
|
||||
if (arraySize.isDefined) ??? // TODO
|
||||
val subv = RelativeVariable(v.name + suffix, addr + offset, t, zeropage = zp, None, isVolatile = v.isVolatile)
|
||||
val subv = RelativeVariable(v.name + suffix, addr + offset, t, zeropage = zp, None, isVolatile = v.isVolatile || vol)
|
||||
addThing(subv, stmt.position)
|
||||
registerAddressConstant(subv, stmt.position, options, Some(t))
|
||||
}
|
||||
@ -1657,7 +1658,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
|
||||
List.fill(tt.size)(LiteralExpression(0, 1))
|
||||
} else {
|
||||
tt.fields.zip(fieldValues).flatMap {
|
||||
case (FieldDesc(fieldTypeName, _, count), expr) =>
|
||||
case (FieldDesc(fieldTypeName, _, _, count), expr) =>
|
||||
// TODO: handle array fields
|
||||
if (count.isDefined) ???
|
||||
extractStructArrayContents(expr, Some(get[Type](fieldTypeName)))
|
||||
@ -1694,7 +1695,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
|
||||
List.fill(tt.size)(LiteralExpression(0, 1))
|
||||
} else {
|
||||
tt.fields.zip(fieldValues).flatMap {
|
||||
case (FieldDesc(fieldTypeName, _, count), expr) =>
|
||||
case (FieldDesc(fieldTypeName, _, _, count), expr) =>
|
||||
// TODO: handle array fields
|
||||
if (count.isDefined) ???
|
||||
extractStructArrayContents(expr, Some(get[Type](fieldTypeName)))
|
||||
@ -1738,7 +1739,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
|
||||
case IndexedExpression(a, i) =>
|
||||
constantsThatShouldHaveBeenImportedEarlier.addBinding(a, node.position)
|
||||
markAsConstantsThatShouldHaveBeenImportedEarlier(i)
|
||||
case DerefExpression(p, _, _) =>
|
||||
case DerefExpression(p, _, _, _) =>
|
||||
markAsConstantsThatShouldHaveBeenImportedEarlier(p)
|
||||
case DerefDebuggingExpression(p, _) =>
|
||||
markAsConstantsThatShouldHaveBeenImportedEarlier(p)
|
||||
@ -2129,7 +2130,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
|
||||
val constantValue = rawConstantValue.fitInto(typ)
|
||||
if (constantValue.requiredSize > typ.size) log.error(s"`$name` is has an invalid value: not in the range of `$typ`", position)
|
||||
addThing(ConstantThing(prefix + name, constantValue, typ), stmt.position)
|
||||
for(Subvariable(suffix, offset, t, arraySize) <- getSubvariables(typ)) {
|
||||
for(Subvariable(suffix, offset, vol, t, arraySize) <- getSubvariables(typ)) {
|
||||
if (arraySize.isDefined) {
|
||||
log.error(s"Constants of type ${t.name} that contains array fields are not supported", stmt.position)
|
||||
} else {
|
||||
@ -2210,7 +2211,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
|
||||
variable match {
|
||||
case v: StackVariable =>
|
||||
addThing(localName, v, position)
|
||||
for (Subvariable(suffix, offset, t, arraySize) <- getSubvariables(v.typ)) {
|
||||
for (Subvariable(suffix, offset, vol, t, arraySize) <- getSubvariables(v.typ)) {
|
||||
if (arraySize.isDefined) {
|
||||
log.error(s"Cannot create a stack variable $localName of compound type ${v.typ.name} that contains an array member", position)
|
||||
} else {
|
||||
@ -2219,10 +2220,10 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
|
||||
}
|
||||
case v: MemoryVariable =>
|
||||
addThing(localName, v, position)
|
||||
for (Subvariable(suffix, offset, t, arrayIndexTypeAndSize) <- getSubvariables(v.typ)) {
|
||||
for (Subvariable(suffix, offset, vol, t, arrayIndexTypeAndSize) <- getSubvariables(v.typ)) {
|
||||
arrayIndexTypeAndSize match {
|
||||
case None =>
|
||||
val subv = RelativeVariable(prefix + localName + suffix, v.toAddress + offset, t, zeropage = v.zeropage, declaredBank = v.declaredBank, isVolatile = v.isVolatile)
|
||||
val subv = RelativeVariable(prefix + localName + suffix, v.toAddress + offset, t, zeropage = v.zeropage, declaredBank = v.declaredBank, isVolatile = v.isVolatile || vol)
|
||||
addThing(subv, position)
|
||||
registerAddressConstant(subv, position, options, Some(t))
|
||||
case Some((indexType, elemCount)) =>
|
||||
@ -2234,10 +2235,10 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
|
||||
case v: VariableInMemory =>
|
||||
addThing(localName, v, position)
|
||||
addThing(ConstantThing(v.name + "`", v.toAddress, get[Type]("word")), position)
|
||||
for (Subvariable(suffix, offset, t, arrayIndexTypeAndSize) <- getSubvariables(v.typ)) {
|
||||
for (Subvariable(suffix, offset, vol, t, arrayIndexTypeAndSize) <- getSubvariables(v.typ)) {
|
||||
arrayIndexTypeAndSize match {
|
||||
case None =>
|
||||
val subv = RelativeVariable(prefix + localName + suffix, v.toAddress + offset, t, zeropage = v.zeropage, declaredBank = v.declaredBank, isVolatile = v.isVolatile)
|
||||
val subv = RelativeVariable(prefix + localName + suffix, v.toAddress + offset, t, zeropage = v.zeropage, declaredBank = v.declaredBank, isVolatile = v.isVolatile || vol)
|
||||
addThing(subv, position)
|
||||
registerAddressConstant(subv, position, options, Some(t))
|
||||
case Some((indexType, elemCount)) =>
|
||||
@ -2250,6 +2251,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
|
||||
}
|
||||
}
|
||||
|
||||
//noinspection NameBooleanParameters
|
||||
def getSubvariables(typ: Type): List[Subvariable] = {
|
||||
val b = get[VariableType]("byte")
|
||||
val w = get[VariableType]("word")
|
||||
@ -2257,109 +2259,109 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
|
||||
if (options.isBigEndian) {
|
||||
throw new IllegalArgumentException("__reg$type on 6809???")
|
||||
}
|
||||
return Subvariable(".lo", 0, b) ::
|
||||
Subvariable(".hi", 1, b) ::
|
||||
Subvariable(".loword", 0, w) ::
|
||||
Subvariable(".loword.lo", 0, b) ::
|
||||
Subvariable(".loword.hi", 1, b) ::
|
||||
Subvariable(".b2b3", 2, w) ::
|
||||
Subvariable(".b2b3.lo", 2, b) ::
|
||||
Subvariable(".b2b3.hi", 3, b) ::
|
||||
List.tabulate(typ.size) { i => Subvariable(".b" + i, i, b) }
|
||||
return Subvariable(".lo", 0, false, b) ::
|
||||
Subvariable(".hi", 1, false, b) ::
|
||||
Subvariable(".loword", 0, false, w) ::
|
||||
Subvariable(".loword.lo", 0, false, b) ::
|
||||
Subvariable(".loword.hi", 1, false, b) ::
|
||||
Subvariable(".b2b3", 2, false, w) ::
|
||||
Subvariable(".b2b3.lo", 2, false, b) ::
|
||||
Subvariable(".b2b3.hi", 3, false, b) ::
|
||||
List.tabulate(typ.size) { i => Subvariable(".b" + i, i, false, b) }
|
||||
}
|
||||
typ match {
|
||||
case _: PlainType => typ.size match {
|
||||
case 2 => if (options.isBigEndian) List(
|
||||
Subvariable(".lo", 1, b),
|
||||
Subvariable(".hi", 0, b)
|
||||
Subvariable(".lo", 1, false, b),
|
||||
Subvariable(".hi", 0, false, b)
|
||||
) else List(
|
||||
Subvariable(".lo", 0, b),
|
||||
Subvariable(".hi", 1, b))
|
||||
Subvariable(".lo", 0, false, b),
|
||||
Subvariable(".hi", 1, false, b))
|
||||
case 3 => if (options.isBigEndian) List(
|
||||
Subvariable(".loword", 1, w),
|
||||
Subvariable(".loword.lo", 2, b),
|
||||
Subvariable(".loword.hi", 1, b),
|
||||
Subvariable(".hiword", 0, w),
|
||||
Subvariable(".hiword.lo", 1, b),
|
||||
Subvariable(".hiword.hi", 0, b),
|
||||
Subvariable(".lo", 2, b),
|
||||
Subvariable(".b0", 2, b),
|
||||
Subvariable(".b1", 1, b),
|
||||
Subvariable(".b2", 0, b)
|
||||
Subvariable(".loword", 1, false, w),
|
||||
Subvariable(".loword.lo", 2, false, b),
|
||||
Subvariable(".loword.hi", 1, false, b),
|
||||
Subvariable(".hiword", 0, false, w),
|
||||
Subvariable(".hiword.lo", 1, false, b),
|
||||
Subvariable(".hiword.hi", 0, false, b),
|
||||
Subvariable(".lo", 2, false, b),
|
||||
Subvariable(".b0", 2, false, b),
|
||||
Subvariable(".b1", 1, false, b),
|
||||
Subvariable(".b2", 0, false, b)
|
||||
) else List(
|
||||
Subvariable(".loword", 0, w),
|
||||
Subvariable(".loword.lo", 0, b),
|
||||
Subvariable(".loword.hi", 1, b),
|
||||
Subvariable(".hiword", 1, w),
|
||||
Subvariable(".hiword.lo", 1, b),
|
||||
Subvariable(".hiword.hi", 2, b),
|
||||
Subvariable(".lo", 0, b),
|
||||
Subvariable(".b0", 0, b),
|
||||
Subvariable(".b1", 1, b),
|
||||
Subvariable(".b2", 2, b))
|
||||
Subvariable(".loword", 0, false, w),
|
||||
Subvariable(".loword.lo", 0, false, b),
|
||||
Subvariable(".loword.hi", 1, false, b),
|
||||
Subvariable(".hiword", 1, false, w),
|
||||
Subvariable(".hiword.lo", 1, false, b),
|
||||
Subvariable(".hiword.hi", 2, false, b),
|
||||
Subvariable(".lo", 0, false, b),
|
||||
Subvariable(".b0", 0, false, b),
|
||||
Subvariable(".b1", 1, false, b),
|
||||
Subvariable(".b2", 2, false, b))
|
||||
case 4 => if (options.isBigEndian) List(
|
||||
Subvariable(".loword", 2, w),
|
||||
Subvariable(".hiword", 0, w),
|
||||
Subvariable(".loword.lo", 3, b),
|
||||
Subvariable(".loword.hi", 2, b),
|
||||
Subvariable(".hiword.lo", 1, b),
|
||||
Subvariable(".hiword.hi", 0, b),
|
||||
Subvariable(".lo", 3, b),
|
||||
Subvariable(".b0", 3, b),
|
||||
Subvariable(".b1", 2, b),
|
||||
Subvariable(".b2", 1, b),
|
||||
Subvariable(".b3", 0, b)
|
||||
Subvariable(".loword", 2, false, w),
|
||||
Subvariable(".hiword", 0, false, w),
|
||||
Subvariable(".loword.lo", 3, false, b),
|
||||
Subvariable(".loword.hi", 2, false, b),
|
||||
Subvariable(".hiword.lo", 1, false, b),
|
||||
Subvariable(".hiword.hi", 0, false, b),
|
||||
Subvariable(".lo", 3, false, b),
|
||||
Subvariable(".b0", 3, false, b),
|
||||
Subvariable(".b1", 2, false, b),
|
||||
Subvariable(".b2", 1, false, b),
|
||||
Subvariable(".b3", 0, false, b)
|
||||
) else List(
|
||||
Subvariable(".loword", 0, w),
|
||||
Subvariable(".hiword", 2, w),
|
||||
Subvariable(".loword.lo", 0, b),
|
||||
Subvariable(".loword.hi", 1, b),
|
||||
Subvariable(".hiword.lo", 2, b),
|
||||
Subvariable(".hiword.hi", 3, b),
|
||||
Subvariable(".lo", 0, b),
|
||||
Subvariable(".b0", 0, b),
|
||||
Subvariable(".b1", 1, b),
|
||||
Subvariable(".b2", 2, b),
|
||||
Subvariable(".b3", 3, b)
|
||||
Subvariable(".loword", 0, false, w),
|
||||
Subvariable(".hiword", 2, false, w),
|
||||
Subvariable(".loword.lo", 0, false, b),
|
||||
Subvariable(".loword.hi", 1, false, b),
|
||||
Subvariable(".hiword.lo", 2, false, b),
|
||||
Subvariable(".hiword.hi", 3, false, b),
|
||||
Subvariable(".lo", 0, false, b),
|
||||
Subvariable(".b0", 0, false, b),
|
||||
Subvariable(".b1", 1, false, b),
|
||||
Subvariable(".b2", 2, false, b),
|
||||
Subvariable(".b3", 3, false, b)
|
||||
)
|
||||
case sz if sz > 4 =>
|
||||
if (options.isBigEndian) {
|
||||
Subvariable(".lo", sz - 1, b) ::
|
||||
Subvariable(".loword", sz - 2, w) ::
|
||||
Subvariable(".loword.lo", sz - 1, b) ::
|
||||
Subvariable(".loword.hi", sz - 2, b) ::
|
||||
List.tabulate(sz){ i => Subvariable(".b" + i, sz - 1 - i, b) }
|
||||
Subvariable(".lo", sz - 1, false, b) ::
|
||||
Subvariable(".loword", sz - 2, false, w) ::
|
||||
Subvariable(".loword.lo", sz - 1, false, b) ::
|
||||
Subvariable(".loword.hi", sz - 2, false, b) ::
|
||||
List.tabulate(sz){ i => Subvariable(".b" + i, sz - 1 - i, false, b) }
|
||||
} else {
|
||||
Subvariable(".lo", 0, b) ::
|
||||
Subvariable(".loword", 0, w) ::
|
||||
Subvariable(".loword.lo", 0, b) ::
|
||||
Subvariable(".loword.hi", 1, b) ::
|
||||
List.tabulate(sz){ i => Subvariable(".b" + i, i, b) }
|
||||
Subvariable(".lo", 0, false, b) ::
|
||||
Subvariable(".loword", 0, false, w) ::
|
||||
Subvariable(".loword.lo", 0, false, b) ::
|
||||
Subvariable(".loword.hi", 1, false, b) ::
|
||||
List.tabulate(sz){ i => Subvariable(".b" + i, i, false, b) }
|
||||
}
|
||||
case _ => Nil
|
||||
}
|
||||
case InterruptPointerType | _: FunctionPointerType | _: PointerType => if (options.isBigEndian) List(
|
||||
Subvariable(".raw", 0, get[VariableType]("pointer")),
|
||||
Subvariable(".raw.lo", 1, b),
|
||||
Subvariable(".raw.hi", 0, b),
|
||||
Subvariable(".lo", 1, b),
|
||||
Subvariable(".hi", 0, b)
|
||||
Subvariable(".raw", 0, false, get[VariableType]("pointer")),
|
||||
Subvariable(".raw.lo", 1, false, b),
|
||||
Subvariable(".raw.hi", 0, false, b),
|
||||
Subvariable(".lo", 1, false, b),
|
||||
Subvariable(".hi", 0, false, b)
|
||||
) else List(
|
||||
Subvariable(".raw", 0, get[VariableType]("pointer")),
|
||||
Subvariable(".raw.lo", 0, b),
|
||||
Subvariable(".raw.hi", 1, b),
|
||||
Subvariable(".lo", 0, b),
|
||||
Subvariable(".hi", 1, b))
|
||||
Subvariable(".raw", 0, false, get[VariableType]("pointer")),
|
||||
Subvariable(".raw.lo", 0, false, b),
|
||||
Subvariable(".raw.hi", 1, false, b),
|
||||
Subvariable(".lo", 0, false, b),
|
||||
Subvariable(".hi", 1, false, b))
|
||||
case s: StructType =>
|
||||
val builder = new ListBuffer[Subvariable]
|
||||
var offset = 0
|
||||
for(ResolvedFieldDesc(typ, fieldName, indexTypeAndCount) <- s.mutableFieldsWithTypes) {
|
||||
for(ResolvedFieldDesc(typ, fieldName, vol, indexTypeAndCount) <- s.mutableFieldsWithTypes) {
|
||||
offset = getTypeAlignment(typ, Set()).roundSizeUp(offset)
|
||||
val suffix = "." + fieldName
|
||||
builder += Subvariable(suffix, offset, typ, indexTypeAndCount)
|
||||
builder += Subvariable(suffix, offset, vol, typ, indexTypeAndCount)
|
||||
if (indexTypeAndCount.isEmpty) {
|
||||
builder ++= getSubvariables(typ).map {
|
||||
case Subvariable(innerSuffix, innerOffset, innerType, innerSize) => Subvariable(suffix + innerSuffix, offset + innerOffset, innerType, innerSize)
|
||||
case Subvariable(innerSuffix, innerOffset, innerVolatile, innerType, innerSize) => Subvariable(suffix + innerSuffix, offset + innerOffset, vol || innerVolatile, innerType, innerSize)
|
||||
}
|
||||
}
|
||||
offset += typ.size * indexTypeAndCount.fold(1)(_._2)
|
||||
@ -2368,13 +2370,13 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
|
||||
builder.toList
|
||||
case s: UnionType =>
|
||||
val builder = new ListBuffer[Subvariable]
|
||||
for(FieldDesc(typeName, fieldName, arraySize) <- s.fields) {
|
||||
for(FieldDesc(typeName, fieldName, vol1, arraySize) <- s.fields) {
|
||||
val typ = get[VariableType](typeName)
|
||||
val suffix = "." + fieldName
|
||||
builder += Subvariable(suffix, 0, typ)
|
||||
builder += Subvariable(suffix, 0, vol1, typ)
|
||||
if (arraySize.isEmpty) {
|
||||
builder ++= getSubvariables(typ).map {
|
||||
case Subvariable(innerSuffix, innerOffset, innerType, innerSize) => Subvariable(suffix + innerSuffix, innerOffset, innerType, innerSize)
|
||||
case Subvariable(innerSuffix, innerOffset, vol2, innerType, innerSize) => Subvariable(suffix + innerSuffix, innerOffset, vol1 || vol2, innerType, innerSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2558,11 +2560,11 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
|
||||
things.values.foreach {
|
||||
case st@StructType(_, fields, _) =>
|
||||
st.mutableFieldsWithTypes = fields.map {
|
||||
case FieldDesc(tn, name, arraySize) => ResolvedFieldDesc(get[VariableType](tn), name, arraySize.map(getArrayFieldIndexTypeAndSize))
|
||||
case FieldDesc(tn, name, vol, arraySize) => ResolvedFieldDesc(get[VariableType](tn), name, vol, arraySize.map(getArrayFieldIndexTypeAndSize))
|
||||
}
|
||||
case ut@UnionType(_, fields, _) =>
|
||||
ut.mutableFieldsWithTypes = fields.map {
|
||||
case FieldDesc(tn, name, arraySize) => ResolvedFieldDesc(get[VariableType](tn), name, arraySize.map(getArrayFieldIndexTypeAndSize))
|
||||
case FieldDesc(tn, name, vol, arraySize) => ResolvedFieldDesc(get[VariableType](tn), name, vol, arraySize.map(getArrayFieldIndexTypeAndSize))
|
||||
}
|
||||
case _ => ()
|
||||
}
|
||||
@ -2745,7 +2747,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
|
||||
nameCheck(index)
|
||||
case DerefDebuggingExpression(inner, _) =>
|
||||
nameCheck(inner)
|
||||
case DerefExpression(inner, _, _) =>
|
||||
case DerefExpression(inner, _, _, _) =>
|
||||
nameCheck(inner)
|
||||
case IndirectFieldExpression(inner, firstIndices, fields) =>
|
||||
nameCheck(inner)
|
||||
|
2
src/main/scala/millfork/env/Thing.scala
vendored
2
src/main/scala/millfork/env/Thing.scala
vendored
@ -55,7 +55,7 @@ sealed trait VariableType extends Type {
|
||||
|
||||
}
|
||||
|
||||
case class Subvariable(suffix: String, offset: Int, typ: VariableType, arrayIndexTypeAndSize: Option[(VariableType, Int)] = None)
|
||||
case class Subvariable(suffix: String, offset: Int, isVolatile: Boolean, typ: VariableType, arrayIndexTypeAndSize: Option[(VariableType, Int)] = None)
|
||||
|
||||
case object VoidType extends Type {
|
||||
def size = 0
|
||||
|
@ -17,7 +17,7 @@ abstract class FloatFormat(val name: String, val hasInfinity: Boolean, val manti
|
||||
val alignment = env.get[Type]("word").alignment
|
||||
val size = format(0.0).size
|
||||
StructDefinitionStatement("float." + name,
|
||||
List.tabulate(size)(i => FieldDesc("byte", "b" + i, None)),
|
||||
List.tabulate(size)(i => FieldDesc("byte", "b" + i, false, None)),
|
||||
Some(if (size % 2 == 0) alignment else NoAlignment))
|
||||
}
|
||||
}
|
||||
|
@ -8,11 +8,13 @@ import millfork.assembly.z80.{NoRegisters, OneRegister, ZOpcode, ZRegisters}
|
||||
import millfork.env.{Constant, EnumType, ParamPassingConvention, Type, VariableType}
|
||||
import millfork.output.MemoryAlignment
|
||||
|
||||
import java.nio.file.Path
|
||||
|
||||
case class Position(moduleName: String, line: Int, column: Int, cursor: Int)
|
||||
|
||||
case class FieldDesc(typeName:String, fieldName: String, arraySize: Option[Expression])
|
||||
case class FieldDesc(typeName:String, fieldName: String, isVolatile: Boolean, arraySize: Option[Expression])
|
||||
|
||||
case class ResolvedFieldDesc(typ:VariableType, fieldName: String, arrayIndexTypeAndSize: Option[(VariableType, Int)])
|
||||
case class ResolvedFieldDesc(typ:VariableType, fieldName: String, isVolatile: Boolean, arrayIndexTypeAndSize: Option[(VariableType, Int)])
|
||||
|
||||
sealed trait Node {
|
||||
var position: Option[Position] = None
|
||||
@ -419,12 +421,12 @@ case class DerefDebuggingExpression(inner: Expression, preferredSize: Int) exten
|
||||
override def prettyPrint: String = s"¥deref(${inner.prettyPrint})"
|
||||
}
|
||||
|
||||
case class DerefExpression(inner: Expression, offset: Int, targetType: Type) extends LhsExpression {
|
||||
override def renameVariable(variable: String, newVariable: String): Expression = DerefExpression(inner.renameVariable(variable, newVariable), offset, targetType)
|
||||
override def replaceVariable(variable: String, actualParam: Expression): Expression = DerefExpression(inner.replaceVariable(variable, actualParam), offset, targetType)
|
||||
case class DerefExpression(inner: Expression, offset: Int, isVolatile: Boolean, targetType: Type) extends LhsExpression {
|
||||
override def renameVariable(variable: String, newVariable: String): Expression = DerefExpression(inner.renameVariable(variable, newVariable), offset, isVolatile, targetType)
|
||||
override def replaceVariable(variable: String, actualParam: Expression): Expression = DerefExpression(inner.replaceVariable(variable, actualParam), offset, isVolatile, targetType)
|
||||
|
||||
override def replaceIndexedExpression(predicate: IndexedExpression => Boolean, replacement: IndexedExpression => Expression): Expression =
|
||||
DerefExpression(inner.replaceIndexedExpression(predicate, replacement), offset, targetType)
|
||||
DerefExpression(inner.replaceIndexedExpression(predicate, replacement), offset, isVolatile, targetType)
|
||||
|
||||
override def containsVariable(variable: String): Boolean = inner.containsVariable(variable)
|
||||
|
||||
|
@ -42,7 +42,7 @@ object UnusedLocalVariables extends NodeOptimization {
|
||||
case SumExpression(xs, _) => getAllReadVariables(xs.map(_._2))
|
||||
case FunctionCallExpression(_, xs) => getAllReadVariables(xs)
|
||||
case IndexedExpression(arr, index) => arr :: getAllReadVariables(List(index))
|
||||
case DerefExpression(inner, _, _) => getAllReadVariables(List(inner))
|
||||
case DerefExpression(inner, _, _, _) => getAllReadVariables(List(inner))
|
||||
case DerefDebuggingExpression(inner, _) => getAllReadVariables(List(inner))
|
||||
case IndirectFieldExpression(inner, firstIndices, fields) => getAllReadVariables(List(inner) ++ firstIndices ++ fields.flatMap(_._3))
|
||||
case SeparateBytesExpression(h, l) => getAllReadVariables(List(h, l))
|
||||
|
@ -778,8 +778,8 @@ abstract class MfParser[T](fileId: String, input: String, currentDirectory: Stri
|
||||
|
||||
val compoundTypeField: P[FieldDesc] = ("array".! ~ !letterOrDigit ~ HWS ~/ Pass).?.flatMap {
|
||||
case None =>
|
||||
(identifier ~/ HWS ~ identifier ~/ HWS).map {
|
||||
case (typ, name) => FieldDesc(typ, name, None)
|
||||
(("volatile" ~ HWS ~/ Pass).!.? ~ identifier ~/ HWS ~ identifier ~/ HWS).map {
|
||||
case (vol, typ, name) => FieldDesc(typ, name, vol.isDefined, None)
|
||||
}
|
||||
|
||||
case Some(_) =>
|
||||
@ -788,7 +788,7 @@ abstract class MfParser[T](fileId: String, input: String, currentDirectory: Stri
|
||||
"[" ~/ AWS ~/ mfExpression(nonStatementLevel, false) ~ AWS ~ "]" ~/ HWS
|
||||
).map{
|
||||
case (elementType, name, length) =>
|
||||
FieldDesc(elementType.getOrElse("byte"), name, Some(length))
|
||||
FieldDesc(elementType.getOrElse("byte"), name, false, Some(length))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,4 +38,33 @@ class VolatileSuite extends FunSuite with Matchers {
|
||||
} while (count < 2)
|
||||
}
|
||||
}
|
||||
|
||||
test("Volatile struct fields test 1") {
|
||||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8086, Cpu.Motorola6809)(
|
||||
"""
|
||||
| struct s { volatile byte b }
|
||||
| s output@$c000
|
||||
| void main () {
|
||||
| output.b = 1
|
||||
| output.b = 2
|
||||
| }
|
||||
""".stripMargin) { m =>
|
||||
m.readByte(0xc000) should equal(2)
|
||||
}
|
||||
}
|
||||
|
||||
test("Volatile struct fields test 2") {
|
||||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8086, Cpu.Motorola6809)(
|
||||
"""
|
||||
| struct s { volatile byte b }
|
||||
| s output@$c000
|
||||
| void main () {
|
||||
| const pointer.s p = output.pointer
|
||||
| p[0].b = 1
|
||||
| p[0].b = 2
|
||||
| }
|
||||
""".stripMargin) { m =>
|
||||
m.readByte(0xc000) should equal(2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user