1
0
mirror of https://github.com/KarolS/millfork.git synced 2025-08-08 18:25:03 +00:00

Z80: Support IXH/IXL/IYH/IYL registers. Add Intel syntax for Z80 instructions.

This commit is contained in:
Karol Stasiak
2020-07-24 17:27:37 +02:00
parent 53973f081a
commit b24ac32932
7 changed files with 858 additions and 9 deletions

View File

@@ -69,8 +69,11 @@ AHX, LAS, LXA, SHX, SHY, TAS, XAA.
## Z80 ## Z80
Original Z80 processors accidentally supported a bunch of extra undocumented instructions. Original Z80 processors accidentally supported a bunch of extra undocumented instructions.
Millfork will not emit them. Millfork will emit some of them if used in an assembly block:
The only exception is SLL, which will be emitted if it occurs in a handwritten 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 ## 8085

View File

@@ -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. 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. 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 partially supported:
Undocumented Z80 instructions are not supported, except for `SLL`. * `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. Labels have to be followed by a colon and they can optionally be on a separate line.
Indentation is not important: 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 * end non-inline assembly functions with `RET`, `JP`, `RETI` or `RETN` (Zilog) / `RET` or `JMP` (Intel) as appropriate
The above list is not exhaustive. 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**

View File

@@ -275,7 +275,7 @@ case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Consta
override def isPrintable: Boolean = true 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.A => "A"
case ZRegister.B => "B" case ZRegister.B => "B"
case ZRegister.C => "C" 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_8 => s"$parameter"
case ZRegister.IMM_16 => s"$parameter" case ZRegister.IMM_16 => s"$parameter"
case ZRegister.MEM_HL => "M" case ZRegister.MEM_HL => "M"
case ZRegister.IX => "IX"
case ZRegister.IY => "IY"
case _ => "???" case _ => "???"
} }
@@ -467,6 +469,12 @@ case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Consta
case DISCARD_IY => " ; DISCARD_IY" case DISCARD_IY => " ; DISCARD_IY"
case BYTE => " DB " + parameter.toString case BYTE => " DB " + parameter.toString
case LD => registers match { 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(target, IMM_8) => s" MVI ${asIntelAssemblyString(target)}, ${parameter.toIntelString}"
case TwoRegisters(A, MEM_ABS_8) => s" LDA ${parameter.toIntelString}" case TwoRegisters(A, MEM_ABS_8) => s" LDA ${parameter.toIntelString}"
case TwoRegisters(MEM_ABS_8, A) => s" STA ${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(MEM_BC, A) => " STAX B"
case TwoRegisters(A, MEM_DE) => " LDAX D" case TwoRegisters(A, MEM_DE) => " LDAX D"
case TwoRegisters(MEM_DE, A) => " STAX 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 TwoRegisters(target, source) => s" MOV ${asIntelAssemblyString(target)}, ${asIntelAssemblyString(source)}"
case _ => "???" case _ => "???"
} }
case LD_16 => registers match { case LD_16 => registers match {
case TwoRegisters(SP, HL) => " SPHL" 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(target, IMM_16) => s" LXI ${asIntelAssemblyString(target)}, ${parameter.toIntelString}"
case TwoRegisters(HL, MEM_ABS_16) => s" LHLD ${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, 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 _ => "???"
} }
case ADD_16 => registers match { 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 TwoRegisters(HL, source) => s" DAD ${asIntelAssemblyString(source)}"
case _ => "???" 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 DEC_16 => registers match {
case OneRegister(IX) => s" DCXIX"
case OneRegister(IY) => s" DCXIY"
case OneRegister(register) => s" DCX ${asIntelAssemblyString(register)}" case OneRegister(register) => s" DCX ${asIntelAssemblyString(register)}"
case _ => "???" case _ => "???"
} }
case INC_16 => registers match { case INC_16 => registers match {
case OneRegister(IX) => s" INXIX"
case OneRegister(IY) => s" INXIY"
case OneRegister(register) => s" INX ${asIntelAssemblyString(register)}" case OneRegister(register) => s" INX ${asIntelAssemblyString(register)}"
case _ => "???" case _ => "???"
} }
case DEC => registers match { 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 OneRegister(register) => s" DCR ${asIntelAssemblyString(register)}"
case _ => "???" case _ => "???"
} }
case INC => registers match { 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 OneRegister(register) => s" INR ${asIntelAssemblyString(register)}"
case _ => "???" 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 PUSH => registers match {
case OneRegister(IX) => s" PUSHIX"
case OneRegister(IY) => s" PUSHIY"
case OneRegister(register) => s" PUSH ${asIntelAssemblyString(register)}" case OneRegister(register) => s" PUSH ${asIntelAssemblyString(register)}"
case _ => "???" case _ => "???"
} }
case POP => registers match { case POP => registers match {
case OneRegister(IX) => s" POPIX"
case OneRegister(IY) => s" POPIY"
case OneRegister(register) => s" POP ${asIntelAssemblyString(register)}" case OneRegister(register) => s" POP ${asIntelAssemblyString(register)}"
case _ => "???" 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 DAA => " DAA"
case RLA => " RAL" case RLA => " RAL"
case RLCA => " RLC" case RLCA => " RLC"
case RRA => " RAR" case RRA => " RAR"
case RRCA => " RRC" case RRCA => " RRC"
case HALT => " HLT" 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 RET => registers match {
case NoRegisters => " RET" case NoRegisters => " RET"
case IfFlagClear(ZFlag.C) => " RNC" case IfFlagClear(ZFlag.C) => " RNC"
@@ -532,6 +659,8 @@ case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Consta
} }
case JP => registers match { case JP => registers match {
case OneRegister(HL) => " PCHL" case OneRegister(HL) => " PCHL"
case OneRegister(IX) => " PCIX"
case OneRegister(IY) => " PCIY"
case NoRegisters => s" JMP ${parameter.toIntelString}" case NoRegisters => s" JMP ${parameter.toIntelString}"
case IfFlagClear(ZFlag.C) => s" JNC ${parameter.toIntelString}" case IfFlagClear(ZFlag.C) => s" JNC ${parameter.toIntelString}"
case IfFlagClear(ZFlag.Z) => s" JNZ ${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 IfFlagSet(ZFlag.K) => s" JK ${parameter.toIntelString}"
case _ => "???" 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 CALL => registers match {
case NoRegisters => s" CALL ${parameter.toIntelString}" case NoRegisters => s" CALL ${parameter.toIntelString}"
case IfFlagClear(ZFlag.C) => s" CNC ${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 ADD => registers match {
case OneRegister(IMM_8) => s" ADI ${parameter.toIntelString}" 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 OneRegister(register) => s" ADD ${asIntelAssemblyString(register)}"
case _ => "???" case _ => "???"
} }
case ADC => registers match { case ADC => registers match {
case OneRegister(IMM_8) => s" ACI ${parameter.toIntelString}" 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 OneRegister(register) => s" ADC ${asIntelAssemblyString(register)}"
case _ => "???" case _ => "???"
} }
case SUB => registers match { case SUB => registers match {
case OneRegister(IMM_8) => s" SUI ${parameter.toIntelString}" 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 OneRegister(register) => s" SUB ${asIntelAssemblyString(register)}"
case _ => "???" case _ => "???"
} }
case SBC => registers match { case SBC => registers match {
case OneRegister(IMM_8) => s" SBI ${parameter.toIntelString}" 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 OneRegister(register) => s" SBB ${asIntelAssemblyString(register)}"
case _ => "???" case _ => "???"
} }
case AND => registers match { case AND => registers match {
case OneRegister(IMM_8) => s" ANI ${parameter.toIntelString}" 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 OneRegister(register) => s" ANA ${asIntelAssemblyString(register)}"
case _ => "???" case _ => "???"
} }
case OR => registers match { case OR => registers match {
case OneRegister(IMM_8) => s" ORI ${parameter.toIntelString}" 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 OneRegister(register) => s" ORA ${asIntelAssemblyString(register)}"
case _ => "???" case _ => "???"
} }
case XOR => registers match { case XOR => registers match {
case OneRegister(IMM_8) => s" XRI ${parameter.toIntelString}" 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 OneRegister(register) => s" XRA ${asIntelAssemblyString(register)}"
case _ => "???" case _ => "???"
} }
case CP => registers match { case CP => registers match {
case OneRegister(IMM_8) => s" CPI ${parameter.toIntelString}" 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 OneRegister(register) => s" CMP ${asIntelAssemblyString(register)}"
case _ => "???" case _ => "???"
} }
case EX_SP => registers match { case EX_SP => registers match {
case OneRegister(HL) => s" XTHL" case OneRegister(HL) => s" XTHL"
case OneRegister(IX) => s" XTIX"
case OneRegister(IY) => s" XTIY"
case _ => "???" case _ => "???"
} }
case RST => parameter match { case RST => parameter match {
case NumericConstant(n, _) if n % 8 == 0 => s" RST ${n / 8}" case NumericConstant(n, _) if n % 8 == 0 => s" RST ${n / 8}"
case _ => "???" 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 IN_IMM => s" IN ${parameter.toIntelString}"
case OUT_IMM => s" OUT ${parameter.toIntelString}" case OUT_IMM => s" OUT ${parameter.toIntelString}"
case EI => " EI" case EI => " EI"
@@ -616,6 +780,8 @@ case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Consta
case CCF => " CMC" case CCF => " CMC"
case EI => " EI" case EI => " EI"
case EX_AF_AF => " EXAF"
case DSUB => " DSUB" case DSUB => " DSUB"
case RRHL => " ARHL" case RRHL => " ARHL"
case RLDE => " RLDE" case RLDE => " RLDE"

View File

@@ -32,6 +32,10 @@ class Z80Assembler(program: Program,
case ZRegister.E => 3 case ZRegister.E => 3
case ZRegister.H => 4 case ZRegister.H => 4
case ZRegister.L => 5 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_HL => 6
case ZRegister.MEM_IX_D => 6 case ZRegister.MEM_IX_D => 6
case ZRegister.MEM_IY_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 { private def prefixByte(reg: ZRegister.Value): Int = reg match {
case ZRegister.IX | ZRegister.MEM_IX_D => 0xdd case ZRegister.IX | ZRegister.MEM_IX_D => 0xdd
case ZRegister.IY | ZRegister.MEM_IY_D => 0xfd 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 = { 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 + 1, o.opcode + internalRegisterIndex(ZRegister.HL) * o.multiplier)
writeByte(bank, index + 2, instr.parameter) writeByte(bank, index + 2, instr.parameter)
index + 3 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) => case ZLine0(op, OneRegister(reg), _) if reg != ZRegister.IMM_8 && oneRegister.contains(op) =>
val o = oneRegister(op) val o = oneRegister(op)
writeByte(bank, index, o.opcode + internalRegisterIndex(reg) * o.multiplier) 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 + 1, 0x40 + internalRegisterIndex(ZRegister.MEM_HL) + internalRegisterIndex(target) * 8)
writeByte(bank, index + 2, offset) writeByte(bank, index + 2, offset)
index + 3 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) => case TwoRegisters(target, source) =>
writeByte(bank, index, 0x40 + internalRegisterIndex(source) + internalRegisterIndex(target) * 8) writeByte(bank, index, 0x40 + internalRegisterIndex(source) + internalRegisterIndex(target) * 8)
index + 1 index + 1

View File

@@ -9,7 +9,7 @@ import millfork.{CompilationFlag, CompilationOptions, node}
import millfork.assembly.z80.{ZOpcode, _} import millfork.assembly.z80.{ZOpcode, _}
import millfork.env.{ByZRegister, Constant, ParamPassingConvention} import millfork.env.{ByZRegister, Constant, ParamPassingConvention}
import millfork.error.ConsoleLogger import millfork.error.ConsoleLogger
import millfork.node._ import millfork.node.{ZRegister, _}
import millfork.output.{MemoryAlignment, NoAlignment, WithinPageAlignment} import millfork.output.{MemoryAlignment, NoAlignment, WithinPageAlignment}
/** /**
@@ -73,6 +73,13 @@ case class Z80Parser(filename: String,
"SP" -> ZRegister.SP, "sp" -> ZRegister.SP, "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( private val toIntelRegister8: Map[String, ZRegister.Value] = Map(
"A" -> ZRegister.A, "a" -> ZRegister.A, "A" -> ZRegister.A, "a" -> ZRegister.A,
"B" -> ZRegister.B, "b" -> ZRegister.B, "B" -> ZRegister.B, "b" -> ZRegister.B,
@@ -86,16 +93,25 @@ case class Z80Parser(filename: String,
private val toIntelRegister16: Map[String, ZRegister.Value] = Map( private val toIntelRegister16: Map[String, ZRegister.Value] = Map(
"H" -> ZRegister.HL, "h" -> ZRegister.HL, "H" -> ZRegister.HL, "h" -> ZRegister.HL,
"HL" -> ZRegister.HL, "hl" -> ZRegister.HL,
"PSW" -> ZRegister.AF, "psw" -> ZRegister.AF, "PSW" -> ZRegister.AF, "psw" -> ZRegister.AF,
"B" -> ZRegister.BC, "b" -> ZRegister.BC, "B" -> ZRegister.BC, "b" -> ZRegister.BC,
"BC" -> ZRegister.BC, "bc" -> ZRegister.BC,
"D" -> ZRegister.DE, "d" -> ZRegister.DE, "D" -> ZRegister.DE, "d" -> ZRegister.DE,
"DE" -> ZRegister.DE, "de" -> ZRegister.DE,
"SP" -> ZRegister.SP, "sp" -> ZRegister.SP, "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 { 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("R" | "r"), false) if allowRI => (ZRegister.R, None)
case (VariableExpression("I" | "i"), false) if allowRI => (ZRegister.I, 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 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( case (SumExpression(List(
(false, LiteralExpression(0xff00, _)), (false, LiteralExpression(0xff00, _)),
(false, VariableExpression("C" | "c")) (false, VariableExpression("C" | "c"))
@@ -138,6 +154,8 @@ case class Z80Parser(filename: String,
case (reg, addr) => (op, OneRegister(reg), None, addr.getOrElse(zero)) 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{ 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@(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) => 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 jumpConditionWithComma: P[ZRegisters] = (jumpCondition ~ "," ~/ HWS).?.map (_.getOrElse(NoRegisters))
private val jumpConditionWithoutComma: 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] = { val zilogAsmInstruction: P[ExecutableStatement] = {
import ZOpcode._ import ZOpcode._
for { for {
@@ -449,7 +488,11 @@ case class Z80Parser(filename: String,
if options.flags(CompilationFlag.EmitSharpOpcodes) => if options.flags(CompilationFlag.EmitSharpOpcodes) =>
(LD_HLDA, NoRegisters, None, zero) (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 { 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 "RIM" => imm(RIM)
case "SIM" => imm(SIM) 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 "HLT" => imm(HALT)
case "EI" => imm(EI) case "EI" => imm(EI)
case "DI" => imm(DI) case "DI" => imm(DI)
case "XCHG" => imm(EX_DE_HL) case "XCHG" => imm(EX_DE_HL)
case "XTHL" => P("").map(_ => (EX_SP, OneRegister(HL), None, zero)) 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 "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 "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 "MOV" => (intel8 ~ HWS ~ position("comma").map(_ => ()) ~ "," ~/ HWS ~ intel8).map {
case (r1, r2) => (LD, TwoRegisters(r1, r2), None, zero) 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 "LXI" => (intel16(false) ~ HWS ~ position("comma").map(_ => ()) ~ "," ~/ HWS ~ asmExpression).map {
case (r, e) => (LD_16, TwoRegisters(r, IMM_16), None, e) 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 "MVI" => (intel8 ~ HWS ~ position("comma").map(_ => ()) ~ "," ~/ HWS ~ asmExpression).map {
case (r, e) => (LD, TwoRegisters(r, IMM_8), None, e) 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 "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 "STAX" => intel16(false).map {
case r@(ZRegister.BC | ZRegister.DE) => (LD, TwoRegisters(r, A), None, zero) case r@(ZRegister.BC | ZRegister.DE) => (LD, TwoRegisters(r, A), None, zero)
case _ => case _ =>
@@ -565,19 +696,47 @@ case class Z80Parser(filename: String,
(NOP, NoRegisters, None, zero) (NOP, NoRegisters, None, zero)
} }
case "INX" => intel16(false).map { r => (INC_16, OneRegister(r), 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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "ADI" => asmExpression.map { e => (ADD, OneRegister(IMM_8), None, e)}
case "ACI" => asmExpression.map { e => (ADC, 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)} 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 "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 "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 "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 "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 "RST" => asmExpression.map {
case LiteralExpression(value, _) if value >=0 && value <= 7=> (RST, NoRegisters, None, LiteralExpression(value * 8, 1)) case LiteralExpression(value, _) if value >=0 && value <= 7=> (RST, NoRegisters, None, LiteralExpression(value * 8, 1))
case _ => case _ =>
@@ -598,10 +771,14 @@ case class Z80Parser(filename: String,
(NOP, NoRegisters, None, zero) (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 "IN" => asmExpression.map { e => (IN_IMM, OneRegister(A), None, e) }
case "OUT" => asmExpression.map { e => (OUT_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 "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 "JC" => asmExpression.map { e => (JP, IfFlagSet(ZFlag.C), None, e)}
case "JZ" => asmExpression.map { e => (JP, IfFlagSet(ZFlag.Z), None, e)} case "JZ" => asmExpression.map { e => (JP, IfFlagSet(ZFlag.Z), None, e)}
case "JM" => asmExpression.map { e => (JP, IfFlagSet(ZFlag.S), 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 "JNZ" => asmExpression.map { e => (JP, IfFlagClear(ZFlag.Z), None, e)}
case "JP" => asmExpression.map { e => (JP, IfFlagClear(ZFlag.S), 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 "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 "RET" => imm(RET)
case "RC" => P("").map { _ => (RET, IfFlagSet(ZFlag.C), None, zero)} 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 "SHLDE" | "SHLX" => imm(SHLX)
case "LHLDE" | "LHLX" =>imm(LHLX) 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 _ => case _ =>
log.error("Unsupported opcode " + opcode, Some(pos)) log.error("Unsupported opcode " + opcode, Some(pos))
imm(NOP) 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 val asmInstruction: P[ExecutableStatement] = if (useIntelSyntax) intelAsmInstruction else zilogAsmInstruction
private def imm(opcode: ZOpcode.Value): P[(ZOpcode.Value, ZRegisters, Option[Expression], Expression)] = private def imm(opcode: ZOpcode.Value): P[(ZOpcode.Value, ZRegisters, Option[Expression], Expression)] =

View File

@@ -873,6 +873,281 @@ class Z80AssemblySuite extends FunSuite with Matchers {
""".stripMargin) """.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") { test("Gameboy instructions") {
EmuUnoptimizedSharpRun( EmuUnoptimizedSharpRun(
""" """
@@ -1012,4 +1287,36 @@ class Z80AssemblySuite extends FunSuite with Matchers {
""".stripMargin) """.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)
}
} }

View File

@@ -77,7 +77,7 @@ class EmuZ80Run(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimizatio
val log = TestErrorReporting.log val log = TestErrorReporting.log
println(source) println(source)
val platform = EmuPlatform.get(cpu) val platform = EmuPlatform.get(cpu)
val extraFlags = Map( var extraFlags = Map(
CompilationFlag.DangerousOptimizations -> true, CompilationFlag.DangerousOptimizations -> true,
CompilationFlag.EnableInternalTestSyntax -> true, CompilationFlag.EnableInternalTestSyntax -> true,
CompilationFlag.InlineFunctions -> this.inline, 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.EmitIllegals -> (cpu == millfork.Cpu.Z80 || cpu == millfork.Cpu.Intel8085 || cpu == millfork.Cpu.Z80Next),
CompilationFlag.EmitZ80NextOpcodes -> (cpu == millfork.Cpu.Z80Next), CompilationFlag.EmitZ80NextOpcodes -> (cpu == millfork.Cpu.Z80Next),
CompilationFlag.LenientTextEncoding -> true) 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)) val options = CompilationOptions(platform, millfork.Cpu.defaultFlags(cpu).map(_ -> true).toMap ++ extraFlags, None, 0, Map(), EmuPlatform.textCodecRepository, JobContext(log, new LabelGenerator))
println(cpu) println(cpu)
println(options.flags.filter(_._2).keys.toSeq.sorted) println(options.flags.filter(_._2).keys.toSeq.sorted)