diff --git a/src/main/scala/millfork/assembly/mos/opt/CoarseFlowAnalyzer.scala b/src/main/scala/millfork/assembly/mos/opt/CoarseFlowAnalyzer.scala index e9461d86..ac3d1423 100644 --- a/src/main/scala/millfork/assembly/mos/opt/CoarseFlowAnalyzer.scala +++ b/src/main/scala/millfork/assembly/mos/opt/CoarseFlowAnalyzer.scala @@ -73,7 +73,7 @@ object CoarseFlowAnalyzer { currentStatus = FlowAnalyzerForImmediate.get(op)(nn.toInt, currentStatus) case AssemblyLine(op, _, _, _) if FlowAnalyzerForTheRest.hasDefinition(op) => - currentStatus = FlowAnalyzerForTheRest.get(op)(currentStatus) + currentStatus = FlowAnalyzerForTheRest.get(op)(currentStatus, None) case AssemblyLine(opcode, addrMode, _, _) => currentStatus = currentStatus.copy(src = AnyStatus) diff --git a/src/main/scala/millfork/assembly/mos/opt/CpuStatus.scala b/src/main/scala/millfork/assembly/mos/opt/CpuStatus.scala index 14d52a1e..ae59fe75 100644 --- a/src/main/scala/millfork/assembly/mos/opt/CpuStatus.scala +++ b/src/main/scala/millfork/assembly/mos/opt/CpuStatus.scala @@ -47,6 +47,10 @@ case class CpuStatus(a: Status[Int] = UnknownStatus, x: Status[Int] = UnknownStatus, y: Status[Int] = UnknownStatus, iz: Status[Int] = UnknownStatus, + r0: Status[Int] = UnknownStatus, + r1: Status[Int] = UnknownStatus, + r2: Status[Int] = UnknownStatus, + r3: Status[Int] = UnknownStatus, src: Status[SourceOfNZ] = UnknownStatus, eqSX: Boolean = false, z: Status[Boolean] = UnknownStatus, @@ -90,7 +94,7 @@ case class CpuStatus(a: Status[Int] = UnknownStatus, // case _ => // } - override def toString: String = s"A=$a,B=$ah,X=$x,Y=$y,Z=$iz; Z=$z,N=$n,C=$c,V=$v,D=$d,M=$m,X=$w; A7=$a7,A0=$a0,NZ:$src" + + override def toString: String = s"A=$a,B=$ah,X=$x,Y=$y,Z=$iz; Z=$z,N=$n,C=$c,V=$v,D=$d,M=$m,X=$w; R0=$r0,R1=$r1,R2=$r2,R3=$r3; A7=$a7,A0=$a0,NZ:$src" + (if (eqSX) "; S=X" else /* */ " ") @@ -159,6 +163,39 @@ case class CpuStatus(a: Status[Int] = UnknownStatus, case State.W => w.contains(true) case _ => false } + + def reg(i: Int) : Status[Int] = i match { + case 0 => r0 + case 1 => r1 + case 2 => r2 + case 3 => r3 + case _ => AnyStatus + } + + def getReg(i: Option[Int]) : Status[Int] = i match { + case Some(0) => r0 + case Some(1) => r1 + case Some(2) => r2 + case Some(3) => r3 + case _ => AnyStatus + } + + def getRegHi(i: Option[Int]) : Status[Int] = i match { + case Some(0) => r1 + case Some(1) => r2 + case Some(2) => r3 + case _ => AnyStatus + } + + def setReg(i: Option[Int], status: Status[Int]): CpuStatus = { + i match { + case Some(0) => this.copy(r0 = status) + case Some(1) => this.copy(r1 = status) + case Some(2) => this.copy(r2 = status) + case Some(3) => this.copy(r3 = status) + case None => this + } + } } object CpuStatus { @@ -173,7 +210,11 @@ object CpuStatus { d = SingleStatus(false), m = SingleStatus(true), w = SingleStatus(true), - iz = SingleStatus(0) + iz = SingleStatus(0), + r0 = AnyStatus, + r1 = AnyStatus, + r2 = AnyStatus, + r3 = AnyStatus, ) val initialStatusCE = CpuStatus( a = AnyStatus, @@ -186,7 +227,11 @@ object CpuStatus { d = SingleStatus(false), m = SingleStatus(true), w = SingleStatus(true), - iz = AnyStatus + iz = AnyStatus, + r0 = AnyStatus, + r1 = AnyStatus, + r2 = AnyStatus, + r3 = AnyStatus, ) val initialInterruptStatusStandard = CpuStatus( @@ -200,7 +245,11 @@ object CpuStatus { d = AnyStatus, m = AnyStatus, w = AnyStatus, - iz = SingleStatus(0) + iz = SingleStatus(0), + r0 = AnyStatus, + r1 = AnyStatus, + r2 = AnyStatus, + r3 = AnyStatus, ) val initialInterruptStatusCmos = CpuStatus( a = AnyStatus, @@ -213,7 +262,11 @@ object CpuStatus { d = SingleStatus(false), m = AnyStatus, w = AnyStatus, - iz = SingleStatus(0) + iz = SingleStatus(0), + r0 = AnyStatus, + r1 = AnyStatus, + r2 = AnyStatus, + r3 = AnyStatus, ) val initialInterruptStatusCE = CpuStatus( a = AnyStatus, @@ -226,7 +279,11 @@ object CpuStatus { d = SingleStatus(false), m = AnyStatus, w = AnyStatus, - iz = AnyStatus + iz = AnyStatus, + r0 = AnyStatus, + r1 = AnyStatus, + r2 = AnyStatus, + r3 = AnyStatus, ) val emptyStatusStandard = CpuStatus(iz = SingleStatus(0)) diff --git a/src/main/scala/millfork/assembly/mos/opt/FlowAnalyzerForImmediate.scala b/src/main/scala/millfork/assembly/mos/opt/FlowAnalyzerForImmediate.scala index c6cdc814..a7bb5e3f 100644 --- a/src/main/scala/millfork/assembly/mos/opt/FlowAnalyzerForImmediate.scala +++ b/src/main/scala/millfork/assembly/mos/opt/FlowAnalyzerForImmediate.scala @@ -72,7 +72,7 @@ object FlowAnalyzerForImmediate { }, ADC -> {(nn, currentStatus) => val n = nn & 0xff - val newA = currentStatus.a.adc(n, currentStatus.c, currentStatus.d) + val (newA, newC) = currentStatus.a.adc(n, currentStatus.c, currentStatus.d) currentStatus.copy( n = newA.n(), z = newA.z(), @@ -80,7 +80,7 @@ object FlowAnalyzerForImmediate { a = newA, a0 = newA.bit0, a7 = newA.bit7, - c = Status.flatMap3(currentStatus.a, currentStatus.c, currentStatus.d) { + c = newC | Status.flatMap3(currentStatus.a, currentStatus.c, currentStatus.d) { case (aa, false, false) => SingleStatus((aa & 0xff) + n >= 0x100) case _ => AnyStatus }, @@ -88,7 +88,7 @@ object FlowAnalyzerForImmediate { }, SBC -> {(nn, currentStatus) => val n = nn & 0xff - val newA = currentStatus.a.sbc(n, currentStatus.c, currentStatus.d) + val (newA, newC) = currentStatus.a.sbc(n, currentStatus.c, currentStatus.d) currentStatus.copy( n = newA.n(), z = newA.z(), @@ -96,7 +96,7 @@ object FlowAnalyzerForImmediate { a = newA, a0 = newA.bit0, a7 = newA.bit7, - c = AnyStatus, + c = newC, v = AnyStatus) }, EOR -> {(nn, currentStatus) => diff --git a/src/main/scala/millfork/assembly/mos/opt/FlowAnalyzerForTheRest.scala b/src/main/scala/millfork/assembly/mos/opt/FlowAnalyzerForTheRest.scala index 932ad9be..a03468cd 100644 --- a/src/main/scala/millfork/assembly/mos/opt/FlowAnalyzerForTheRest.scala +++ b/src/main/scala/millfork/assembly/mos/opt/FlowAnalyzerForTheRest.scala @@ -8,35 +8,35 @@ import millfork.assembly.opt.{AnyStatus, SingleStatus, Status} * @author Karol Stasiak */ object FlowAnalyzerForTheRest { - private val map: Map[Opcode.Value, CpuStatus => CpuStatus] = Map( - STA -> identity, - STX -> identity, - STY -> identity, - STZ -> identity, - SAX -> identity, - NOP -> identity, - DISCARD_AF -> identity, - DISCARD_XF -> identity, - DISCARD_YF -> identity, - REP -> (currentStatus => { + private val map: Map[Opcode.Value, (CpuStatus, Option[Int]) => CpuStatus] = Map( + STA -> ((c,zpreg) => c.setReg(zpreg, c.a)), + STX -> ((c,zpreg) => c.setReg(zpreg, c.x)), + STY -> ((c,zpreg) => c.setReg(zpreg, c.y)), + STZ -> ((c,zpreg) => c.setReg(zpreg, c.iz)), + SAX -> ((c,zpreg) => c.setReg(zpreg, (c.a <*> c.x)(_ & _))), + NOP -> ((x,_) => x), + DISCARD_AF -> ((x,_) => x), + DISCARD_XF -> ((x,_) => x), + DISCARD_YF -> ((x,_) => x), + REP -> ((currentStatus, zpreg) => { currentStatus.copy(c = AnyStatus, d = AnyStatus, n = AnyStatus, z= AnyStatus, v = AnyStatus, m = AnyStatus, w = AnyStatus) }), - SEP -> (currentStatus => { + SEP -> ((currentStatus, zpreg) => { currentStatus.copy(c = AnyStatus, d = AnyStatus, n = AnyStatus, z= AnyStatus, v = AnyStatus, m = AnyStatus, w = AnyStatus) }), - BCC -> (currentStatus => { + BCC -> ((currentStatus, zpreg) => { currentStatus.copy(c = Status.SingleTrue) }), - BCS -> (currentStatus => { + BCS -> ((currentStatus, zpreg) => { currentStatus.copy(c = Status.SingleFalse) }), - BVS -> (currentStatus => { + BVS -> ((currentStatus, zpreg) => { currentStatus.copy(v = Status.SingleFalse) }), - BVC -> (currentStatus => { + BVC -> ((currentStatus, zpreg) => { currentStatus.copy(v = Status.SingleTrue) }), - BMI -> (c => { + BMI -> ((c, zpreg) => { var currentStatus = c currentStatus = currentStatus.copy(n = Status.SingleFalse) if (currentStatus.src.isFromA) { @@ -44,7 +44,7 @@ object FlowAnalyzerForTheRest { } currentStatus }), - BPL -> (c => { + BPL -> ((c, zpreg) => { var currentStatus = c currentStatus = currentStatus.copy(n = Status.SingleTrue) if (currentStatus.src.isFromA) { @@ -52,10 +52,10 @@ object FlowAnalyzerForTheRest { } currentStatus }), - BEQ -> (currentStatus => { + BEQ -> ((currentStatus, zpreg) => { currentStatus.copy(z = Status.SingleFalse) }), - BNE -> (c => { + BNE -> ((c, zpreg) => { var currentStatus = c currentStatus = currentStatus.copy(z = Status.SingleTrue) if (currentStatus.src.isFromA) { @@ -79,100 +79,123 @@ object FlowAnalyzerForTheRest { } currentStatus }), - LDX -> (currentStatus => { + LDX -> ((currentStatus, zpreg) => { + val newX = currentStatus.getReg(zpreg) currentStatus.copy( - x = AnyStatus, - n = AnyStatus, - z = AnyStatus, + x = newX, + n = newX.n(), + z = newX.z(), src = SourceOfNZ.X) }), - LDY -> (currentStatus => { + LDY -> ((currentStatus, zpreg) => { + val newY = currentStatus.getReg(zpreg) currentStatus.copy( - y = AnyStatus, - n = AnyStatus, - z = AnyStatus, + y = newY, + n = newY.n(), + z = newY.z(), src = SourceOfNZ.Y) }), - LDA -> (currentStatus => { + LDA -> ((currentStatus, zpreg) => { + val newA = currentStatus.getReg(zpreg) currentStatus.copy( - a = AnyStatus, - a7 = AnyStatus, - a0 = AnyStatus, - n = AnyStatus, - z = AnyStatus, + a = newA, + a7 = newA.bit7, + a0 = newA.bit0, + n = newA.n(), + z = newA.z(), src = SourceOfNZ.A) }), - LDZ -> (currentStatus => { + LDZ -> ((currentStatus, zpreg) => { + val newZ = currentStatus.getReg(zpreg) currentStatus.copy( - iz = AnyStatus, - n = AnyStatus, - z = AnyStatus, + iz = newZ, + n = newZ.n(), + z = newZ.z(), src = SourceOfNZ.Z) }), - LAX -> (currentStatus => { + LAX -> ((currentStatus, zpreg) => { + val newA = currentStatus.getReg(zpreg) currentStatus.copy( - x = AnyStatus, - a = AnyStatus, - a7 = AnyStatus, - a0 = AnyStatus, - n = AnyStatus, - z = AnyStatus, + x = newA, + a = newA, + a7 = newA.bit7, + a0 = newA.bit0, + n = newA.n(), + z = newA.z(), src = SourceOfNZ.AX) }), - LDA_W -> (currentStatus => { + LDA_W -> ((currentStatus, zpreg) => { + val newA = currentStatus.getReg(zpreg) + val newAH = currentStatus.getRegHi(zpreg) currentStatus.copy( - ah = AnyStatus, - a = AnyStatus, + ah = newAH, + a = newA, a7 = AnyStatus, - a0 = AnyStatus, + a0 = newA.bit0, n = AnyStatus, z = AnyStatus, src = SourceOfNZ.AW) }), - LDX_W -> (currentStatus => { + LDX_W -> ((currentStatus, zpreg) => { currentStatus.copy( x = AnyStatus, n = AnyStatus, z = AnyStatus, src = AnyStatus) }), - LDY_W -> (currentStatus => { + LDY_W -> ((currentStatus, zpreg) => { currentStatus.copy( y = AnyStatus, n = AnyStatus, z = AnyStatus, src = AnyStatus) }), - ADC -> (currentStatus => { + ADC -> ((currentStatus, zpreg) => { + val r = currentStatus.getReg(zpreg) + val newA: Status[Int]= if (currentStatus.d.contains(false)) Status.flatMap3(currentStatus.a, r, currentStatus.c) { + case (m, n, false) => SingleStatus((m + n) & 0xff) + case (m, n, true) => SingleStatus((m + n + 1) & 0xff) + } else AnyStatus + val newC: Status[Boolean]= if (currentStatus.d.contains(false)) Status.flatMap3(currentStatus.a, r, currentStatus.c) { + case (m, n, false) => SingleStatus((m.&(0xff) + n.&(0xff)) > 0xff) + case (m, n, true) => SingleStatus((m.&(0xff) + n.&(0xff) + 1) > 0xff) + } else AnyStatus currentStatus.copy( - a = AnyStatus, - a7 = AnyStatus, - a0 = AnyStatus, + a = newA, + a7 = newA.bit7, + a0 = newA.bit0, v = AnyStatus, - c = Status.flatMap3(currentStatus.a, currentStatus.c, currentStatus.d) { + c = newC | Status.flatMap3(currentStatus.a, currentStatus.c, currentStatus.d) { case (0, false, false) => SingleStatus[Boolean](false) case _ => AnyStatus }, - z = AnyStatus, - n = AnyStatus, + z = newA.z(), + n = newA.n(), src = currentStatus.d.flatMap((dec: Boolean) => if (dec) AnyStatus else SourceOfNZ.A)) }), - SBC -> (currentStatus => { + SBC -> ((currentStatus, zpreg) => { + val r = currentStatus.getReg(zpreg) + val newA: Status[Int]= if (currentStatus.d.contains(false)) Status.flatMap3(currentStatus.a, r, currentStatus.c) { + case (m, n, false) => SingleStatus((m - n + 0xff) & 0xff) + case (m, n, true) => SingleStatus((m - n + 0x100) & 0xff) + } else AnyStatus currentStatus.copy( - a = AnyStatus, - a7 = AnyStatus, - a0 = AnyStatus, + a = newA, + a7 = newA.bit7, + a0 = newA.bit0, v = AnyStatus, c = Status.flatMap3(currentStatus.a, currentStatus.c, currentStatus.d) { case (0xff, true, false) => SingleStatus[Boolean](true) case _ => AnyStatus }, - z = AnyStatus, - n = AnyStatus, + z = newA.z(), + n = newA.n(), src = currentStatus.d.flatMap((dec: Boolean) => if (dec) AnyStatus else SourceOfNZ.A)) }), - AND -> (currentStatus => { - val newA: Status[Int] = currentStatus.a.flatMap(v => if ((v & 0xff) == 0) Status.SingleZero else AnyStatus) + AND -> ((currentStatus, zpreg) => { + val newA: Status[Int] = + currentStatus.a.flatMap(v => if ((v & 0xff) == 0) Status.SingleZero else AnyStatus) | + (currentStatus.a <*> currentStatus.getReg(zpreg))(_ & _) currentStatus.copy( a = newA, a7 = currentStatus.a7.flatMap(v => if (!v) Status.SingleFalse else AnyStatus), @@ -181,8 +204,10 @@ object FlowAnalyzerForTheRest { z = newA.z(), src = SourceOfNZ.A) }), - ORA -> (currentStatus => { - val newA: Status[Int] = currentStatus.a.flatMap(v => if ((v & 0xff) == 0xff) Status.SingleFF else AnyStatus) + ORA -> ((currentStatus, zpreg) => { + val newA: Status[Int] = + currentStatus.a.flatMap(v => if ((v & 0xff) == 0xff) Status.SingleFF else AnyStatus) | + (currentStatus.a <*> currentStatus.getReg(zpreg))(_ | _) currentStatus.copy( a = newA, a7 = currentStatus.a7.flatMap(v => if (v) Status.SingleTrue else AnyStatus), @@ -191,7 +216,7 @@ object FlowAnalyzerForTheRest { z = newA.z(), src = SourceOfNZ.A) }), - SLO -> (currentStatus => { + SLO -> ((currentStatus, zpreg) => { val newA: Status[Int] = currentStatus.a.flatMap(v => if ((v & 0xff) == 0xff) Status.SingleFF else AnyStatus) currentStatus.copy( c = AnyStatus, @@ -200,18 +225,19 @@ object FlowAnalyzerForTheRest { a0 = currentStatus.a0.flatMap(v => if (v) Status.SingleTrue else AnyStatus), n = newA.n(), z = newA.z(), - src = SourceOfNZ.A) + src = SourceOfNZ.A).setReg(zpreg, AnyStatus) }), - EOR -> (currentStatus => { + EOR -> ((currentStatus, zpreg) => { + val newA: Status[Int] = (currentStatus.a <*> currentStatus.getReg(zpreg))(_ ^ _) currentStatus.copy( - n = AnyStatus, - z = AnyStatus, - a = AnyStatus, - a7 = AnyStatus, - a0 = AnyStatus, - src = SourceOfNZ.A) + n = newA.n(), + z = newA.z(), + a = newA, + a7 = newA.bit7, + a0 = newA.bit0, + src = SourceOfNZ.A).setReg(zpreg, AnyStatus) }), - SRE -> (currentStatus => { + SRE -> ((currentStatus, zpreg) => { currentStatus.copy( c = AnyStatus, n = AnyStatus, @@ -219,9 +245,9 @@ object FlowAnalyzerForTheRest { a = AnyStatus, a7 = AnyStatus, a0 = AnyStatus, - src = SourceOfNZ.A) + src = SourceOfNZ.A).setReg(zpreg, AnyStatus) }), - RLA -> (currentStatus => { + RLA -> ((currentStatus, zpreg) => { currentStatus.copy( c = AnyStatus, n = AnyStatus, @@ -229,9 +255,9 @@ object FlowAnalyzerForTheRest { a = AnyStatus, a7 = AnyStatus, a0 = AnyStatus, - src = SourceOfNZ.A) + src = SourceOfNZ.A).setReg(zpreg, AnyStatus) }), - RRA -> (currentStatus => { + RRA -> ((currentStatus, zpreg) => { currentStatus.copy( c = AnyStatus, n = AnyStatus, @@ -240,9 +266,18 @@ object FlowAnalyzerForTheRest { a7 = AnyStatus, a0 = AnyStatus, z = AnyStatus, - src = currentStatus.d.flatMap(dec => if (dec) AnyStatus else SourceOfNZ.A)) + src = currentStatus.d.flatMap(dec => if (dec) AnyStatus else SourceOfNZ.A)).setReg(zpreg, AnyStatus) }), - ISC -> (currentStatus => { + DCP -> ((currentStatus, zpreg) => { + val r = currentStatus.getReg(zpreg) + currentStatus.copy( + c = AnyStatus, + n = AnyStatus, + z = AnyStatus, + src = AnyStatus).setReg(zpreg, r.map(n => (n - 1) & 0xff)) + }), + ISC -> ((currentStatus, zpreg) => { + val r = currentStatus.getReg(zpreg) currentStatus.copy( c = AnyStatus, n = AnyStatus, @@ -251,27 +286,61 @@ object FlowAnalyzerForTheRest { a7 = AnyStatus, a0 = AnyStatus, z = AnyStatus, - src = currentStatus.d.flatMap(dec => if (dec) AnyStatus else SourceOfNZ.A)) + src = currentStatus.d.flatMap(dec => if (dec) AnyStatus else SourceOfNZ.A)).setReg(zpreg, r.map(n => (n + 1) & 0xff)) }), - ROL -> (_.copy(c = AnyStatus, n = AnyStatus, z = AnyStatus, src = AnyStatus)), - ROR -> (_.copy(c = AnyStatus, n = AnyStatus, z = AnyStatus, src = AnyStatus)), - ASL -> (_.copy(c = AnyStatus, n = AnyStatus, z = AnyStatus, src = AnyStatus)), - LSR -> (_.copy(c = AnyStatus, n = AnyStatus, z = AnyStatus, src = AnyStatus)), - INC -> (_.copy(n = AnyStatus, z = AnyStatus, src = AnyStatus)), - DEC -> (_.copy(n = AnyStatus, z = AnyStatus, src = AnyStatus)), - CMP -> (_.copy(c = AnyStatus, n = AnyStatus, z = AnyStatus, src = AnyStatus)), - CPX -> (_.copy(c = AnyStatus, n = AnyStatus, z = AnyStatus, src = AnyStatus)), - CPY -> (_.copy(c = AnyStatus, n = AnyStatus, z = AnyStatus, src = AnyStatus)), - CPZ -> (_.copy(c = AnyStatus, n = AnyStatus, z = AnyStatus, src = AnyStatus)), - BIT -> (_.copy(v = AnyStatus, n = AnyStatus, z = AnyStatus, src = AnyStatus)), - TRB -> (_.copy(z = AnyStatus, src = AnyStatus)), - TSB -> (_.copy(z = AnyStatus, src = AnyStatus)), - JMP -> (_ => CpuStatus()), - BRA -> (_ => CpuStatus()), - BRL -> (_ => CpuStatus()), + ROL -> ((currentStatus, zpreg) => { + val r = currentStatus.getReg(zpreg) + currentStatus.copy(c = r.bit7, n = AnyStatus, z = AnyStatus, src = AnyStatus).setReg(zpreg, currentStatus.c.flatMap { c => + r.map(n => (n << 1) & 0xff | (if (c) 1 else 0)) + }) + }), + ROR -> ((currentStatus, zpreg) => { + val r = currentStatus.getReg(zpreg) + currentStatus.copy(c = r.bit0, n = AnyStatus, z = AnyStatus, src = AnyStatus).setReg(zpreg, currentStatus.c.flatMap { c => + r.map(n => (n >> 1) & 0x7f | (if (c) 0x80 else 0)) + }) + }), + ASL -> ((currentStatus, zpreg) => { + val r = currentStatus.getReg(zpreg) + currentStatus.copy(c = r.bit7, n = AnyStatus, z = AnyStatus, src = AnyStatus).setReg(zpreg, r.map(n => (n << 1) & 0xff)) + }), + LSR -> ((currentStatus, zpreg) => { + val r = currentStatus.getReg(zpreg) + currentStatus.copy(c = r.bit0, n = AnyStatus, z = AnyStatus, src = AnyStatus).setReg(zpreg, r.map(n => (n >> 1) & 0xff)) + }), + INC -> ((currentStatus, zpreg) => { + val r = currentStatus.getReg(zpreg) + currentStatus.copy(n = AnyStatus, z = AnyStatus, src = AnyStatus).setReg(zpreg, r.map(n => (n + 1) & 0xff)) + }), + DEC -> ((currentStatus, zpreg) => { + val r = currentStatus.getReg(zpreg) + currentStatus.copy(n = AnyStatus, z = AnyStatus, src = AnyStatus).setReg(zpreg, r.map(n => (n - 1) & 0xff)) + }), + CMP -> ((currentStatus, zpreg) => { + val r = currentStatus.getReg(zpreg) + currentStatus.copy(c = AnyStatus, n = AnyStatus, z = (currentStatus.a <*> r)(_==_), src = if (r.contains(0)) SourceOfNZ.A else AnyStatus) + }), + CPX -> ((currentStatus, zpreg) => { + val r = currentStatus.getReg(zpreg) + currentStatus.copy(c = AnyStatus, n = AnyStatus, z = (currentStatus.x <*> r)(_==_), src = if (r.contains(0)) SourceOfNZ.X else AnyStatus) + }), + CPY -> ((currentStatus, zpreg) => { + val r = currentStatus.getReg(zpreg) + currentStatus.copy(c = AnyStatus, n = AnyStatus, z = (currentStatus.y <*> r)(_==_), src = if (r.contains(0)) SourceOfNZ.Y else AnyStatus) + }), + CPZ -> ((currentStatus, zpreg) => { + val r = currentStatus.getReg(zpreg) + currentStatus.copy(c = AnyStatus, n = AnyStatus, z = (currentStatus.iz <*> r)(_==_), src = if (r.contains(0)) SourceOfNZ.Z else AnyStatus) + }), + BIT -> ((currentStatus, zpreg) => currentStatus.copy(v = AnyStatus, n = AnyStatus, z = AnyStatus, src = AnyStatus)), + TRB -> ((currentStatus, zpreg) => currentStatus.copy(z = AnyStatus, src = AnyStatus).setReg(zpreg, AnyStatus)), + TSB -> ((currentStatus, zpreg) => currentStatus.copy(z = AnyStatus, src = AnyStatus).setReg(zpreg, AnyStatus)), + JMP -> ((_,_) => CpuStatus()), + BRA -> ((_,_) => CpuStatus()), + BRL -> ((_,_) => CpuStatus()), ) def hasDefinition(opcode: Opcode.Value): Boolean = map.contains(opcode) - def get(opcode: Opcode.Value): CpuStatus => CpuStatus = map(opcode) + def get(opcode: Opcode.Value): (CpuStatus, Option[Int]) => CpuStatus = map(opcode) } diff --git a/src/main/scala/millfork/assembly/mos/opt/RuleBasedAssemblyOptimization.scala b/src/main/scala/millfork/assembly/mos/opt/RuleBasedAssemblyOptimization.scala index 5099a193..441c5c6c 100644 --- a/src/main/scala/millfork/assembly/mos/opt/RuleBasedAssemblyOptimization.scala +++ b/src/main/scala/millfork/assembly/mos/opt/RuleBasedAssemblyOptimization.scala @@ -547,6 +547,17 @@ case class MatchY(i: Int) extends AssemblyLinePattern { } } +case class MatchZpReg(i: Int, registerIndex: Int) extends AssemblyLinePattern { + override def validate(needsFlowInfo: FlowInfoRequirement.Value): Unit = + FlowInfoRequirement.assertForward(needsFlowInfo) + + override def matchLineTo(ctx: AssemblyMatchingContext, flowInfo: FlowInfo, line: AssemblyLine): Boolean = + flowInfo.statusBefore.reg(registerIndex) match { + case SingleStatus(value) => ctx.addObject(i, value) + case _ => false + } +} + case class HasA(value: Int) extends AssemblyLinePattern { override def validate(needsFlowInfo: FlowInfoRequirement.Value): Unit = FlowInfoRequirement.assertForward(needsFlowInfo) diff --git a/src/main/scala/millfork/assembly/mos/opt/ZeropageRegisterOptimizations.scala b/src/main/scala/millfork/assembly/mos/opt/ZeropageRegisterOptimizations.scala index fa151db6..63a2d9fb 100644 --- a/src/main/scala/millfork/assembly/mos/opt/ZeropageRegisterOptimizations.scala +++ b/src/main/scala/millfork/assembly/mos/opt/ZeropageRegisterOptimizations.scala @@ -5,7 +5,7 @@ import millfork.assembly.mos.AddrMode._ import millfork.assembly.AssemblyOptimization import millfork.assembly.mos.{AssemblyLine, Opcode, State} import millfork.env.{CompoundConstant, Constant, MathOperator} - +import millfork.DecimalUtils.asDecimal /** * @author Karol Stasiak */ @@ -27,6 +27,11 @@ object ZeropageRegisterOptimizations { code.init :+ AssemblyLine.immediate(LDA, product & 0xff) }, + (Elidable & HasOpcode(JSR) & RefersTo("__mul_u8u8u8", 0) & MatchZpReg(4, 0) & MatchZpReg(5, 1)) ~~> { (code, ctx) => + val product = ctx.get[Int](4) * ctx.get[Int](5) + code.init :+ AssemblyLine.immediate(LDA, product & 0xff) + }, + // TODO: constants other than power of 2: (Elidable & HasOpcode(STA) & RefersTo("__reg", 0) & MatchAddrMode(0) & MatchParameter(1)) ~ @@ -171,41 +176,74 @@ object ZeropageRegisterOptimizations { }) ) + val PointlessLoad = new RuleBasedAssemblyOptimization("Pointless load from zeropage register", + needsFlowInfo = FlowInfoRequirement.BothFlows, + MultipleAssemblyRules((0 until 4).flatMap{ zpregIndex => + List( + (Elidable & HasOpcode(LDA) & RefersTo("__reg", zpregIndex) & + MatchZpReg(4, zpregIndex) & MatchA(4) & + DoesntMatterWhatItDoesWith(State.N, State.Z)) ~~> (_ => Nil), + (Elidable & HasOpcode(LDX) & RefersTo("__reg", zpregIndex) & + MatchZpReg(4, zpregIndex) & MatchX(4) & + DoesntMatterWhatItDoesWith(State.N, State.Z)) ~~> (_ => Nil), + (Elidable & HasOpcode(LDY) & RefersTo("__reg", zpregIndex) & + MatchZpReg(4, zpregIndex) & MatchY(4) & + DoesntMatterWhatItDoesWith(State.N, State.Z)) ~~> (_ => Nil), - private def parseNormalToDecimalValue(a: Long): Long = { - if (a < 0) -parseNormalToDecimalValue(-a) - var x = a - var result = 0L - var multiplier = 1L - while (x > 0) { - result += multiplier * (x % 16L) - x /= 16L - multiplier *= 10L - } - result - } + (Elidable & HasOpcode(LDA) & RefersTo("__reg", zpregIndex) & + MatchZpReg(4, zpregIndex) & MatchX(4)) ~~> (_ => List(AssemblyLine.implied(TXA))), + (Elidable & HasOpcode(LDA) & RefersTo("__reg", zpregIndex) & + MatchZpReg(4, zpregIndex) & MatchY(4)) ~~> (_ => List(AssemblyLine.implied(TYA))), + (Elidable & HasOpcode(LDX) & RefersTo("__reg", zpregIndex) & + MatchZpReg(4, zpregIndex) & MatchA(4)) ~~> (_ => List(AssemblyLine.implied(TAX))), + (Elidable & HasOpcode(LDY) & RefersTo("__reg", zpregIndex) & + MatchZpReg(4, zpregIndex) & MatchA(4)) ~~> (_ => List(AssemblyLine.implied(TAY))), + (Elidable & HasOpcode(LAX) & RefersTo("__reg", zpregIndex) & + MatchZpReg(4, zpregIndex) & MatchX(4)) ~~> (_ => List(AssemblyLine.implied(TXA))), + (Elidable & HasOpcode(LAX) & RefersTo("__reg", zpregIndex) & + MatchZpReg(4, zpregIndex) & MatchA(4)) ~~> (_ => List(AssemblyLine.implied(TAX))), - private def storeDecimalValueInNormalRespresentation(a: Long): Long = { - if (a < 0) -storeDecimalValueInNormalRespresentation(-a) - var x = a - var result = 0L - var multiplier = 1L - while (x > 0) { - result += multiplier * (x % 10L) - x /= 10L - multiplier *= 16L - } - result - } + (Elidable & HasOpcode(ADC) & RefersTo("__reg", zpregIndex) & + MatchZpReg(5, zpregIndex) & MatchA(4) & HasClear(State.D) & HasClear(State.C) & + DoesntMatterWhatItDoesWith(State.C, State.V)) ~~> { (code, ctx) => + val sum = ctx.get[Int](4) + ctx.get[Int](5) + List(AssemblyLine.immediate(LDA, sum & 0xff)) + }, - private def asDecimal(a: Long, b: Long, f: (Long, Long) => Long): Long = - storeDecimalValueInNormalRespresentation(f(parseNormalToDecimalValue(a), parseNormalToDecimalValue(b))) + (Elidable & HasOpcode(SBC) & RefersTo("__reg", zpregIndex) & + MatchZpReg(5, zpregIndex) & MatchA(4) & HasClear(State.D) & HasSet(State.C) & + DoesntMatterWhatItDoesWith(State.C, State.V)) ~~> { (code, ctx) => + val sum = ctx.get[Int](4) - ctx.get[Int](5) + List(AssemblyLine.immediate(LDA, sum & 0xff)) + }, + + (Elidable & HasOpcode(AND) & RefersTo("__reg", zpregIndex) & + MatchZpReg(5, zpregIndex) & MatchA(4)) ~~> { (code, ctx) => + val sum = ctx.get[Int](4) & ctx.get[Int](5) + List(AssemblyLine.immediate(LDA, sum & 0xff)) + }, + + (Elidable & HasOpcode(ORA) & RefersTo("__reg", zpregIndex) & + MatchZpReg(5, zpregIndex) & MatchA(4)) ~~> { (code, ctx) => + val sum = ctx.get[Int](4) | ctx.get[Int](5) + List(AssemblyLine.immediate(LDA, sum & 0xff)) + }, + + (Elidable & HasOpcode(EOR) & RefersTo("__reg", zpregIndex) & + MatchZpReg(5, zpregIndex) & MatchA(4)) ~~> { (code, ctx) => + val sum = ctx.get[Int](4) ^ ctx.get[Int](5) + List(AssemblyLine.immediate(LDA, sum & 0xff)) + } + ) + }) + ) val All: List[AssemblyOptimization[AssemblyLine]] = List( ConstantDecimalMath, ConstantMultiplication, DeadRegStore, DeadRegStoreFromFlow, + PointlessLoad, StashInRegInsteadOfStack, ) diff --git a/src/main/scala/millfork/assembly/opt/Status.scala b/src/main/scala/millfork/assembly/opt/Status.scala index b7358b87..f6b8367f 100644 --- a/src/main/scala/millfork/assembly/opt/Status.scala +++ b/src/main/scala/millfork/assembly/opt/Status.scala @@ -93,6 +93,12 @@ object Status { case _ => AnyStatus } + def flatMap4[T, U, V, W, R](a: Status[T], b: Status[U], c: Status[V], d: Status[W])(f: (T, U, V, W) => Status[R]): Status[R] = (a, b, c, d) match { + case (SingleStatus(t), SingleStatus(u), SingleStatus(v), SingleStatus(w)) => f(t, u, v, w) + case (UnknownStatus, UnknownStatus, UnknownStatus, UnknownStatus) => UnknownStatus + case _ => AnyStatus + } + implicit class BoolStatusOps(val inner: Status[Boolean]) extends AnyVal { def withHiddenHi: Status[Boolean] = inner match { case SingleStatus(false) => inner @@ -187,28 +193,28 @@ object Status { case _ => AnyStatus } - def adc(value: Int, carry: Status[Boolean], decimal: Status[Boolean]): Status[Int] = inner match { + def adc(value: Int, carry: Status[Boolean], decimal: Status[Boolean]): (Status[Int], Status[Boolean]) = inner match { case SingleStatus(x) => decimal match { case SingleStatus(false) => carry match { - case SingleStatus(true) => SingleStatus((x + value + 1) & 0xff) - case SingleStatus(false) => SingleStatus((x + value) & 0xff) - case _ => AnyStatus + case SingleStatus(true) => SingleStatus((x + value + 1) & 0xff) -> SingleStatus((x.&(0xff) + value.&(0xff) + 1) > 0xff) + case SingleStatus(false) => SingleStatus((x + value) & 0xff) -> SingleStatus((x.&(0xff) + value.&(0xff)) > 0xff) + case _ => AnyStatus -> (if (value == 0) SingleFalse else AnyStatus) } - case _ => AnyStatus + case _ => AnyStatus -> AnyStatus } - case _ => AnyStatus + case _ => AnyStatus -> AnyStatus } - def sbc(value: Int, carry: Status[Boolean], decimal: Status[Boolean]): Status[Int] = inner match { + def sbc(value: Int, carry: Status[Boolean], decimal: Status[Boolean]): (Status[Int], Status[Boolean]) = inner match { case SingleStatus(x) => decimal match { case SingleStatus(false) => carry match { - case SingleStatus(true) => SingleStatus((x - value) & 0xff) - case SingleStatus(false) => SingleStatus((x - value - 1) & 0xff) - case _ => AnyStatus + case SingleStatus(true) => SingleStatus((x - value) & 0xff) -> SingleStatus((x.&(0xff) - value.&(0xff)) >= 0) + case SingleStatus(false) => SingleStatus((x - value - 1) & 0xff) -> SingleStatus((x.&(0xff) - value.&(0xff) - 1) >= 0) + case _ => AnyStatus -> (if (value == 0) SingleTrue else AnyStatus) } - case _ => AnyStatus + case _ => AnyStatus -> AnyStatus } - case _ => AnyStatus + case _ => AnyStatus -> AnyStatus } def adc_w(value: Int, carry: Status[Boolean], decimal: Status[Boolean]): Status[Int] = inner match {