1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-06-12 22:29:33 +00:00
millfork/src/main/scala/millfork/output/Z80ToX86Crossassembler.scala

440 lines
16 KiB
Scala

package millfork.output
import millfork.{CompilationFlag, CompilationOptions, Cpu, Platform}
import millfork.assembly.z80.{ZOpcode, _}
import millfork.assembly.z80.opt.{ConditionalInstructions, JumpFollowing, JumpShortening}
import millfork.compiler.z80.Z80Compiler
import millfork.env._
import millfork.node.{NiceFunctionProperty, Position, Program, ZRegister}
import scala.collection.mutable
/**
* @author Karol Stasiak
*/
class Z80ToX86Crossassembler(program: Program,
rootEnv: Environment,
platform: Platform) extends AbstractAssembler[ZLine](program, rootEnv, platform, Z80InliningCalculator, Z80Compiler) {
override def performFinalOptimizationPass(f: NormalFunction, actuallyOptimize: Boolean, options: CompilationOptions, code: List[ZLine]): List[ZLine] = {
if (actuallyOptimize) {
JumpShortening(f, ConditionalInstructions(options, JumpFollowing(options, code)), options)
} else code
}
override def injectLabels(labelMap: Map[String, (String, Int)], code: List[ZLine]): List[ZLine] = code // TODO
override def quickSimplify(code: List[ZLine]): List[ZLine] = code.map(a => a.copy(parameter = a.parameter.quickSimplify))
override def gatherNiceFunctionProperties(options: CompilationOptions, niceFunctionProperties: mutable.Set[(NiceFunctionProperty, String)], function: NormalFunction, code: List[ZLine]): Unit = {
// do nothing yet
}
override def gatherFunctionOptimizationHints(options: CompilationOptions, niceFunctionProperties: mutable.Set[(NiceFunctionProperty, String)], function: FunctionInMemory): Unit = {
import NiceFunctionProperty._
val functionName = function.name
if (function.optimizationHints("preserves_memory")) niceFunctionProperties += DoesntWriteMemory -> functionName
if (function.optimizationHints("idempotent")) niceFunctionProperties += Idempotent -> functionName
}
override def bytePseudoopcode: String = "DB"
override def deduplicate(options: CompilationOptions, compiledFunctions: mutable.Map[String, CompiledFunction[ZLine]]): Unit =
new Z80Deduplicate(rootEnv, options).apply(compiledFunctions)
private def registerIndex(r: ZRegister.Value) = {
import ZRegister._
r match {
case A => 0
case C => 1
case E => 2
case L => 3
case B => 5
case D => 6
case H => 7
case AF => 0
case BC => 1
case DE => 2
case HL => 3
case SP => 4
case IX => 5
}
}
private def flagSkip(flag: ZRegisters): Int = flag match {
case IfFlagSet(ZFlag.C) => 0x73 // JAE
case IfFlagClear(ZFlag.C) => 0x72 // JB
case IfFlagSet(ZFlag.S) => 0x79 // JNS
case IfFlagClear(ZFlag.S) => 0x78 // JS
case IfFlagSet(ZFlag.Z) => 0x75 // JNE
case IfFlagClear(ZFlag.Z) => 0x74 // JE
case IfFlagSet(ZFlag.P) => 0x7b // JPO
case IfFlagClear(ZFlag.P) => 0x7a // JPE
case IfFlagSet(ZFlag.K) => 0x7d // JGE
case IfFlagClear(ZFlag.K) => 0x7c // JL
}
override def emitInstruction(bank: String, options: CompilationOptions, index: Int, instr: ZLine): Int = {
import millfork.assembly.z80.ZOpcode._
import ZRegister._
import CompilationFlag._
import Z80ToX86Crossassembler._
implicit val position = instr.source.map(sl => Position(sl.moduleName, sl.line, 0, 0))
instr match {
case ZLine0(LABEL, NoRegisters, MemoryAddressConstant(Label(labelName))) =>
val bank0 = mem.banks(bank)
labelMap(labelName) = bank -> index
index
case ZLine0(BYTE, NoRegisters, param) =>
writeByte(bank, index, param)
index + 1
case ZLine0(DISCARD_F | DISCARD_HL | DISCARD_BC | DISCARD_DE | DISCARD_IX | DISCARD_IY | DISCARD_A | CHANGED_MEM, NoRegisters, _) =>
index
case ZLine0(LABEL | BYTE | DISCARD_F | DISCARD_HL | DISCARD_BC | DISCARD_DE | DISCARD_IX | DISCARD_IY | DISCARD_A | CHANGED_MEM, _, _) =>
???
case ZLine0(op, NoRegisters, _) if implieds.contains(op) =>
writeByte(bank, index, implieds(op))
index + 1
case ZLine0(JP, NoRegisters, param) =>
writeByte(bank, index, 0xe9)
writeWord(bank, index + 1, param + (- 3 - index))
index + 3
case ZLine0(JP, OneRegister(HL), param) =>
writeByte(bank, index, 0xff)
writeByte(bank, index + 1, 0xe3)
index + 2
case ZLine0(CALL, NoRegisters, param) =>
writeByte(bank, index, 0xe8)
writeWord(bank, index + 1, param + (- 3 -index))
index + 3
case ZLine0(RET, flag@(IfFlagSet(_) | IfFlagClear(_)), _) =>
writeByte(bank, index, flagSkip(flag))
writeByte(bank, index + 1, 1)
writeByte(bank, index + 2, 0xc3)
index + 3
case ZLine0(JP, flag@(IfFlagSet(_) | IfFlagClear(_)), param) =>
writeByte(bank, index, flagSkip(flag))
writeByte(bank, index + 1, 3)
writeByte(bank, index + 2, 0xe9)
writeWord(bank, index + 3, param + (- 5 - index))
index + 5
case ZLine0(CALL, flag@(IfFlagSet(_) | IfFlagClear(_)), param) =>
writeByte(bank, index, flagSkip(flag))
writeByte(bank, index + 1, 3)
writeByte(bank, index + 2, 0xe8)
writeWord(bank, index + 3, param + (- 5 - index))
index + 5
case ZLine0(PUSH, OneRegister(AF), _) =>
writeByte(bank, index, 0x9f)
writeByte(bank, index+1, 0x86)
writeByte(bank, index+2, 0xc4)
writeByte(bank, index+3, 0x50)
writeByte(bank, index+4, 0x86)
writeByte(bank, index+5, 0xc4)
index + 6
case ZLine0(POP, OneRegister(AF), _) =>
writeByte(bank, index, 0x58)
writeByte(bank, index+1, 0x86)
writeByte(bank, index+2, 0xc4)
writeByte(bank, index+3, 0x9e)
index + 4
case ZLine0(PUSH, OneRegister(reg), _) =>
writeByte(bank, index, 0x50 + registerIndex(reg))
index + 1
case ZLine0(POP, OneRegister(reg), _) =>
writeByte(bank, index, 0x58 + registerIndex(reg))
index + 1
case ZLine0(LD, TwoRegisters(MEM_HL, IMM_8), param) =>
writeByte(bank, index, 0xc6)
writeByte(bank, index+1, 0x07)
writeByte(bank, index+2, param)
index + 3
case ZLine0(LD, TwoRegisters(MEM_ABS_8, A), param) =>
writeByte(bank, index, 0xa2)
writeWord(bank, index+1, param)
index + 3
case ZLine0(LD, TwoRegisters(A, MEM_ABS_8), param) =>
writeByte(bank, index, 0xa0)
writeWord(bank, index+1, param)
index + 3
case ZLine0(LD, TwoRegistersOffset(MEM_IX_D, IMM_8, offset), param) =>
writeByte(bank, index, 0xc6)
writeByte(bank, index+1, 0x46)
writeByte(bank, index+2, offset)
writeByte(bank, index+3, param)
index + 4
case ZLine0(LD, TwoRegistersOffset(MEM_IX_D, reg, offset), param) =>
writeByte(bank, index, 0x88)
writeByte(bank, index + 1, 0x46 + registerIndex(reg) * 8)
writeByte(bank, index + 2, offset)
index + 3
case ZLine0(LD, TwoRegistersOffset(reg, MEM_IX_D, offset), param) =>
writeByte(bank, index, 0x8a)
writeByte(bank, index + 1, 0x46 + registerIndex(reg) * 8)
writeByte(bank, index + 2, offset)
index + 3
case ZLine0(LD, TwoRegisters(MEM_HL, reg), param) =>
writeByte(bank, index, 0x88)
writeByte(bank, index + 1, 0x7 + registerIndex(reg) * 8)
index + 2
case ZLine0(LD, TwoRegisters(reg, MEM_HL), param) =>
writeByte(bank, index, 0x8a)
writeByte(bank, index + 1, 0x7 + registerIndex(reg) * 8)
index + 2
case ZLine0(LD, TwoRegisters(MEM_DE, A), param) =>
writeByte(bank, index, 0x89)
writeByte(bank, index + 1, 0xd6)
writeByte(bank, index + 2, 0x88)
writeByte(bank, index + 3, 0x04)
index + 4
case ZLine0(LD, TwoRegisters(A, MEM_DE), param) =>
writeByte(bank, index, 0x89)
writeByte(bank, index + 1, 0xd6)
writeByte(bank, index + 2, 0x8a)
writeByte(bank, index + 3, 0x04)
index + 4
case ZLine0(LD, TwoRegisters(MEM_BC, A), param) =>
writeByte(bank, index, 0x89)
writeByte(bank, index + 1, 0xde)
writeByte(bank, index + 2, 0x88)
writeByte(bank, index + 3, 0x04)
index + 4
case ZLine0(LD, TwoRegisters(A, MEM_BC), param) =>
writeByte(bank, index, 0x89)
writeByte(bank, index + 1, 0xde)
writeByte(bank, index + 2, 0x8a)
writeByte(bank, index + 3, 0x04)
index + 4
case ZLine0(LD, TwoRegisters(reg, IMM_8), param) =>
writeByte(bank, index, 0xb0 + registerIndex(reg))
writeByte(bank, index + 1, param)
index + 2
case ZLine0(LD, TwoRegisters(target, source), param) =>
writeByte(bank, index, 0x88)
writeByte(bank, index + 1, 0xc0 + registerIndex(source) * 8 + registerIndex(target))
index + 2
case ZLine0(LD_16, TwoRegisters(reg, MEM_ABS_16), param) =>
writeByte(bank, index, 0x8b)
writeByte(bank, index + 1, 0x6 + registerIndex(reg) * 8)
writeWord(bank, index + 2, param)
index + 4
case ZLine0(LD_16, TwoRegisters(MEM_ABS_16, reg), param) =>
writeByte(bank, index, 0x89)
writeByte(bank, index + 1, 0x6 + registerIndex(reg) * 8)
writeWord(bank, index + 2, param)
index + 4
case ZLine0(LD_16, TwoRegisters(reg, IMM_16), param) =>
writeByte(bank, index, 0xb8 + registerIndex(reg))
writeWord(bank, index + 1, param)
index + 3
case ZLine0(LD_16, TwoRegisters(SP, HL), param) =>
writeByte(bank, index, 0x89)
writeByte(bank, index + 1, 0xdc)
index + 2
case ZLine0(LD_16, TwoRegisters(SP, IX), param) =>
writeByte(bank, index, 0x89)
writeByte(bank, index + 1, 0xec)
index + 2
// TODO: other loads
case ZLine0(CPL, _, _) =>
writeByte(bank, index, 0xf6)
writeByte(bank, index + 1, 0xd0)
index + 2
case ZLine0(op, OneRegister(IMM_8), param) if arith.contains(op) =>
writeByte(bank, index, arith(op)+4)
writeByte(bank, index + 1, param)
index + 2
case ZLine0(op, OneRegisterOffset(MEM_IX_D, offset), _) if arith.contains(op) =>
writeByte(bank, index, arith(op)+2)
writeByte(bank, index + 1, 0x46)
writeByte(bank, index + 2, offset)
index + 3
case ZLine0(op, OneRegister(MEM_HL), _) if arith.contains(op) =>
writeByte(bank, index, arith(op)+2)
writeByte(bank, index + 1, 0x07)
index + 2
case ZLine0(op, OneRegister(reg), _) if arith.contains(op) =>
writeByte(bank, index, arith(op))
writeByte(bank, index + 1, 0xc0 + registerIndex(reg) * 8)
index + 2
case ZLine0(INC, OneRegisterOffset(MEM_IX_D, offset), _) =>
writeByte(bank, index, 0xfe)
writeByte(bank, index + 1, 0x46)
writeByte(bank, index + 2, offset)
index + 3
case ZLine0(INC, OneRegister(MEM_HL), _) =>
writeByte(bank, index, 0xfe)
writeByte(bank, index + 1, 0x07)
index + 2
case ZLine0(INC, OneRegister(reg), _) =>
writeByte(bank, index, 0xfe)
writeByte(bank, index + 1, 0xc0 + registerIndex(reg))
index + 2
case ZLine0(DEC, OneRegisterOffset(MEM_IX_D, offset), _) =>
writeByte(bank, index, 0xfe)
writeByte(bank, index + 1, 0x4e)
writeByte(bank, index + 2, offset)
index + 3
case ZLine0(DEC, OneRegister(MEM_HL), _) =>
writeByte(bank, index, 0xfe)
writeByte(bank, index + 1, 0x0f)
index + 2
case ZLine0(DEC, OneRegister(reg), _) =>
writeByte(bank, index, 0xfe)
writeByte(bank, index + 1, 0xc8 + registerIndex(reg))
index + 2
case ZLine0(INC_16, OneRegister(reg), _) =>
writeByte(bank, index, 0x40 + registerIndex(reg))
index + 1
case ZLine0(DEC_16, OneRegister(reg), _) =>
writeByte(bank, index, 0x48 + registerIndex(reg))
index + 1
case ZLine0(ADD_16, TwoRegisters(HL, reg), _) =>
writeByte(bank, index, 0x1)
writeByte(bank, index + 1, 0xc3 + registerIndex(reg) * 8)
index + 2
case ZLine0(ADD_16, TwoRegisters(IX, reg), _) =>
writeByte(bank, index, 0x1)
writeByte(bank, index + 1, 0xc5 + registerIndex(reg) * 8)
index + 2
case ZLine0(EX_DE_HL, _, _) =>
writeByte(bank, index, 0x87)
writeByte(bank, index + 1, 0xd3)
index + 2
case ZLine0(EX_SP, OneRegister(HL), _) =>
writeByte(bank, index, 0x89)
writeByte(bank, index + 1, 0x86)
writeByte(bank, index + 2, 0x87)
writeByte(bank, index + 3, 0x1c)
index + 2
case ZLine0(EX_SP, OneRegister(IX), _) =>
writeByte(bank, index, 0x89)
writeByte(bank, index + 1, 0x86)
writeByte(bank, index + 2, 0x87)
writeByte(bank, index + 3, 0x2c)
index + 2
case ZLine0(RRA, _, _) =>
writeByte(bank, index, 0xd0)
writeByte(bank, index + 1, 0xd8)
index + 2
case ZLine0(RRCA, _, _) =>
writeByte(bank, index, 0xd0)
writeByte(bank, index + 1, 0xc8)
index + 2
case ZLine0(RLA, _, _) =>
writeByte(bank, index, 0xd0)
writeByte(bank, index + 1, 0xd0)
index + 2
case ZLine0(RLCA, _, _) =>
writeByte(bank, index, 0xd0)
writeByte(bank, index + 1, 0xc0)
index + 2
case ZLine0(IN_IMM, _, param) =>
writeByte(bank, index, 0xe4)
writeByte(bank, index + 1, param)
index + 2
case ZLine0(OUT_IMM, _, param) =>
writeByte(bank, index, 0xe6)
writeByte(bank, index + 1, param)
index + 2
case ZLine0(LD_DEHL, _, param) =>
writeByte(bank, index, 0x8d)
writeByte(bank, index + 1 , 0x57)
writeByte(bank, index + 2, param)
index + 3
case ZLine0(LD_DESP, _, param) =>
writeByte(bank, index, 0x89)
writeByte(bank, index + 1, 0xe6)
writeByte(bank, index + 2, 0x8d)
writeByte(bank, index + 3 , 0x54)
writeByte(bank, index + 4, param)
index + 5
case ZLine0(LD_HLSP, _, param) =>
writeByte(bank, index, 0x89)
writeByte(bank, index + 1, 0xe6)
writeByte(bank, index + 2, 0x8d)
writeByte(bank, index + 3 , 0x5c)
writeByte(bank, index + 4, param)
index + 5
case ZLine0(DSUB, _, param) =>
writeByte(bank, index, 0x29)
writeByte(bank, index + 1, 0xcb)
index + 2
case ZLine0(SHLX, _, param) =>
writeByte(bank, index, 0x89)
writeByte(bank, index + 1, 0xd6)
writeByte(bank, index + 2, 0x89)
writeByte(bank, index + 3 , 0x1c)
index + 4
case ZLine0(LHLX, _, param) =>
writeByte(bank, index, 0x89)
writeByte(bank, index + 1, 0xd6)
writeByte(bank, index + 2, 0x8b)
writeByte(bank, index + 3 , 0x1c)
index + 4
case _ =>
println("TODO: " + instr)
???
}
}
}
object Z80ToX86Crossassembler {
case class One(opcode: Int, multiplier: Int)
val implieds: mutable.Map[ZOpcode.Value, Int] = mutable.Map[ZOpcode.Value, Int]()
val arith: mutable.Map[ZOpcode.Value, Int] = mutable.Map[ZOpcode.Value, Int]()
val edImplieds: mutable.Map[ZOpcode.Value, Int] = mutable.Map[ZOpcode.Value, Int]()
val oneRegister: mutable.Map[ZOpcode.Value, One] = mutable.Map[ZOpcode.Value, One]()
val cbOneRegister: mutable.Map[ZOpcode.Value, One] = mutable.Map[ZOpcode.Value, One]()
do {
import ZOpcode._
implieds(NOP) = 0x90
implieds(DAA) = 0x27
implieds(SCF) = 0xf9
implieds(CCF) = 0xf5
implieds(RET) = 0xc3
implieds(EI) = 0xfb
implieds(DI) = 0xfa
implieds(HALT) = 0xf4
arith(ADD) = 0x00
arith(ADC) = 0x10
arith(SUB) = 0x28
arith(SBC) = 0x18
arith(AND) = 0x20
arith(XOR) = 0x30
arith(OR) = 0x08
arith(CP) = 0x38
} while (false)
}