mirror of
https://github.com/KarolS/millfork.git
synced 2024-09-10 11:54:30 +00:00
6502: Track values of zeropage registers
This commit is contained in:
parent
64744f7559
commit
8dd8415432
@ -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)
|
||||
|
@ -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))
|
||||
|
@ -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) =>
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
)
|
||||
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user