1
0
mirror of https://github.com/KarolS/millfork.git synced 2025-01-27 11:30:19 +00:00

Z80: RLA and RL A are two very different instructions

This commit is contained in:
Karol Stasiak 2018-07-30 23:49:25 +02:00
parent 2ef79d6894
commit 453ce93952
11 changed files with 70 additions and 47 deletions

View File

@ -12,6 +12,8 @@ import millfork.node.ZRegister
object ZFlag extends Enumeration {
val Z, P, C, S, H, N = Value
val AllButSZ: Seq[Value] = Seq(P, C, H, N)
}
sealed trait ZRegisters
@ -179,7 +181,6 @@ case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Consta
case JR => 2
case o if ZOpcodeClasses.EdInstructions(o) => 2
case o if ZOpcodeClasses.CbInstructions(o) => 2
case o if ZOpcodeClasses.CbInstructionsUnlessA(o) => if (registers == OneRegister(ZRegister.A)) 1 else 2
case _ => 1 // TODO!!!
}
val fromParams = registers match {
@ -244,6 +245,7 @@ case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Consta
case RST => s" RST $parameter"
case IM => s" IM $parameter"
case EX_AF_AF => " EX AF,AF'"
case EX_DE_HL => " EX DE,HL"
case LD_AHLI => " LD A,(HLI)"
case LD_AHLD => " LD A,(HLD)"
case LD_HLIA => " LD (HLI),A"
@ -373,7 +375,7 @@ case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Consta
case OneRegisterOffset(s, _) => r == s
case _ => r == A
}
case INC | DEC | RL | RLC | RR | RRC | SLA | SLL | SRA | SRL => registers match {
case INC | DEC | RL | RLC | RR | RRC | SLA | SLL | SRA | SRL | SWAP => registers match {
case OneRegister(MEM_HL) => r == H || r == L
case OneRegister(MEM_BC) => r == B || r == C
case OneRegister(MEM_DE) => r == D || r == E
@ -401,11 +403,12 @@ case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Consta
case OneRegisterOffset(s, _) => r == s
case _ => false
}
case EX_DE_HL => r == D || r == E || r == H || r == L
case JP | JR | RET | RETI | RETN |
POP |
DISCARD_A | DISCARD_BC | DISCARD_DE | DISCARD_IX | DISCARD_IY | DISCARD_HL | DISCARD_F => false
case DJNZ => r == B
case DAA | NEG | CPL => r == A
case DAA | NEG | CPL | RLA | RRA | RLCA | RRCA => r == A
case LABEL | DI | EI | NOP | HALT => false
case _ => true // TODO
}
@ -511,7 +514,7 @@ case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Consta
case TwoRegistersOffset(s, _, _) => r == s
case _ => false
}
case INC | DEC | RL | RLC | RR | RRC | SLA | SLL | SRA | SRL => registers match {
case INC | DEC | RL | RLC | RR | RRC | SLA | SLL | SRA | SRL | SWAP => registers match {
case OneRegister(s) => r == s
case OneRegisterOffset(s, _) => r == s
case _ => false
@ -534,10 +537,11 @@ case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Consta
case OneRegisterOffset(s, _) => r == s
case _ => false
}
case EX_DE_HL => r == D || r == E || r == H || r == L
case JP | JR | RET | RETI | RETN |
PUSH |
DISCARD_A | DISCARD_BC | DISCARD_DE | DISCARD_IX | DISCARD_IY | DISCARD_HL | DISCARD_F => false
case ADD | ADC | AND | OR | XOR | SUB | SBC | DAA | NEG | CPL => r == A
case ADD | ADC | AND | OR | XOR | SUB | SBC | DAA | NEG | CPL | RLA | RRA | RLCA | RRCA => r == A
case CP => false
case DJNZ => r == B
case LABEL | DI | EI | NOP | HALT => false
@ -568,6 +572,7 @@ case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Consta
case JP | JR | RET | RETI | RETN |
PUSH | DJNZ | DAA |
DISCARD_A | DISCARD_BC | DISCARD_DE | DISCARD_IX | DISCARD_IY | DISCARD_HL | DISCARD_F => false
case EX_DE_HL | NEG => false
case LABEL | DI | EI | NOP => false
case _ => true // TODO
}
@ -589,6 +594,7 @@ case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Consta
case JP | JR | RET | RETI | RETN |
PUSH | DJNZ | DAA |
DISCARD_A | DISCARD_BC | DISCARD_DE | DISCARD_IX | DISCARD_IY | DISCARD_HL | DISCARD_F => false
case EX_DE_HL | NEG => false
case LABEL | DI | EI | NOP | HALT => false
case _ => true // TODO
}

View File

@ -19,6 +19,7 @@ object ZOpcode extends Enumeration {
POP, PUSH,
NOP,
RLC, RRC, RL, RR, SLA, SRA, SRL, SLL, RLD, RRD,
RLCA, RLA, RRA, RRCA,
EXX, EX_DE_HL, EX_AF_AF, EX_SP,
RST, IM, EI, DI,
DJNZ, JP, JR, CALL, RET, RETN, RETI, HALT,
@ -46,8 +47,7 @@ object ZOpcodeClasses {
val AllSingleBit: Set[ZOpcode.Value] = RES ++ SET ++ BIT
val RES_or_SET: Set[ZOpcode.Value] = RES ++ SET
val CbInstructions: Set[ZOpcode.Value] = Set(SLA, SRA, SRL, SLL) ++ BIT ++ RES ++ SET
val CbInstructionsUnlessA = Set(RLC, RRC, RL, RR)
val CbInstructions: Set[ZOpcode.Value] = Set(SLA, SRA, SRL, SLL, RLC, RRC, RL, RR) ++ BIT ++ RES ++ SET
val EdInstructions: Set[ZOpcode.Value] = Set(NEG, RETN, RETI, IM, RRD, RLD,
INI, INIR, OUTI, OUTIR, IND, INDR, OUTD, OUTDR,
LDI, LDIR, LDD, LDDR, CPI, CPIR, CPD, CPDR) ++ BIT ++ RES ++ SET

View File

@ -1,10 +1,10 @@
package millfork.assembly.z80.opt
import millfork.assembly.opt.{AnyStatus, SingleStatus}
import millfork.assembly.opt.{AnyStatus, SingleStatus, Status}
import millfork.assembly.z80._
import millfork.env.{Label, MemoryAddressConstant, NormalFunction, NumericConstant}
import millfork.node.ZRegister
import millfork.CompilationOptions
import millfork.{CompilationOptions, Cpu}
/**
* @author Karol Stasiak
@ -102,6 +102,8 @@ object CoarseFlowAnalyzer {
currentStatus = currentStatus.setRegister(t, currentStatus.getRegister(s))
case ZLine(LD | LD_16, TwoRegistersOffset(t, s, o), _, _) =>
currentStatus = currentStatus.setRegister(t, currentStatus.getRegister(s, o), o)
case ZLine(EX_DE_HL, _, _, _) =>
currentStatus = currentStatus.copy(d = currentStatus.h, e = currentStatus.l, h = currentStatus.d, l = currentStatus.e)
case ZLine(ADD_16, TwoRegisters(t, s), _, _) =>
currentStatus = currentStatus.copy(cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
.setRegister(t, (currentStatus.getRegister(t) <*> currentStatus.getRegister(s)) ((m, n) => (m + n) & 0xffff))
@ -113,6 +115,13 @@ object CoarseFlowAnalyzer {
currentStatus = currentStatus.copy(cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
.setRegister(r, currentStatus.getRegister(r).map(_.>>(1).&(0x7f)))
case ZLine(RLA | RRA | RLCA | RRCA, _, _, _) =>
currentStatus = currentStatus.copy(
a = AnyStatus, cf = AnyStatus,
zf = AnyStatus,
pf = AnyStatus, hf = Status.SingleFalse)
case ZLine(opcode, registers, _, _) =>
currentStatus = currentStatus.copy(cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
if (ZOpcodeClasses.ChangesAAlways(opcode)) currentStatus = currentStatus.copy(a = AnyStatus)

View File

@ -227,6 +227,8 @@ object ReverseFlowAnalyzer {
currentImportance = currentImportance.butWritesRegister(t, o).butReadsRegister(s, o)
case ZLine(LD | LD_16, TwoRegisters(t, s), _, _) =>
currentImportance = currentImportance.butWritesRegister(t).butReadsRegister(s)
case ZLine(EX_DE_HL, TwoRegisters(t, s), _, _) =>
currentImportance = currentImportance.copy(d = currentImportance.h, e = currentImportance.l, h = currentImportance.d, l = currentImportance.e)
case ZLine(ADD_16, TwoRegisters(t, s), _, _) =>
currentImportance = currentImportance.butReadsRegister(t).butReadsRegister(s)
case ZLine(ADC_16 | SBC_16, TwoRegisters(t, s), _, _) =>
@ -243,7 +245,7 @@ object ReverseFlowAnalyzer {
)
case ZLine(OR | AND, OneRegister(ZRegister.A), _, _) =>
currentImportance = currentImportance.copy(
a = currentImportance.zf ~ currentImportance.sf ~ currentImportance.pf,
a = currentImportance.zf ~ currentImportance.sf ~ currentImportance.pf ~ currentImportance.a,
cf = Unimportant,
zf = Unimportant,
sf = Unimportant,
@ -429,9 +431,13 @@ object ReverseFlowAnalyzer {
}
case ZLine(SLA | SRL, OneRegister(r), _, _) =>
currentImportance = currentImportance.butReadsRegister(r).butWritesFlag(ZFlag.C).butWritesFlag(ZFlag.Z)
currentImportance = currentImportance.butReadsRegister(r).copy(cf = Unimportant, zf = Unimportant, hf = Unimportant, nf = Unimportant, pf = Unimportant)
case ZLine(RL | RR | RLC | RRC, OneRegister(r), _, _) =>
currentImportance = currentImportance.butReadsRegister(r).butReadsFlag(ZFlag.C).butWritesFlag(ZFlag.Z)
currentImportance = currentImportance.butReadsRegister(r).copy(cf = Important, zf = Unimportant, hf = Unimportant, nf = Unimportant, pf = Unimportant)
case ZLine(SWAP, OneRegister(r), _, _) =>
currentImportance = currentImportance.butReadsRegister(r).copy(cf = Unimportant, zf = Unimportant, hf = Unimportant, nf = Unimportant, pf = Unimportant)
case ZLine(RLA | RRA | RLCA | RRCA, _, _, _) =>
currentImportance = currentImportance.butReadsRegister(ZRegister.A).copy(cf = Important, hf = Unimportant, nf = Unimportant)
case _ =>
currentImportance = finalImportance // TODO
}

View File

@ -278,7 +278,7 @@ object Z80BulkMemoryOperations {
// TODO: tricks with AND?
for (_ <- 0 until n.toInt) {
builder += ZLine.register(OR, ZRegister.A)
builder += ZLine.register(RR, ZRegister.A)
builder += ZLine.implied(RRA)
}
builder += ZLine.ld8(element, ZRegister.A)
Some(builder.toList)

View File

@ -89,7 +89,7 @@ object Z80DecimalBuiltIns {
case 1 => Nil
case x =>
val add1 = List(ZLine.register(ADD, D), ZLine.implied(DAA), ZLine.ld8(E, A))
val times10 = List(ZLine.register(RL, A), ZLine.register(RL, A), ZLine.register(RL, A), ZLine.register(RL, A), ZLine.imm8(AND, 0xf0))
val times10 = List(ZLine.implied(RLA), ZLine.implied(RLA), ZLine.implied(RLA), ZLine.implied(RLA), ZLine.imm8(AND, 0xf0))
// TODO: rethink this:
val ways = if (ctx.options.flag(CompilationFlag.OptimizeForSpeed)) waysOptimizedForCycles else waysOptimizedForBytes
ZLine.ld8(D, A) :: ZLine.ld8(E, A) :: ways(x).flatMap {

View File

@ -497,7 +497,7 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
List(
ZLine.ld8(ZRegister.L, ZRegister.A),
ZLine.ldImm8(ZRegister.A, 0),
ZLine.register(RL, ZRegister.A),
ZLine.implied(RLA),
ZLine.ld8(ZRegister.H, ZRegister.A))
}
case ZExpressionTarget.BC =>
@ -510,7 +510,7 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
List(
ZLine.ld8(ZRegister.C, ZRegister.A),
ZLine.ldImm8(ZRegister.A, 0),
ZLine.register(RL, ZRegister.A),
ZLine.implied(RLA),
ZLine.ld8(ZRegister.B, ZRegister.A))
}
case ZExpressionTarget.DE =>
@ -523,7 +523,7 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
List(
ZLine.ld8(ZRegister.E, ZRegister.A),
ZLine.ldImm8(ZRegister.A, 0),
ZLine.register(RL, ZRegister.A),
ZLine.implied(RLA),
ZLine.ld8(ZRegister.D, ZRegister.A))
}
})

View File

@ -54,9 +54,10 @@ object Z80Multiply {
label(lblStart),
register(OR, A),
ld8(A, D),
register(RR, A),
implied(RRA),
ld8(D, A),
jumpR(ctx, lblAdd, IfFlagSet(ZFlag.C)),
register(OR, A),
jumpR(ctx, lblLoop, IfFlagClear(ZFlag.Z)),
ld8(A, C))
}

View File

@ -26,9 +26,9 @@ object Z80Shifting {
val extendedOps = ctx.options.flag(CompilationFlag.EmitExtended80Opcodes)
val op =
if (extendedOps) {
if (left) ZOpcode.ADD else ZOpcode.SRL
if (left) ZLine.register(ZOpcode.ADD, ZRegister.A) else ZLine.register(ZOpcode.SRL, ZRegister.A)
} else {
if (left) ZOpcode.ADD else ZOpcode.RRC
if (left) ZLine.register(ZOpcode.ADD, ZRegister.A) else ZLine.implied(ZOpcode.RRCA)
}
val l = Z80ExpressionCompiler.compileToA(ctx, lhs)
env.eval(rhs) match {
@ -38,12 +38,12 @@ object Z80Shifting {
} else if (i >= 8) {
l :+ ZLine.ldImm8(ZRegister.A, 0)
} else {
l ++ List.tabulate(i.toInt)(_ => ZLine.register(op, ZRegister.A)) ++ fixAfterShiftIfNeeded(extendedOps, left, i)
l ++ List.tabulate(i.toInt)(_ => op) ++ fixAfterShiftIfNeeded(extendedOps, left, i)
}
case _ =>
val calcCount = Z80ExpressionCompiler.compileToA(ctx, rhs) :+ ZLine.ld8(ZRegister.B, ZRegister.A)
val l = Z80ExpressionCompiler.stashBCIfChanged(ctx, Z80ExpressionCompiler.compileToA(ctx, lhs))
val loopBody = ZLine.register(op, ZRegister.A) :: fixAfterShiftIfNeeded(extendedOps, left, 1)
val loopBody = op :: fixAfterShiftIfNeeded(extendedOps, left, 1)
val label = Z80Compiler.nextLabel("sh")
calcCount ++ l ++ List(ZLine.label(label)) ++ loopBody ++ ZLine.djnz(ctx, label)
}
@ -52,11 +52,11 @@ object Z80Shifting {
def compile8BitShiftInPlace(ctx: CompilationContext, lhs: LhsExpression, rhs: Expression, left: Boolean): List[ZLine] = {
val env = ctx.env
val extendedOps = ctx.options.flag(CompilationFlag.EmitExtended80Opcodes)
val op =
val (op, opLine) =
if (extendedOps) {
if (left) ZOpcode.ADD else ZOpcode.SRL
if (left) ZOpcode.ADD -> ZLine.register(ZOpcode.ADD, ZRegister.A) else ZOpcode.SRL -> ZLine.register(ZOpcode.SRL, ZRegister.A)
} else {
if (left) ZOpcode.ADD else ZOpcode.RRC
if (left) ZOpcode.ADD -> ZLine.register(ZOpcode.ADD, ZRegister.A) else ZOpcode.LABEL -> ZLine.implied(ZOpcode.RRCA)
}
env.eval(rhs) match {
case Some(NumericConstant(i, _)) =>
@ -110,7 +110,7 @@ object Z80Shifting {
l ++ List.tabulate(i.toInt)(_ => ZLine.register(ZOpcode.SLA, register))
} else {
l ++ List(ZLine.ld8(ZRegister.A, register)) ++
List.tabulate(i.toInt)(_ => ZLine.register(op, ZRegister.A)) ++
List.tabulate(i.toInt)(_ => opLine) ++
fixAfterShiftIfNeeded(extendedOps, left, i) ++
List(ZLine.ld8(register, ZRegister.A))
}
@ -150,18 +150,18 @@ object Z80Shifting {
l ++ (1L until i).flatMap(_ => List(
ZLine.ld8(ZRegister.A, ZRegister.H),
ZLine.register(ZOpcode.OR, ZRegister.A),
ZLine.register(ZOpcode.RR, ZRegister.A),
ZLine.implied(ZOpcode.RRA),
ZLine.ld8(ZRegister.H, ZRegister.A),
ZLine.ld8(ZRegister.A, ZRegister.L),
ZLine.register(ZOpcode.RR, ZRegister.A),
ZLine.implied(ZOpcode.RRA),
ZLine.ld8(ZRegister.L, ZRegister.A)
)) ++ List(
ZLine.ld8(ZRegister.A, ZRegister.H),
ZLine.register(ZOpcode.OR, ZRegister.A),
ZLine.register(ZOpcode.RR, ZRegister.A),
ZLine.implied(ZOpcode.RRA),
ZLine.ld8(ZRegister.H, ZRegister.A),
ZLine.ld8(ZRegister.A, ZRegister.L),
ZLine.register(ZOpcode.RR, ZRegister.A),
ZLine.implied(ZOpcode.RRA),
ZLine.ld8(ZRegister.L, ZRegister.A)
)
}
@ -187,16 +187,16 @@ object Z80Shifting {
ZLine.register(ZOpcode.ADD, ZRegister.A),
ZLine.ld8(ZRegister.L, ZRegister.A),
ZLine.ld8(ZRegister.A, ZRegister.H),
ZLine.register(ZOpcode.RL, ZRegister.A),
ZLine.implied(ZOpcode.RLA),
ZLine.ld8(ZRegister.H, ZRegister.A))
} else {
List(
ZLine.ld8(ZRegister.A, ZRegister.H),
ZLine.register(ZOpcode.OR, ZRegister.A),
ZLine.register(ZOpcode.RR, ZRegister.A),
ZLine.implied(ZOpcode.RRA),
ZLine.ld8(ZRegister.H, ZRegister.A),
ZLine.ld8(ZRegister.A, ZRegister.L),
ZLine.register(ZOpcode.RR, ZRegister.A),
ZLine.implied(ZOpcode.RRA),
ZLine.ld8(ZRegister.L, ZRegister.A))
}
}
@ -221,14 +221,14 @@ object Z80Shifting {
if (extended)
List(ZLine.register(SRL, H), ZLine.ld8(A, L), ZLine.register(RR, A))
else
List(ZLine.ld8(A, H), ZLine.register(RR, A), ZLine.ld8(A, L), ZLine.register(RR, A))
List(ZLine.ld8(A, H), ZLine.implied(RRA), ZLine.ld8(A, L), ZLine.implied(RRA))
case Some(NumericConstant(2, _)) if extended=>
List(ZLine.register(SRL, H), ZLine.ld8(A, L), ZLine.register(RR, A), ZLine.register(SRL, A))
List(ZLine.register(SRL, H), ZLine.ld8(A, L), ZLine.implied(RRA), ZLine.register(SRL, A))
case Some(NumericConstant(n, _)) =>
if (extended)
List(ZLine.register(SRL, H), ZLine.ld8(A, L)) ++ (List.fill(n.toInt)(ZLine.register(RR, A)) :+ ZLine.imm8(AND, 0x1ff >> n))
List(ZLine.register(SRL, H), ZLine.ld8(A, L)) ++ (List.fill(n.toInt)(ZLine.implied(RRA)) :+ ZLine.imm8(AND, 0x1ff >> n))
else
List(ZLine.ld8(A, H), ZLine.register(RR, A), ZLine.ld8(A, L)) ++ (List.fill(n.toInt)(ZLine.register(RR, A)) :+ ZLine.imm8(AND, 0x1ff >> n))
List(ZLine.ld8(A, H), ZLine.implied(RRA), ZLine.ld8(A, L)) ++ (List.fill(n.toInt)(ZLine.implied(RRA)) :+ ZLine.imm8(AND, 0x1ff >> n))
case _ =>
ctx.log.error("Non-constant shift amount", rhs.position) // TODO
@ -247,7 +247,7 @@ object Z80Shifting {
import ZRegister._
val shiftByte =
if (ix == 0) List(ZLine.register(ADD, A))
else List(ZLine.register(RL, A))
else List(ZLine.implied(RLA))
ld ++ shiftByte ++ st
}
} else {
@ -257,8 +257,8 @@ object Z80Shifting {
import ZRegister._
val shiftByte = if (ix == 0) {
if (extended) List(ZLine.register(SRL, A))
else List(ZLine.register(OR, A), ZLine.register(RR, A))
} else List(ZLine.register(RR, A))
else List(ZLine.register(OR, A), ZLine.implied(RRA))
} else List(ZLine.implied(RRA))
ld ++ shiftByte ++ st
}
}

View File

@ -245,9 +245,6 @@ class Z80Assembler(program: Program,
val o = oneRegister(op)
writeByte(bank, index, o.opcode + internalRegisterIndex(reg) * o.multiplier)
index + 1
case ZLine(op@(RR|RRC|RL|RLC), OneRegister(A), _, _) =>
writeByte(bank, index, cbOneRegister(op).opcode + 7)
index + 1
case ZLine(SLL, OneRegister(reg), _, _) =>
requireZ80Illegals()
writeByte(bank, index, 0xcb)
@ -641,6 +638,10 @@ object Z80Assembler {
implieds(EI) = 0xfb
implieds(DI) = 0xf3
implieds(HALT) = 0x76
implieds(RLCA) = 7
implieds(RRCA) = 0xf
implieds(RLA) = 0x17
implieds(RRA) = 0x1f
immediates(ADD) = 0xc6
immediates(ADC) = 0xce

View File

@ -198,10 +198,10 @@ case class Z80Parser(filename: String, input: String, currentDirectory: String,
case "DEC" => one8Register(DEC)
case "INC" => one8Register(INC)
case "RLA" => regA(RL)
case "RRA" => regA(RR)
case "RLCA" => regA(RLC)
case "RRCA" => regA(RRC)
case "RLA" => imm(RLA)
case "RRA" => imm(RRA)
case "RLCA" => imm(RLCA)
case "RRCA" => imm(RRCA)
case "RL" => one8Register(RL)
case "RR" => one8Register(RR)
case "RLC" => one8Register(RLC)