1
0
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:
Karol Stasiak 2018-08-07 21:36:53 +02:00
parent 64744f7559
commit 8dd8415432
7 changed files with 333 additions and 152 deletions

View File

@ -73,7 +73,7 @@ object CoarseFlowAnalyzer {
currentStatus = FlowAnalyzerForImmediate.get(op)(nn.toInt, currentStatus) currentStatus = FlowAnalyzerForImmediate.get(op)(nn.toInt, currentStatus)
case AssemblyLine(op, _, _, _) if FlowAnalyzerForTheRest.hasDefinition(op) => case AssemblyLine(op, _, _, _) if FlowAnalyzerForTheRest.hasDefinition(op) =>
currentStatus = FlowAnalyzerForTheRest.get(op)(currentStatus) currentStatus = FlowAnalyzerForTheRest.get(op)(currentStatus, None)
case AssemblyLine(opcode, addrMode, _, _) => case AssemblyLine(opcode, addrMode, _, _) =>
currentStatus = currentStatus.copy(src = AnyStatus) currentStatus = currentStatus.copy(src = AnyStatus)

View File

@ -47,6 +47,10 @@ case class CpuStatus(a: Status[Int] = UnknownStatus,
x: Status[Int] = UnknownStatus, x: Status[Int] = UnknownStatus,
y: Status[Int] = UnknownStatus, y: Status[Int] = UnknownStatus,
iz: 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, src: Status[SourceOfNZ] = UnknownStatus,
eqSX: Boolean = false, eqSX: Boolean = false,
z: Status[Boolean] = UnknownStatus, z: Status[Boolean] = UnknownStatus,
@ -90,7 +94,7 @@ case class CpuStatus(a: Status[Int] = UnknownStatus,
// case _ => // 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" (if (eqSX) "; S=X"
else /* */ " ") else /* */ " ")
@ -159,6 +163,39 @@ case class CpuStatus(a: Status[Int] = UnknownStatus,
case State.W => w.contains(true) case State.W => w.contains(true)
case _ => false 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 { object CpuStatus {
@ -173,7 +210,11 @@ object CpuStatus {
d = SingleStatus(false), d = SingleStatus(false),
m = SingleStatus(true), m = SingleStatus(true),
w = SingleStatus(true), w = SingleStatus(true),
iz = SingleStatus(0) iz = SingleStatus(0),
r0 = AnyStatus,
r1 = AnyStatus,
r2 = AnyStatus,
r3 = AnyStatus,
) )
val initialStatusCE = CpuStatus( val initialStatusCE = CpuStatus(
a = AnyStatus, a = AnyStatus,
@ -186,7 +227,11 @@ object CpuStatus {
d = SingleStatus(false), d = SingleStatus(false),
m = SingleStatus(true), m = SingleStatus(true),
w = SingleStatus(true), w = SingleStatus(true),
iz = AnyStatus iz = AnyStatus,
r0 = AnyStatus,
r1 = AnyStatus,
r2 = AnyStatus,
r3 = AnyStatus,
) )
val initialInterruptStatusStandard = CpuStatus( val initialInterruptStatusStandard = CpuStatus(
@ -200,7 +245,11 @@ object CpuStatus {
d = AnyStatus, d = AnyStatus,
m = AnyStatus, m = AnyStatus,
w = AnyStatus, w = AnyStatus,
iz = SingleStatus(0) iz = SingleStatus(0),
r0 = AnyStatus,
r1 = AnyStatus,
r2 = AnyStatus,
r3 = AnyStatus,
) )
val initialInterruptStatusCmos = CpuStatus( val initialInterruptStatusCmos = CpuStatus(
a = AnyStatus, a = AnyStatus,
@ -213,7 +262,11 @@ object CpuStatus {
d = SingleStatus(false), d = SingleStatus(false),
m = AnyStatus, m = AnyStatus,
w = AnyStatus, w = AnyStatus,
iz = SingleStatus(0) iz = SingleStatus(0),
r0 = AnyStatus,
r1 = AnyStatus,
r2 = AnyStatus,
r3 = AnyStatus,
) )
val initialInterruptStatusCE = CpuStatus( val initialInterruptStatusCE = CpuStatus(
a = AnyStatus, a = AnyStatus,
@ -226,7 +279,11 @@ object CpuStatus {
d = SingleStatus(false), d = SingleStatus(false),
m = AnyStatus, m = AnyStatus,
w = AnyStatus, w = AnyStatus,
iz = AnyStatus iz = AnyStatus,
r0 = AnyStatus,
r1 = AnyStatus,
r2 = AnyStatus,
r3 = AnyStatus,
) )
val emptyStatusStandard = CpuStatus(iz = SingleStatus(0)) val emptyStatusStandard = CpuStatus(iz = SingleStatus(0))

View File

@ -72,7 +72,7 @@ object FlowAnalyzerForImmediate {
}, },
ADC -> {(nn, currentStatus) => ADC -> {(nn, currentStatus) =>
val n = nn & 0xff 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( currentStatus.copy(
n = newA.n(), n = newA.n(),
z = newA.z(), z = newA.z(),
@ -80,7 +80,7 @@ object FlowAnalyzerForImmediate {
a = newA, a = newA,
a0 = newA.bit0, a0 = newA.bit0,
a7 = newA.bit7, 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 (aa, false, false) => SingleStatus((aa & 0xff) + n >= 0x100)
case _ => AnyStatus case _ => AnyStatus
}, },
@ -88,7 +88,7 @@ object FlowAnalyzerForImmediate {
}, },
SBC -> {(nn, currentStatus) => SBC -> {(nn, currentStatus) =>
val n = nn & 0xff 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( currentStatus.copy(
n = newA.n(), n = newA.n(),
z = newA.z(), z = newA.z(),
@ -96,7 +96,7 @@ object FlowAnalyzerForImmediate {
a = newA, a = newA,
a0 = newA.bit0, a0 = newA.bit0,
a7 = newA.bit7, a7 = newA.bit7,
c = AnyStatus, c = newC,
v = AnyStatus) v = AnyStatus)
}, },
EOR -> {(nn, currentStatus) => EOR -> {(nn, currentStatus) =>

View File

@ -8,35 +8,35 @@ import millfork.assembly.opt.{AnyStatus, SingleStatus, Status}
* @author Karol Stasiak * @author Karol Stasiak
*/ */
object FlowAnalyzerForTheRest { object FlowAnalyzerForTheRest {
private val map: Map[Opcode.Value, CpuStatus => CpuStatus] = Map( private val map: Map[Opcode.Value, (CpuStatus, Option[Int]) => CpuStatus] = Map(
STA -> identity, STA -> ((c,zpreg) => c.setReg(zpreg, c.a)),
STX -> identity, STX -> ((c,zpreg) => c.setReg(zpreg, c.x)),
STY -> identity, STY -> ((c,zpreg) => c.setReg(zpreg, c.y)),
STZ -> identity, STZ -> ((c,zpreg) => c.setReg(zpreg, c.iz)),
SAX -> identity, SAX -> ((c,zpreg) => c.setReg(zpreg, (c.a <*> c.x)(_ & _))),
NOP -> identity, NOP -> ((x,_) => x),
DISCARD_AF -> identity, DISCARD_AF -> ((x,_) => x),
DISCARD_XF -> identity, DISCARD_XF -> ((x,_) => x),
DISCARD_YF -> identity, DISCARD_YF -> ((x,_) => x),
REP -> (currentStatus => { REP -> ((currentStatus, zpreg) => {
currentStatus.copy(c = AnyStatus, d = AnyStatus, n = AnyStatus, z= AnyStatus, v = AnyStatus, m = AnyStatus, w = AnyStatus) 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) 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) currentStatus.copy(c = Status.SingleTrue)
}), }),
BCS -> (currentStatus => { BCS -> ((currentStatus, zpreg) => {
currentStatus.copy(c = Status.SingleFalse) currentStatus.copy(c = Status.SingleFalse)
}), }),
BVS -> (currentStatus => { BVS -> ((currentStatus, zpreg) => {
currentStatus.copy(v = Status.SingleFalse) currentStatus.copy(v = Status.SingleFalse)
}), }),
BVC -> (currentStatus => { BVC -> ((currentStatus, zpreg) => {
currentStatus.copy(v = Status.SingleTrue) currentStatus.copy(v = Status.SingleTrue)
}), }),
BMI -> (c => { BMI -> ((c, zpreg) => {
var currentStatus = c var currentStatus = c
currentStatus = currentStatus.copy(n = Status.SingleFalse) currentStatus = currentStatus.copy(n = Status.SingleFalse)
if (currentStatus.src.isFromA) { if (currentStatus.src.isFromA) {
@ -44,7 +44,7 @@ object FlowAnalyzerForTheRest {
} }
currentStatus currentStatus
}), }),
BPL -> (c => { BPL -> ((c, zpreg) => {
var currentStatus = c var currentStatus = c
currentStatus = currentStatus.copy(n = Status.SingleTrue) currentStatus = currentStatus.copy(n = Status.SingleTrue)
if (currentStatus.src.isFromA) { if (currentStatus.src.isFromA) {
@ -52,10 +52,10 @@ object FlowAnalyzerForTheRest {
} }
currentStatus currentStatus
}), }),
BEQ -> (currentStatus => { BEQ -> ((currentStatus, zpreg) => {
currentStatus.copy(z = Status.SingleFalse) currentStatus.copy(z = Status.SingleFalse)
}), }),
BNE -> (c => { BNE -> ((c, zpreg) => {
var currentStatus = c var currentStatus = c
currentStatus = currentStatus.copy(z = Status.SingleTrue) currentStatus = currentStatus.copy(z = Status.SingleTrue)
if (currentStatus.src.isFromA) { if (currentStatus.src.isFromA) {
@ -79,100 +79,123 @@ object FlowAnalyzerForTheRest {
} }
currentStatus currentStatus
}), }),
LDX -> (currentStatus => { LDX -> ((currentStatus, zpreg) => {
val newX = currentStatus.getReg(zpreg)
currentStatus.copy( currentStatus.copy(
x = AnyStatus, x = newX,
n = AnyStatus, n = newX.n(),
z = AnyStatus, z = newX.z(),
src = SourceOfNZ.X) src = SourceOfNZ.X)
}), }),
LDY -> (currentStatus => { LDY -> ((currentStatus, zpreg) => {
val newY = currentStatus.getReg(zpreg)
currentStatus.copy( currentStatus.copy(
y = AnyStatus, y = newY,
n = AnyStatus, n = newY.n(),
z = AnyStatus, z = newY.z(),
src = SourceOfNZ.Y) src = SourceOfNZ.Y)
}), }),
LDA -> (currentStatus => { LDA -> ((currentStatus, zpreg) => {
val newA = currentStatus.getReg(zpreg)
currentStatus.copy( currentStatus.copy(
a = AnyStatus, a = newA,
a7 = AnyStatus, a7 = newA.bit7,
a0 = AnyStatus, a0 = newA.bit0,
n = AnyStatus, n = newA.n(),
z = AnyStatus, z = newA.z(),
src = SourceOfNZ.A) src = SourceOfNZ.A)
}), }),
LDZ -> (currentStatus => { LDZ -> ((currentStatus, zpreg) => {
val newZ = currentStatus.getReg(zpreg)
currentStatus.copy( currentStatus.copy(
iz = AnyStatus, iz = newZ,
n = AnyStatus, n = newZ.n(),
z = AnyStatus, z = newZ.z(),
src = SourceOfNZ.Z) src = SourceOfNZ.Z)
}), }),
LAX -> (currentStatus => { LAX -> ((currentStatus, zpreg) => {
val newA = currentStatus.getReg(zpreg)
currentStatus.copy( currentStatus.copy(
x = AnyStatus, x = newA,
a = AnyStatus, a = newA,
a7 = AnyStatus, a7 = newA.bit7,
a0 = AnyStatus, a0 = newA.bit0,
n = AnyStatus, n = newA.n(),
z = AnyStatus, z = newA.z(),
src = SourceOfNZ.AX) src = SourceOfNZ.AX)
}), }),
LDA_W -> (currentStatus => { LDA_W -> ((currentStatus, zpreg) => {
val newA = currentStatus.getReg(zpreg)
val newAH = currentStatus.getRegHi(zpreg)
currentStatus.copy( currentStatus.copy(
ah = AnyStatus, ah = newAH,
a = AnyStatus, a = newA,
a7 = AnyStatus, a7 = AnyStatus,
a0 = AnyStatus, a0 = newA.bit0,
n = AnyStatus, n = AnyStatus,
z = AnyStatus, z = AnyStatus,
src = SourceOfNZ.AW) src = SourceOfNZ.AW)
}), }),
LDX_W -> (currentStatus => { LDX_W -> ((currentStatus, zpreg) => {
currentStatus.copy( currentStatus.copy(
x = AnyStatus, x = AnyStatus,
n = AnyStatus, n = AnyStatus,
z = AnyStatus, z = AnyStatus,
src = AnyStatus) src = AnyStatus)
}), }),
LDY_W -> (currentStatus => { LDY_W -> ((currentStatus, zpreg) => {
currentStatus.copy( currentStatus.copy(
y = AnyStatus, y = AnyStatus,
n = AnyStatus, n = AnyStatus,
z = AnyStatus, z = AnyStatus,
src = 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( currentStatus.copy(
a = AnyStatus, a = newA,
a7 = AnyStatus, a7 = newA.bit7,
a0 = AnyStatus, a0 = newA.bit0,
v = AnyStatus, 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 (0, false, false) => SingleStatus[Boolean](false)
case _ => AnyStatus case _ => AnyStatus
}, },
z = AnyStatus, z = newA.z(),
n = AnyStatus, n = newA.n(),
src = currentStatus.d.flatMap((dec: Boolean) => if (dec) AnyStatus else SourceOfNZ.A)) 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( currentStatus.copy(
a = AnyStatus, a = newA,
a7 = AnyStatus, a7 = newA.bit7,
a0 = AnyStatus, a0 = newA.bit0,
v = AnyStatus, v = AnyStatus,
c = Status.flatMap3(currentStatus.a, currentStatus.c, currentStatus.d) { c = Status.flatMap3(currentStatus.a, currentStatus.c, currentStatus.d) {
case (0xff, true, false) => SingleStatus[Boolean](true) case (0xff, true, false) => SingleStatus[Boolean](true)
case _ => AnyStatus case _ => AnyStatus
}, },
z = AnyStatus, z = newA.z(),
n = AnyStatus, n = newA.n(),
src = currentStatus.d.flatMap((dec: Boolean) => if (dec) AnyStatus else SourceOfNZ.A)) src = currentStatus.d.flatMap((dec: Boolean) => if (dec) AnyStatus else SourceOfNZ.A))
}), }),
AND -> (currentStatus => { AND -> ((currentStatus, zpreg) => {
val newA: Status[Int] = currentStatus.a.flatMap(v => if ((v & 0xff) == 0) Status.SingleZero else AnyStatus) val newA: Status[Int] =
currentStatus.a.flatMap(v => if ((v & 0xff) == 0) Status.SingleZero else AnyStatus) |
(currentStatus.a <*> currentStatus.getReg(zpreg))(_ & _)
currentStatus.copy( currentStatus.copy(
a = newA, a = newA,
a7 = currentStatus.a7.flatMap(v => if (!v) Status.SingleFalse else AnyStatus), a7 = currentStatus.a7.flatMap(v => if (!v) Status.SingleFalse else AnyStatus),
@ -181,8 +204,10 @@ object FlowAnalyzerForTheRest {
z = newA.z(), z = newA.z(),
src = SourceOfNZ.A) src = SourceOfNZ.A)
}), }),
ORA -> (currentStatus => { ORA -> ((currentStatus, zpreg) => {
val newA: Status[Int] = currentStatus.a.flatMap(v => if ((v & 0xff) == 0xff) Status.SingleFF else AnyStatus) val newA: Status[Int] =
currentStatus.a.flatMap(v => if ((v & 0xff) == 0xff) Status.SingleFF else AnyStatus) |
(currentStatus.a <*> currentStatus.getReg(zpreg))(_ | _)
currentStatus.copy( currentStatus.copy(
a = newA, a = newA,
a7 = currentStatus.a7.flatMap(v => if (v) Status.SingleTrue else AnyStatus), a7 = currentStatus.a7.flatMap(v => if (v) Status.SingleTrue else AnyStatus),
@ -191,7 +216,7 @@ object FlowAnalyzerForTheRest {
z = newA.z(), z = newA.z(),
src = SourceOfNZ.A) src = SourceOfNZ.A)
}), }),
SLO -> (currentStatus => { SLO -> ((currentStatus, zpreg) => {
val newA: Status[Int] = currentStatus.a.flatMap(v => if ((v & 0xff) == 0xff) Status.SingleFF else AnyStatus) val newA: Status[Int] = currentStatus.a.flatMap(v => if ((v & 0xff) == 0xff) Status.SingleFF else AnyStatus)
currentStatus.copy( currentStatus.copy(
c = AnyStatus, c = AnyStatus,
@ -200,18 +225,19 @@ object FlowAnalyzerForTheRest {
a0 = currentStatus.a0.flatMap(v => if (v) Status.SingleTrue else AnyStatus), a0 = currentStatus.a0.flatMap(v => if (v) Status.SingleTrue else AnyStatus),
n = newA.n(), n = newA.n(),
z = newA.z(), 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( currentStatus.copy(
n = AnyStatus, n = newA.n(),
z = AnyStatus, z = newA.z(),
a = AnyStatus, a = newA,
a7 = AnyStatus, a7 = newA.bit7,
a0 = AnyStatus, a0 = newA.bit0,
src = SourceOfNZ.A) src = SourceOfNZ.A).setReg(zpreg, AnyStatus)
}), }),
SRE -> (currentStatus => { SRE -> ((currentStatus, zpreg) => {
currentStatus.copy( currentStatus.copy(
c = AnyStatus, c = AnyStatus,
n = AnyStatus, n = AnyStatus,
@ -219,9 +245,9 @@ object FlowAnalyzerForTheRest {
a = AnyStatus, a = AnyStatus,
a7 = AnyStatus, a7 = AnyStatus,
a0 = AnyStatus, a0 = AnyStatus,
src = SourceOfNZ.A) src = SourceOfNZ.A).setReg(zpreg, AnyStatus)
}), }),
RLA -> (currentStatus => { RLA -> ((currentStatus, zpreg) => {
currentStatus.copy( currentStatus.copy(
c = AnyStatus, c = AnyStatus,
n = AnyStatus, n = AnyStatus,
@ -229,9 +255,9 @@ object FlowAnalyzerForTheRest {
a = AnyStatus, a = AnyStatus,
a7 = AnyStatus, a7 = AnyStatus,
a0 = AnyStatus, a0 = AnyStatus,
src = SourceOfNZ.A) src = SourceOfNZ.A).setReg(zpreg, AnyStatus)
}), }),
RRA -> (currentStatus => { RRA -> ((currentStatus, zpreg) => {
currentStatus.copy( currentStatus.copy(
c = AnyStatus, c = AnyStatus,
n = AnyStatus, n = AnyStatus,
@ -240,9 +266,18 @@ object FlowAnalyzerForTheRest {
a7 = AnyStatus, a7 = AnyStatus,
a0 = AnyStatus, a0 = AnyStatus,
z = 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( currentStatus.copy(
c = AnyStatus, c = AnyStatus,
n = AnyStatus, n = AnyStatus,
@ -251,27 +286,61 @@ object FlowAnalyzerForTheRest {
a7 = AnyStatus, a7 = AnyStatus,
a0 = AnyStatus, a0 = AnyStatus,
z = 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)), ROL -> ((currentStatus, zpreg) => {
ROR -> (_.copy(c = AnyStatus, n = AnyStatus, z = AnyStatus, src = AnyStatus)), val r = currentStatus.getReg(zpreg)
ASL -> (_.copy(c = AnyStatus, n = AnyStatus, z = AnyStatus, src = AnyStatus)), currentStatus.copy(c = r.bit7, n = AnyStatus, z = AnyStatus, src = AnyStatus).setReg(zpreg, currentStatus.c.flatMap { c =>
LSR -> (_.copy(c = AnyStatus, n = AnyStatus, z = AnyStatus, src = AnyStatus)), r.map(n => (n << 1) & 0xff | (if (c) 1 else 0))
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)), ROR -> ((currentStatus, zpreg) => {
CPX -> (_.copy(c = AnyStatus, n = AnyStatus, z = AnyStatus, src = AnyStatus)), val r = currentStatus.getReg(zpreg)
CPY -> (_.copy(c = AnyStatus, n = AnyStatus, z = AnyStatus, src = AnyStatus)), currentStatus.copy(c = r.bit0, n = AnyStatus, z = AnyStatus, src = AnyStatus).setReg(zpreg, currentStatus.c.flatMap { c =>
CPZ -> (_.copy(c = AnyStatus, n = AnyStatus, z = AnyStatus, src = AnyStatus)), r.map(n => (n >> 1) & 0x7f | (if (c) 0x80 else 0))
BIT -> (_.copy(v = AnyStatus, n = AnyStatus, z = AnyStatus, src = AnyStatus)), })
TRB -> (_.copy(z = AnyStatus, src = AnyStatus)), }),
TSB -> (_.copy(z = AnyStatus, src = AnyStatus)), ASL -> ((currentStatus, zpreg) => {
JMP -> (_ => CpuStatus()), val r = currentStatus.getReg(zpreg)
BRA -> (_ => CpuStatus()), currentStatus.copy(c = r.bit7, n = AnyStatus, z = AnyStatus, src = AnyStatus).setReg(zpreg, r.map(n => (n << 1) & 0xff))
BRL -> (_ => CpuStatus()), }),
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 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)
} }

View File

@ -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 { case class HasA(value: Int) extends AssemblyLinePattern {
override def validate(needsFlowInfo: FlowInfoRequirement.Value): Unit = override def validate(needsFlowInfo: FlowInfoRequirement.Value): Unit =
FlowInfoRequirement.assertForward(needsFlowInfo) FlowInfoRequirement.assertForward(needsFlowInfo)

View File

@ -5,7 +5,7 @@ import millfork.assembly.mos.AddrMode._
import millfork.assembly.AssemblyOptimization import millfork.assembly.AssemblyOptimization
import millfork.assembly.mos.{AssemblyLine, Opcode, State} import millfork.assembly.mos.{AssemblyLine, Opcode, State}
import millfork.env.{CompoundConstant, Constant, MathOperator} import millfork.env.{CompoundConstant, Constant, MathOperator}
import millfork.DecimalUtils.asDecimal
/** /**
* @author Karol Stasiak * @author Karol Stasiak
*/ */
@ -27,6 +27,11 @@ object ZeropageRegisterOptimizations {
code.init :+ AssemblyLine.immediate(LDA, product & 0xff) 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: // TODO: constants other than power of 2:
(Elidable & HasOpcode(STA) & RefersTo("__reg", 0) & MatchAddrMode(0) & MatchParameter(1)) ~ (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 = { (Elidable & HasOpcode(LDA) & RefersTo("__reg", zpregIndex) &
if (a < 0) -parseNormalToDecimalValue(-a) MatchZpReg(4, zpregIndex) & MatchX(4)) ~~> (_ => List(AssemblyLine.implied(TXA))),
var x = a (Elidable & HasOpcode(LDA) & RefersTo("__reg", zpregIndex) &
var result = 0L MatchZpReg(4, zpregIndex) & MatchY(4)) ~~> (_ => List(AssemblyLine.implied(TYA))),
var multiplier = 1L (Elidable & HasOpcode(LDX) & RefersTo("__reg", zpregIndex) &
while (x > 0) { MatchZpReg(4, zpregIndex) & MatchA(4)) ~~> (_ => List(AssemblyLine.implied(TAX))),
result += multiplier * (x % 16L) (Elidable & HasOpcode(LDY) & RefersTo("__reg", zpregIndex) &
x /= 16L MatchZpReg(4, zpregIndex) & MatchA(4)) ~~> (_ => List(AssemblyLine.implied(TAY))),
multiplier *= 10L (Elidable & HasOpcode(LAX) & RefersTo("__reg", zpregIndex) &
} MatchZpReg(4, zpregIndex) & MatchX(4)) ~~> (_ => List(AssemblyLine.implied(TXA))),
result (Elidable & HasOpcode(LAX) & RefersTo("__reg", zpregIndex) &
} MatchZpReg(4, zpregIndex) & MatchA(4)) ~~> (_ => List(AssemblyLine.implied(TAX))),
private def storeDecimalValueInNormalRespresentation(a: Long): Long = { (Elidable & HasOpcode(ADC) & RefersTo("__reg", zpregIndex) &
if (a < 0) -storeDecimalValueInNormalRespresentation(-a) MatchZpReg(5, zpregIndex) & MatchA(4) & HasClear(State.D) & HasClear(State.C) &
var x = a DoesntMatterWhatItDoesWith(State.C, State.V)) ~~> { (code, ctx) =>
var result = 0L val sum = ctx.get[Int](4) + ctx.get[Int](5)
var multiplier = 1L List(AssemblyLine.immediate(LDA, sum & 0xff))
while (x > 0) { },
result += multiplier * (x % 10L)
x /= 10L
multiplier *= 16L
}
result
}
private def asDecimal(a: Long, b: Long, f: (Long, Long) => Long): Long = (Elidable & HasOpcode(SBC) & RefersTo("__reg", zpregIndex) &
storeDecimalValueInNormalRespresentation(f(parseNormalToDecimalValue(a), parseNormalToDecimalValue(b))) 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( val All: List[AssemblyOptimization[AssemblyLine]] = List(
ConstantDecimalMath, ConstantDecimalMath,
ConstantMultiplication, ConstantMultiplication,
DeadRegStore, DeadRegStore,
DeadRegStoreFromFlow, DeadRegStoreFromFlow,
PointlessLoad,
StashInRegInsteadOfStack, StashInRegInsteadOfStack,
) )

View File

@ -93,6 +93,12 @@ object Status {
case _ => AnyStatus 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 { implicit class BoolStatusOps(val inner: Status[Boolean]) extends AnyVal {
def withHiddenHi: Status[Boolean] = inner match { def withHiddenHi: Status[Boolean] = inner match {
case SingleStatus(false) => inner case SingleStatus(false) => inner
@ -187,28 +193,28 @@ object Status {
case _ => AnyStatus 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(x) => decimal match {
case SingleStatus(false) => carry match { case SingleStatus(false) => carry match {
case SingleStatus(true) => SingleStatus((x + value + 1) & 0xff) case SingleStatus(true) => SingleStatus((x + value + 1) & 0xff) -> SingleStatus((x.&(0xff) + value.&(0xff) + 1) > 0xff)
case SingleStatus(false) => SingleStatus((x + value) & 0xff) case SingleStatus(false) => SingleStatus((x + value) & 0xff) -> SingleStatus((x.&(0xff) + value.&(0xff)) > 0xff)
case _ => AnyStatus 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(x) => decimal match {
case SingleStatus(false) => carry match { case SingleStatus(false) => carry match {
case SingleStatus(true) => SingleStatus((x - value) & 0xff) case SingleStatus(true) => SingleStatus((x - value) & 0xff) -> SingleStatus((x.&(0xff) - value.&(0xff)) >= 0)
case SingleStatus(false) => SingleStatus((x - value - 1) & 0xff) case SingleStatus(false) => SingleStatus((x - value - 1) & 0xff) -> SingleStatus((x.&(0xff) - value.&(0xff) - 1) >= 0)
case _ => AnyStatus 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 { def adc_w(value: Int, carry: Status[Boolean], decimal: Status[Boolean]): Status[Int] = inner match {