1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-06-11 15:29:34 +00:00

Internal support for pointers to volatile objects; add volatile fields (closes #112)

This commit is contained in:
Karol Stasiak 2021-06-21 14:20:24 +02:00
parent 73beafd65e
commit 431a25d325
14 changed files with 384 additions and 326 deletions

View File

@ -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) =>

View File

@ -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

View File

@ -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 {

View File

@ -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(

View File

@ -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] = {

View File

@ -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 _ =>

View File

@ -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)
}
}

View File

@ -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)

View File

@ -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

View File

@ -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))
}
}

View File

@ -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)

View File

@ -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))

View File

@ -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))
}
}

View File

@ -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)
}
}
}