mirror of
https://github.com/KarolS/millfork.git
synced 2025-01-16 16:31:04 +00:00
Z80: Support IXH/IXL/IYH/IYL registers. Add Intel syntax for Z80 instructions.
This commit is contained in:
parent
53973f081a
commit
b24ac32932
@ -69,8 +69,11 @@ AHX, LAS, LXA, SHX, SHY, TAS, XAA.
|
||||
## Z80
|
||||
|
||||
Original Z80 processors accidentally supported a bunch of extra undocumented instructions.
|
||||
Millfork will not emit them.
|
||||
The only exception is SLL, which will be emitted if it occurs in a handwritten assembly block.
|
||||
Millfork will emit some of them if used in an assembly block:
|
||||
|
||||
* `SLL` – supported
|
||||
* instructions using the IXH, IXL, IYH, IYL registers – supported (can only be used in Zilog syntax)
|
||||
* instructions of the form `RLC IX(1),B` – not supported
|
||||
|
||||
## 8085
|
||||
|
||||
|
@ -22,10 +22,15 @@ LR35902 instructions that load/store the accumulator indirectly via HL and then
|
||||
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.
|
||||
Intel syntax does not support instructions that are unavailable on the 8080.
|
||||
Undocumented Z80 instructions are not supported, except for `SLL`.
|
||||
Undocumented Z80 instructions are partially supported:
|
||||
* `SLL` – supported
|
||||
* instructions using the IXH, IXL, IYH, IYL registers – supported (can only be used in Zilog syntax)
|
||||
* instructions of the form `RLC IX(1),B` – not supported
|
||||
|
||||
Not all ZX Spectrum Next are supported. `JP (C)`, `BSLA` and similar instructions are not supported.
|
||||
Intel syntax supports the 8080 instructions, the documented Z80 instructions and `SLL`.
|
||||
It does not support instructions that are unavailable on the Z80 or other undocumented Z80 instructions.
|
||||
|
||||
Not all ZX Spectrum Next instructions are supported. `JP (C)`, `BSLA` and similar instructions are not supported.
|
||||
|
||||
Labels have to be followed by a colon and they can optionally be on a separate line.
|
||||
Indentation is not important:
|
||||
@ -200,3 +205,108 @@ it should abide to the following rules:
|
||||
* end non-inline assembly functions with `RET`, `JP`, `RETI` or `RETN` (Zilog) / `RET` or `JMP` (Intel) as appropriate
|
||||
|
||||
The above list is not exhaustive.
|
||||
|
||||
## Z80 instructions in the Intel syntax
|
||||
|
||||
Millfork uses the same extensions for Intel syntax as Z80.LIB from Digital Research.
|
||||
Some mnemonics from the TDL Z80 Relocating/Linking Assembler are also supported.
|
||||
|
||||
In the list below, `c` is a flag, `r` is a register, and `n` and `d` are parameters.
|
||||
For instructions using the index registers, only the IY variant is given;
|
||||
the IX variant has the same mnemonic, but with `Y` replaced with `X`.
|
||||
|
||||
Intel syntax | Zilog syntax
|
||||
----|----
|
||||
**EXAF** | **EX AF,AF'**
|
||||
**JR n**, JMPR n | **JR n**
|
||||
**JRc n** | **JR c,n**
|
||||
**INP r** | **IN r,(C)**
|
||||
**OUTP r** | **OUT r,(C)**
|
||||
**CCI** | **CPI**
|
||||
**CCIR** | **CPIR**
|
||||
**CCD** | **CPD**
|
||||
**CCDR** | **CPDR**
|
||||
**OUTIR** | **OTIR**, OUTIR
|
||||
**OUTDR** | **OTDR**, OUTDR
|
||||
**IM0** | **IM 0**
|
||||
**IM1** | **IM 1**
|
||||
**IM2** | **IM 2**
|
||||
**DSBC r** | **SBC HL,rr**
|
||||
**DADC r** | **ADC HL,rr**
|
||||
**DADY r** | **ADD IY,rr**
|
||||
**INXIY**, INX IY | **INC IY**
|
||||
**DCXIY**, DCX IY | **DEC IY**
|
||||
**SBCD nn** | **LD (nn),BC**
|
||||
**SDED nn** | **LD (nn),DE**
|
||||
**SSPD nn** | **LD (nn),SP**
|
||||
**SIYD nn** | **LD (nn),IY**
|
||||
**LBCD nn** | **LD BC,(nn)**
|
||||
**LDED nn** | **LD DE,(nn)**
|
||||
**LSPD nn** | **LD SP,(nn)**
|
||||
**LIYD nn** | **LD IY,(nn)**
|
||||
**SETB n,r**, SET n,r | **SET n,r**
|
||||
**BITY n,d** | **BIT n,IY(d)**
|
||||
**SETY n,d** | **SET n,IY(d)**
|
||||
**RESY n,d** | **RES n,IY(d)**
|
||||
**PCIY** | **JP IY**
|
||||
**RLCR r** | **RLC r**
|
||||
**RALR r** | **RL r**
|
||||
**RRCR r** | **RRC r**
|
||||
**RARR r** | **RR r**
|
||||
**SLAR r** | **SLA r**
|
||||
**SRAR r** | **SRA r**
|
||||
**SRLR r** | **SRL r**
|
||||
**RLCX r** | **RLC r**
|
||||
**RALY d** | **RL IY(d)**
|
||||
**RRCY d** | **RRC IY(d)**
|
||||
**RARY d** | **RR IY(d)**
|
||||
**SLAY d** | **SLA IY(d)**
|
||||
**SRAY d** | **SRA IY(d)**
|
||||
**SRLY d** | **SRL IY(d)**
|
||||
**SLLR r** | **SLL r**
|
||||
**SLLY d** | **SLL IY(d)**
|
||||
**SPIY** | **LD SP,IY**
|
||||
**PUSHIY**, PUSH IY | **PUSH IY**
|
||||
**POPIY**, POP IY | **POP IY**
|
||||
**XTIY** | **EX (SP),IY**
|
||||
**LDAI** | **LD A,I**
|
||||
**LDAR** | **LD A,R**
|
||||
**STAI** | **LD I,A**
|
||||
**STAR** | **LD R,A**
|
||||
**LXIY nn**, LXI IY,nn | **LD IY,nn**
|
||||
**ADDY d** | **ADD A,IY(d)**
|
||||
**ADCY d** | **ADC A,IY(d)**
|
||||
**SUBY d** | **SUB IY(d)**
|
||||
**SBCY d** | **SBC A,IY(d)**
|
||||
**ANDY d** | **AND IY(d)**
|
||||
**XORY d** | **XOR IY(d)**
|
||||
**ORY d** | **OR IY(d)**
|
||||
**CMPY d** | **CMP IY(d)**
|
||||
**INRY d** | **INC IY(d)**
|
||||
**DCRY d** | **DEC IY(d)**
|
||||
**MVIY n,d** | **LD IY(d),n**
|
||||
**LDY r,d** | **LD r,IY(d)**
|
||||
**STY r,d** | **LD IY(d),r**
|
||||
|
||||
|
||||
Instructions that are the same in both syntaxes:
|
||||
|
||||
**BIT n,r**,
|
||||
**RES n,r**,
|
||||
**DJNZ n**,
|
||||
**EXX**,
|
||||
**NEG**,
|
||||
**RETI**,
|
||||
**RETN**,
|
||||
**RLD**,
|
||||
**RRD**,
|
||||
**LDI**,
|
||||
**LDIR**,
|
||||
**LDD**,
|
||||
**LDDR**,
|
||||
**INI**,
|
||||
**INIR**,
|
||||
**IND**,
|
||||
**INDR**,
|
||||
**OUTI**,
|
||||
**OUTD**
|
||||
|
@ -275,7 +275,7 @@ case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Consta
|
||||
|
||||
override def isPrintable: Boolean = true
|
||||
|
||||
private def asAssemblyString(r: ZRegister.Value, offset: Int = 0): String = r match {
|
||||
private def asAssemblyString(r: ZRegister.Value, offset: Int = 666): String = r match {
|
||||
case ZRegister.A => "A"
|
||||
case ZRegister.B => "B"
|
||||
case ZRegister.C => "C"
|
||||
@ -325,6 +325,8 @@ case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Consta
|
||||
case ZRegister.IMM_8 => s"$parameter"
|
||||
case ZRegister.IMM_16 => s"$parameter"
|
||||
case ZRegister.MEM_HL => "M"
|
||||
case ZRegister.IX => "IX"
|
||||
case ZRegister.IY => "IY"
|
||||
case _ => "???"
|
||||
}
|
||||
|
||||
@ -467,6 +469,12 @@ case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Consta
|
||||
case DISCARD_IY => " ; DISCARD_IY"
|
||||
case BYTE => " DB " + parameter.toString
|
||||
case LD => registers match {
|
||||
case TwoRegistersOffset(MEM_IX_D, IMM_8, offset) => s" MVIX ${parameter.toIntelString}, ${offset}"
|
||||
case TwoRegistersOffset(MEM_IY_D, IMM_8, offset) => s" MVIY ${parameter.toIntelString}, ${offset}"
|
||||
case TwoRegistersOffset(MEM_IX_D, source, offset) => s" STX ${asIntelAssemblyString(source)}, ${offset}"
|
||||
case TwoRegistersOffset(MEM_IY_D, source, offset) => s" STY ${asIntelAssemblyString(source)}, ${offset}"
|
||||
case TwoRegistersOffset(target, MEM_IX_D, offset) => s" LDX ${asIntelAssemblyString(target)}, ${offset}"
|
||||
case TwoRegistersOffset(target, MEM_IY_D, offset) => s" LDY ${asIntelAssemblyString(target)}, ${offset}"
|
||||
case TwoRegisters(target, IMM_8) => s" MVI ${asIntelAssemblyString(target)}, ${parameter.toIntelString}"
|
||||
case TwoRegisters(A, MEM_ABS_8) => s" LDA ${parameter.toIntelString}"
|
||||
case TwoRegisters(MEM_ABS_8, A) => s" STA ${parameter.toIntelString}"
|
||||
@ -474,50 +482,169 @@ case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Consta
|
||||
case TwoRegisters(MEM_BC, A) => " STAX B"
|
||||
case TwoRegisters(A, MEM_DE) => " LDAX D"
|
||||
case TwoRegisters(MEM_DE, A) => " STAX D"
|
||||
case TwoRegisters(I, A) => " STAI"
|
||||
case TwoRegisters(A, I) => " LDAI"
|
||||
case TwoRegisters(R, A) => " STAR"
|
||||
case TwoRegisters(A, R) => " LDAR"
|
||||
case TwoRegisters(target, source) => s" MOV ${asIntelAssemblyString(target)}, ${asIntelAssemblyString(source)}"
|
||||
case _ => "???"
|
||||
}
|
||||
case LD_16 => registers match {
|
||||
case TwoRegisters(SP, HL) => " SPHL"
|
||||
case TwoRegisters(SP, IX) => " SPIX"
|
||||
case TwoRegisters(SP, IY) => " SPIY"
|
||||
case TwoRegisters(IX, IMM_16) => s" LXIX ${parameter.toIntelString}"
|
||||
case TwoRegisters(IY, IMM_16) => s" LXIY ${parameter.toIntelString}"
|
||||
case TwoRegisters(target, IMM_16) => s" LXI ${asIntelAssemblyString(target)}, ${parameter.toIntelString}"
|
||||
case TwoRegisters(HL, MEM_ABS_16) => s" LHLD ${parameter.toIntelString}"
|
||||
case TwoRegisters(BC, MEM_ABS_16) => s" LBCD ${parameter.toIntelString}"
|
||||
case TwoRegisters(DE, MEM_ABS_16) => s" LDED ${parameter.toIntelString}"
|
||||
case TwoRegisters(IX, MEM_ABS_16) => s" LIXD ${parameter.toIntelString}"
|
||||
case TwoRegisters(IY, MEM_ABS_16) => s" LIYD ${parameter.toIntelString}"
|
||||
case TwoRegisters(SP, MEM_ABS_16) => s" LSPD ${parameter.toIntelString}"
|
||||
case TwoRegisters(MEM_ABS_16, HL) => s" SHLD ${parameter.toIntelString}"
|
||||
case TwoRegisters(MEM_ABS_16, BC) => s" SBCD ${parameter.toIntelString}"
|
||||
case TwoRegisters(MEM_ABS_16, DE) => s" SDED ${parameter.toIntelString}"
|
||||
case TwoRegisters(MEM_ABS_16, IX) => s" SIXD ${parameter.toIntelString}"
|
||||
case TwoRegisters(MEM_ABS_16, IY) => s" SIYD ${parameter.toIntelString}"
|
||||
case TwoRegisters(MEM_ABS_16, SP) => s" SSPD ${parameter.toIntelString}"
|
||||
case _ => "???"
|
||||
}
|
||||
case ADD_16 => registers match {
|
||||
case TwoRegisters(IX, source) => s" DADX ${asIntelAssemblyString(source)}"
|
||||
case TwoRegisters(IY, source) => s" DADY ${asIntelAssemblyString(source)}"
|
||||
case TwoRegisters(HL, source) => s" DAD ${asIntelAssemblyString(source)}"
|
||||
case _ => "???"
|
||||
}
|
||||
case ADC_16 => registers match {
|
||||
case TwoRegisters(HL, source) => s" DADC ${asIntelAssemblyString(source)}"
|
||||
case _ => "???"
|
||||
}
|
||||
case SBC_16 => registers match {
|
||||
case TwoRegisters(HL, source) => s" DSBC ${asIntelAssemblyString(source)}"
|
||||
case _ => "???"
|
||||
}
|
||||
case DEC_16 => registers match {
|
||||
case OneRegister(IX) => s" DCXIX"
|
||||
case OneRegister(IY) => s" DCXIY"
|
||||
case OneRegister(register) => s" DCX ${asIntelAssemblyString(register)}"
|
||||
case _ => "???"
|
||||
}
|
||||
case INC_16 => registers match {
|
||||
case OneRegister(IX) => s" INXIX"
|
||||
case OneRegister(IY) => s" INXIY"
|
||||
case OneRegister(register) => s" INX ${asIntelAssemblyString(register)}"
|
||||
case _ => "???"
|
||||
}
|
||||
case DEC => registers match {
|
||||
case OneRegisterOffset(MEM_IX_D, offset) => s" DCRX ${offset}"
|
||||
case OneRegisterOffset(MEM_IY_D, offset) => s" DCRY ${offset}"
|
||||
case OneRegister(register) => s" DCR ${asIntelAssemblyString(register)}"
|
||||
case _ => "???"
|
||||
}
|
||||
case INC => registers match {
|
||||
case OneRegisterOffset(MEM_IX_D, offset) => s" INRX ${offset}"
|
||||
case OneRegisterOffset(MEM_IY_D, offset) => s" INRY ${offset}"
|
||||
case OneRegister(register) => s" INR ${asIntelAssemblyString(register)}"
|
||||
case _ => "???"
|
||||
}
|
||||
case op if ZOpcodeClasses.RES(op) => registers match {
|
||||
case OneRegisterOffset(MEM_IX_D, offset) => s" RESX ${ZOpcodeClasses.RES_seq.indexOf(op)},${offset}"
|
||||
case OneRegisterOffset(MEM_IY_D, offset) => s" RESY ${ZOpcodeClasses.RES_seq.indexOf(op)},${offset}"
|
||||
case OneRegister(register) => s" RES ${ZOpcodeClasses.RES_seq.indexOf(op)},${asIntelAssemblyString(register)}"
|
||||
case _ => "???"
|
||||
}
|
||||
case op if ZOpcodeClasses.SET(op) => registers match {
|
||||
case OneRegisterOffset(MEM_IX_D, offset) => s" SETX ${ZOpcodeClasses.SET_seq.indexOf(op)},${offset}"
|
||||
case OneRegisterOffset(MEM_IY_D, offset) => s" SETY ${ZOpcodeClasses.SET_seq.indexOf(op)},${offset}"
|
||||
case OneRegister(register) => s" SETB ${ZOpcodeClasses.SET_seq.indexOf(op)},${asIntelAssemblyString(register)}"
|
||||
case _ => "???"
|
||||
}
|
||||
case op if ZOpcodeClasses.BIT(op) => registers match {
|
||||
case OneRegisterOffset(MEM_IX_D, offset) => s" BITX ${ZOpcodeClasses.BIT_seq.indexOf(op)},${offset}"
|
||||
case OneRegisterOffset(MEM_IY_D, offset) => s" BITY ${ZOpcodeClasses.BIT_seq.indexOf(op)},${offset}"
|
||||
case OneRegister(register) => s" BIT ${ZOpcodeClasses.BIT_seq.indexOf(op)},${asIntelAssemblyString(register)}"
|
||||
case _ => "???"
|
||||
}
|
||||
case PUSH => registers match {
|
||||
case OneRegister(IX) => s" PUSHIX"
|
||||
case OneRegister(IY) => s" PUSHIY"
|
||||
case OneRegister(register) => s" PUSH ${asIntelAssemblyString(register)}"
|
||||
case _ => "???"
|
||||
}
|
||||
case POP => registers match {
|
||||
case OneRegister(IX) => s" POPIX"
|
||||
case OneRegister(IY) => s" POPIY"
|
||||
case OneRegister(register) => s" POP ${asIntelAssemblyString(register)}"
|
||||
case _ => "???"
|
||||
}
|
||||
case IM => parameter match {
|
||||
case NumericConstant(0, _) => s" IM0"
|
||||
case NumericConstant(1, _) => s" IM1"
|
||||
case NumericConstant(2, _) => s" IM2"
|
||||
case _ => "???"
|
||||
}
|
||||
case RL => registers match {
|
||||
case OneRegister(register) => s" RALR ${asIntelAssemblyString(register)}"
|
||||
case OneRegisterOffset(MEM_IX_D, offset) => s" RALX $offset"
|
||||
case OneRegisterOffset(MEM_IY_D, offset) => s" RALY $offset"
|
||||
case _ => "???"
|
||||
}
|
||||
case RLC => registers match {
|
||||
case OneRegister(register) => s" RLCR ${asIntelAssemblyString(register)}"
|
||||
case OneRegisterOffset(MEM_IX_D, offset) => s" RLCX $offset"
|
||||
case OneRegisterOffset(MEM_IY_D, offset) => s" RLCY $offset"
|
||||
case _ => "???"
|
||||
}
|
||||
case RR => registers match {
|
||||
case OneRegister(register) => s" RARR ${asIntelAssemblyString(register)}"
|
||||
case OneRegisterOffset(MEM_IX_D, offset) => s" RARX $offset"
|
||||
case OneRegisterOffset(MEM_IY_D, offset) => s" RARY $offset"
|
||||
case _ => "???"
|
||||
}
|
||||
case RRC => registers match {
|
||||
case OneRegister(register) => s" RRCR ${asIntelAssemblyString(register)}"
|
||||
case OneRegisterOffset(MEM_IX_D, offset) => s" RRCX $offset"
|
||||
case OneRegisterOffset(MEM_IY_D, offset) => s" RRCY $offset"
|
||||
case _ => "???"
|
||||
}
|
||||
case SLA => registers match {
|
||||
case OneRegister(register) => s" SLAR ${asIntelAssemblyString(register)}"
|
||||
case OneRegisterOffset(MEM_IX_D, offset) => s" SLAX $offset"
|
||||
case OneRegisterOffset(MEM_IY_D, offset) => s" SLAY $offset"
|
||||
case _ => "???"
|
||||
}
|
||||
case SLL => registers match {
|
||||
case OneRegister(register) => s" SLLR ${asIntelAssemblyString(register)}"
|
||||
case OneRegisterOffset(MEM_IX_D, offset) => s" SLLX $offset"
|
||||
case OneRegisterOffset(MEM_IY_D, offset) => s" SLLY $offset"
|
||||
case _ => "???"
|
||||
}
|
||||
case SRA => registers match {
|
||||
case OneRegister(register) => s" SRAR ${asIntelAssemblyString(register)}"
|
||||
case OneRegisterOffset(MEM_IX_D, offset) => s" SRAX $offset"
|
||||
case OneRegisterOffset(MEM_IY_D, offset) => s" SRAY $offset"
|
||||
case _ => "???"
|
||||
}
|
||||
case SRL => registers match {
|
||||
case OneRegister(register) => s" SRLR ${asIntelAssemblyString(register)}"
|
||||
case OneRegisterOffset(MEM_IX_D, offset) => s" SRLX $offset"
|
||||
case OneRegisterOffset(MEM_IY_D, offset) => s" SRLY $offset"
|
||||
case _ => "???"
|
||||
}
|
||||
case DAA => " DAA"
|
||||
case RLA => " RAL"
|
||||
case RLCA => " RLC"
|
||||
case RRA => " RAR"
|
||||
case RRCA => " RRC"
|
||||
case HALT => " HLT"
|
||||
case LDI|LDIR|LDD|LDDR|INI|INIR|IND|INDR|OUTI|OUTD|EXX|NEG|RLD|RRD|RETN|RETI => " " + opcode
|
||||
case OUTIR => " OUTIR"
|
||||
case OUTDR => " OUTDR"
|
||||
case CPI => " CCI"
|
||||
case CPIR => " CCIR"
|
||||
case CPD => " CCD"
|
||||
case CPDR => " CCDR"
|
||||
case RET => registers match {
|
||||
case NoRegisters => " RET"
|
||||
case IfFlagClear(ZFlag.C) => " RNC"
|
||||
@ -532,6 +659,8 @@ case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Consta
|
||||
}
|
||||
case JP => registers match {
|
||||
case OneRegister(HL) => " PCHL"
|
||||
case OneRegister(IX) => " PCIX"
|
||||
case OneRegister(IY) => " PCIY"
|
||||
case NoRegisters => s" JMP ${parameter.toIntelString}"
|
||||
case IfFlagClear(ZFlag.C) => s" JNC ${parameter.toIntelString}"
|
||||
case IfFlagClear(ZFlag.Z) => s" JNZ ${parameter.toIntelString}"
|
||||
@ -545,6 +674,15 @@ case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Consta
|
||||
case IfFlagSet(ZFlag.K) => s" JK ${parameter.toIntelString}"
|
||||
case _ => "???"
|
||||
}
|
||||
case JR => registers match {
|
||||
case NoRegisters => s" JR ${parameter.toIntelString}"
|
||||
case IfFlagClear(ZFlag.C) => s" JRNC ${parameter.toIntelString}"
|
||||
case IfFlagClear(ZFlag.Z) => s" JRNZ ${parameter.toIntelString}"
|
||||
case IfFlagSet(ZFlag.C) => s" JRC ${parameter.toIntelString}"
|
||||
case IfFlagSet(ZFlag.Z) => s" JRZ ${parameter.toIntelString}"
|
||||
case _ => "???"
|
||||
}
|
||||
case DJNZ => s" DJNZ ${parameter.toIntelString}"
|
||||
case CALL => registers match {
|
||||
case NoRegisters => s" CALL ${parameter.toIntelString}"
|
||||
case IfFlagClear(ZFlag.C) => s" CNC ${parameter.toIntelString}"
|
||||
@ -559,52 +697,78 @@ case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Consta
|
||||
}
|
||||
case ADD => registers match {
|
||||
case OneRegister(IMM_8) => s" ADI ${parameter.toIntelString}"
|
||||
case OneRegisterOffset(MEM_IX_D, offset) => s" ADDX ${offset}"
|
||||
case OneRegisterOffset(MEM_IY_D, offset) => s" ADDY ${offset}"
|
||||
case OneRegister(register) => s" ADD ${asIntelAssemblyString(register)}"
|
||||
case _ => "???"
|
||||
}
|
||||
case ADC => registers match {
|
||||
case OneRegister(IMM_8) => s" ACI ${parameter.toIntelString}"
|
||||
case OneRegisterOffset(MEM_IX_D, offset) => s" ADCX ${offset}"
|
||||
case OneRegisterOffset(MEM_IY_D, offset) => s" ADCY ${offset}"
|
||||
case OneRegister(register) => s" ADC ${asIntelAssemblyString(register)}"
|
||||
case _ => "???"
|
||||
}
|
||||
case SUB => registers match {
|
||||
case OneRegister(IMM_8) => s" SUI ${parameter.toIntelString}"
|
||||
case OneRegisterOffset(MEM_IX_D, offset) => s" SUBX ${offset}"
|
||||
case OneRegisterOffset(MEM_IY_D, offset) => s" SUBY ${offset}"
|
||||
case OneRegister(register) => s" SUB ${asIntelAssemblyString(register)}"
|
||||
case _ => "???"
|
||||
}
|
||||
case SBC => registers match {
|
||||
case OneRegister(IMM_8) => s" SBI ${parameter.toIntelString}"
|
||||
case OneRegisterOffset(MEM_IX_D, offset) => s" SBCX ${offset}"
|
||||
case OneRegisterOffset(MEM_IY_D, offset) => s" SBCY ${offset}"
|
||||
case OneRegister(register) => s" SBB ${asIntelAssemblyString(register)}"
|
||||
case _ => "???"
|
||||
}
|
||||
case AND => registers match {
|
||||
case OneRegister(IMM_8) => s" ANI ${parameter.toIntelString}"
|
||||
case OneRegisterOffset(MEM_IX_D, offset) => s" ANDX ${offset}"
|
||||
case OneRegisterOffset(MEM_IY_D, offset) => s" ANDY ${offset}"
|
||||
case OneRegister(register) => s" ANA ${asIntelAssemblyString(register)}"
|
||||
case _ => "???"
|
||||
}
|
||||
case OR => registers match {
|
||||
case OneRegister(IMM_8) => s" ORI ${parameter.toIntelString}"
|
||||
case OneRegisterOffset(MEM_IX_D, offset) => s" ORX ${offset}"
|
||||
case OneRegisterOffset(MEM_IY_D, offset) => s" ORY ${offset}"
|
||||
case OneRegister(register) => s" ORA ${asIntelAssemblyString(register)}"
|
||||
case _ => "???"
|
||||
}
|
||||
case XOR => registers match {
|
||||
case OneRegister(IMM_8) => s" XRI ${parameter.toIntelString}"
|
||||
case OneRegisterOffset(MEM_IX_D, offset) => s" XORX ${offset}"
|
||||
case OneRegisterOffset(MEM_IY_D, offset) => s" XORY ${offset}"
|
||||
case OneRegister(register) => s" XRA ${asIntelAssemblyString(register)}"
|
||||
case _ => "???"
|
||||
}
|
||||
case CP => registers match {
|
||||
case OneRegister(IMM_8) => s" CPI ${parameter.toIntelString}"
|
||||
case OneRegisterOffset(MEM_IX_D, offset) => s" CMPX ${offset}"
|
||||
case OneRegisterOffset(MEM_IY_D, offset) => s" CMPY ${offset}"
|
||||
case OneRegister(register) => s" CMP ${asIntelAssemblyString(register)}"
|
||||
case _ => "???"
|
||||
}
|
||||
case EX_SP => registers match {
|
||||
case OneRegister(HL) => s" XTHL"
|
||||
case OneRegister(IX) => s" XTIX"
|
||||
case OneRegister(IY) => s" XTIY"
|
||||
case _ => "???"
|
||||
}
|
||||
case RST => parameter match {
|
||||
case NumericConstant(n, _) if n % 8 == 0 => s" RST ${n / 8}"
|
||||
case _ => "???"
|
||||
}
|
||||
case IN_C => registers match {
|
||||
case OneRegister(register) => s" INP ${asIntelAssemblyString(register)}"
|
||||
case _ => "???"
|
||||
}
|
||||
case OUT_C => registers match {
|
||||
case OneRegister(register) => s" OUTP ${asIntelAssemblyString(register)}"
|
||||
case _ => "???"
|
||||
}
|
||||
case IN_IMM => s" IN ${parameter.toIntelString}"
|
||||
case OUT_IMM => s" OUT ${parameter.toIntelString}"
|
||||
case EI => " EI"
|
||||
@ -616,6 +780,8 @@ case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Consta
|
||||
case CCF => " CMC"
|
||||
case EI => " EI"
|
||||
|
||||
case EX_AF_AF => " EXAF"
|
||||
|
||||
case DSUB => " DSUB"
|
||||
case RRHL => " ARHL"
|
||||
case RLDE => " RLDE"
|
||||
|
@ -32,6 +32,10 @@ class Z80Assembler(program: Program,
|
||||
case ZRegister.E => 3
|
||||
case ZRegister.H => 4
|
||||
case ZRegister.L => 5
|
||||
case ZRegister.IXH => 4
|
||||
case ZRegister.IXL => 5
|
||||
case ZRegister.IYH => 4
|
||||
case ZRegister.IYL => 5
|
||||
case ZRegister.MEM_HL => 6
|
||||
case ZRegister.MEM_IX_D => 6
|
||||
case ZRegister.MEM_IY_D => 6
|
||||
@ -46,6 +50,8 @@ class Z80Assembler(program: Program,
|
||||
private def prefixByte(reg: ZRegister.Value): Int = reg match {
|
||||
case ZRegister.IX | ZRegister.MEM_IX_D => 0xdd
|
||||
case ZRegister.IY | ZRegister.MEM_IY_D => 0xfd
|
||||
case ZRegister.IXH | ZRegister.IXL => 0xdd
|
||||
case ZRegister.IYH | ZRegister.IYL => 0xfd
|
||||
}
|
||||
|
||||
override def emitInstruction(bank: String, options: CompilationOptions, index: Int, instr: ZLine): Int = {
|
||||
@ -317,6 +323,12 @@ class Z80Assembler(program: Program,
|
||||
writeByte(bank, index + 1, o.opcode + internalRegisterIndex(ZRegister.HL) * o.multiplier)
|
||||
writeByte(bank, index + 2, instr.parameter)
|
||||
index + 3
|
||||
case ZLine0(op, OneRegister(ix@(IXH | IYH | IXL | IYL)), _) if oneRegister.contains(op) =>
|
||||
requireZ80Illegals()
|
||||
val o = oneRegister(op)
|
||||
writeByte(bank, index, prefixByte(ix))
|
||||
writeByte(bank, index + 1, o.opcode + internalRegisterIndex(ix) * o.multiplier)
|
||||
index + 2
|
||||
case ZLine0(op, OneRegister(reg), _) if reg != ZRegister.IMM_8 && oneRegister.contains(op) =>
|
||||
val o = oneRegister(op)
|
||||
writeByte(bank, index, o.opcode + internalRegisterIndex(reg) * o.multiplier)
|
||||
@ -428,6 +440,33 @@ class Z80Assembler(program: Program,
|
||||
writeByte(bank, index + 1, 0x40 + internalRegisterIndex(ZRegister.MEM_HL) + internalRegisterIndex(target) * 8)
|
||||
writeByte(bank, index + 2, offset)
|
||||
index + 3
|
||||
case TwoRegisters(target@(IXH | IYH | IXL | IYL), source@(A | B | C | D | E)) =>
|
||||
requireZ80Illegals()
|
||||
writeByte(bank, index, prefixByte(target))
|
||||
writeByte(bank, index, 0x40 + internalRegisterIndex(source) + internalRegisterIndex(target) * 8)
|
||||
index + 2
|
||||
case TwoRegisters(target@(A | B | C | D | E), source@(IXH | IYH | IXL | IYL)) =>
|
||||
requireZ80Illegals()
|
||||
writeByte(bank, index, prefixByte(source))
|
||||
writeByte(bank, index, 0x40 + internalRegisterIndex(source) + internalRegisterIndex(target) * 8)
|
||||
index + 2
|
||||
case TwoRegisters(target@(IXH | IXL), source@(IXH | IXL)) =>
|
||||
requireZ80Illegals()
|
||||
writeByte(bank, index, prefixByte(source))
|
||||
writeByte(bank, index, 0x40 + internalRegisterIndex(source) + internalRegisterIndex(target) * 8)
|
||||
index + 2
|
||||
case TwoRegisters(target@(IYH | IYL), source@(IYH | IYL)) =>
|
||||
requireZ80Illegals()
|
||||
writeByte(bank, index, prefixByte(source))
|
||||
writeByte(bank, index, 0x40 + internalRegisterIndex(source) + internalRegisterIndex(target) * 8)
|
||||
index + 2
|
||||
case TwoRegisters(target@(H | L), source@(H | L)) =>
|
||||
writeByte(bank, index, 0x40 + internalRegisterIndex(source) + internalRegisterIndex(target) * 8)
|
||||
index + 1
|
||||
case TwoRegisters(target@(IXH | IYH | IXL | IYL | H | L), source@(IXH | IYH | IXL | IYL | H | L)) =>
|
||||
log.error("Cannot assemble " + instr)
|
||||
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
|
||||
|
@ -9,7 +9,7 @@ import millfork.{CompilationFlag, CompilationOptions, node}
|
||||
import millfork.assembly.z80.{ZOpcode, _}
|
||||
import millfork.env.{ByZRegister, Constant, ParamPassingConvention}
|
||||
import millfork.error.ConsoleLogger
|
||||
import millfork.node._
|
||||
import millfork.node.{ZRegister, _}
|
||||
import millfork.output.{MemoryAlignment, NoAlignment, WithinPageAlignment}
|
||||
|
||||
/**
|
||||
@ -73,6 +73,13 @@ case class Z80Parser(filename: String,
|
||||
"SP" -> ZRegister.SP, "sp" -> ZRegister.SP,
|
||||
)
|
||||
|
||||
private val toIndexHalf: Map[String, ZRegister.Value] = Map(
|
||||
"IXH" -> ZRegister.IXH, "ixh" -> ZRegister.IXH,
|
||||
"IXL" -> ZRegister.IXL, "ixl" -> ZRegister.IXL,
|
||||
"IYH" -> ZRegister.IYH, "iyh" -> ZRegister.IYH,
|
||||
"IYL" -> ZRegister.IYL, "iyl" -> ZRegister.IYL,
|
||||
)
|
||||
|
||||
private val toIntelRegister8: Map[String, ZRegister.Value] = Map(
|
||||
"A" -> ZRegister.A, "a" -> ZRegister.A,
|
||||
"B" -> ZRegister.B, "b" -> ZRegister.B,
|
||||
@ -86,16 +93,25 @@ case class Z80Parser(filename: String,
|
||||
|
||||
private val toIntelRegister16: Map[String, ZRegister.Value] = Map(
|
||||
"H" -> ZRegister.HL, "h" -> ZRegister.HL,
|
||||
"HL" -> ZRegister.HL, "hl" -> ZRegister.HL,
|
||||
"PSW" -> ZRegister.AF, "psw" -> ZRegister.AF,
|
||||
"B" -> ZRegister.BC, "b" -> ZRegister.BC,
|
||||
"BC" -> ZRegister.BC, "bc" -> ZRegister.BC,
|
||||
"D" -> ZRegister.DE, "d" -> ZRegister.DE,
|
||||
"DE" -> ZRegister.DE, "de" -> ZRegister.DE,
|
||||
"SP" -> ZRegister.SP, "sp" -> ZRegister.SP,
|
||||
"IX" -> ZRegister.IX, "ix" -> ZRegister.IX,
|
||||
"IY" -> ZRegister.IY, "iy" -> ZRegister.IY,
|
||||
)
|
||||
|
||||
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 (VariableExpression(r), false)
|
||||
if options.flag(CompilationFlag.EmitZ80Opcodes) &&
|
||||
options.flag(CompilationFlag.EmitIllegals) &&
|
||||
toIndexHalf.contains(r)=> (toIndexHalf(r), None)
|
||||
case (SumExpression(List(
|
||||
(false, LiteralExpression(0xff00, _)),
|
||||
(false, VariableExpression("C" | "c"))
|
||||
@ -138,6 +154,8 @@ case class Z80Parser(filename: String,
|
||||
case (reg, addr) => (op, OneRegister(reg), None, addr.getOrElse(zero))
|
||||
}
|
||||
|
||||
def one8RegisterIntel(op: ZOpcode.Value): P[(ZOpcode.Value, OneRegister, Option[Expression], Expression)] = intel8.map(reg => (op, OneRegister(reg), None, zero))
|
||||
|
||||
def one8RegisterOr8085Illegal(op: ZOpcode.Value, illegalTarget: ZRegister.Value, illegalOp: ZOpcode.Value): P[(ZOpcode.Value, ZRegisters, Option[Expression], Expression)] = param(allowAbsolute = false).map{
|
||||
case (reg@(ZRegister.MEM_IX_D | ZRegister.MEM_IY_D), Some(e)) => (op, OneRegister(reg), Some(e), zero)
|
||||
case (reg, _) if reg == illegalTarget && options.flag(CompilationFlag.EmitIntel8085Opcodes) && options.flag(CompilationFlag.EmitIllegals) =>
|
||||
@ -237,6 +255,27 @@ case class Z80Parser(filename: String,
|
||||
private val jumpConditionWithComma: P[ZRegisters] = (jumpCondition ~ "," ~/ HWS).?.map (_.getOrElse(NoRegisters))
|
||||
private val jumpConditionWithoutComma: P[ZRegisters] = (jumpCondition ~/ HWS).?.map (_.getOrElse(NoRegisters))
|
||||
|
||||
private val indexHalves: Set[ZRegister.Value] = {
|
||||
import ZRegister._
|
||||
Set(IXH, IXL, IYH, IYL)
|
||||
}
|
||||
private val MEM_R: Set[ZRegister.Value] = {
|
||||
import ZRegister._
|
||||
Set(MEM_HL,MEM_IX_D,MEM_IY_D)
|
||||
}
|
||||
|
||||
def invalidIllegalRegisters(r1: ZRegister.Value, r2: ZRegister.Value): Boolean = {
|
||||
import ZRegister._
|
||||
if (MEM_R(r1) && MEM_R(r2)) return true
|
||||
if (!indexHalves(r1) && !indexHalves(r2)) return false
|
||||
if (!options.flag(CompilationFlag.EmitIllegals) && !options.flag(CompilationFlag.EmitZ80Opcodes) && (indexHalves(r1) || indexHalves(r2))) return true
|
||||
if ((r1 == H || r1 == L || r1 == MEM_IX_D || r1 == MEM_IY_D) && indexHalves(r2)) return true
|
||||
if ((r2 == H || r2 == L || r2 == MEM_IX_D || r2 == MEM_IY_D) && indexHalves(r1)) return true
|
||||
if ((r1 == IYH || r1 == IYL) && (r2 == IXH || r2 == IXL)) return true
|
||||
if ((r1 == IXH || r1 == IXL) && (r2 == IYH || r2 == IYL)) return true
|
||||
false // TODO
|
||||
}
|
||||
|
||||
val zilogAsmInstruction: P[ExecutableStatement] = {
|
||||
import ZOpcode._
|
||||
for {
|
||||
@ -449,7 +488,11 @@ case class Z80Parser(filename: String,
|
||||
if options.flags(CompilationFlag.EmitSharpOpcodes) =>
|
||||
(LD_HLDA, NoRegisters, None, zero)
|
||||
|
||||
case (r1, e1, (r2, e2)) => merge(LD, LD_16, skipTargetA = false)((r1, e1, r2, e2))
|
||||
case (r1, e1, (r2, e2)) =>
|
||||
if (invalidIllegalRegisters(r1,r2)) {
|
||||
log.error("Invalid parameters for LD", Some(pos))
|
||||
}
|
||||
merge(LD, LD_16, skipTargetA = false)((r1, e1, r2, e2))
|
||||
}
|
||||
case "ADD" => (param(allowAbsolute = false) ~ HWS ~ position("comma").map(_ => ()) ~ "," ~/ HWS ~ param(allowAbsolute = false)).map {
|
||||
|
||||
@ -534,13 +577,73 @@ case class Z80Parser(filename: String,
|
||||
case "RIM" => imm(RIM)
|
||||
case "SIM" => imm(SIM)
|
||||
|
||||
case "EXAF" => imm(EX_AF_AF)
|
||||
case "EXX" => imm(EXX)
|
||||
case "NEG" => imm(NEG)
|
||||
case "IM0" => P("").map(_ => (IM, NoRegisters, None, LiteralExpression(0, 1)))
|
||||
case "IM1" => P("").map(_ => (IM, NoRegisters, None, LiteralExpression(1, 1)))
|
||||
case "IM2" => P("").map(_ => (IM, NoRegisters, None, LiteralExpression(2, 1)))
|
||||
case "RETI" => imm(RETI)
|
||||
case "RETN" => imm(RETN)
|
||||
case "RLD" => imm(RLD)
|
||||
case "RRD" => imm(RRD)
|
||||
case "INI" => imm(INI)
|
||||
case "INIR" => imm(INIR)
|
||||
case "IND" => imm(IND)
|
||||
case "INDR" => imm(INDR)
|
||||
case "OUTI" => imm(OUTI)
|
||||
case "OUTIR" => imm(OUTIR)
|
||||
case "OUTD" => imm(OUTD)
|
||||
case "OUTDR" => imm(OUTDR)
|
||||
case "LDI" => imm(LDI)
|
||||
case "LDIR" => imm(LDIR)
|
||||
case "LDD" => imm(LDD)
|
||||
case "LDDR" => imm(LDDR)
|
||||
case "CCI" => imm(CPI)
|
||||
case "CCIR" => imm(CPIR)
|
||||
case "CCD" => imm(CPD)
|
||||
case "CCDR" => imm(CPDR)
|
||||
|
||||
case "RALR" => one8RegisterIntel(RL)
|
||||
case "RARR" => one8RegisterIntel(RR)
|
||||
case "RLCR" => one8RegisterIntel(RLC)
|
||||
case "RRCR" => one8RegisterIntel(RRC)
|
||||
case "SLAR" => one8RegisterIntel(SLA)
|
||||
case "SLLR" => one8RegisterIntel(SLL)
|
||||
case "SRAR" => one8RegisterIntel(SRA)
|
||||
case "SRLR" => one8RegisterIntel(SRL)
|
||||
|
||||
case "RALX" => asmExpression.map(d => (RL, OneRegister(MEM_IX_D), Some(d), zero))
|
||||
case "RARX" => asmExpression.map(d => (RR, OneRegister(MEM_IX_D), Some(d), zero))
|
||||
case "RLCX" => asmExpression.map(d => (RLC, OneRegister(MEM_IX_D), Some(d), zero))
|
||||
case "RRCX" => asmExpression.map(d => (RRC, OneRegister(MEM_IX_D), Some(d), zero))
|
||||
case "SLAX" => asmExpression.map(d => (SLA, OneRegister(MEM_IX_D), Some(d), zero))
|
||||
case "SLLX" => asmExpression.map(d => (SLL, OneRegister(MEM_IX_D), Some(d), zero))
|
||||
case "SRAX" => asmExpression.map(d => (SRA, OneRegister(MEM_IX_D), Some(d), zero))
|
||||
case "SRLX" => asmExpression.map(d => (SRL, OneRegister(MEM_IX_D), Some(d), zero))
|
||||
|
||||
case "RALY" => asmExpression.map(d => (RL, OneRegister(MEM_IY_D), Some(d), zero))
|
||||
case "RARY" => asmExpression.map(d => (RR, OneRegister(MEM_IY_D), Some(d), zero))
|
||||
case "RLCY" => asmExpression.map(d => (RLC, OneRegister(MEM_IY_D), Some(d), zero))
|
||||
case "RRCY" => asmExpression.map(d => (RRC, OneRegister(MEM_IY_D), Some(d), zero))
|
||||
case "SLAY" => asmExpression.map(d => (SLA, OneRegister(MEM_IY_D), Some(d), zero))
|
||||
case "SLLY" => asmExpression.map(d => (SLL, OneRegister(MEM_IY_D), Some(d), zero))
|
||||
case "SRAY" => asmExpression.map(d => (SRA, OneRegister(MEM_IY_D), Some(d), zero))
|
||||
case "SRLY" => asmExpression.map(d => (SRL, OneRegister(MEM_IY_D), Some(d), zero))
|
||||
|
||||
case "HLT" => imm(HALT)
|
||||
case "EI" => imm(EI)
|
||||
case "DI" => imm(DI)
|
||||
case "XCHG" => imm(EX_DE_HL)
|
||||
case "XTHL" => P("").map(_ => (EX_SP, OneRegister(HL), None, zero))
|
||||
case "XTIX" => P("").map(_ => (EX_SP, OneRegister(IX), None, zero))
|
||||
case "XTIY" => P("").map(_ => (EX_SP, OneRegister(IY), None, zero))
|
||||
case "SPHL" => P("").map(_ => (LD_16, TwoRegisters(SP, HL), None, zero))
|
||||
case "SPIX" => P("").map(_ => (LD_16, TwoRegisters(SP, IX), None, zero))
|
||||
case "SPIY" => P("").map(_ => (LD_16, TwoRegisters(SP, IY), None, zero))
|
||||
case "PCHL" => P("").map(_ => (JP, z80.OneRegister(HL), None, zero))
|
||||
case "PCIX" => P("").map(_ => (JP, z80.OneRegister(IX), None, zero))
|
||||
case "PCIY" => P("").map(_ => (JP, z80.OneRegister(IY), None, zero))
|
||||
|
||||
case "MOV" => (intel8 ~ HWS ~ position("comma").map(_ => ()) ~ "," ~/ HWS ~ intel8).map {
|
||||
case (r1, r2) => (LD, TwoRegisters(r1, r2), None, zero)
|
||||
@ -548,10 +651,38 @@ case class Z80Parser(filename: String,
|
||||
case "LXI" => (intel16(false) ~ HWS ~ position("comma").map(_ => ()) ~ "," ~/ HWS ~ asmExpression).map {
|
||||
case (r, e) => (LD_16, TwoRegisters(r, IMM_16), None, e)
|
||||
}
|
||||
case "LXIX" => asmExpression.map {
|
||||
case (e) => (LD_16, TwoRegisters(IX, IMM_16), None, e)
|
||||
}
|
||||
case "LXIY" => asmExpression.map {
|
||||
case (e) => (LD_16, TwoRegisters(IY, IMM_16), None, e)
|
||||
}
|
||||
case "MVI" => (intel8 ~ HWS ~ position("comma").map(_ => ()) ~ "," ~/ HWS ~ asmExpression).map {
|
||||
case (r, e) => (LD, TwoRegisters(r, IMM_8), None, e)
|
||||
}
|
||||
case "MVIX" => (asmExpression ~ HWS ~ position("comma").map(_ => ()) ~ "," ~/ HWS ~ asmExpression).map {
|
||||
case (e, d) => (LD, TwoRegisters(MEM_IX_D, IMM_8), Some(d), e)
|
||||
}
|
||||
case "MVIY" => (asmExpression ~ HWS ~ position("comma").map(_ => ()) ~ "," ~/ HWS ~ asmExpression).map {
|
||||
case (e, d) => (LD, TwoRegisters(MEM_IY_D, IMM_8), Some(d), e)
|
||||
}
|
||||
case "LDX" => (intel8 ~ HWS ~ position("comma").map(_ => ()) ~ "," ~/ HWS ~ asmExpression).map {
|
||||
case (r, d) => (LD, TwoRegisters(r, MEM_IX_D), Some(d), zero)
|
||||
}
|
||||
case "LDY" => (intel8 ~ HWS ~ position("comma").map(_ => ()) ~ "," ~/ HWS ~ asmExpression).map {
|
||||
case (r, d) => (LD, TwoRegisters(r, MEM_IY_D), Some(d), zero)
|
||||
}
|
||||
case "STX" => (intel8 ~ HWS ~ position("comma").map(_ => ()) ~ "," ~/ HWS ~ asmExpression).map {
|
||||
case (r, d) => (LD, TwoRegisters(MEM_IX_D, r), Some(d), zero)
|
||||
}
|
||||
case "STY" => (intel8 ~ HWS ~ position("comma").map(_ => ()) ~ "," ~/ HWS ~ asmExpression).map {
|
||||
case (r, d) => (LD, TwoRegisters(MEM_IY_D, r), Some(d), zero)
|
||||
}
|
||||
case "DAD" => intel16(false).map { r => (ADD_16, TwoRegisters(HL, r), None, zero)}
|
||||
case "DADC" => intel16(false).map { r => (ADC_16, TwoRegisters(HL, r), None, zero)}
|
||||
case "DSBC" => intel16(false).map { r => (SBC_16, TwoRegisters(HL, r), None, zero)}
|
||||
case "DADX" => intel16(false).map { r => (ADD_16, TwoRegisters(IX, r), None, zero)}
|
||||
case "DADY" => intel16(false).map { r => (ADD_16, TwoRegisters(IY, r), None, zero)}
|
||||
case "STAX" => intel16(false).map {
|
||||
case r@(ZRegister.BC | ZRegister.DE) => (LD, TwoRegisters(r, A), None, zero)
|
||||
case _ =>
|
||||
@ -565,19 +696,47 @@ case class Z80Parser(filename: String,
|
||||
(NOP, NoRegisters, None, zero)
|
||||
}
|
||||
case "INX" => intel16(false).map { r => (INC_16, OneRegister(r), None, zero)}
|
||||
case "INXIX" => P("").map(_ => (INC_16, OneRegister(IX), None, zero))
|
||||
case "INXIY" => P("").map(_ => (INC_16, OneRegister(IY), None, zero))
|
||||
case "DCX" => intel16(false).map { r => (DEC_16, OneRegister(r), None, zero)}
|
||||
case "DCXIX" => P("").map(_ => (DEC_16, OneRegister(IX), None, zero))
|
||||
case "DCXIY" => P("").map(_ => (DEC_16, OneRegister(IY), None, zero))
|
||||
case "POP" => intel16(true).map { r => (POP, OneRegister(r), None, zero)}
|
||||
case "POPIX" => P("").map(_ => (POP, OneRegister(IX), None, zero))
|
||||
case "POPIY" => P("").map(_ => (POP, OneRegister(IY), None, zero))
|
||||
case "PUSH" => intel16(true).map { r => (PUSH, OneRegister(r), None, zero)}
|
||||
case "PUSHIX" => P("").map(_ => (PUSH, OneRegister(IX), None, zero))
|
||||
case "PUSHIY" => P("").map(_ => (PUSH, OneRegister(IY), None, zero))
|
||||
case "INR" => intel8.map { r => (INC, OneRegister(r), None, zero)}
|
||||
case "INRX" => asmExpression.map { d => (INC, OneRegister(MEM_IX_D), Some(d), zero)}
|
||||
case "INRY" => asmExpression.map { d => (INC, OneRegister(MEM_IY_D), Some(d), zero)}
|
||||
case "DCR" => intel8.map { r => (DEC, OneRegister(r), None, zero)}
|
||||
case "DCRX" => asmExpression.map { d => (DEC, OneRegister(MEM_IX_D), Some(d), zero)}
|
||||
case "DCRY" => asmExpression.map { d => (DEC, OneRegister(MEM_IY_D), Some(d), zero)}
|
||||
case "ADD" => intel8.map { r => (ADD, OneRegister(r), None, zero)}
|
||||
case "ADDX" => asmExpression.map { d => (ADD, OneRegister(MEM_IX_D), Some(d), zero)}
|
||||
case "ADDY" => asmExpression.map { d => (ADD, OneRegister(MEM_IY_D), Some(d), zero)}
|
||||
case "SUB" => intel8.map { r => (SUB, OneRegister(r), None, zero)}
|
||||
case "SUBX" => asmExpression.map { d => (SUB, OneRegister(MEM_IX_D), Some(d), zero)}
|
||||
case "SUBY" => asmExpression.map { d => (SUB, OneRegister(MEM_IY_D), Some(d), zero)}
|
||||
case "ADC" => intel8.map { r => (ADC, OneRegister(r), None, zero)}
|
||||
case "ADCX" => asmExpression.map { d => (ADC, OneRegister(MEM_IX_D), Some(d), zero)}
|
||||
case "ADCY" => asmExpression.map { d => (ADC, OneRegister(MEM_IY_D), Some(d), zero)}
|
||||
case "SBB" => intel8.map { r => (SBC, OneRegister(r), None, zero)}
|
||||
case "SBCX" => asmExpression.map { d => (SBC, OneRegister(MEM_IX_D), Some(d), zero)}
|
||||
case "SBCY" => asmExpression.map { d => (SBC, OneRegister(MEM_IY_D), Some(d), zero)}
|
||||
case "ORA" => intel8.map { r => (OR, OneRegister(r), None, zero)}
|
||||
case "ORX" => asmExpression.map { d => (OR, OneRegister(MEM_IX_D), Some(d), zero)}
|
||||
case "ORY" => asmExpression.map { d => (OR, OneRegister(MEM_IY_D), Some(d), zero)}
|
||||
case "ANA" => intel8.map { r => (AND, OneRegister(r), None, zero)}
|
||||
case "ANDX" => asmExpression.map { d => (AND, OneRegister(MEM_IX_D), Some(d), zero)}
|
||||
case "ANDY" => asmExpression.map { d => (AND, OneRegister(MEM_IY_D), Some(d), zero)}
|
||||
case "XRA" => intel8.map { r => (XOR, OneRegister(r), None, zero)}
|
||||
case "XORX" => asmExpression.map { d => (XOR, OneRegister(MEM_IX_D), Some(d), zero)}
|
||||
case "XORY" => asmExpression.map { d => (XOR, OneRegister(MEM_IY_D), Some(d), zero)}
|
||||
case "CMP" => intel8.map { r => (CP, OneRegister(r), None, zero)}
|
||||
case "CMPX" => asmExpression.map { d => (CP, OneRegister(MEM_IX_D), Some(d), zero)}
|
||||
case "CMPY" => asmExpression.map { d => (CP, OneRegister(MEM_IY_D), Some(d), zero)}
|
||||
case "ADI" => asmExpression.map { e => (ADD, OneRegister(IMM_8), None, e)}
|
||||
case "ACI" => asmExpression.map { e => (ADC, OneRegister(IMM_8), None, e)}
|
||||
case "SUI" => asmExpression.map { e => (SUB, OneRegister(IMM_8), None, e)}
|
||||
@ -589,8 +748,22 @@ case class Z80Parser(filename: String,
|
||||
|
||||
case "SHLD" => asmExpression.map { e => (LD_16, TwoRegisters(MEM_ABS_16, HL), None, e)}
|
||||
case "LHLD" => asmExpression.map { e => (LD_16, TwoRegisters(HL, MEM_ABS_16), None, e)}
|
||||
case "LBCD" => asmExpression.map { e => (LD_16, TwoRegisters(BC, MEM_ABS_16), None, e)}
|
||||
case "SBCD" => asmExpression.map { e => (LD_16, TwoRegisters(MEM_ABS_16, BC), None, e)}
|
||||
case "LDED" => asmExpression.map { e => (LD_16, TwoRegisters(DE, MEM_ABS_16), None, e)}
|
||||
case "SDED" => asmExpression.map { e => (LD_16, TwoRegisters(MEM_ABS_16, DE), None, e)}
|
||||
case "LSPD" => asmExpression.map { e => (LD_16, TwoRegisters(SP, MEM_ABS_16), None, e)}
|
||||
case "SSPD" => asmExpression.map { e => (LD_16, TwoRegisters(MEM_ABS_16, SP), None, e)}
|
||||
case "LIXD" => asmExpression.map { e => (LD_16, TwoRegisters(IX, MEM_ABS_16), None, e)}
|
||||
case "SIXD" => asmExpression.map { e => (LD_16, TwoRegisters(MEM_ABS_16, IX), None, e)}
|
||||
case "LIYD" => asmExpression.map { e => (LD_16, TwoRegisters(IY, MEM_ABS_16), None, e)}
|
||||
case "SIYD" => asmExpression.map { e => (LD_16, TwoRegisters(MEM_ABS_16, IY), None, e)}
|
||||
case "STA" => asmExpression.map { e => (LD, TwoRegisters(MEM_ABS_8, A), None, e)}
|
||||
case "LDA" => asmExpression.map { e => (LD, TwoRegisters(A, MEM_ABS_8), None, e)}
|
||||
case "LDAI" => P("").map(_ => (LD, TwoRegisters(A, I), None, zero))
|
||||
case "LDAR" => P("").map(_ => (LD, TwoRegisters(A, R), None, zero))
|
||||
case "STAI" => P("").map(_ => (LD, TwoRegisters(I, A), None, zero))
|
||||
case "STAR" => P("").map(_ => (LD, TwoRegisters(R, A), None, zero))
|
||||
case "RST" => asmExpression.map {
|
||||
case LiteralExpression(value, _) if value >=0 && value <= 7=> (RST, NoRegisters, None, LiteralExpression(value * 8, 1))
|
||||
case _ =>
|
||||
@ -598,10 +771,14 @@ case class Z80Parser(filename: String,
|
||||
(NOP, NoRegisters, None, zero)
|
||||
}
|
||||
|
||||
case "INP" => intel8.map { r => (IN_C, OneRegister(r), None, zero) }
|
||||
case "OUTP" => intel8.map { r => (OUT_C, OneRegister(r), None, zero) }
|
||||
case "IN" => asmExpression.map { e => (IN_IMM, OneRegister(A), None, e) }
|
||||
case "OUT" => asmExpression.map { e => (OUT_IMM, OneRegister(A), None, e) }
|
||||
|
||||
case "DJNZ" => asmExpression.map { e => (DJNZ, NoRegisters, None, e)}
|
||||
case "JMP" => asmExpression.map { e => (JP, NoRegisters, None, e)}
|
||||
case "JMPR" | "JR" => asmExpression.map { e => (JR, NoRegisters, None, e)}
|
||||
case "JC" => asmExpression.map { e => (JP, IfFlagSet(ZFlag.C), None, e)}
|
||||
case "JZ" => asmExpression.map { e => (JP, IfFlagSet(ZFlag.Z), None, e)}
|
||||
case "JM" => asmExpression.map { e => (JP, IfFlagSet(ZFlag.S), None, e)}
|
||||
@ -610,6 +787,14 @@ case class Z80Parser(filename: String,
|
||||
case "JNZ" => asmExpression.map { e => (JP, IfFlagClear(ZFlag.Z), None, e)}
|
||||
case "JP" => asmExpression.map { e => (JP, IfFlagClear(ZFlag.S), None, e)}
|
||||
case "JPO" => asmExpression.map { e => (JP, IfFlagClear(ZFlag.P), None, e)}
|
||||
case "JRC" => asmExpression.map { e => (JR, IfFlagSet(ZFlag.C), None, e)}
|
||||
case "JRZ" => asmExpression.map { e => (JR, IfFlagSet(ZFlag.Z), None, e)}
|
||||
case "JRM" => asmExpression.map { e => (JR, IfFlagSet(ZFlag.S), None, e)}
|
||||
case "JRPE" => asmExpression.map { e => (JR, IfFlagSet(ZFlag.P), None, e)}
|
||||
case "JRNC" => asmExpression.map { e => (JR, IfFlagClear(ZFlag.C), None, e)}
|
||||
case "JRNZ" => asmExpression.map { e => (JR, IfFlagClear(ZFlag.Z), None, e)}
|
||||
case "JRP" => asmExpression.map { e => (JR, IfFlagClear(ZFlag.S), None, e)}
|
||||
case "JRPO" => asmExpression.map { e => (JR, IfFlagClear(ZFlag.P), None, e)}
|
||||
|
||||
case "RET" => imm(RET)
|
||||
case "RC" => P("").map { _ => (RET, IfFlagSet(ZFlag.C), None, zero)}
|
||||
@ -642,6 +827,18 @@ case class Z80Parser(filename: String,
|
||||
case "SHLDE" | "SHLX" => imm(SHLX)
|
||||
case "LHLDE" | "LHLX" =>imm(LHLX)
|
||||
|
||||
|
||||
case "RES" => parseSingleBitOpWithIntelSyntax(ZOpcodeClasses.RES_seq, "RES", pos)
|
||||
case "SETB" => parseSingleBitOpWithIntelSyntax(ZOpcodeClasses.SET_seq, "SETB", pos)
|
||||
case "SET" => parseSingleBitOpWithIntelSyntax(ZOpcodeClasses.SET_seq, "SET", pos)
|
||||
case "BIT" => parseSingleBitOpWithIntelSyntax(ZOpcodeClasses.BIT_seq, "BIT", pos)
|
||||
case "RESX" => parseSingleBitIndexedOpWithIntelSyntax(ZOpcodeClasses.RES_seq, MEM_IX_D, "RESX", pos)
|
||||
case "SETX" => parseSingleBitIndexedOpWithIntelSyntax(ZOpcodeClasses.SET_seq, MEM_IX_D, "SETX", pos)
|
||||
case "BITX" => parseSingleBitIndexedOpWithIntelSyntax(ZOpcodeClasses.BIT_seq, MEM_IX_D, "BITX", pos)
|
||||
case "RESY" => parseSingleBitIndexedOpWithIntelSyntax(ZOpcodeClasses.RES_seq, MEM_IY_D, "RESY", pos)
|
||||
case "SETY" => parseSingleBitIndexedOpWithIntelSyntax(ZOpcodeClasses.SET_seq, MEM_IY_D, "SETY", pos)
|
||||
case "BITY" => parseSingleBitIndexedOpWithIntelSyntax(ZOpcodeClasses.BIT_seq, MEM_IY_D, "BITY", pos)
|
||||
|
||||
case _ =>
|
||||
log.error("Unsupported opcode " + opcode, Some(pos))
|
||||
imm(NOP)
|
||||
@ -652,6 +849,30 @@ case class Z80Parser(filename: String,
|
||||
}
|
||||
}
|
||||
|
||||
private def parseSingleBitOpWithIntelSyntax(OP_seq: IndexedSeq[ZOpcode.Value], opcodeString: String, pos: Position): P[(ZOpcode.Value, ZRegisters, Option[Expression], Expression)] = {
|
||||
import ZOpcode.NOP
|
||||
(param(allowAbsolute = false) ~ HWS ~ position("comma").map(_ => ()) ~ "," ~/ HWS ~ intel8).map {
|
||||
case (ZRegister.IMM_8, Some(LiteralExpression(n, _)), r2)
|
||||
if n >= 0 && n <= 7 && r2 != ZRegister.MEM_BC && r2 != ZRegister.MEM_DE =>
|
||||
(OP_seq(n.toInt), OneRegister(r2), None, zero)
|
||||
case _ =>
|
||||
log.error("Invalid parameters for " + opcodeString, Some(pos))
|
||||
(NOP, NoRegisters, None, zero)
|
||||
}
|
||||
}
|
||||
|
||||
private def parseSingleBitIndexedOpWithIntelSyntax(OP_seq: IndexedSeq[ZOpcode.Value], memIndex: ZRegister.Value, opcodeString: String, pos: Position): P[(ZOpcode.Value, ZRegisters, Option[Expression], Expression)] = {
|
||||
import ZOpcode.NOP
|
||||
(param(allowAbsolute = false) ~ HWS ~ position("comma").map(_ => ()) ~ "," ~/ HWS ~ asmExpression).map {
|
||||
case (ZRegister.IMM_8, Some(LiteralExpression(n, _)), e2)
|
||||
if n >= 0 && n <= 7 =>
|
||||
(OP_seq(n.toInt), OneRegister(memIndex), Some(e2), zero)
|
||||
case _ =>
|
||||
log.error("Invalid parameters for " + opcodeString, Some(pos))
|
||||
(NOP, NoRegisters, None, zero)
|
||||
}
|
||||
}
|
||||
|
||||
val asmInstruction: P[ExecutableStatement] = if (useIntelSyntax) intelAsmInstruction else zilogAsmInstruction
|
||||
|
||||
private def imm(opcode: ZOpcode.Value): P[(ZOpcode.Value, ZRegisters, Option[Expression], Expression)] =
|
||||
|
@ -873,6 +873,281 @@ class Z80AssemblySuite extends FunSuite with Matchers {
|
||||
""".stripMargin)
|
||||
}
|
||||
|
||||
test("Extended I80 instructions (Intel syntax)") {
|
||||
EmuUnoptimizedZ80Run(
|
||||
"""
|
||||
| #pragma intel_syntax
|
||||
| asm void main () {
|
||||
| ret
|
||||
|
|
||||
| reti
|
||||
|
|
||||
| jmpr main
|
||||
| jrnz main
|
||||
| jrz main
|
||||
| jrnc main
|
||||
| jrc main
|
||||
| lspd 34
|
||||
|
|
||||
| rlcr b
|
||||
| rlcr c
|
||||
| rlcr d
|
||||
| rlcr e
|
||||
| rlcr h
|
||||
| rlcr l
|
||||
| rlcr m
|
||||
| rlcr a
|
||||
|
|
||||
| rrcr b
|
||||
| rrcr c
|
||||
| rrcr d
|
||||
| rrcr e
|
||||
| rrcr h
|
||||
| rrcr l
|
||||
| rrcr m
|
||||
| rrcr a
|
||||
|
|
||||
| ralr b
|
||||
| ralr c
|
||||
| ralr d
|
||||
| ralr e
|
||||
| ralr h
|
||||
| ralr l
|
||||
| ralr m
|
||||
| ralr a
|
||||
|
|
||||
| rarr b
|
||||
| rarr c
|
||||
| rarr d
|
||||
| rarr e
|
||||
| rarr h
|
||||
| rarr l
|
||||
| rarr m
|
||||
| rarr a
|
||||
|
|
||||
| slar b
|
||||
| slar c
|
||||
| slar d
|
||||
| slar e
|
||||
| slar h
|
||||
| slar l
|
||||
| slar m
|
||||
| slar a
|
||||
|
|
||||
| srar b
|
||||
| srar c
|
||||
| srar d
|
||||
| srar e
|
||||
| srar h
|
||||
| srar l
|
||||
| srar m
|
||||
| srar a
|
||||
|
|
||||
| srlr b
|
||||
| srlr c
|
||||
| srlr d
|
||||
| srlr e
|
||||
| srlr h
|
||||
| srlr l
|
||||
| srlr m
|
||||
| srlr a
|
||||
|
|
||||
| bit 1,a
|
||||
| res 1,a
|
||||
| setb 1,a
|
||||
| set 1,a
|
||||
| bit 1,m
|
||||
| res 1,m
|
||||
| setb 1,m
|
||||
| set 1,m
|
||||
|
|
||||
| ret
|
||||
| }
|
||||
""".stripMargin)
|
||||
}
|
||||
|
||||
test("Z80 instructions with IX (Intel syntax)") {
|
||||
EmuUnoptimizedZ80Run(
|
||||
"""
|
||||
| #pragma intel_syntax
|
||||
| asm void main () {
|
||||
| ret
|
||||
| addx 0
|
||||
| adcx 0
|
||||
| subx 0
|
||||
| sbcx 0
|
||||
| andx 0
|
||||
| xorx 0
|
||||
| orx 0
|
||||
| cmpx 0
|
||||
|
|
||||
| rrcx 0
|
||||
| rarx 0
|
||||
| rlcx 0
|
||||
| ralx 0
|
||||
| slax 0
|
||||
| srax 0
|
||||
| srlx 0
|
||||
| sllx 0
|
||||
|
|
||||
| popix
|
||||
| pushix
|
||||
| pop ix
|
||||
| push ix
|
||||
| dadx sp
|
||||
| dadx ix
|
||||
| dadx d
|
||||
| dadx b
|
||||
| inxix
|
||||
| dcxix
|
||||
| inx ix
|
||||
| dcx ix
|
||||
| lxix 3
|
||||
| lixd 3
|
||||
| sixd 3
|
||||
| xtix
|
||||
| pcix
|
||||
| spix
|
||||
| ldx a,0
|
||||
| stx a,0
|
||||
|
|
||||
| ret
|
||||
| }
|
||||
""".stripMargin)
|
||||
}
|
||||
|
||||
test("Z80 instructions with IY (Intel syntax)") {
|
||||
EmuUnoptimizedZ80Run(
|
||||
"""
|
||||
| #pragma intel_syntax
|
||||
| asm void main () {
|
||||
| ret
|
||||
| addy 0
|
||||
| adcy 0
|
||||
| suby 0
|
||||
| sbcy 0
|
||||
| andy 0
|
||||
| xory 0
|
||||
| ory 0
|
||||
| cmpy 0
|
||||
|
|
||||
| rrcy 0
|
||||
| rary 0
|
||||
| rlcy 0
|
||||
| raly 0
|
||||
| slay 0
|
||||
| sray 0
|
||||
| srly 0
|
||||
| slly 0
|
||||
|
|
||||
| popiy
|
||||
| pushiy
|
||||
| pop iy
|
||||
| push iy
|
||||
| dady sp
|
||||
| dady iy
|
||||
| dady d
|
||||
| dady b
|
||||
| inxiy
|
||||
| dcxiy
|
||||
| inx iy
|
||||
| dcx iy
|
||||
| lxiy 3
|
||||
| liyd 3
|
||||
| siyd 3
|
||||
| xtiy
|
||||
| pciy
|
||||
| spiy
|
||||
| ldy a,0
|
||||
| sty a,0
|
||||
|
|
||||
| ret
|
||||
| }
|
||||
""".stripMargin)
|
||||
}
|
||||
|
||||
test("Other Z80 instructions (Intel syntax)") {
|
||||
EmuUnoptimizedZ80Run(
|
||||
"""
|
||||
| #pragma intel_syntax
|
||||
| asm void main () {
|
||||
| ret
|
||||
|
|
||||
| djnz main
|
||||
| exaf
|
||||
| exx
|
||||
|
|
||||
| sllr b
|
||||
| sllr c
|
||||
| sllr d
|
||||
| sllr e
|
||||
| sllr h
|
||||
| sllr l
|
||||
| sllr m
|
||||
| sllr a
|
||||
|
|
||||
| inp b
|
||||
| outp b
|
||||
| dsbc b
|
||||
| lbcd 34
|
||||
| neg
|
||||
| retn
|
||||
| im0
|
||||
| stai
|
||||
| inp c
|
||||
| outp c
|
||||
| dadc b
|
||||
| lbcd 7
|
||||
| star
|
||||
| inp d
|
||||
| outp d
|
||||
| dsbc d
|
||||
| lded 55
|
||||
| im1
|
||||
| ldai
|
||||
| inp e
|
||||
| outp e
|
||||
| dadc d
|
||||
| lded 33
|
||||
| im2
|
||||
| ldar
|
||||
|
|
||||
| inp h
|
||||
| outp h
|
||||
| dsbc h
|
||||
| rrd
|
||||
| inp l
|
||||
| outp l
|
||||
| dadc h
|
||||
| rld
|
||||
| dsbc sp
|
||||
| inp a
|
||||
| outp a
|
||||
| dadc sp
|
||||
| lspd 345
|
||||
|
|
||||
| ldi
|
||||
| cci
|
||||
| ini
|
||||
| outi
|
||||
| ldd
|
||||
| ccd
|
||||
| ind
|
||||
| outd
|
||||
| ldir
|
||||
| ccir
|
||||
| inir
|
||||
| outir
|
||||
| lddr
|
||||
| ccdr
|
||||
| indr
|
||||
| outdr
|
||||
|
|
||||
| ret
|
||||
| }
|
||||
""".stripMargin)
|
||||
}
|
||||
|
||||
test("Gameboy instructions") {
|
||||
EmuUnoptimizedSharpRun(
|
||||
"""
|
||||
@ -1012,4 +1287,36 @@ class Z80AssemblySuite extends FunSuite with Matchers {
|
||||
""".stripMargin)
|
||||
}
|
||||
|
||||
test("Z80 halves of index registers") {
|
||||
EmuUnoptimizedZ80NextRun(
|
||||
"""
|
||||
| #pragma zilog_syntax
|
||||
| asm void main () {
|
||||
| ret
|
||||
| inc ixh
|
||||
| inc ixl
|
||||
| inc iyh
|
||||
| inc iyl
|
||||
| dec ixh
|
||||
| dec ixl
|
||||
| dec iyh
|
||||
| dec iyl
|
||||
| ld a,ixh
|
||||
| ld a,ixl
|
||||
| ld iyh,a
|
||||
| ld iyl,a
|
||||
| add a,iyl
|
||||
| adc a,iyl
|
||||
| sub iyl
|
||||
| sbc a,iyl
|
||||
| or iyl
|
||||
| xor iyl
|
||||
| and iyl
|
||||
| cp iyl
|
||||
| ld ixh,0
|
||||
| ret
|
||||
| }
|
||||
""".stripMargin)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ class EmuZ80Run(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimizatio
|
||||
val log = TestErrorReporting.log
|
||||
println(source)
|
||||
val platform = EmuPlatform.get(cpu)
|
||||
val extraFlags = Map(
|
||||
var extraFlags = Map(
|
||||
CompilationFlag.DangerousOptimizations -> true,
|
||||
CompilationFlag.EnableInternalTestSyntax -> true,
|
||||
CompilationFlag.InlineFunctions -> this.inline,
|
||||
@ -87,6 +87,9 @@ class EmuZ80Run(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimizatio
|
||||
CompilationFlag.EmitIllegals -> (cpu == millfork.Cpu.Z80 || cpu == millfork.Cpu.Intel8085 || cpu == millfork.Cpu.Z80Next),
|
||||
CompilationFlag.EmitZ80NextOpcodes -> (cpu == millfork.Cpu.Z80Next),
|
||||
CompilationFlag.LenientTextEncoding -> true)
|
||||
if (source.contains("intel_syntax")) {
|
||||
extraFlags += CompilationFlag.UseIntelSyntaxForOutput -> true
|
||||
}
|
||||
val options = CompilationOptions(platform, millfork.Cpu.defaultFlags(cpu).map(_ -> true).toMap ++ extraFlags, None, 0, Map(), EmuPlatform.textCodecRepository, JobContext(log, new LabelGenerator))
|
||||
println(cpu)
|
||||
println(options.flags.filter(_._2).keys.toSeq.sorted)
|
||||
|
Loading…
x
Reference in New Issue
Block a user