1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-08-13 02:28:59 +00:00

Z80: LDH instruction for LR35902

This commit is contained in:
Karol Stasiak 2018-08-03 16:43:31 +02:00
parent f4a2c96512
commit 48b183828b
6 changed files with 60 additions and 6 deletions

View File

@ -12,15 +12,13 @@ There are two ways to include raw assembly code in your Millfork programs:
Millfork uses Zilog syntax for Intel 8080, Z80 and LR35902 assembly.
**Work in progress**:
Intel syntax is not supported yet.
LR35902 instructions for faster access to the $FFxx addresses are not available yet.
Indexing via the IX/IY register uses the following syntax: `IX(1)`
LR35902 instructions that load/store the accumulator indirectly via HL and then increment/decrement HL are written
`LD A,(HLI)`, `LD, A,(HLD)`, `LD (HLI),A` and `LD (HLD),A`
LR35902 instructions for faster access to the $FFxx addresses use the `LDH` mnemonic: `LDH A,(4)`, `LDH (C),A` etc.
Only instructions available on the current CPU architecture are available.
Undocumented instructions are not supported, except for `SLL`.

View File

@ -279,6 +279,10 @@ case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Consta
case LD_AHLD => " LD A,(HLD)"
case LD_HLIA => " LD (HLI),A"
case LD_HLDA => " LD (HLD),A"
case LDH_AC => " LDH A,(C)"
case LDH_CA => " LDH (C),A"
case LDH_DA => s" LDH ($parameter),A"
case LDH_AD => s" LDH A,($parameter)"
case LD_HLSP => " LD HL,SP+" + parameter
case ADD_SP => " ADD SP," + parameter
case EX_SP => registers match {
@ -606,6 +610,12 @@ case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Consta
case DJNZ => r == B
case DAA | NEG | CPL | RLA | RRA | RLCA | RRCA => r == A
case LABEL | DI | EI | NOP | HALT => false
case LDH_AC => r == C
case LDH_CA => r == C || r == A
case LDH_DA => r == A
case LDH_AD => false
case LD_HLIA | LD_HLDA => r == H || r == L | r == A
case LD_AHLI | LD_AHLD => r == H || r == L
case _ => true // TODO
}
}
@ -742,6 +752,10 @@ case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Consta
case DJNZ => r == B
case LABEL | DI | EI | NOP | HALT => false
case CALL => r != IXH && r != IXL && r != SP
case LDH_CA | LDH_DA => false
case LDH_AC | LDH_AD => r == A
case LD_HLIA | LD_HLDA => r == H || r == L
case LD_AHLI | LD_AHLD => r == H || r == L | r == A
case _ => true // TODO
}
}
@ -770,6 +784,8 @@ case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Consta
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 LDH_AC | LDH_AD | LD_AHLI | LD_AHLD => false
case LDH_CA | LDH_DA | LD_HLIA | LD_HLDA => true
case _ => true // TODO
}
}
@ -792,6 +808,8 @@ case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Consta
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 LDH_AC | LDH_AD | LD_AHLI | LD_AHLD => true
case LDH_CA | LDH_DA | LD_HLIA | LD_HLDA => false
case _ => true // TODO
}
}

View File

@ -24,7 +24,7 @@ object ZOpcode extends Enumeration {
RST, IM, EI, DI,
DJNZ, JP, JR, CALL, RET, RETN, RETI, HALT,
//sharp:
LD_AHLI, LD_AHLD, LD_HLIA, LD_HLDA, SWAP, LD_H, LD_HLSP, ADD_SP, STOP,
LD_AHLI, LD_AHLD, LD_HLIA, LD_HLDA, SWAP, LDH_DA, LDH_AD, LDH_CA, LDH_AC, LD_HLSP, ADD_SP, STOP,
DISCARD_A, DISCARD_F, DISCARD_HL, DISCARD_BC, DISCARD_DE, DISCARD_IX, DISCARD_IY,
LABEL, BYTE = Value
}
@ -57,6 +57,7 @@ object ZOpcodeClasses {
val ChangesAFAlways = Set( // TODO: !
DAA, ADD, ADC, SUB, SBC, XOR, OR, AND, INC, DEC,
SCF, CCF, NEG,
LDH_AC, LDH_AD, LD_AHLI, LD_AHLD,
ADD_16, ADC_16, SBC_16, INC_16, DEC_16,
INI, INIR, OUTI, OUTIR, IND, INDR, OUTD, OUTDR,
LDI, LDIR, LDD, LDDR, CPI, CPIR, CPD, CPDR,
@ -68,6 +69,7 @@ object ZOpcodeClasses {
val ChangesHLAlways = Set(
INI, INIR, OUTI, OUTIR, IND, INDR, OUTD, OUTDR,
LDI, LDIR, LDD, LDDR, CPI, CPIR, CPD, CPDR,
LD_AHLI, LD_AHLD, LD_HLIA, LD_HLDA,
EXX, EX_DE_HL, CALL, JR, JP, LABEL)
val ChangesDEAlways = Set(
LDI, LDIR, LDD, LDDR,

View File

@ -596,6 +596,24 @@ class Z80Assembler(program: Program,
requireSharp()
writeByte(bank, index, 0x32)
index + 1
case ZLine(LDH_AD, _, param, _) =>
requireSharp()
writeByte(bank, index, 0xf0)
writeByte(bank, index + 1, param.loByte)
index + 2
case ZLine(LDH_DA, _, param, _) =>
requireSharp()
writeByte(bank, index, 0xe0)
writeByte(bank, index + 1, param.loByte)
index + 2
case ZLine(LDH_AC, _, _, _) =>
requireSharp()
writeByte(bank, index, 0xf2)
index + 1
case ZLine(LDH_CA, _, _, _) =>
requireSharp()
writeByte(bank, index, 0xe2)
index + 1
case ZLine(STOP, _, _, _) =>
requireSharp()
writeByte(bank, index, 0x10)

View File

@ -88,10 +88,15 @@ case class Z80Parser(filename: String,
"SP" -> ZRegister.SP, "sp" -> ZRegister.SP,
)
private def param(allowAbsolute: Boolean, allowRI: Boolean = false): P[(ZRegister.Value, Option[Expression])] = asmExpressionWithParens.map {
private def param(allowAbsolute: Boolean, allowRI: Boolean = false, allowFfc: Boolean = false): P[(ZRegister.Value, Option[Expression])] = asmExpressionWithParens.map {
case (VariableExpression("R" | "r"), false) if allowRI => (ZRegister.R, None)
case (VariableExpression("I" | "i"), false) if allowRI => (ZRegister.I, None)
case (VariableExpression(r), false) if toRegister.contains(r)=> (toRegister(r), None)
case (SumExpression(List(
(false, LiteralExpression(0xff00, _)),
(false, VariableExpression("C" | "c"))
), false), true) if allowFfc => (ZRegister.MEM_BC, None) // MEM_BC is a placeholder here for ($FF00 + C)
case (VariableExpression("C" | "c"), true) if allowFfc => (ZRegister.MEM_BC, None) // MEM_BC is a placeholder here for ($FF00 + C)
case (VariableExpression("HL" | "hl"), true) => (ZRegister.MEM_HL, None)
case (VariableExpression("BC" | "bc"), true) => (ZRegister.MEM_BC, None)
case (VariableExpression("DE" | "de"), true) => (ZRegister.MEM_DE, None)
@ -361,6 +366,15 @@ case class Z80Parser(filename: String,
}
}
case "LDH" => (param(allowAbsolute = true, allowFfc = true) ~ HWS ~ position("comma").map(_ => ()) ~ "," ~/ HWS ~ param(allowAbsolute = true, allowFfc = true)).map {
case (ZRegister.MEM_ABS_8, Some(expr), (ZRegister.A, None)) => (LDH_DA, NoRegisters, None, expr)
case (ZRegister.A, None, (ZRegister.MEM_ABS_8, Some(expr))) => (LDH_AD, NoRegisters, None, expr)
case (ZRegister.A, None, (ZRegister.MEM_BC, None)) => (LDH_AC, NoRegisters, None, zero)
case (ZRegister.MEM_BC, None, (ZRegister.A, None)) => (LDH_CA, NoRegisters, None, zero)
case _ =>
log.error("Invalid parameters for LDH", Some(pos))
(NOP, NoRegisters, None, zero)
}
case "LD" => (param(allowAbsolute = true, allowRI = true) ~ HWS ~ position("comma").map(_ => ()) ~ "," ~/ HWS ~ param(allowAbsolute = true, allowRI = true)).map {
case (ZRegister.HL, None, (ZRegister.IMM_8 | ZRegister.IMM_16, Some(SumExpression((false, VariableExpression("sp" | "SP")) :: offset, false))))
if options.flags(CompilationFlag.EmitSharpOpcodes) =>

View File

@ -879,6 +879,10 @@ class Z80AssemblySuite extends FunSuite with Matchers {
| swap c
| swap(hl)
|
| ldh a,(9)
| ldh (9),a
| ldh a,(c)
| ldh (c),a
| ret
| }
""".stripMargin)