diff --git a/src/main/scala/millfork/compiler/m6809/M6809ExpressionCompiler.scala b/src/main/scala/millfork/compiler/m6809/M6809ExpressionCompiler.scala index d417116c..984549b8 100644 --- a/src/main/scala/millfork/compiler/m6809/M6809ExpressionCompiler.scala +++ b/src/main/scala/millfork/compiler/m6809/M6809ExpressionCompiler.scala @@ -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 "<<=" => diff --git a/src/main/scala/millfork/compiler/mos/BuiltIns.scala b/src/main/scala/millfork/compiler/mos/BuiltIns.scala index 75d85d4c..39b94b94 100644 --- a/src/main/scala/millfork/compiler/mos/BuiltIns.scala +++ b/src/main/scala/millfork/compiler/mos/BuiltIns.scala @@ -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") diff --git a/src/main/scala/millfork/compiler/mos/MosExpressionCompiler.scala b/src/main/scala/millfork/compiler/mos/MosExpressionCompiler.scala index a0ea64cb..7bf8652e 100644 --- a/src/main/scala/millfork/compiler/mos/MosExpressionCompiler.scala +++ b/src/main/scala/millfork/compiler/mos/MosExpressionCompiler.scala @@ -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) diff --git a/src/main/scala/millfork/compiler/z80/ZBuiltIns.scala b/src/main/scala/millfork/compiler/z80/ZBuiltIns.scala index 535d5418..a99b1acd 100644 --- a/src/main/scala/millfork/compiler/z80/ZBuiltIns.scala +++ b/src/main/scala/millfork/compiler/z80/ZBuiltIns.scala @@ -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 diff --git a/src/test/scala/millfork/test/ArraySuite.scala b/src/test/scala/millfork/test/ArraySuite.scala index 54a87570..ef1e2abe 100644 --- a/src/test/scala/millfork/test/ArraySuite.scala +++ b/src/test/scala/millfork/test/ArraySuite.scala @@ -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") { diff --git a/src/test/scala/millfork/test/PointerSuite.scala b/src/test/scala/millfork/test/PointerSuite.scala index 40de854d..28c1a23a 100644 --- a/src/test/scala/millfork/test/PointerSuite.scala +++ b/src/test/scala/millfork/test/PointerSuite.scala @@ -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) + } + } }