millfork/src/main/scala/millfork/assembly/z80/opt/CoarseFlowAnalyzer.scala

387 lines
23 KiB
Scala

package millfork.assembly.z80.opt
import millfork.assembly.OptimizationContext
import millfork.assembly.opt.{AnyStatus, FlowCache, SingleStatus, Status}
import millfork.assembly.z80._
import millfork.env._
import millfork.node.Z80NiceFunctionProperty.{DoesntChangeA, DoesntChangeBC, DoesntChangeCF, DoesntChangeDE, DoesntChangeHL, SetsATo}
import millfork.node.{NiceFunctionProperty, ZRegister}
import millfork.CompilationFlag
import scala.util.control.Breaks._
/**
* @author Karol Stasiak
*/
object CoarseFlowAnalyzer {
val cache = new FlowCache[ZLine, CpuStatus]("z80 forward")
def analyze(f: NormalFunction, code: List[ZLine], optimizationContext: OptimizationContext): List[CpuStatus] = {
cache.get(code).foreach(return _)
val initialStatus = CpuStatus()
val functionStartStatus = CpuStatus()
val emptyStatus = CpuStatus()
val flagArray = Array.fill[CpuStatus](code.length)(emptyStatus)
val codeArray = code.toArray
val compilationOptions = optimizationContext.options
val z80 = compilationOptions.flag(CompilationFlag.EmitZ80Opcodes)
val niceFunctionProperties = optimizationContext.niceFunctionProperties
def extractNiceConstant[T](callee: String)(matcher: NiceFunctionProperty => Option[T]): Status[T] = {
var result: Status[T] = AnyStatus
breakable {
niceFunctionProperties.foreach{ np =>
if (np._2 == callee) matcher(np._1) match {
case Some(x) =>
result = SingleStatus(x)
break
case _ =>
}
}
}
result
}
// TODO: u16u16u16u16 division
val preservesB: Set[String] = Set("__mul_u8u8u8", "__mul_u16u16u16")
val preservesC: Set[String] = if (z80) Set("__mul_u8u8u8", "__mul_u16u16u16") else Set("__mul_u16u16u16")
val preservesD: Set[String] = Set()
val preservesE: Set[String] = Set("__divmod_u16u8u16u8")
val preservesH: Set[String] = Set("__mul_u8u8u8")
val preservesL: Set[String] = Set("__mul_u8u8u8")
// does the code preserve the stack variables apart from direct writes, assuming Z80 and base pointer in IX?
val preservesStackVariables = code.forall {
case ZLine0(ZOpcode.ADD_16, TwoRegisters(ZRegister.HL, ZRegister.SP), _) => false
case ZLine0(ZOpcode.ADD_16, TwoRegisters(ZRegister.IY, ZRegister.SP), _) => false
case ZLine0(ZOpcode.ADD_16, TwoRegisters(ZRegister.IX, ZRegister.SP), _) => compilationOptions.flag(CompilationFlag.UseIxForStack)
case _ => true
}
var changed = true
while (changed) {
changed = false
var currentStatus: CpuStatus = functionStartStatus
for (i <- codeArray.indices) {
import millfork.assembly.z80.ZOpcode._
if (flagArray(i) != currentStatus) {
changed = true
flagArray(i) = currentStatus
}
codeArray(i) match {
case ZLine0(LABEL, _, MemoryAddressConstant(Label(l))) =>
val L = l
currentStatus = codeArray.indices.flatMap(j => codeArray(j) match {
case ZLine0(DJNZ, _, MemoryAddressConstant(Label(L))) => Some(flagArray(j).copy(b = AnyStatus))
case ZLine0(_, _, MemoryAddressConstant(Label(L))) => Some(flagArray(j))
case _ => None
}).fold(currentStatus)(_ ~ _)
case ZLine0(CALL, reg, MemoryAddressConstant(fun: FunctionInMemory)) =>
val n = fun.name
val mayBeCalled = reg match {
case IfFlagSet(f) => !currentStatus.getFlag(f).contains(false)
case IfFlagClear(f) => !currentStatus.getFlag(f).contains(true)
case _ => true
}
if (mayBeCalled) {
val result = if (preservesStackVariables) initialStatus.copy(memIx = currentStatus.memIx) else initialStatus
currentStatus = result.copy(
b = if (preservesB(n) || niceFunctionProperties(DoesntChangeBC -> n)) currentStatus.b else result.b,
c = if (preservesC(n) || niceFunctionProperties(DoesntChangeBC -> n)) currentStatus.c else result.c,
d = if (preservesD(n) || niceFunctionProperties(DoesntChangeDE -> n)) currentStatus.d else result.d,
e = if (preservesE(n) || niceFunctionProperties(DoesntChangeDE-> n)) currentStatus.e else result.e,
h = if (preservesH(n) || niceFunctionProperties(DoesntChangeHL -> n)) currentStatus.h else result.h,
l = if (preservesL(n) || niceFunctionProperties(DoesntChangeHL -> n)) currentStatus.l else result.l,
hl = if (preservesH(n) && preservesL(n) || niceFunctionProperties(DoesntChangeHL -> n)) currentStatus.hl else result.hl,
a = if (niceFunctionProperties(DoesntChangeA -> n)) currentStatus.a else extractNiceConstant(n){
case SetsATo(a) => Some(a)
case _ => None
},
cf = if (niceFunctionProperties(DoesntChangeCF -> n)) currentStatus.cf else AnyStatus
)
}
case ZLine0(NOP | DISCARD_A | DISCARD_BC | DISCARD_DE | DISCARD_HL | DISCARD_F | SIM, _, _) =>
()
case ZLine0(PUSH, _, _) =>
()
case ZLine0(POP, OneRegister(r), _) =>
currentStatus = currentStatus.setRegister(r, AnyStatus)
case ZLine0(JR | JP | RET, IfFlagSet(flag), _) =>
currentStatus = currentStatus.setFlag(flag, newStatus = false)
case ZLine0(JR | JP | RET, IfFlagClear(flag), _) =>
currentStatus = currentStatus.setFlag(flag, newStatus = true)
case ZLine0(JR | JP | RET, NoRegisters | OneRegister(_), _) =>
currentStatus = initialStatus.copy(memIx = currentStatus.memIx)
case ZLine0(DJNZ, _, _) =>
// TODO
currentStatus = currentStatus.copy(
b = Status.SingleZero,
zf = Status.SingleTrue,
nf = AnyStatus,
cf = AnyStatus,
hf = AnyStatus,
sf = AnyStatus)
case ZLine0(BYTE, _, _) =>
currentStatus = initialStatus
case ZLine0(SUB, OneRegister(ZRegister.IMM_8), NumericConstant(0, _)) =>
currentStatus = currentStatus.copy(
nf = Status.SingleTrue,
cf = Status.SingleFalse,
zf = currentStatus.a.z(),
sf = currentStatus.a.n(),
pf = if (z80) Status.SingleFalse else AnyStatus,
hf = Status.SingleFalse)
case l@ZLine0(ADD, OneRegister(ZRegister.IMM_8), NumericConstant(n, _)) =>
val (newA, newC) = currentStatus.a.adc(n.toInt, currentStatus.cf, Status.SingleFalse)
currentStatus = currentStatus.copy(a = newA,
nf = Status.SingleFalse, cf = newC, zf = newA.z(), sf = newA.n(), pf = AnyStatus, hf = AnyStatus)
case l@ZLine0(ADC, OneRegister(ZRegister.IMM_8), NumericConstant(n, _)) =>
val (newA, newC) = currentStatus.a.adc(n.toInt, currentStatus.cf, Status.SingleFalse)
currentStatus = currentStatus.copy(a = newA,
nf = Status.SingleFalse, cf = newC, zf = newA.z(), sf = newA.n(), pf = AnyStatus, hf = AnyStatus)
case l@ZLine0(ADD, OneRegister(s), _) =>
val (newA, newC) = currentStatus.a.adc(currentStatus.getRegister(s), Status.SingleFalse)
currentStatus = currentStatus.copy(a = newA,
nf = Status.SingleFalse, cf = newC, zf = newA.z(), sf = newA.n(), pf = AnyStatus, hf = AnyStatus)
case l@ZLine0(ADC, OneRegister(s), _) =>
val (newA, newC) = currentStatus.a.adc(currentStatus.getRegister(s), currentStatus.cf)
currentStatus = currentStatus.copy(a = newA,
nf = Status.SingleFalse, cf = newC, zf = newA.z(), sf = newA.n(), pf = AnyStatus, hf = AnyStatus)
case ZLine0(SUB, OneRegister(ZRegister.IMM_8), NumericConstant(n, _)) =>
val (newA, newC) = currentStatus.a.sbb(SingleStatus(n.toInt & 0xff), Status.SingleFalse)
currentStatus = currentStatus.copy(a = newA,
nf = Status.SingleTrue, cf = newC, zf = newA.z(), sf = newA.n(), pf = AnyStatus, hf = AnyStatus)
case ZLine0(SBC,OneRegister(ZRegister.IMM_8), NumericConstant(n, _))=>
val (newA, newC) = currentStatus.a.sbb(SingleStatus(n.toInt & 0xff), currentStatus.cf)
currentStatus = currentStatus.copy(a = newA,
nf = Status.SingleTrue, cf = newC,zf = newA.z(), sf = newA.n(), pf = AnyStatus, hf = AnyStatus)
case ZLine0(SUB, OneRegister(s), _) =>
val (newA, newC) = currentStatus.a.sbb(currentStatus.getRegister(s), Status.SingleFalse)
currentStatus = currentStatus.copy(a = newA,
nf = Status.SingleTrue, cf = newC, zf = newA.z(), sf = newA.n(), pf = AnyStatus, hf = AnyStatus)
case ZLine0(SBC, OneRegister(s), _) =>
val (newA, newC) = currentStatus.a.sbb(currentStatus.getRegister(s), currentStatus.cf)
currentStatus = currentStatus.copy(a = newA,
nf = Status.SingleTrue, cf = newC,zf = newA.z(), sf = newA.n(), pf = AnyStatus, hf = AnyStatus)
case ZLine0(AND, OneRegister(s), _) =>
currentStatus = currentStatus.copy(a = (currentStatus.a <*> currentStatus.getRegister(s)) ((m, n) => (m & n) & 0xff),
nf = Status.SingleFalse, cf = Status.SingleFalse, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
case ZLine0(OR, OneRegister(ZRegister.A), _) =>
currentStatus = currentStatus.copy(nf = Status.SingleFalse, cf = Status.SingleFalse, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
case ZLine0(XOR, OneRegister(ZRegister.A), _) =>
currentStatus = currentStatus.copy(a = Status.SingleZero, nf = Status.SingleFalse, cf = Status.SingleFalse, zf = Status.SingleTrue, sf = Status.SingleFalse, pf = AnyStatus, hf = AnyStatus)
case ZLine0(OR, OneRegister(s), _) =>
currentStatus = currentStatus.copy(a = (currentStatus.a <*> currentStatus.getRegister(s)) ((m, n) => (m | n) & 0xff),
nf = Status.SingleFalse, cf = Status.SingleFalse, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
case ZLine0(XOR, OneRegister(s), _) =>
currentStatus = currentStatus.copy(a = (currentStatus.a <*> currentStatus.getRegister(s)) ((m, n) => (m ^ n) & 0xff),
nf = Status.SingleFalse, cf = Status.SingleFalse, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
case ZLine0(CP, OneRegister(ZRegister.IMM_8), NumericConstant(n, _)) =>
val (newA, newC) = currentStatus.a.sbb(SingleStatus(n.toInt & 0xff), Status.SingleFalse)
currentStatus = currentStatus.copy(nf = AnyStatus, cf = newC, zf = newA.z(), sf = newA.n(), pf = AnyStatus, hf = AnyStatus)
case ZLine0(CP, OneRegister(s), _) =>
val (newA, newC) = currentStatus.a.sbb(currentStatus.getRegister(s), Status.SingleFalse)
currentStatus = currentStatus.copy(nf = AnyStatus, cf = newC, zf = newA.z(), sf = newA.n(), pf = AnyStatus, hf = AnyStatus)
case ZLine0(INC, OneRegister(r), _) =>
val newV = currentStatus.getRegister(r).map(i => i.+(1).&(0xff))
currentStatus = currentStatus.
copy(cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus).
setRegister(r, newV).
cleanMemIxIfNeeded(preservesStackVariables, r)
case ZLine0(DEC, OneRegister(r), _) =>
val newV = currentStatus.getRegister(r).map(i => i.-(1).&(0xff))
currentStatus = currentStatus.
copy(cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus).
setRegister(r, newV).
cleanMemIxIfNeeded(preservesStackVariables, r)
case ZLine0(INC, OneRegisterOffset(r, o), _) =>
val newV = currentStatus.cleanMemIxIfNeeded(preservesStackVariables, r).getRegister(r, o).map(i => i.+(1).&(0xff))
currentStatus = currentStatus.
copy(cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus).
setRegister(r, newV, o)
case ZLine0(DEC, OneRegisterOffset(r, o), _) =>
val newV = currentStatus.cleanMemIxIfNeeded(preservesStackVariables, r).getRegister(r, o).map(i => i.-(1).&(0xff))
currentStatus = currentStatus.
copy(cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus).
setRegister(r, newV, o)
case ZLine0(INC_16, OneRegister(r), _) =>
val newV = currentStatus.getRegister(r).map(i => i.+(1).&(0xffff))
currentStatus = currentStatus.
copy(cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus).
setRegister(r, newV)
case ZLine0(DEC_16, OneRegister(r), _) =>
val newV = currentStatus.getRegister(r).map(i => i.-(1).&(0xffff))
currentStatus = currentStatus.
copy(cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus).
setRegister(r, newV)
case ZLine0(LD_AHLI, _, _) =>
val newHL = currentStatus.getRegister(ZRegister.HL).map(i => i.+(1).&(0xffff))
currentStatus = currentStatus.copy(a = AnyStatus).setRegister(ZRegister.HL, newHL).
cleanMemIxIfNeeded(preservesStackVariables, ZRegister.MEM_HL)
case ZLine0(LD_HLIA, _, _) =>
val newHL = currentStatus.getRegister(ZRegister.HL).map(i => i.+(1).&(0xffff))
currentStatus = currentStatus.setRegister(ZRegister.HL, newHL).
cleanMemIxIfNeeded(preservesStackVariables, ZRegister.MEM_HL)
case ZLine0(LD_AHLD, _, _) =>
val newHL = currentStatus.getRegister(ZRegister.HL).map(i => i.-(1).&(0xffff))
currentStatus = currentStatus.copy(a = AnyStatus).setRegister(ZRegister.HL, newHL).
cleanMemIxIfNeeded(preservesStackVariables, ZRegister.MEM_HL)
case ZLine0(LD_HLDA, _, _) =>
val newHL = currentStatus.getRegister(ZRegister.HL).map(i => i.-(1).&(0xffff))
currentStatus = currentStatus.setRegister(ZRegister.HL, newHL).
cleanMemIxIfNeeded(preservesStackVariables, ZRegister.MEM_HL)
case ZLine0(op, OneRegister(r), _) if ZOpcodeClasses.SET(op) =>
currentStatus = currentStatus.setRegister(r, currentStatus.getRegister(r).map(i => i | 1.<<(ZOpcodeClasses.SET_seq.indexOf(op)))).
cleanMemIxIfNeeded(preservesStackVariables, r)
case ZLine0(op, OneRegister(r), _) if ZOpcodeClasses.RES(op) =>
currentStatus = currentStatus.setRegister(r, currentStatus.getRegister(r).map(i => i & ~1.<<(ZOpcodeClasses.RES_seq.indexOf(op)))).
cleanMemIxIfNeeded(preservesStackVariables, r)
case l@ZLine0(ADD, OneRegisterOffset(s, o), _) =>
val (newA, newC) = currentStatus.a.adc(currentStatus.getRegister(s, o), Status.SingleFalse)
currentStatus = currentStatus.copy(a = newA,
nf = Status.SingleFalse, cf = newC, zf = newA.z(), sf = newA.n(), pf = AnyStatus, hf = AnyStatus)
case l@ZLine0(ADC, OneRegisterOffset(s, o), _) =>
val (newA, newC) = currentStatus.a.adc(currentStatus.getRegister(s, o), currentStatus.cf)
currentStatus = currentStatus.copy(a = newA,
nf = Status.SingleFalse, cf = newC, zf = newA.z(), sf = newA.n(), pf = AnyStatus, hf = AnyStatus)
case ZLine0(SUB, OneRegisterOffset(s, o), _) =>
currentStatus = currentStatus.copy(a = (currentStatus.a <*> currentStatus.getRegister(s, o)) ((m, n) => (m - n) & 0xff),
cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
case ZLine0(AND, OneRegisterOffset(s, o), _) =>
currentStatus = currentStatus.copy(a = (currentStatus.a <*> currentStatus.getRegister(s, o)) ((m, n) => (m & n) & 0xff),
cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
case ZLine0(OR, OneRegisterOffset(s, o), _) =>
currentStatus = currentStatus.copy(a = (currentStatus.a <*> currentStatus.getRegister(s, o)) ((m, n) => (m | n) & 0xff),
cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
case ZLine0(XOR, OneRegisterOffset(s, o), _) =>
currentStatus = currentStatus.copy(a = (currentStatus.a <*> currentStatus.getRegister(s, o)) ((m, n) => (m ^ n) & 0xff),
cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
case ZLine0(CP, _, _) =>
currentStatus = currentStatus.copy(cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
case ZLine0(LD_16, TwoRegisters(t, ZRegister.IMM_16), NumericConstant(value, _)) =>
currentStatus = currentStatus.setRegister(t, SingleStatus(value.toInt))
case ZLine0(LD_16, TwoRegisters(ZRegister.HL, ZRegister.IMM_16), xx) =>
currentStatus = currentStatus.setHL(SingleStatus(xx))
case ZLine0(LD_16, TwoRegisters(ZRegister.DE, ZRegister.IMM_16), xx) if xx.isProvablyDivisibleBy256 =>
currentStatus = currentStatus.copy(d = AnyStatus, e = Status.SingleZero)
case ZLine0(LD_16, TwoRegisters(ZRegister.BC, ZRegister.IMM_16), xx) if xx.isProvablyDivisibleBy256 =>
currentStatus = currentStatus.copy(b = AnyStatus, c = Status.SingleZero)
case ZLine0(LD, TwoRegisters(ZRegister.A, ZRegister.I | ZRegister.R), _) =>
currentStatus = currentStatus.copy(a = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus, nf = AnyStatus)
case ZLine0(LD, TwoRegisters(t, ZRegister.IMM_8), NumericConstant(value, _)) =>
currentStatus = currentStatus.setRegister(t, SingleStatus(value.toInt)).
cleanMemIxIfNeeded(preservesStackVariables, t)
case ZLine0(LD, TwoRegistersOffset(t, ZRegister.IMM_8, o), NumericConstant(value, _)) =>
currentStatus = currentStatus.cleanMemIxIfNeeded(preservesStackVariables, t).setRegister(t, SingleStatus(value.toInt), o)
case ZLine0(LD | LD_16, TwoRegisters(t, s), _) =>
currentStatus = currentStatus.setRegister(t, currentStatus.getRegister(s)).cleanMemIxIfNeeded(preservesStackVariables, t)
case ZLine0(LD | LD_16, TwoRegistersOffset(t, s, o), _) =>
currentStatus = currentStatus.setRegister(t, currentStatus.getRegister(s, o), o)
case ZLine0(EX_DE_HL, _, _) =>
currentStatus = currentStatus.copy(d = currentStatus.h, e = currentStatus.l, h = currentStatus.d, l = currentStatus.e)
case ZLine0(ADD_16, TwoRegisters(t, s), _) =>
currentStatus = currentStatus.copy(cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
.setRegister(t, (currentStatus.getRegister(t) <*> currentStatus.getRegister(s)) ((m, n) => (m + n) & 0xffff))
case ZLine0(SLA, OneRegister(r), _) =>
currentStatus = currentStatus.copy(cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
.setRegister(r, currentStatus.getRegister(r).map(_.<<(1).&(0xff)))
.cleanMemIxIfNeeded(preservesStackVariables, r)
case ZLine0(SRL, OneRegister(r), _) =>
currentStatus = currentStatus.copy(cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
.setRegister(r, currentStatus.getRegister(r).map(_.>>(1).&(0x7f)))
.cleanMemIxIfNeeded(preservesStackVariables, r)
case ZLine0(RLA | RRA | RLCA | RRCA, _, _) =>
currentStatus = currentStatus.copy(
a = AnyStatus, cf = AnyStatus,
zf = AnyStatus,
pf = AnyStatus, hf = Status.SingleFalse)
case ZLine0(SCF, _, _) =>
currentStatus = currentStatus.copy(cf = Status.SingleTrue, hf = Status.SingleFalse, nf = Status.SingleFalse)
case ZLine0(CCF, _, _) =>
currentStatus = currentStatus.copy(cf = currentStatus.cf.negate, hf = AnyStatus, nf = AnyStatus)
case ZLine0(CPL, _, _) =>
currentStatus = currentStatus.copy(a = currentStatus.a.map(_ ^ 0xff), hf = AnyStatus, nf = Status.SingleTrue)
case ZLine0(NEG, _, _) =>
currentStatus = currentStatus.copy(
a = currentStatus.a.map(x => (-x)&0xff),
hf = AnyStatus,
zf = currentStatus.a.z(),
sf = AnyStatus,
cf = AnyStatus,
pf = AnyStatus,
nf = Status.SingleTrue)
case ZLine0(DAA, _, _) =>
// TODO: full algorithm?
currentStatus = currentStatus.copy(
a = if (currentStatus.h.contains(false)) currentStatus.a else AnyStatus,
hf = AnyStatus,
zf = AnyStatus,
sf = AnyStatus,
cf = AnyStatus,
pf = AnyStatus)
case ZLine0(BIT7, OneRegister(r), _) =>
currentStatus = currentStatus.copy(
zf = currentStatus.getRegister(r).bit7.negate,
hf = Status.SingleTrue,
sf = AnyStatus,
pf = AnyStatus,
nf = Status.SingleFalse)
case ZLine0(BIT0, OneRegister(r), _) =>
currentStatus = currentStatus.copy(
zf = currentStatus.getRegister(r).bit0.negate,
hf = Status.SingleTrue,
sf = AnyStatus,
pf = AnyStatus,
nf = Status.SingleFalse)
case ZLine0(RIM, _, _) =>
currentStatus = currentStatus.copy(a = AnyStatus)
case ZLine0(opcode, registers, _) =>
currentStatus = currentStatus.copy(cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
if (ZOpcodeClasses.ChangesAAlways(opcode)) currentStatus = currentStatus.copy(a = AnyStatus)
if (ZOpcodeClasses.ChangesBCAlways(opcode)) currentStatus = currentStatus.copy(b = AnyStatus, c = AnyStatus)
if (ZOpcodeClasses.ChangesDEAlways(opcode)) currentStatus = currentStatus.copy(d = AnyStatus, e = AnyStatus)
registers match {
case OneRegister(r) => currentStatus = currentStatus.setRegister(r, AnyStatus)
case TwoRegisters(r1, r2) => currentStatus = currentStatus.setRegister(r1, AnyStatus).setRegister(r2, AnyStatus)
case OneRegisterOffset(r1, o) => currentStatus = currentStatus.setRegister(r1, AnyStatus, o)
case TwoRegistersOffset(r1, r2, o) => currentStatus = currentStatus.setRegister(r1, AnyStatus, o).setRegister(r2, AnyStatus, o)
case _ => ()
}
}
}
// flagArray.zip(codeArray).foreach{
// case (fl, y) => if (y.isPrintable) println(f"$fl%-32s $y%-32s")
// }
// println("---------------------")
}
cache.put(code, flagArray.toList)
}
}