1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-07-05 09:28:54 +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)
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)

View File

@ -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))

View File

@ -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) =>

View File

@ -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)
}

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 {
override def validate(needsFlowInfo: FlowInfoRequirement.Value): Unit =
FlowInfoRequirement.assertForward(needsFlowInfo)

View File

@ -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,
)

View File

@ -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 {