diff --git a/CHANGELOG.md b/CHANGELOG.md index feccc126..ab0ba99a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Current version +* Added `memory_barrier` macro. + * Added `random` module. * Added `ensure_mixedcase` function and `oldpet` and `origpet` text encodings. diff --git a/docs/stdlib/frequent.md b/docs/stdlib/frequent.md index 96719582..31954a01 100644 --- a/docs/stdlib/frequent.md +++ b/docs/stdlib/frequent.md @@ -61,3 +61,11 @@ Various colour constants. Available for: VIC-20, C64, C264 series, ZX Spectrum. +#### `macro void memory_barrier()` + +Informs the optimizer that at this point arbitrary memory has been accessed and either read or written by an external device. +The optimizer should not optimize any memory accesses across that macro. + +Available for: all targets. + + diff --git a/src/main/scala/millfork/assembly/mos/AssemblyLine.scala b/src/main/scala/millfork/assembly/mos/AssemblyLine.scala index c678b0af..555234ab 100644 --- a/src/main/scala/millfork/assembly/mos/AssemblyLine.scala +++ b/src/main/scala/millfork/assembly/mos/AssemblyLine.scala @@ -142,6 +142,7 @@ object OpcodeClasses { SLO, RLA, SRE, RRA, AHX, SHY, SHX, TAS, LAS, COP, + CHANGED_MEM, ) val ChangesMemoryIfNotImplied = Set( DEC, INC, ASL, ROL, LSR, ROR, @@ -158,6 +159,7 @@ object OpcodeClasses { LAS, TRB, TSB, TRB_W, TSB_W, + CHANGED_MEM, ) val AccessesWordInMemory = Set( @@ -332,7 +334,7 @@ object OpcodeClasses { CSH, CSL, TXY, TYX, XBA, PHD, PHB, PHK, - DISCARD_AF, DISCARD_XF, DISCARD_YF) + DISCARD_AF, DISCARD_XF, DISCARD_YF, CHANGED_MEM) val NoopDiscardsFlags = Set(DISCARD_AF, DISCARD_XF, DISCARD_YF) val DiscardsV = NoopDiscardsFlags | OverwritesV diff --git a/src/main/scala/millfork/assembly/mos/Opcode.scala b/src/main/scala/millfork/assembly/mos/Opcode.scala index 609b8a4a..deefec36 100644 --- a/src/main/scala/millfork/assembly/mos/Opcode.scala +++ b/src/main/scala/millfork/assembly/mos/Opcode.scala @@ -120,7 +120,7 @@ object Opcode extends Enumeration { PHA_W, PLA_W, PHX_W, PHY_W, PLY_W, PLX_W, - DISCARD_AF, DISCARD_XF, DISCARD_YF, + DISCARD_AF, DISCARD_XF, DISCARD_YF, CHANGED_MEM, BYTE, LABEL = Value def widen(opcode: Opcode.Value): Option[Opcode.Value] = opcode match { diff --git a/src/main/scala/millfork/assembly/mos/opt/RuleBasedAssemblyOptimization.scala b/src/main/scala/millfork/assembly/mos/opt/RuleBasedAssemblyOptimization.scala index e444c25b..5b1199f0 100644 --- a/src/main/scala/millfork/assembly/mos/opt/RuleBasedAssemblyOptimization.scala +++ b/src/main/scala/millfork/assembly/mos/opt/RuleBasedAssemblyOptimization.scala @@ -268,6 +268,7 @@ object HelperCheckers { val a2 = l2.addrMode if (goodAddrModes(a1) || goodAddrModes(a2)) return true if (badAddrModes(a1) || badAddrModes(a2)) return false + if (l1.opcode == Opcode.CHANGED_MEM || l2.opcode == Opcode.CHANGED_MEM) return false if ((a1 == IndexedSY) != (a2 == IndexedSY)) return true // bold assertion, but usually true val p1 = l1.parameter val p2 = l2.parameter diff --git a/src/main/scala/millfork/assembly/z80/ZLine.scala b/src/main/scala/millfork/assembly/z80/ZLine.scala index f21b0e0b..ce06062a 100644 --- a/src/main/scala/millfork/assembly/z80/ZLine.scala +++ b/src/main/scala/millfork/assembly/z80/ZLine.scala @@ -868,6 +868,7 @@ case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Consta import ZOpcode._ import ZRegister._ opcode match { + case CHANGED_MEM => true case POP => true case LD | LD_16 | ADC_16 | ADD_16 | SBC_16 => registers match { case TwoRegisters(MEM_IX_D | MEM_ABS_16 | MEM_ABS_8 | MEM_DE | MEM_BC | MEM_IY_D | MEM_HL, _) => true diff --git a/src/main/scala/millfork/assembly/z80/ZOpcode.scala b/src/main/scala/millfork/assembly/z80/ZOpcode.scala index 8cc08ba1..32d81ad2 100644 --- a/src/main/scala/millfork/assembly/z80/ZOpcode.scala +++ b/src/main/scala/millfork/assembly/z80/ZOpcode.scala @@ -25,7 +25,7 @@ object ZOpcode extends Enumeration { DJNZ, JP, JR, CALL, RET, RETN, RETI, HALT, //sharp: LD_AHLI, LD_AHLD, LD_HLIA, LD_HLDA, SWAP, LDH_DA, LDH_AD, LDH_CA, LDH_AC, LD_HLSP, ADD_SP, STOP, - DISCARD_A, DISCARD_F, DISCARD_HL, DISCARD_BC, DISCARD_DE, DISCARD_IX, DISCARD_IY, + DISCARD_A, DISCARD_F, DISCARD_HL, DISCARD_BC, DISCARD_DE, DISCARD_IX, DISCARD_IY, CHANGED_MEM, LABEL, BYTE = Value } diff --git a/src/main/scala/millfork/assembly/z80/opt/RuleBasedAssemblyOptimization.scala b/src/main/scala/millfork/assembly/z80/opt/RuleBasedAssemblyOptimization.scala index 527f8824..2fa1ca2a 100644 --- a/src/main/scala/millfork/assembly/z80/opt/RuleBasedAssemblyOptimization.scala +++ b/src/main/scala/millfork/assembly/z80/opt/RuleBasedAssemblyOptimization.scala @@ -196,6 +196,7 @@ object HelperCheckers { case OneRegister(MEM_HL | MEM_IX_D | MEM_IY_D | MEM_BC | MEM_DE) => true case OneRegister(_) => false } + case CHANGED_MEM => true case POP | PUSH => false case _ => true // TODO } diff --git a/src/main/scala/millfork/env/Environment.scala b/src/main/scala/millfork/env/Environment.scala index 0ece32d5..5f0c0ee3 100644 --- a/src/main/scala/millfork/env/Environment.scala +++ b/src/main/scala/millfork/env/Environment.scala @@ -1,9 +1,9 @@ package millfork.env -import millfork.assembly.BranchingOpcodeMapping +import millfork.assembly.{BranchingOpcodeMapping, Elidability} import millfork.{env, _} -import millfork.assembly.mos.Opcode -import millfork.assembly.z80.{IfFlagClear, IfFlagSet, ZFlag} +import millfork.assembly.mos.{AddrMode, Opcode} +import millfork.assembly.z80._ import millfork.compiler.{AbstractExpressionCompiler, LabelGenerator} import millfork.error.Logger import millfork.node._ @@ -1300,6 +1300,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa def collectDeclarations(program: Program, options: CompilationOptions): Unit = { val b = get[VariableType]("byte") + val v = get[Type]("void") if (options.flag(CompilationFlag.OptimizeForSonicSpeed)) { addThing(InitializedArray("identity$", None, List.tabulate(256)(n => LiteralExpression(n, 1)), declaredBank = None, b, b, defaultArrayAlignment(options, 256)), None) } @@ -1345,6 +1346,14 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa } } } + + if (!things.contains("memory_barrier")) { + things("memory_barrier") = MacroFunction("memory_barrier", v, NormalParamSignature(Nil), this, CpuFamily.forType(options.platform.cpu) match { + case CpuFamily.M6502 => List(MosAssemblyStatement(Opcode.CHANGED_MEM, AddrMode.DoesNotExist, LiteralExpression(0, 1), Elidability.Fixed)) + case CpuFamily.I80 => List(Z80AssemblyStatement(ZOpcode.CHANGED_MEM, NoRegisters, None, LiteralExpression(0, 1), Elidability.Fixed)) + case _ => ??? + }) + } } def hintTypo(name: String): Unit = { diff --git a/src/main/scala/millfork/output/Z80Assembler.scala b/src/main/scala/millfork/output/Z80Assembler.scala index 26e9f5e2..357dfa8a 100644 --- a/src/main/scala/millfork/output/Z80Assembler.scala +++ b/src/main/scala/millfork/output/Z80Assembler.scala @@ -74,9 +74,9 @@ class Z80Assembler(program: Program, case ZLine0(BYTE, NoRegisters, param) => writeByte(bank, index, param) index + 1 - case ZLine0(DISCARD_F | DISCARD_HL | DISCARD_BC | DISCARD_DE | DISCARD_IX | DISCARD_IY | DISCARD_A, NoRegisters, _) => + case ZLine0(DISCARD_F | DISCARD_HL | DISCARD_BC | DISCARD_DE | DISCARD_IX | DISCARD_IY | DISCARD_A | CHANGED_MEM, NoRegisters, _) => index - case ZLine0(LABEL | BYTE | DISCARD_F | DISCARD_HL | DISCARD_BC | DISCARD_DE | DISCARD_IX | DISCARD_IY | DISCARD_A, _, _) => + case ZLine0(LABEL | BYTE | DISCARD_F | DISCARD_HL | DISCARD_BC | DISCARD_DE | DISCARD_IX | DISCARD_IY | DISCARD_A | CHANGED_MEM, _, _) => ??? case ZLine0(RST, NoRegisters, param) => val opcode = param.quickSimplify match {