mirror of
https://github.com/KarolS/millfork.git
synced 2025-01-12 03:30:09 +00:00
Preliminary and partial machine code output for Z80
This commit is contained in:
parent
893515b649
commit
dc3425f64e
@ -38,6 +38,14 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
|
||||
mem.banks(bank).output(addr) = value.toByte
|
||||
}
|
||||
|
||||
protected def writeByte(bank: String, addr: Int, value: Int): Unit = {
|
||||
mem.banks(bank).occupied(addr) = true
|
||||
mem.banks(bank).initialized(addr) = true
|
||||
mem.banks(bank).readable(addr) = true
|
||||
if ((value & 0xff) != value) ???
|
||||
mem.banks(bank).output(addr) = value.toByte
|
||||
}
|
||||
|
||||
def writeByte(bank: String, addr: Int, value: Constant): Unit = {
|
||||
mem.banks(bank).occupied(addr) = true
|
||||
mem.banks(bank).initialized(addr) = true
|
||||
|
@ -1,10 +1,11 @@
|
||||
package millfork.output
|
||||
|
||||
import millfork.{CompilationOptions, Platform}
|
||||
import millfork.assembly.z80.ZLine
|
||||
import millfork.assembly.z80._
|
||||
import millfork.compiler.z80.Z80Compiler
|
||||
import millfork.env.{Environment, NormalFunction}
|
||||
import millfork.node.{NiceFunctionProperty, Program}
|
||||
import millfork.env._
|
||||
import millfork.error.ErrorReporting
|
||||
import millfork.node.{NiceFunctionProperty, Program, ZRegister}
|
||||
|
||||
import scala.collection.mutable
|
||||
|
||||
@ -16,9 +17,301 @@ class Z80Assembler(program: Program,
|
||||
platform: Platform) extends AbstractAssembler[ZLine](program, rootEnv, platform, Z80InliningCalculator, Z80Compiler) {
|
||||
override def performFinalOptimizationPass(f: NormalFunction, actuallyOptimize: Boolean, options: CompilationOptions, code: List[ZLine]): List[ZLine] = code
|
||||
|
||||
private def internalRegisterIndex(reg: ZRegister.Value): Int = reg match {
|
||||
case ZRegister.B => 0
|
||||
case ZRegister.C => 1
|
||||
case ZRegister.D => 2
|
||||
case ZRegister.E => 3
|
||||
case ZRegister.H => 4
|
||||
case ZRegister.L => 5
|
||||
case ZRegister.MEM_HL => 6
|
||||
case ZRegister.MEM_IX_D => 6
|
||||
case ZRegister.MEM_IY_D => 6
|
||||
case ZRegister.A => 7
|
||||
case ZRegister.BC => 0
|
||||
case ZRegister.DE => 1
|
||||
case ZRegister.HL => 2
|
||||
case ZRegister.AF => 3
|
||||
case ZRegister.SP => 3
|
||||
}
|
||||
|
||||
private def internalArithmeticIndex(opcode: ZOpcode.Value): Int = {
|
||||
import ZOpcode._
|
||||
opcode match {
|
||||
case ADD => 0x80
|
||||
case ADC => 0x88
|
||||
case SUB => 0x90
|
||||
case SBC => 0x98
|
||||
case AND => 0xa0
|
||||
case XOR => 0xa8
|
||||
case OR => 0xb0
|
||||
case CP => 0xb8
|
||||
}
|
||||
}
|
||||
|
||||
override def emitInstruction(bank: String, options: CompilationOptions, index: Int, instr: ZLine): Int = {
|
||||
// TODO
|
||||
index
|
||||
import millfork.assembly.z80.ZOpcode._
|
||||
import Z80Assembler._
|
||||
instr match {
|
||||
case ZLine(LABEL, NoRegisters, MemoryAddressConstant(Label(labelName)), _) =>
|
||||
labelMap(labelName) = index
|
||||
index
|
||||
case ZLine(BYTE, NoRegisters, param, _) =>
|
||||
writeByte(bank, index, param)
|
||||
index + 1
|
||||
case ZLine(DISCARD_F | DISCARD_HL | DISCARD_BCDEIX | DISCARD_A, NoRegisters, _, _) =>
|
||||
index
|
||||
case ZLine(LABEL | BYTE | DISCARD_F | DISCARD_HL | DISCARD_BCDEIX | DISCARD_A, _, _, _) =>
|
||||
???
|
||||
case ZLine(op, NoRegisters, _, _) if implieds.contains(op) =>
|
||||
writeByte(bank, index, implieds(op))
|
||||
index + 1
|
||||
case ZLine(op, NoRegisters, _, _) if edImplieds.contains(op) =>
|
||||
writeByte(bank, index, 0xed)
|
||||
writeByte(bank, index + 1, edImplieds(op))
|
||||
index + 2
|
||||
case ZLine(ADD_16, TwoRegisters(ZRegister.HL, source), param, _) =>
|
||||
writeByte(bank, index, 9 + 16 * internalRegisterIndex(source))
|
||||
index + 1
|
||||
case ZLine(LD_16, TwoRegisters(target, ZRegister.IMM_16), param, _) =>
|
||||
writeByte(bank, index, 1 + 16 * internalRegisterIndex(target))
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case ZLine(LD_16, TwoRegisters(ZRegister.HL, ZRegister.MEM_ABS_16), param, _) =>
|
||||
writeByte(bank, index, 0x2a)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case ZLine(LD_16, TwoRegisters(ZRegister.MEM_ABS_16, ZRegister.HL), param, _) =>
|
||||
writeByte(bank, index, 0x22)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case ZLine(op, OneRegister(ZRegister.IMM_8), param, _) if immediates.contains(op) =>
|
||||
val o = immediates(op)
|
||||
writeByte(bank, index, o)
|
||||
writeByte(bank, index + 1, param)
|
||||
index + 2
|
||||
case ZLine(op, OneRegister(ZRegister.MEM_IX_D), _, _) if oneRegister.contains(op) =>
|
||||
val o = oneRegister(op)
|
||||
writeByte(bank, index, 0xdd)
|
||||
writeByte(bank, index + 1, o.opcode + internalRegisterIndex(ZRegister.MEM_HL) * o.multiplier)
|
||||
writeByte(bank, index + 2, instr.parameter)
|
||||
index + 3
|
||||
case ZLine(op, OneRegister(ZRegister.MEM_IY_D), _, _) if oneRegister.contains(op) =>
|
||||
val o = oneRegister(op)
|
||||
writeByte(bank, index, 0xfd)
|
||||
writeByte(bank, index + 1, o.opcode + internalRegisterIndex(ZRegister.MEM_HL) * o.multiplier)
|
||||
writeByte(bank, index + 2, instr.parameter)
|
||||
index + 3
|
||||
case ZLine(op, OneRegister(ZRegister.IX), _, _) if oneRegister.contains(op) =>
|
||||
val o = oneRegister(op)
|
||||
writeByte(bank, index, 0xdd)
|
||||
writeByte(bank, index + 1, o.opcode + internalRegisterIndex(ZRegister.HL) * o.multiplier)
|
||||
writeByte(bank, index + 2, instr.parameter)
|
||||
index + 3
|
||||
case ZLine(op, OneRegister(ZRegister.IY), _, _) if oneRegister.contains(op) =>
|
||||
val o = oneRegister(op)
|
||||
writeByte(bank, index, 0xfd)
|
||||
writeByte(bank, index + 1, o.opcode + internalRegisterIndex(ZRegister.HL) * o.multiplier)
|
||||
writeByte(bank, index + 2, instr.parameter)
|
||||
index + 3
|
||||
case ZLine(op, OneRegister(reg), _, _) if reg != ZRegister.IMM_8 && oneRegister.contains(op) =>
|
||||
val o = oneRegister(op)
|
||||
writeByte(bank, index, o.opcode + internalRegisterIndex(reg) * o.multiplier)
|
||||
index + 1
|
||||
case ZLine(op, OneRegister(reg), _, _) if cbOneRegister.contains(op) =>
|
||||
val o = cbOneRegister(op)
|
||||
writeByte(bank, index, 0xcb)
|
||||
writeByte(bank, index + 1, o.opcode + internalRegisterIndex(reg) * o.multiplier)
|
||||
index + 2
|
||||
case ZLine(LD, registers, _, _) =>
|
||||
registers match {
|
||||
case TwoRegisters(reg, ZRegister.IMM_8) =>
|
||||
writeByte(bank, index, 6 + 8 * internalRegisterIndex(reg))
|
||||
writeByte(bank, index + 1, instr.parameter)
|
||||
index + 2
|
||||
case TwoRegisters(ZRegister.A, ZRegister.MEM_ABS_8) =>
|
||||
writeByte(bank, index, 0x3a)
|
||||
writeWord(bank, index + 1, instr.parameter)
|
||||
index + 3
|
||||
case TwoRegisters(ZRegister.MEM_ABS_8, ZRegister.A) =>
|
||||
writeByte(bank, index, 0x32)
|
||||
writeWord(bank, index + 1, instr.parameter)
|
||||
index + 3
|
||||
case TwoRegisters(ZRegister.MEM_BC, ZRegister.A) =>
|
||||
writeByte(bank, index, 2)
|
||||
index + 1
|
||||
case TwoRegisters(ZRegister.MEM_DE, ZRegister.A) =>
|
||||
writeByte(bank, index, 0x12)
|
||||
index + 1
|
||||
case TwoRegisters(ZRegister.A, ZRegister.MEM_BC) =>
|
||||
writeByte(bank, index, 0x0a)
|
||||
index + 1
|
||||
case TwoRegisters(ZRegister.A, ZRegister.MEM_DE) =>
|
||||
writeByte(bank, index, 0x1a)
|
||||
index + 1
|
||||
case TwoRegisters(ZRegister.MEM_IX_D, source) =>
|
||||
writeByte(bank, index, 0xdd)
|
||||
writeByte(bank, index + 1, 0x40 + internalRegisterIndex(source) + internalRegisterIndex(ZRegister.MEM_HL) * 8)
|
||||
writeByte(bank, index + 1, instr.parameter)
|
||||
index + 3
|
||||
case TwoRegisters(ZRegister.MEM_IY_D, source) =>
|
||||
writeByte(bank, index, 0xfd)
|
||||
writeByte(bank, index + 1, 0x40 + internalRegisterIndex(source) + internalRegisterIndex(ZRegister.MEM_HL) * 8)
|
||||
writeByte(bank, index + 1, instr.parameter)
|
||||
index + 3
|
||||
case TwoRegisters(target, ZRegister.MEM_IX_D) =>
|
||||
writeByte(bank, index, 0xdd)
|
||||
writeByte(bank, index, 0x40 + internalRegisterIndex(ZRegister.MEM_HL) + internalRegisterIndex(target) * 8)
|
||||
writeByte(bank, index + 1, instr.parameter)
|
||||
index + 3
|
||||
case TwoRegisters(target, ZRegister.MEM_IY_D) =>
|
||||
writeByte(bank, index, 0xfd)
|
||||
writeByte(bank, index, 0x40 + internalRegisterIndex(ZRegister.MEM_HL) + internalRegisterIndex(target) * 8)
|
||||
writeByte(bank, index + 1, instr.parameter)
|
||||
index + 3
|
||||
case TwoRegisters(target, source) =>
|
||||
writeByte(bank, index, 0x40 + internalRegisterIndex(source) + internalRegisterIndex(target) * 8)
|
||||
index + 1
|
||||
case TwoRegisters(target, source) =>
|
||||
writeByte(bank, index, 0x40 + internalRegisterIndex(source) + internalRegisterIndex(target) * 8)
|
||||
index + 1
|
||||
}
|
||||
case ZLine(CALL, NoRegisters, param, _) =>
|
||||
writeByte(bank, index, 0xcd)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
|
||||
|
||||
|
||||
case ZLine(CALL, IfFlagClear(ZFlag.Z), param, _) =>
|
||||
writeByte(bank, index, 0xc4)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case ZLine(CALL, IfFlagClear(ZFlag.C), param, _) =>
|
||||
writeByte(bank, index, 0xd4)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case ZLine(CALL, IfFlagClear(ZFlag.P), param, _) =>
|
||||
writeByte(bank, index, 0xe4)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case ZLine(CALL, IfFlagClear(ZFlag.S), param, _) =>
|
||||
writeByte(bank, index, 0xf4)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
|
||||
case ZLine(CALL, IfFlagSet(ZFlag.Z), param, _) =>
|
||||
writeByte(bank, index, 0xcc)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case ZLine(CALL, IfFlagSet(ZFlag.C), param, _) =>
|
||||
writeByte(bank, index, 0xdc)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case ZLine(CALL, IfFlagSet(ZFlag.P), param, _) =>
|
||||
writeByte(bank, index, 0xec)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case ZLine(CALL, IfFlagSet(ZFlag.S), param, _) =>
|
||||
writeByte(bank, index, 0xfc)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
|
||||
case ZLine(JP, NoRegisters, param, _) =>
|
||||
writeByte(bank, index, 0xc3)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
|
||||
case ZLine(JP, IfFlagClear(ZFlag.Z), param, _) =>
|
||||
writeByte(bank, index, 0xc2)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case ZLine(JP, IfFlagClear(ZFlag.C), param, _) =>
|
||||
writeByte(bank, index, 0xd2)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case ZLine(JP, IfFlagClear(ZFlag.P), param, _) =>
|
||||
writeByte(bank, index, 0xe2)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case ZLine(JP, IfFlagClear(ZFlag.S), param, _) =>
|
||||
writeByte(bank, index, 0xf2)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
|
||||
case ZLine(JP, IfFlagSet(ZFlag.Z), param, _) =>
|
||||
writeByte(bank, index, 0xca)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case ZLine(JP, IfFlagSet(ZFlag.C), param, _) =>
|
||||
writeByte(bank, index, 0xda)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case ZLine(JP, IfFlagSet(ZFlag.P), param, _) =>
|
||||
writeByte(bank, index, 0xea)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case ZLine(JP, IfFlagSet(ZFlag.S), param, _) =>
|
||||
writeByte(bank, index, 0xfa)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
|
||||
case ZLine(RET, IfFlagClear(ZFlag.Z), param, _) =>
|
||||
writeByte(bank, index, 0xc0)
|
||||
index + 1
|
||||
case ZLine(RET, IfFlagClear(ZFlag.C), param, _) =>
|
||||
writeByte(bank, index, 0xd0)
|
||||
index + 1
|
||||
case ZLine(RET, IfFlagClear(ZFlag.P), param, _) =>
|
||||
writeByte(bank, index, 0xe0)
|
||||
index + 1
|
||||
case ZLine(RET, IfFlagClear(ZFlag.S), param, _) =>
|
||||
writeByte(bank, index, 0xf0)
|
||||
index + 1
|
||||
|
||||
case ZLine(RET, IfFlagSet(ZFlag.Z), param, _) =>
|
||||
writeByte(bank, index, 0xc8)
|
||||
index + 1
|
||||
case ZLine(RET, IfFlagSet(ZFlag.C), param, _) =>
|
||||
writeByte(bank, index, 0xd8)
|
||||
index + 1
|
||||
case ZLine(RET, IfFlagSet(ZFlag.P), param, _) =>
|
||||
writeByte(bank, index, 0xe8)
|
||||
index + 1
|
||||
case ZLine(RET, IfFlagSet(ZFlag.S), param, _) =>
|
||||
writeByte(bank, index, 0xf8)
|
||||
index + 1
|
||||
|
||||
case ZLine(JR, IfFlagClear(ZFlag.Z), param, _) =>
|
||||
writeByte(bank, index, 0x20)
|
||||
writeByte(bank, index + 1, AssertByte(param - index - 2))
|
||||
index + 2
|
||||
case ZLine(JR, IfFlagClear(ZFlag.C), param, _) =>
|
||||
writeByte(bank, index, 0x30)
|
||||
writeByte(bank, index + 1, AssertByte(param - index - 2))
|
||||
index + 2
|
||||
|
||||
case ZLine(JR, IfFlagSet(ZFlag.Z), param, _) =>
|
||||
writeByte(bank, index, 0x28)
|
||||
writeByte(bank, index + 1, AssertByte(param - index - 2))
|
||||
index + 2
|
||||
case ZLine(JR, IfFlagSet(ZFlag.C), param, _) =>
|
||||
writeByte(bank, index, 0x38)
|
||||
writeByte(bank, index + 1, AssertByte(param - index - 2))
|
||||
index + 2
|
||||
|
||||
case ZLine(JR, NoRegisters, param, _) =>
|
||||
writeByte(bank, index, 0x18)
|
||||
writeByte(bank, index + 1, AssertByte(param - index - 2))
|
||||
index + 2
|
||||
case ZLine(DJNZ, NoRegisters, param, _) =>
|
||||
writeByte(bank, index, 0x10)
|
||||
writeByte(bank, index + 1, AssertByte(param - index - 2))
|
||||
index + 2
|
||||
case _ =>
|
||||
ErrorReporting.fatal("Cannot assemble " + instr)
|
||||
index
|
||||
}
|
||||
}
|
||||
|
||||
override def injectLabels(labelMap: Map[String, Int], code: List[ZLine]): List[ZLine] = code // TODO
|
||||
@ -27,6 +320,85 @@ class Z80Assembler(program: Program,
|
||||
// do nothing yet
|
||||
}
|
||||
}
|
||||
|
||||
object Z80Assembler {
|
||||
|
||||
}
|
||||
case class One(opcode: Int, multiplier: Int)
|
||||
|
||||
val implieds = mutable.Map[ZOpcode.Value, Int]()
|
||||
val immediates = mutable.Map[ZOpcode.Value, Int]()
|
||||
val edImplieds = mutable.Map[ZOpcode.Value, Int]()
|
||||
val oneRegister = mutable.Map[ZOpcode.Value, One]()
|
||||
val cbOneRegister = mutable.Map[ZOpcode.Value, One]()
|
||||
|
||||
do {
|
||||
import ZOpcode._
|
||||
implieds(NOP) = 0
|
||||
implieds(DAA) = 0x27
|
||||
implieds(SCF) = 0x37
|
||||
implieds(CPL) = 0x37
|
||||
implieds(CCF) = 0x3f
|
||||
implieds(EX_AF_AF) = 8
|
||||
implieds(RET) = 0xc9
|
||||
implieds(EXX) = 0xd9
|
||||
implieds(EI) = 0xfb
|
||||
implieds(DI) = 0xf3
|
||||
implieds(HALT) = 0x76
|
||||
|
||||
immediates(ADD) = 0xc6
|
||||
immediates(ADC) = 0xce
|
||||
immediates(SUB) = 0xd6
|
||||
immediates(SBC) = 0xde
|
||||
immediates(AND) = 0xe6
|
||||
immediates(XOR) = 0xee
|
||||
immediates(OR) = 0xf6
|
||||
immediates(CP) = 0xfe
|
||||
|
||||
edImplieds(NEG) = 0x44
|
||||
edImplieds(RETI) = 0x4d
|
||||
edImplieds(RETN) = 0x45
|
||||
edImplieds(LDI) = 0xa0
|
||||
edImplieds(LDIR) = 0xb0
|
||||
edImplieds(CPI) = 0xa1
|
||||
edImplieds(CPIR) = 0xb1
|
||||
edImplieds(INI) = 0xa2
|
||||
edImplieds(INIR) = 0xb2
|
||||
edImplieds(OUTI) = 0xa3
|
||||
edImplieds(OUTIR) = 0xb3
|
||||
edImplieds(LDD) = 0xa8
|
||||
edImplieds(LDDR) = 0xb8
|
||||
edImplieds(CPD) = 0xa9
|
||||
edImplieds(CPDR) = 0xb9
|
||||
edImplieds(IND) = 0xaa
|
||||
edImplieds(INDR) = 0xba
|
||||
edImplieds(OUTD) = 0xab
|
||||
edImplieds(OUTDR) = 0xbb
|
||||
|
||||
oneRegister(ADD) = One(0x80, 1)
|
||||
oneRegister(ADC) = One(0x88, 1)
|
||||
oneRegister(SUB) = One(0x90, 1)
|
||||
oneRegister(SBC) = One(0x98, 1)
|
||||
oneRegister(AND) = One(0xa0, 1)
|
||||
oneRegister(XOR) = One(0xa8, 1)
|
||||
oneRegister(OR) = One(0xb0, 1)
|
||||
oneRegister(CP) = One(0xb8, 1)
|
||||
oneRegister(INC) = One(4, 8)
|
||||
oneRegister(DEC) = One(5, 8)
|
||||
oneRegister(INC_16) = One(3, 0x10)
|
||||
oneRegister(DEC_16) = One(0xb, 0x10)
|
||||
|
||||
oneRegister(POP) = One(0xc1, 0x10)
|
||||
oneRegister(PUSH) = One(0xc5, 0x10)
|
||||
|
||||
cbOneRegister(RL) = One(0x10, 1)
|
||||
cbOneRegister(RLC) = One(0, 1)
|
||||
cbOneRegister(RR) = One(8, 1)
|
||||
cbOneRegister(RRC) = One(0x18, 1)
|
||||
cbOneRegister(SLA) = One(0x20, 1)
|
||||
cbOneRegister(SRA) = One(0x28, 1)
|
||||
cbOneRegister(SLL) = One(0x30, 1)
|
||||
cbOneRegister(SRL) = One(0x38, 1)
|
||||
} while (false)
|
||||
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user