mirror of
https://github.com/KarolS/millfork.git
synced 2025-01-27 11:30:19 +00:00
Allow complex word-sized LHS for most compound operators, implementing #24
This commit is contained in:
parent
69c82d90a8
commit
e69b7084bc
@ -345,21 +345,21 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
|
||||
val (l, r, size) = assertArithmeticAssignmentLike(ctx, params)
|
||||
size match {
|
||||
case 1 => M6809Buitins.perform8BitInPlace(ctx, l, r, ANDB)
|
||||
case 2 => M6809Buitins.perform16BitInPlace(ctx, l, r, ANDB, commutative = true)
|
||||
case 2 => M6809Buitins.perform16BitInPlace(ctx, l, r, ANDA, ANDB, commutative = true)
|
||||
case _ => ???
|
||||
}
|
||||
case "|=" =>
|
||||
val (l, r, size) = assertArithmeticAssignmentLike(ctx, params)
|
||||
size match {
|
||||
case 1 => M6809Buitins.perform8BitInPlace(ctx, l, r, ORB)
|
||||
case 2 => M6809Buitins.perform16BitInPlace(ctx, l, r, ORB, commutative = true)
|
||||
case 2 => M6809Buitins.perform16BitInPlace(ctx, l, r, ORA, ORB, commutative = true)
|
||||
case _ => ???
|
||||
}
|
||||
case "^=" =>
|
||||
val (l, r, size) = assertArithmeticAssignmentLike(ctx, params)
|
||||
size match {
|
||||
case 1 => M6809Buitins.perform8BitInPlace(ctx, l, r, EORB)
|
||||
case 2 => M6809Buitins.perform16BitInPlace(ctx, l, r, EORB, commutative = true)
|
||||
case 2 => M6809Buitins.perform16BitInPlace(ctx, l, r, EORA, EORB, commutative = true)
|
||||
case _ => ???
|
||||
}
|
||||
case "<<=" =>
|
||||
|
@ -333,9 +333,74 @@ object BuiltIns {
|
||||
}
|
||||
|
||||
def compileInPlaceWordOrLongShiftOps(ctx: CompilationContext, lhs: LhsExpression, rhs: Expression, aslRatherThanLsr: Boolean): List[AssemblyLine] = {
|
||||
if (lhs.isInstanceOf[DerefExpression]) {
|
||||
ctx.log.error("Too complex left-hand-side expression", lhs.position)
|
||||
return MosExpressionCompiler.compileToAX(ctx, lhs) ++ MosExpressionCompiler.compileToAX(ctx, rhs)
|
||||
lhs match {
|
||||
case dx: DerefExpression =>
|
||||
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)
|
||||
}
|
||||
return handleWordOrLongInPlaceModificationViaDeref(ctx, dx, rhs){ (ptr, reg, offset, r) =>
|
||||
val shiftAmount = r match {
|
||||
case List(AssemblyLine0(LDA, Immediate, NumericConstant(a, _)), AssemblyLine0(LDX, Immediate, _)) => Some(a.toInt)
|
||||
case _ => None
|
||||
}
|
||||
val loadToR2 =
|
||||
List(
|
||||
AssemblyLine.immediate(LDY, offset),
|
||||
AssemblyLine.indexedY(LDA, ptr),
|
||||
AssemblyLine.zeropage(STA, reg, 2),
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine.indexedY(LDA, ptr),
|
||||
AssemblyLine.zeropage(STA, reg, 3))
|
||||
val storeFromR2 =
|
||||
List(
|
||||
AssemblyLine.immediate(LDY, offset),
|
||||
AssemblyLine.zeropage(LDA, reg, 2),
|
||||
AssemblyLine.indexedY(STA, ptr),
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine.zeropage(LDA, reg, 3),
|
||||
AssemblyLine.indexedY(STA, ptr))
|
||||
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))
|
||||
shiftAmount match {
|
||||
case Some(0) => Nil
|
||||
case Some(1) if aslRatherThanLsr =>
|
||||
List(
|
||||
AssemblyLine.immediate(LDY, offset),
|
||||
AssemblyLine.indexedY(LDA, ptr),
|
||||
AssemblyLine.implied(ASL),
|
||||
AssemblyLine.indexedY(STA, ptr),
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine.indexedY(LDA, ptr),
|
||||
AssemblyLine.implied(ROL),
|
||||
AssemblyLine.indexedY(STA, ptr))
|
||||
case Some(1) if !aslRatherThanLsr =>
|
||||
List(
|
||||
AssemblyLine.immediate(LDY, offset + 1),
|
||||
AssemblyLine.indexedY(LDA, ptr),
|
||||
AssemblyLine.implied(LSR),
|
||||
AssemblyLine.indexedY(STA, ptr),
|
||||
AssemblyLine.implied(DEY),
|
||||
AssemblyLine.indexedY(LDA, ptr),
|
||||
AssemblyLine.implied(ROR),
|
||||
AssemblyLine.indexedY(STA, ptr))
|
||||
case Some(n) if n >= 1 && n <= 7 => // TODO: pick optimal
|
||||
loadToR2 ++ List.fill(n)(shiftR2).flatten ++ storeFromR2
|
||||
case _ =>
|
||||
val labelSkip = ctx.nextLabel("ss")
|
||||
val labelRepeat = ctx.nextLabel("sr")
|
||||
List(AssemblyLine.implied(TAX), AssemblyLine.relative(BEQ, labelSkip)) ++
|
||||
loadToR2 ++
|
||||
List(AssemblyLine.label(labelRepeat)) ++
|
||||
shiftR2 ++ List(
|
||||
AssemblyLine.implied(DEX),
|
||||
AssemblyLine.relative(BNE, labelRepeat)) ++
|
||||
storeFromR2 ++ List(
|
||||
AssemblyLine.label(labelSkip))
|
||||
}
|
||||
}
|
||||
case _ =>
|
||||
}
|
||||
val env = ctx.env
|
||||
val b = env.get[Type]("byte")
|
||||
@ -1046,9 +1111,85 @@ object BuiltIns {
|
||||
private def isPowerOfTwoUpTo15(n: Long): Boolean = if (n <= 0 || n >= 0x8000) false else 0 == ((n-1) & n)
|
||||
|
||||
def compileInPlaceWordMultiplication(ctx: CompilationContext, v: LhsExpression, addend: Expression): List[AssemblyLine] = {
|
||||
if (v.isInstanceOf[DerefExpression]) {
|
||||
ctx.log.error("Too complex left-hand-side expression", v.position)
|
||||
return MosExpressionCompiler.compileToAX(ctx, v) ++ MosExpressionCompiler.compileToAX(ctx, addend)
|
||||
v match {
|
||||
case dx: DerefExpression =>
|
||||
// this is ugly, needs a rewrite
|
||||
return handleWordOrLongInPlaceModificationViaDeref(ctx, dx, addend){(ptr, reg, offset, r) =>
|
||||
val constR = r match {
|
||||
case List(AssemblyLine0(LDA, Immediate, l), AssemblyLine0(LDX, Immediate, h)) =>
|
||||
h.asl(8).+(l).quickSimplify match {
|
||||
case NumericConstant(n, _) => Some(n.toInt & 0xffff)
|
||||
case _ => None
|
||||
}
|
||||
case _ => None
|
||||
}
|
||||
constR match {
|
||||
case Some(1) => Nil
|
||||
case Some(0) => List(
|
||||
AssemblyLine.immediate(LDA, 0),
|
||||
AssemblyLine.immediate(LDY, offset),
|
||||
AssemblyLine.indexedY(STA, ptr),
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine.indexedY(STA, ptr))
|
||||
case Some(2) => List(
|
||||
AssemblyLine.immediate(LDA, 0),
|
||||
AssemblyLine.immediate(LDY, offset),
|
||||
AssemblyLine.indexedY(LDA, ptr),
|
||||
AssemblyLine.implied(ASL),
|
||||
AssemblyLine.indexedY(STA, ptr),
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine.indexedY(LDA, ptr),
|
||||
AssemblyLine.implied(ROL),
|
||||
AssemblyLine.indexedY(STA, ptr))
|
||||
// TODO: other powers of two
|
||||
case _ if reg.toAddress == ptr => List(
|
||||
AssemblyLine.implied(PHA),
|
||||
AssemblyLine.immediate(LDY, offset),
|
||||
AssemblyLine.indexedY(LDA, reg),
|
||||
AssemblyLine.zeropage(STA, reg, 2),
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine.indexedY(LDA, reg),
|
||||
AssemblyLine.zeropage(STA, reg, 3),
|
||||
AssemblyLine.implied(PLA),
|
||||
AssemblyLine.implied(TAY),
|
||||
AssemblyLine.zeropage(LDA, reg, 1),
|
||||
AssemblyLine.implied(PHA),
|
||||
AssemblyLine.zeropage(LDA, reg),
|
||||
AssemblyLine.implied(PHA),
|
||||
AssemblyLine.zeropage(STY, reg),
|
||||
AssemblyLine.zeropage(STX, reg, 1),
|
||||
AssemblyLine.absolute(JSR, ctx.env.get[ThingInMemory]("__mul_u16u16u16")),
|
||||
AssemblyLine.zeropage(STA, reg, 2),
|
||||
AssemblyLine.implied(PLA),
|
||||
AssemblyLine.zeropage(STA, reg),
|
||||
AssemblyLine.implied(PLA),
|
||||
AssemblyLine.zeropage(STA, reg, 1),
|
||||
AssemblyLine.immediate(LDY, offset),
|
||||
AssemblyLine.zeropage(LDA, reg, 2),
|
||||
AssemblyLine.indexedY(STA, reg),
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine.implied(TXA),
|
||||
AssemblyLine.indexedY(STA, reg),
|
||||
)
|
||||
case _ => List(
|
||||
AssemblyLine.zeropage(STA, reg),
|
||||
AssemblyLine.zeropage(STX, reg, 1),
|
||||
AssemblyLine.immediate(LDY, offset),
|
||||
AssemblyLine.indexedY(LDA, ptr),
|
||||
AssemblyLine.zeropage(STA, reg, 2),
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine.indexedY(LDA, ptr),
|
||||
AssemblyLine.zeropage(STA, reg, 3),
|
||||
AssemblyLine.absolute(JSR, ctx.env.get[ThingInMemory]("__mul_u16u16u16")),
|
||||
AssemblyLine.immediate(LDY, offset),
|
||||
AssemblyLine.indexedY(STA, ptr),
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine.implied(TXA),
|
||||
AssemblyLine.indexedY(STA, ptr),
|
||||
)
|
||||
}
|
||||
}
|
||||
case _ =>
|
||||
}
|
||||
val b = ctx.env.get[Type]("byte")
|
||||
val w = ctx.env.get[Type]("word")
|
||||
@ -1301,14 +1442,74 @@ object BuiltIns {
|
||||
ctx.env.evalVariableAndConstantSubParts(indexExpr)._1.map(v => MosExpressionCompiler.getExpressionType(ctx, v).size).sum
|
||||
}
|
||||
|
||||
@inline
|
||||
private def handleWordOrLongInPlaceModificationViaDeref(ctx: CompilationContext, lhs: DerefExpression, rhs: Expression)(footer: (Constant, VariableInMemory, Int, List[AssemblyLine]) => List[AssemblyLine]): List[AssemblyLine] = {
|
||||
if (ctx.options.zpRegisterSize < 2) {
|
||||
ctx.log.error("Unsupported operation. Consider increasing the size of the zeropage register.", lhs.position)
|
||||
return MosExpressionCompiler.compileToAX(ctx, lhs) ++ MosExpressionCompiler.compileToAX(ctx, rhs)
|
||||
}
|
||||
val env = ctx.env
|
||||
val targetType = MosExpressionCompiler.getExpressionType(ctx, lhs)
|
||||
if (targetType.size == 2 ) {
|
||||
val reg = env.get[VariableInMemory]("__reg")
|
||||
var l = MosExpressionCompiler.compileToZReg(ctx, lhs.inner)
|
||||
val ptr = l match {
|
||||
case List(AssemblyLine0(LDA, ZeroPage, p), AssemblyLine0(STA, ZeroPage, _), AssemblyLine0(LDA, ZeroPage, q), AssemblyLine0(STA, ZeroPage, _)) if p.succ == q =>
|
||||
l = Nil
|
||||
p
|
||||
case List(AssemblyLine0(LDA, ZeroPage, p), AssemblyLine0(LDX, ZeroPage, q), AssemblyLine0(STA, ZeroPage, _), AssemblyLine0(STX, ZeroPage, _)) if p.succ == q =>
|
||||
l = Nil
|
||||
p
|
||||
case _ =>
|
||||
reg.toAddress
|
||||
}
|
||||
val r = MosExpressionCompiler.compileToAX(ctx, rhs)
|
||||
val s = footer(ptr, reg, lhs.offset, r)
|
||||
if (MosExpressionCompiler.changesZpreg(r, 0) || MosExpressionCompiler.changesZpreg(r, 1)) {
|
||||
r ++ MosExpressionCompiler.preserveRegisterIfNeeded(ctx, MosRegister.AX, l) ++ s
|
||||
} else {
|
||||
l ++ r ++ s
|
||||
}
|
||||
} else {
|
||||
ctx.log.error("Too complex left-hand-side expression", lhs.position)
|
||||
MosExpressionCompiler.compileToAX(ctx, lhs) ++ MosExpressionCompiler.compileToAX(ctx, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
def compileInPlaceWordOrLongAddition(ctx: CompilationContext, lhs: LhsExpression, addend: Expression, subtract: Boolean, decimal: Boolean): List[AssemblyLine] = {
|
||||
if (decimal && !ctx.options.flag(CompilationFlag.DecimalMode) && ctx.options.zpRegisterSize < 4) {
|
||||
ctx.log.error("Unsupported decimal operation. Consider increasing the size of the zeropage register.", lhs.position)
|
||||
return compileInPlaceWordOrLongAddition(ctx, lhs, addend, subtract, decimal = false)
|
||||
}
|
||||
if (lhs.isInstanceOf[DerefExpression]) {
|
||||
ctx.log.error("Too complex left-hand-side expression", lhs.position)
|
||||
return MosExpressionCompiler.compileToAX(ctx, lhs) ++ MosExpressionCompiler.compileToAX(ctx, addend)
|
||||
lhs match {
|
||||
case dx: DerefExpression =>
|
||||
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)
|
||||
}
|
||||
return if (subtract) handleWordOrLongInPlaceModificationViaDeref(ctx, dx, addend)((ptr, reg, offset, _) => wrapInSedCldIfNeeded(decimal, List(
|
||||
AssemblyLine.immediate(LDY, offset),
|
||||
AssemblyLine.implied(SEC),
|
||||
AssemblyLine.zeropage(STA, reg, 2),
|
||||
AssemblyLine.indexedY(LDA, ptr),
|
||||
AssemblyLine.zeropage(SBC, reg, 2),
|
||||
AssemblyLine.indexedY(STA, ptr),
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine.zeropage(STX, reg, 2),
|
||||
AssemblyLine.indexedY(LDA, ptr),
|
||||
AssemblyLine.zeropage(SBC, reg, 2),
|
||||
AssemblyLine.indexedY(STA, ptr),
|
||||
))) else handleWordOrLongInPlaceModificationViaDeref(ctx, dx, addend)((ptr, _, offset, _) => wrapInSedCldIfNeeded(decimal, List(
|
||||
AssemblyLine.immediate(LDY, offset),
|
||||
AssemblyLine.implied(CLC),
|
||||
AssemblyLine.indexedY(ADC, ptr),
|
||||
AssemblyLine.indexedY(STA, ptr),
|
||||
AssemblyLine.implied(TXA),
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine.indexedY(ADC, ptr),
|
||||
AssemblyLine.indexedY(STA, ptr),
|
||||
)))
|
||||
case _ =>
|
||||
}
|
||||
val env = ctx.env
|
||||
val b = env.get[Type]("byte")
|
||||
@ -1656,9 +1857,17 @@ object BuiltIns {
|
||||
|
||||
|
||||
def compileInPlaceWordOrLongBitOp(ctx: CompilationContext, lhs: LhsExpression, param: Expression, operation: Opcode.Value): List[AssemblyLine] = {
|
||||
if (lhs.isInstanceOf[DerefExpression]) {
|
||||
ctx.log.error("Too complex left-hand-side expression", lhs.position)
|
||||
return MosExpressionCompiler.compileToAX(ctx, lhs) ++ MosExpressionCompiler.compileToAX(ctx, param)
|
||||
lhs match {
|
||||
case dx: DerefExpression => return handleWordOrLongInPlaceModificationViaDeref(ctx, dx, param)((ptr, _, offset, _) => List(
|
||||
AssemblyLine.immediate(LDY, offset),
|
||||
AssemblyLine.indexedY(operation, ptr),
|
||||
AssemblyLine.indexedY(STA, ptr),
|
||||
AssemblyLine.implied(TXA),
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine.indexedY(operation, ptr),
|
||||
AssemblyLine.indexedY(STA, ptr),
|
||||
))
|
||||
case _ =>
|
||||
}
|
||||
val env = ctx.env
|
||||
val b = env.get[Type]("byte")
|
||||
|
@ -135,6 +135,9 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
||||
}
|
||||
|
||||
val cmos = ctx.options.flag(CompilationFlag.EmitCmosOpcodes)
|
||||
if (register == MosRegister.AX && !code.exists(_.concernsX)) {
|
||||
return preserveRegisterIfNeeded(ctx, MosRegister.A, code)
|
||||
}
|
||||
if (states.exists(state => AssemblyLine.treatment(code, state) != Treatment.Unchanged)) {
|
||||
register match {
|
||||
case MosRegister.A => AssemblyLine.implied(PHA) +: fixTsx(code) :+ AssemblyLine.implied(PLA)
|
||||
|
@ -467,9 +467,89 @@ object ZBuiltIns {
|
||||
|
||||
|
||||
def performLongInPlace(ctx: CompilationContext, lhs: LhsExpression, rhs: Expression, opcodeFirst: ZOpcode.Value, opcodeLater: ZOpcode.Value, size: Int, decimal: Boolean = false): List[ZLine] = {
|
||||
if (lhs.isInstanceOf[DerefExpression]) {
|
||||
ctx.log.error("Too complex left-hand-side expression", lhs.position)
|
||||
return Z80ExpressionCompiler.compile(ctx, lhs, ZExpressionTarget.NOTHING) ++ Z80ExpressionCompiler.compile(ctx, rhs, ZExpressionTarget.NOTHING)
|
||||
lhs match {
|
||||
case dx@DerefExpression(inner, offset, targetType) =>
|
||||
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.L, ZRegister.A),
|
||||
ZLine.register(INC_16, ZRegister.BC),
|
||||
ZLine.ld8(ZRegister.A, ZRegister.MEM_BC),
|
||||
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.register(DEC_16, ZRegister.BC),
|
||||
ZLine.ld8(ZRegister.A, ZRegister.L),
|
||||
ZLine.ld8(ZRegister.MEM_BC, ZRegister.A),
|
||||
)
|
||||
if (!r.exists(Z80ExpressionCompiler.changesBC)) {
|
||||
return l ++ r ++ s
|
||||
} else if (!l.exists(Z80ExpressionCompiler.changesDE)) {
|
||||
return r ++ l ++ s
|
||||
} else {
|
||||
return l ++ Z80ExpressionCompiler.stashBCIfChanged(ctx, r) ++ s
|
||||
}
|
||||
} else {
|
||||
val l = Z80ExpressionCompiler.compileDerefPointer(ctx, dx)
|
||||
val r = Z80ExpressionCompiler.compileToDE(ctx, rhs)
|
||||
val s = if (opcodeFirst == SUB && decimal) {
|
||||
if (ctx.options.flag(CompilationFlag.EmitExtended80Opcodes)) {
|
||||
List(
|
||||
ZLine.ld8(ZRegister.A, ZRegister.MEM_HL),
|
||||
ZLine.register(SUB, ZRegister.E),
|
||||
ZLine.implied(DAA),
|
||||
ZLine.ld8(ZRegister.MEM_HL, ZRegister.A),
|
||||
ZLine.register(INC_16, ZRegister.HL),
|
||||
ZLine.ld8(ZRegister.A, ZRegister.MEM_HL),
|
||||
ZLine.register(SBC, ZRegister.D),
|
||||
ZLine.implied(DAA),
|
||||
ZLine.ld8(ZRegister.MEM_HL, ZRegister.A),
|
||||
)
|
||||
} else {
|
||||
ctx.log.error("Decimal subtraction from such a complex LHS is not yet supported", dx.position)
|
||||
Nil
|
||||
}
|
||||
} else if (opcodeFirst == ADD && decimal) {
|
||||
List(
|
||||
ZLine.ld8(ZRegister.A, ZRegister.MEM_HL),
|
||||
ZLine.register(ADD, ZRegister.E),
|
||||
ZLine.implied(DAA),
|
||||
ZLine.ld8(ZRegister.MEM_HL, ZRegister.A),
|
||||
ZLine.register(INC_16, ZRegister.HL),
|
||||
ZLine.ld8(ZRegister.A, ZRegister.MEM_HL),
|
||||
ZLine.register(ADC, ZRegister.D),
|
||||
ZLine.implied(DAA),
|
||||
ZLine.ld8(ZRegister.MEM_HL, ZRegister.A),
|
||||
)
|
||||
} else {
|
||||
List(
|
||||
ZLine.ld8(ZRegister.A, ZRegister.MEM_HL),
|
||||
ZLine.register(opcodeFirst, ZRegister.E),
|
||||
ZLine.ld8(ZRegister.MEM_HL, ZRegister.A),
|
||||
ZLine.register(INC_16, ZRegister.HL),
|
||||
ZLine.ld8(ZRegister.A, ZRegister.MEM_HL),
|
||||
ZLine.register(opcodeLater, ZRegister.D),
|
||||
ZLine.ld8(ZRegister.MEM_HL, ZRegister.A),
|
||||
)
|
||||
}
|
||||
if (!r.exists(Z80ExpressionCompiler.changesHL)) {
|
||||
return l ++ r ++ s
|
||||
} else if (!l.exists(Z80ExpressionCompiler.changesDE)) {
|
||||
return r ++ l ++ s
|
||||
} else {
|
||||
return l ++ Z80ExpressionCompiler.stashHLIfChanged(ctx, r) ++ s
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ctx.log.error("Too complex left-hand-side expression", lhs.position)
|
||||
return Z80ExpressionCompiler.compile(ctx, lhs, ZExpressionTarget.NOTHING) ++ Z80ExpressionCompiler.compile(ctx, rhs, ZExpressionTarget.NOTHING)
|
||||
}
|
||||
case _ =>
|
||||
}
|
||||
if (size == 2 && !decimal) {
|
||||
// n × INC HL
|
||||
|
@ -464,17 +464,6 @@ class ArraySuite extends FunSuite with Matchers with AppendedClues {
|
||||
| a[0] += 2
|
||||
| }
|
||||
""".stripMargin)
|
||||
ShouldNotCompile(
|
||||
"""
|
||||
| array(word) a[7] @$c000
|
||||
| void main () {
|
||||
| // the 6809 backend is apparently too smart right now and this actually works!:
|
||||
| a[0] += 2
|
||||
| #if ARCH_6809
|
||||
| a[0]*'a[1]
|
||||
| #endif
|
||||
| }
|
||||
""".stripMargin)
|
||||
}
|
||||
|
||||
test("Various large assignments involving arrays") {
|
||||
|
@ -339,4 +339,92 @@ class PointerSuite extends FunSuite with Matchers with AppendedClues {
|
||||
m.readWord(0xc000) should equal(555)
|
||||
}
|
||||
}
|
||||
|
||||
test("Modifying a word via a pointer") {
|
||||
EmuUnoptimizedCrossPlatformRun(/*Cpu.Mos, Cpu.Z80,*/ Cpu.Motorola6809)(
|
||||
"""
|
||||
|word output @$c000
|
||||
|void main () {
|
||||
| byte constant
|
||||
| constant = $50
|
||||
| output = $850
|
||||
|
|
||||
| pointer.word value_pointer
|
||||
| value_pointer = output.pointer
|
||||
| value_pointer[0] += constant
|
||||
| value_pointer[0] |= constant
|
||||
| value_pointer[0] <<= f(2)
|
||||
| value_pointer[0] >>= f(2)
|
||||
|}
|
||||
|noinline byte f(byte i) = i
|
||||
|
|
||||
""".stripMargin
|
||||
) { m =>
|
||||
m.readWord(0xc000) should equal(0x850.+(0x50).|(0x50))
|
||||
}
|
||||
}
|
||||
|
||||
test("Modifying a word via a pointer 2") {
|
||||
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80) (
|
||||
"""
|
||||
|import zp_reg
|
||||
|word output2 @$c002
|
||||
|array(word) tmp[6] @$c100
|
||||
|void main () {
|
||||
| byte constant
|
||||
| constant = $50
|
||||
| output2 = 0
|
||||
| pointer.word value_pointer
|
||||
| value_pointer = output2.pointer
|
||||
| value_pointer[0] +'= constant
|
||||
| tmp[0] = output2
|
||||
| value_pointer[0] +'= constant
|
||||
| tmp[1] = output2
|
||||
| value_pointer[0] -'= constant
|
||||
| tmp[2] = output2
|
||||
| value_pointer[0] <<= f(1)
|
||||
| tmp[3] = output2
|
||||
| value_pointer[0] *= f(1)
|
||||
| tmp[4] = output2
|
||||
| value_pointer[0] /= f(1)
|
||||
| tmp[5] = output2
|
||||
|}
|
||||
|noinline byte f(byte i) = i
|
||||
|
|
||||
""".stripMargin
|
||||
){ m =>
|
||||
println(m.readWord(0xc100).toHexString)
|
||||
println(m.readWord(0xc102).toHexString)
|
||||
println(m.readWord(0xc104).toHexString)
|
||||
println(m.readWord(0xc106).toHexString)
|
||||
println(m.readWord(0xc108).toHexString)
|
||||
println(m.readWord(0xc10a).toHexString)
|
||||
m.readWord(0xc002) should equal(0xA0)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
test("Modifying a word via a pointer 3") {
|
||||
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Motorola6809) (
|
||||
"""
|
||||
|struct entity_t {
|
||||
| word x, byte y,
|
||||
| byte frame_i, byte frame_tick,
|
||||
| int24 padding // TODO: remove padding after 6809 gets multiplication support
|
||||
|}
|
||||
|array(entity_t) enemy[7] @$c100
|
||||
|
|
||||
|void main() {
|
||||
| enemy[0].x = 0x3ff
|
||||
| byte i
|
||||
| i = f(0)
|
||||
| enemy[i].x += 1
|
||||
|}
|
||||
|noinline byte f(byte x) = x
|
||||
|
|
||||
|""".stripMargin
|
||||
){ m =>
|
||||
m.readWord(0xc100) should equal(0x400)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user