1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-07-05 09:28:54 +00:00

Preliminary and partial machine code output for Z80

This commit is contained in:
Karol Stasiak 2018-07-01 22:28:09 +02:00
parent 893515b649
commit dc3425f64e
2 changed files with 386 additions and 6 deletions

View File

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

View File

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