From 59afc24db6288e881f3b1421ec25636726314630 Mon Sep 17 00:00:00 2001 From: Karol Stasiak Date: Thu, 27 Dec 2018 14:19:04 +0100 Subject: [PATCH] Fix memset --- .../mos/MosBulkMemoryOperations.scala | 40 +++++++++++---- .../z80/Z80BulkMemoryOperations.scala | 6 +-- .../scala/millfork/test/MemsetSuite.scala | 51 +++++++++++++++++++ 3 files changed, 85 insertions(+), 12 deletions(-) create mode 100644 src/test/scala/millfork/test/MemsetSuite.scala diff --git a/src/main/scala/millfork/compiler/mos/MosBulkMemoryOperations.scala b/src/main/scala/millfork/compiler/mos/MosBulkMemoryOperations.scala index 0d831992..828d99de 100644 --- a/src/main/scala/millfork/compiler/mos/MosBulkMemoryOperations.scala +++ b/src/main/scala/millfork/compiler/mos/MosBulkMemoryOperations.scala @@ -1,7 +1,7 @@ package millfork.compiler.mos import millfork.CompilationFlag -import millfork.assembly.mos.AssemblyLine +import millfork.assembly.mos.{AssemblyLine, AssemblyLine0} import millfork.compiler.{BranchSpec, CompilationContext} import millfork.env.{NumericConstant, Type, VariableInMemory} import millfork.node._ @@ -34,10 +34,31 @@ object MosBulkMemoryOperations { case _ => return MosStatementCompiler.compileForStatement(ctx, f)._1 } val useTwoRegs = ctx.options.flag(CompilationFlag.OptimizeForSpeed) && ctx.options.zpRegisterSize >= 4 - val loadReg = MosExpressionCompiler.compile(ctx, SumExpression(List(false -> f.start, false -> target.index), decimal = false), Some(w -> reg), BranchSpec.None) ++ ( - if (useTwoRegs) List(AssemblyLine.zeropage(LDA, reg), AssemblyLine.zeropage(STA, reg,2), AssemblyLine.zeropage(LDA, reg,1), AssemblyLine.zeropage(STA, reg,3)) - else Nil - ) + val loadReg = + if (useTwoRegs) { + import millfork.assembly.mos.AddrMode._ + val first = MosExpressionCompiler.compile(ctx, SumExpression(List(false -> f.start, false -> target.index), decimal = false), Some(w -> reg), BranchSpec.None) + first ++ (first match { + case List(AssemblyLine0(LDA, Immediate, l), AssemblyLine0(LDA, ZeroPage, r0), AssemblyLine0(LDA, Immediate, h), AssemblyLine0(LDA, ZeroPage, r1)) + if (r1-r0).quickSimplify.isProvably(1) => + val c = (h.asl(8) + l+ 0x80).quickSimplify + List( + AssemblyLine.immediate(LDA, c.loByte), + AssemblyLine.zeropage(STA, reg, 2), + AssemblyLine.immediate(LDA, c.subbyte(1)), + AssemblyLine.zeropage(STA, reg, 3)) + case _ => + List( + AssemblyLine.zeropage(LDA, reg), + AssemblyLine.implied(CLC), + AssemblyLine.immediate(ADC, 0x80), + AssemblyLine.zeropage(STA, reg, 2), + AssemblyLine.zeropage(LDA, reg, 1), + AssemblyLine.immediate(ADC, 0), + AssemblyLine.zeropage(STA, reg, 3)) + }) + }else MosExpressionCompiler.compile(ctx, SumExpression(List(false -> f.start, false -> target.index), decimal = false), Some(w -> reg), BranchSpec.None) + val loadSource = MosExpressionCompiler.compileToA(ctx, source) val loadAll = if (MosExpressionCompiler.changesZpreg(loadSource, 0) || MosExpressionCompiler.changesZpreg(loadSource, 1)) { loadSource ++ MosExpressionCompiler.preserveRegisterIfNeeded(ctx, MosRegister.A, loadReg) @@ -53,20 +74,20 @@ object MosBulkMemoryOperations { List( AssemblyLine.immediate(LDY, 0x80), AssemblyLine.label(label), + AssemblyLine.implied(DEY), AssemblyLine.indexedY(STA, reg), AssemblyLine.indexedY(STA, reg, 2), - AssemblyLine.implied(INY), + AssemblyLine.implied(DEY), AssemblyLine.indexedY(STA, reg), AssemblyLine.indexedY(STA, reg, 2), - AssemblyLine.implied(INY), AssemblyLine.relative(BNE, label)) } else if (ctx.options.flag(CompilationFlag.OptimizeForSpeed)) { List( AssemblyLine.immediate(LDY, 0x80), AssemblyLine.label(label), + AssemblyLine.implied(DEY), AssemblyLine.indexedY(STA, reg), AssemblyLine.indexedY(STA, reg, 2), - AssemblyLine.implied(INY), AssemblyLine.relative(BNE, label)) } else ??? } else { @@ -113,7 +134,8 @@ object MosBulkMemoryOperations { List( AssemblyLine.immediate(LDX, wholePageCount), AssemblyLine.relative(BEQ, labelXSkip), - AssemblyLine.label(labelX)) ++ fillOnePage ++ List( + AssemblyLine.label(labelX)) ++ fillOnePage ++ + (if (useTwoRegs) List(AssemblyLine.zeropage(INC, reg, 3)) else Nil) ++ List( AssemblyLine.zeropage(INC, reg, 1), AssemblyLine.implied(DEX), AssemblyLine.relative(BNE, labelX), diff --git a/src/main/scala/millfork/compiler/z80/Z80BulkMemoryOperations.scala b/src/main/scala/millfork/compiler/z80/Z80BulkMemoryOperations.scala index ede40d8f..fe9a8562 100644 --- a/src/main/scala/millfork/compiler/z80/Z80BulkMemoryOperations.scala +++ b/src/main/scala/millfork/compiler/z80/Z80BulkMemoryOperations.scala @@ -54,11 +54,11 @@ object Z80BulkMemoryOperations { val calculateAddress = Z80ExpressionCompiler.calculateAddressToHL(ctx, IndexedExpression(array, targetIndexExpression)) val calculateSize = f.direction match { case ForDirection.DownTo => - Z80ExpressionCompiler.stashHLIfChanged(ctx, Z80ExpressionCompiler.compileToBC(ctx, SumExpression(List(false -> f.start, true -> f.end, false -> LiteralExpression(1, 1)), decimal = false))) + Z80ExpressionCompiler.stashHLIfChanged(ctx, Z80ExpressionCompiler.compileToBC(ctx, SumExpression(List(false -> f.start, true -> f.end), decimal = false))) case ForDirection.To | ForDirection.ParallelTo => - Z80ExpressionCompiler.stashHLIfChanged(ctx, Z80ExpressionCompiler.compileToBC(ctx, SumExpression(List(false -> f.end, true -> f.start, false -> LiteralExpression(1, 1)), decimal = false))) - case ForDirection.Until | ForDirection.ParallelUntil => Z80ExpressionCompiler.stashHLIfChanged(ctx, Z80ExpressionCompiler.compileToBC(ctx, SumExpression(List(false -> f.end, true -> f.start), decimal = false))) + case ForDirection.Until | ForDirection.ParallelUntil => + Z80ExpressionCompiler.stashHLIfChanged(ctx, Z80ExpressionCompiler.compileToBC(ctx, SumExpression(List(false -> f.end, true -> f.start, true -> LiteralExpression(1, 1)), decimal = false))) } val (incOp, ldOp) = f.direction match { case ForDirection.DownTo => DEC_16 -> LDDR diff --git a/src/test/scala/millfork/test/MemsetSuite.scala b/src/test/scala/millfork/test/MemsetSuite.scala new file mode 100644 index 00000000..0033cf4c --- /dev/null +++ b/src/test/scala/millfork/test/MemsetSuite.scala @@ -0,0 +1,51 @@ +package millfork.test + +import millfork.Cpu +import millfork.test.emu.EmuCrossPlatformBenchmarkRun +import org.scalatest.{AppendedClues, FunSuite, Matchers} + +/** + * @author Karol Stasiak + */ +class MemsetSuite extends FunSuite with Matchers with AppendedClues { + + test("memset $1000") { + memsetCase(0x1000) + } + test("memset $40") { + memsetCase(0x40) + } + test("memset $80") { + memsetCase(0x80) + } + test("memset $100") { + memsetCase(0x100) + } + test("memset $200") { + memsetCase(0x200) + } + test("memset $fff") { + memsetCase(0xfff) + } + + def memsetCase(size: Int): Unit = { + EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Intel8080, Cpu.Z80)( + "const word SIZE = " + size + """ + | array output [SIZE] @$c000 + | void main () { + | pointer p + | for p,output.addr,paralleluntil,output.addr+SIZE { + | p[0] = 42 + | } + | } + """.stripMargin) { m => + for(addr <- 0 until 0x1000) { + if (addr < size) { + m.readByte(addr + 0xc000) should equal(42) withClue f"$$$addr%04x" + } else { + m.readByte(addr + 0xc000) should equal(0) withClue f"$$$addr%04x" + } + } + } + } +} \ No newline at end of file