1 |
/** Z80: portable Z80 emulator *******************************/ |
2 |
/** **/ |
3 |
/** Z80.c **/ |
4 |
/** **/ |
5 |
/** This file contains implementation for Z80 CPU. Don't **/ |
6 |
/** forget to provide RdZ80(), WrZ80(), InZ80(), OutZ80(), **/ |
7 |
/** LoopZ80(), and PatchZ80() functions to accomodate the **/ |
8 |
/** emulated machine's architecture. **/ |
9 |
/** **/ |
10 |
/** Copyright (C) Marat Fayzullin 1994-2007 **/ |
11 |
/** You are not allowed to distribute this software **/ |
12 |
/** commercially. Please, notify me, if you make any **/ |
13 |
/** changes to this file. **/ |
14 |
/*************************************************************/ |
15 |
|
16 |
#include "Z80.h" |
17 |
#include "Tables.h" |
18 |
#include <stdio.h> |
19 |
|
20 |
/** INLINE ***************************************************/ |
21 |
/** C99 standard has "inline", but older compilers used **/ |
22 |
/** __inline for the same purpose. **/ |
23 |
/*************************************************************/ |
24 |
#ifdef __C99__ |
25 |
#define INLINE static inline |
26 |
#else |
27 |
#define INLINE static __inline |
28 |
#endif |
29 |
|
30 |
/** System-Dependent Stuff ***********************************/ |
31 |
/** This is system-dependent code put here to speed things **/ |
32 |
/** up. It has to stay inlined to be fast. **/ |
33 |
/*************************************************************/ |
34 |
#ifdef COLEM |
35 |
#define RdZ80 RDZ80 |
36 |
extern byte *ROMPage[]; |
37 |
INLINE byte RdZ80(word A) { return(ROMPage[A>>13][A&0x1FFF]); } |
38 |
#endif |
39 |
|
40 |
#ifdef SPECCY |
41 |
#define RdZ80 RDZ80 |
42 |
extern byte *Page[]; |
43 |
INLINE byte RdZ80(word A) { return(Page[A>>13][A&0x1FFF]); } |
44 |
#endif |
45 |
|
46 |
#ifdef MG |
47 |
#define RdZ80 RDZ80 |
48 |
extern byte *Page[]; |
49 |
INLINE byte RdZ80(word A) { return(Page[A>>13][A&0x1FFF]); } |
50 |
#endif |
51 |
|
52 |
#ifdef FMSX |
53 |
#define RdZ80 RDZ80 |
54 |
extern byte *RAM[],PSL[],SSLReg; |
55 |
INLINE byte RdZ80(word A) |
56 |
{ |
57 |
if(A!=0xFFFF) return(RAM[A>>13][A&0x1FFF]); |
58 |
else return((PSL[3]==3)? ~SSLReg:RAM[7][0x1FFF]); |
59 |
} |
60 |
#endif |
61 |
|
62 |
#define S(Fl) R->AF.B.l|=Fl |
63 |
#define R(Fl) R->AF.B.l&=~(Fl) |
64 |
#define FLAGS(Rg,Fl) R->AF.B.l=Fl|ZSTable[Rg] |
65 |
|
66 |
#define M_RLC(Rg) \ |
67 |
R->AF.B.l=Rg>>7;Rg=(Rg<<1)|R->AF.B.l;R->AF.B.l|=PZSTable[Rg] |
68 |
#define M_RRC(Rg) \ |
69 |
R->AF.B.l=Rg&0x01;Rg=(Rg>>1)|(R->AF.B.l<<7);R->AF.B.l|=PZSTable[Rg] |
70 |
#define M_RL(Rg) \ |
71 |
if(Rg&0x80) \ |
72 |
{ \ |
73 |
Rg=(Rg<<1)|(R->AF.B.l&C_FLAG); \ |
74 |
R->AF.B.l=PZSTable[Rg]|C_FLAG; \ |
75 |
} \ |
76 |
else \ |
77 |
{ \ |
78 |
Rg=(Rg<<1)|(R->AF.B.l&C_FLAG); \ |
79 |
R->AF.B.l=PZSTable[Rg]; \ |
80 |
} |
81 |
#define M_RR(Rg) \ |
82 |
if(Rg&0x01) \ |
83 |
{ \ |
84 |
Rg=(Rg>>1)|(R->AF.B.l<<7); \ |
85 |
R->AF.B.l=PZSTable[Rg]|C_FLAG; \ |
86 |
} \ |
87 |
else \ |
88 |
{ \ |
89 |
Rg=(Rg>>1)|(R->AF.B.l<<7); \ |
90 |
R->AF.B.l=PZSTable[Rg]; \ |
91 |
} |
92 |
|
93 |
#define M_SLA(Rg) \ |
94 |
R->AF.B.l=Rg>>7;Rg<<=1;R->AF.B.l|=PZSTable[Rg] |
95 |
#define M_SRA(Rg) \ |
96 |
R->AF.B.l=Rg&C_FLAG;Rg=(Rg>>1)|(Rg&0x80);R->AF.B.l|=PZSTable[Rg] |
97 |
|
98 |
#define M_SLL(Rg) \ |
99 |
R->AF.B.l=Rg>>7;Rg=(Rg<<1)|0x01;R->AF.B.l|=PZSTable[Rg] |
100 |
#define M_SRL(Rg) \ |
101 |
R->AF.B.l=Rg&0x01;Rg>>=1;R->AF.B.l|=PZSTable[Rg] |
102 |
|
103 |
#define M_BIT(Bit,Rg) \ |
104 |
R->AF.B.l=(R->AF.B.l&C_FLAG)|H_FLAG|PZSTable[Rg&(1<<Bit)] |
105 |
|
106 |
#define M_SET(Bit,Rg) Rg|=1<<Bit |
107 |
#define M_RES(Bit,Rg) Rg&=~(1<<Bit) |
108 |
|
109 |
#define M_POP(Rg) \ |
110 |
R->Rg.B.l=RdZ80(R->SP.W++);R->Rg.B.h=RdZ80(R->SP.W++) |
111 |
#define M_PUSH(Rg) \ |
112 |
WrZ80(--R->SP.W,R->Rg.B.h);WrZ80(--R->SP.W,R->Rg.B.l) |
113 |
|
114 |
#define M_CALL \ |
115 |
J.B.l=RdZ80(R->PC.W++);J.B.h=RdZ80(R->PC.W++); \ |
116 |
WrZ80(--R->SP.W,R->PC.B.h);WrZ80(--R->SP.W,R->PC.B.l); \ |
117 |
R->PC.W=J.W; \ |
118 |
JumpZ80(J.W) |
119 |
|
120 |
#define M_JP J.B.l=RdZ80(R->PC.W++);J.B.h=RdZ80(R->PC.W);R->PC.W=J.W;JumpZ80(J.W) |
121 |
#define M_JR R->PC.W+=(offset)RdZ80(R->PC.W)+1;JumpZ80(R->PC.W) |
122 |
#define M_RET R->PC.B.l=RdZ80(R->SP.W++);R->PC.B.h=RdZ80(R->SP.W++);JumpZ80(R->PC.W) |
123 |
|
124 |
#define M_RST(Ad) \ |
125 |
WrZ80(--R->SP.W,R->PC.B.h);WrZ80(--R->SP.W,R->PC.B.l);R->PC.W=Ad;JumpZ80(Ad) |
126 |
|
127 |
#define M_LDWORD(Rg) \ |
128 |
R->Rg.B.l=RdZ80(R->PC.W++);R->Rg.B.h=RdZ80(R->PC.W++) |
129 |
|
130 |
#define M_ADD(Rg) \ |
131 |
J.W=R->AF.B.h+Rg; \ |
132 |
R->AF.B.l= \ |
133 |
(~(R->AF.B.h^Rg)&(Rg^J.B.l)&0x80? V_FLAG:0)| \ |
134 |
J.B.h|ZSTable[J.B.l]| \ |
135 |
((R->AF.B.h^Rg^J.B.l)&H_FLAG); \ |
136 |
R->AF.B.h=J.B.l |
137 |
|
138 |
#define M_SUB(Rg) \ |
139 |
J.W=R->AF.B.h-Rg; \ |
140 |
R->AF.B.l= \ |
141 |
((R->AF.B.h^Rg)&(R->AF.B.h^J.B.l)&0x80? V_FLAG:0)| \ |
142 |
N_FLAG|-J.B.h|ZSTable[J.B.l]| \ |
143 |
((R->AF.B.h^Rg^J.B.l)&H_FLAG); \ |
144 |
R->AF.B.h=J.B.l |
145 |
|
146 |
#define M_ADC(Rg) \ |
147 |
J.W=R->AF.B.h+Rg+(R->AF.B.l&C_FLAG); \ |
148 |
R->AF.B.l= \ |
149 |
(~(R->AF.B.h^Rg)&(Rg^J.B.l)&0x80? V_FLAG:0)| \ |
150 |
J.B.h|ZSTable[J.B.l]| \ |
151 |
((R->AF.B.h^Rg^J.B.l)&H_FLAG); \ |
152 |
R->AF.B.h=J.B.l |
153 |
|
154 |
#define M_SBC(Rg) \ |
155 |
J.W=R->AF.B.h-Rg-(R->AF.B.l&C_FLAG); \ |
156 |
R->AF.B.l= \ |
157 |
((R->AF.B.h^Rg)&(R->AF.B.h^J.B.l)&0x80? V_FLAG:0)| \ |
158 |
N_FLAG|-J.B.h|ZSTable[J.B.l]| \ |
159 |
((R->AF.B.h^Rg^J.B.l)&H_FLAG); \ |
160 |
R->AF.B.h=J.B.l |
161 |
|
162 |
#define M_CP(Rg) \ |
163 |
J.W=R->AF.B.h-Rg; \ |
164 |
R->AF.B.l= \ |
165 |
((R->AF.B.h^Rg)&(R->AF.B.h^J.B.l)&0x80? V_FLAG:0)| \ |
166 |
N_FLAG|-J.B.h|ZSTable[J.B.l]| \ |
167 |
((R->AF.B.h^Rg^J.B.l)&H_FLAG) |
168 |
|
169 |
#define M_AND(Rg) R->AF.B.h&=Rg;R->AF.B.l=H_FLAG|PZSTable[R->AF.B.h] |
170 |
#define M_OR(Rg) R->AF.B.h|=Rg;R->AF.B.l=PZSTable[R->AF.B.h] |
171 |
#define M_XOR(Rg) R->AF.B.h^=Rg;R->AF.B.l=PZSTable[R->AF.B.h] |
172 |
|
173 |
#define M_IN(Rg) \ |
174 |
Rg=InZ80(R->BC.W); \ |
175 |
R->AF.B.l=PZSTable[Rg]|(R->AF.B.l&C_FLAG) |
176 |
|
177 |
#define M_INC(Rg) \ |
178 |
Rg++; \ |
179 |
R->AF.B.l= \ |
180 |
(R->AF.B.l&C_FLAG)|ZSTable[Rg]| \ |
181 |
(Rg==0x80? V_FLAG:0)|(Rg&0x0F? 0:H_FLAG) |
182 |
|
183 |
#define M_DEC(Rg) \ |
184 |
Rg--; \ |
185 |
R->AF.B.l= \ |
186 |
N_FLAG|(R->AF.B.l&C_FLAG)|ZSTable[Rg]| \ |
187 |
(Rg==0x7F? V_FLAG:0)|((Rg&0x0F)==0x0F? H_FLAG:0) |
188 |
|
189 |
#define M_ADDW(Rg1,Rg2) \ |
190 |
J.W=(R->Rg1.W+R->Rg2.W)&0xFFFF; \ |
191 |
R->AF.B.l= \ |
192 |
(R->AF.B.l&~(H_FLAG|N_FLAG|C_FLAG))| \ |
193 |
((R->Rg1.W^R->Rg2.W^J.W)&0x1000? H_FLAG:0)| \ |
194 |
(((long)R->Rg1.W+(long)R->Rg2.W)&0x10000? C_FLAG:0); \ |
195 |
R->Rg1.W=J.W |
196 |
|
197 |
#define M_ADCW(Rg) \ |
198 |
I=R->AF.B.l&C_FLAG;J.W=(R->HL.W+R->Rg.W+I)&0xFFFF; \ |
199 |
R->AF.B.l= \ |
200 |
(((long)R->HL.W+(long)R->Rg.W+(long)I)&0x10000? C_FLAG:0)| \ |
201 |
(~(R->HL.W^R->Rg.W)&(R->Rg.W^J.W)&0x8000? V_FLAG:0)| \ |
202 |
((R->HL.W^R->Rg.W^J.W)&0x1000? H_FLAG:0)| \ |
203 |
(J.W? 0:Z_FLAG)|(J.B.h&S_FLAG); \ |
204 |
R->HL.W=J.W |
205 |
|
206 |
#define M_SBCW(Rg) \ |
207 |
I=R->AF.B.l&C_FLAG;J.W=(R->HL.W-R->Rg.W-I)&0xFFFF; \ |
208 |
R->AF.B.l= \ |
209 |
N_FLAG| \ |
210 |
(((long)R->HL.W-(long)R->Rg.W-(long)I)&0x10000? C_FLAG:0)| \ |
211 |
((R->HL.W^R->Rg.W)&(R->HL.W^J.W)&0x8000? V_FLAG:0)| \ |
212 |
((R->HL.W^R->Rg.W^J.W)&0x1000? H_FLAG:0)| \ |
213 |
(J.W? 0:Z_FLAG)|(J.B.h&S_FLAG); \ |
214 |
R->HL.W=J.W |
215 |
|
216 |
enum Codes |
217 |
{ |
218 |
NOP,LD_BC_WORD,LD_xBC_A,INC_BC,INC_B,DEC_B,LD_B_BYTE,RLCA, |
219 |
EX_AF_AF,ADD_HL_BC,LD_A_xBC,DEC_BC,INC_C,DEC_C,LD_C_BYTE,RRCA, |
220 |
DJNZ,LD_DE_WORD,LD_xDE_A,INC_DE,INC_D,DEC_D,LD_D_BYTE,RLA, |
221 |
JR,ADD_HL_DE,LD_A_xDE,DEC_DE,INC_E,DEC_E,LD_E_BYTE,RRA, |
222 |
JR_NZ,LD_HL_WORD,LD_xWORD_HL,INC_HL,INC_H,DEC_H,LD_H_BYTE,DAA, |
223 |
JR_Z,ADD_HL_HL,LD_HL_xWORD,DEC_HL,INC_L,DEC_L,LD_L_BYTE,CPL, |
224 |
JR_NC,LD_SP_WORD,LD_xWORD_A,INC_SP,INC_xHL,DEC_xHL,LD_xHL_BYTE,SCF, |
225 |
JR_C,ADD_HL_SP,LD_A_xWORD,DEC_SP,INC_A,DEC_A,LD_A_BYTE,CCF, |
226 |
LD_B_B,LD_B_C,LD_B_D,LD_B_E,LD_B_H,LD_B_L,LD_B_xHL,LD_B_A, |
227 |
LD_C_B,LD_C_C,LD_C_D,LD_C_E,LD_C_H,LD_C_L,LD_C_xHL,LD_C_A, |
228 |
LD_D_B,LD_D_C,LD_D_D,LD_D_E,LD_D_H,LD_D_L,LD_D_xHL,LD_D_A, |
229 |
LD_E_B,LD_E_C,LD_E_D,LD_E_E,LD_E_H,LD_E_L,LD_E_xHL,LD_E_A, |
230 |
LD_H_B,LD_H_C,LD_H_D,LD_H_E,LD_H_H,LD_H_L,LD_H_xHL,LD_H_A, |
231 |
LD_L_B,LD_L_C,LD_L_D,LD_L_E,LD_L_H,LD_L_L,LD_L_xHL,LD_L_A, |
232 |
LD_xHL_B,LD_xHL_C,LD_xHL_D,LD_xHL_E,LD_xHL_H,LD_xHL_L,HALT,LD_xHL_A, |
233 |
LD_A_B,LD_A_C,LD_A_D,LD_A_E,LD_A_H,LD_A_L,LD_A_xHL,LD_A_A, |
234 |
ADD_B,ADD_C,ADD_D,ADD_E,ADD_H,ADD_L,ADD_xHL,ADD_A, |
235 |
ADC_B,ADC_C,ADC_D,ADC_E,ADC_H,ADC_L,ADC_xHL,ADC_A, |
236 |
SUB_B,SUB_C,SUB_D,SUB_E,SUB_H,SUB_L,SUB_xHL,SUB_A, |
237 |
SBC_B,SBC_C,SBC_D,SBC_E,SBC_H,SBC_L,SBC_xHL,SBC_A, |
238 |
AND_B,AND_C,AND_D,AND_E,AND_H,AND_L,AND_xHL,AND_A, |
239 |
XOR_B,XOR_C,XOR_D,XOR_E,XOR_H,XOR_L,XOR_xHL,XOR_A, |
240 |
OR_B,OR_C,OR_D,OR_E,OR_H,OR_L,OR_xHL,OR_A, |
241 |
CP_B,CP_C,CP_D,CP_E,CP_H,CP_L,CP_xHL,CP_A, |
242 |
RET_NZ,POP_BC,JP_NZ,JP,CALL_NZ,PUSH_BC,ADD_BYTE,RST00, |
243 |
RET_Z,RET,JP_Z,PFX_CB,CALL_Z,CALL,ADC_BYTE,RST08, |
244 |
RET_NC,POP_DE,JP_NC,OUTA,CALL_NC,PUSH_DE,SUB_BYTE,RST10, |
245 |
RET_C,EXX,JP_C,INA,CALL_C,PFX_DD,SBC_BYTE,RST18, |
246 |
RET_PO,POP_HL,JP_PO,EX_HL_xSP,CALL_PO,PUSH_HL,AND_BYTE,RST20, |
247 |
RET_PE,LD_PC_HL,JP_PE,EX_DE_HL,CALL_PE,PFX_ED,XOR_BYTE,RST28, |
248 |
RET_P,POP_AF,JP_P,DI,CALL_P,PUSH_AF,OR_BYTE,RST30, |
249 |
RET_M,LD_SP_HL,JP_M,EI,CALL_M,PFX_FD,CP_BYTE,RST38 |
250 |
}; |
251 |
|
252 |
enum CodesCB |
253 |
{ |
254 |
RLC_B,RLC_C,RLC_D,RLC_E,RLC_H,RLC_L,RLC_xHL,RLC_A, |
255 |
RRC_B,RRC_C,RRC_D,RRC_E,RRC_H,RRC_L,RRC_xHL,RRC_A, |
256 |
RL_B,RL_C,RL_D,RL_E,RL_H,RL_L,RL_xHL,RL_A, |
257 |
RR_B,RR_C,RR_D,RR_E,RR_H,RR_L,RR_xHL,RR_A, |
258 |
SLA_B,SLA_C,SLA_D,SLA_E,SLA_H,SLA_L,SLA_xHL,SLA_A, |
259 |
SRA_B,SRA_C,SRA_D,SRA_E,SRA_H,SRA_L,SRA_xHL,SRA_A, |
260 |
SLL_B,SLL_C,SLL_D,SLL_E,SLL_H,SLL_L,SLL_xHL,SLL_A, |
261 |
SRL_B,SRL_C,SRL_D,SRL_E,SRL_H,SRL_L,SRL_xHL,SRL_A, |
262 |
BIT0_B,BIT0_C,BIT0_D,BIT0_E,BIT0_H,BIT0_L,BIT0_xHL,BIT0_A, |
263 |
BIT1_B,BIT1_C,BIT1_D,BIT1_E,BIT1_H,BIT1_L,BIT1_xHL,BIT1_A, |
264 |
BIT2_B,BIT2_C,BIT2_D,BIT2_E,BIT2_H,BIT2_L,BIT2_xHL,BIT2_A, |
265 |
BIT3_B,BIT3_C,BIT3_D,BIT3_E,BIT3_H,BIT3_L,BIT3_xHL,BIT3_A, |
266 |
BIT4_B,BIT4_C,BIT4_D,BIT4_E,BIT4_H,BIT4_L,BIT4_xHL,BIT4_A, |
267 |
BIT5_B,BIT5_C,BIT5_D,BIT5_E,BIT5_H,BIT5_L,BIT5_xHL,BIT5_A, |
268 |
BIT6_B,BIT6_C,BIT6_D,BIT6_E,BIT6_H,BIT6_L,BIT6_xHL,BIT6_A, |
269 |
BIT7_B,BIT7_C,BIT7_D,BIT7_E,BIT7_H,BIT7_L,BIT7_xHL,BIT7_A, |
270 |
RES0_B,RES0_C,RES0_D,RES0_E,RES0_H,RES0_L,RES0_xHL,RES0_A, |
271 |
RES1_B,RES1_C,RES1_D,RES1_E,RES1_H,RES1_L,RES1_xHL,RES1_A, |
272 |
RES2_B,RES2_C,RES2_D,RES2_E,RES2_H,RES2_L,RES2_xHL,RES2_A, |
273 |
RES3_B,RES3_C,RES3_D,RES3_E,RES3_H,RES3_L,RES3_xHL,RES3_A, |
274 |
RES4_B,RES4_C,RES4_D,RES4_E,RES4_H,RES4_L,RES4_xHL,RES4_A, |
275 |
RES5_B,RES5_C,RES5_D,RES5_E,RES5_H,RES5_L,RES5_xHL,RES5_A, |
276 |
RES6_B,RES6_C,RES6_D,RES6_E,RES6_H,RES6_L,RES6_xHL,RES6_A, |
277 |
RES7_B,RES7_C,RES7_D,RES7_E,RES7_H,RES7_L,RES7_xHL,RES7_A, |
278 |
SET0_B,SET0_C,SET0_D,SET0_E,SET0_H,SET0_L,SET0_xHL,SET0_A, |
279 |
SET1_B,SET1_C,SET1_D,SET1_E,SET1_H,SET1_L,SET1_xHL,SET1_A, |
280 |
SET2_B,SET2_C,SET2_D,SET2_E,SET2_H,SET2_L,SET2_xHL,SET2_A, |
281 |
SET3_B,SET3_C,SET3_D,SET3_E,SET3_H,SET3_L,SET3_xHL,SET3_A, |
282 |
SET4_B,SET4_C,SET4_D,SET4_E,SET4_H,SET4_L,SET4_xHL,SET4_A, |
283 |
SET5_B,SET5_C,SET5_D,SET5_E,SET5_H,SET5_L,SET5_xHL,SET5_A, |
284 |
SET6_B,SET6_C,SET6_D,SET6_E,SET6_H,SET6_L,SET6_xHL,SET6_A, |
285 |
SET7_B,SET7_C,SET7_D,SET7_E,SET7_H,SET7_L,SET7_xHL,SET7_A |
286 |
}; |
287 |
|
288 |
enum CodesED |
289 |
{ |
290 |
DB_00,DB_01,DB_02,DB_03,DB_04,DB_05,DB_06,DB_07, |
291 |
DB_08,DB_09,DB_0A,DB_0B,DB_0C,DB_0D,DB_0E,DB_0F, |
292 |
DB_10,DB_11,DB_12,DB_13,DB_14,DB_15,DB_16,DB_17, |
293 |
DB_18,DB_19,DB_1A,DB_1B,DB_1C,DB_1D,DB_1E,DB_1F, |
294 |
DB_20,DB_21,DB_22,DB_23,DB_24,DB_25,DB_26,DB_27, |
295 |
DB_28,DB_29,DB_2A,DB_2B,DB_2C,DB_2D,DB_2E,DB_2F, |
296 |
DB_30,DB_31,DB_32,DB_33,DB_34,DB_35,DB_36,DB_37, |
297 |
DB_38,DB_39,DB_3A,DB_3B,DB_3C,DB_3D,DB_3E,DB_3F, |
298 |
IN_B_xC,OUT_xC_B,SBC_HL_BC,LD_xWORDe_BC,NEG,RETN,IM_0,LD_I_A, |
299 |
IN_C_xC,OUT_xC_C,ADC_HL_BC,LD_BC_xWORDe,DB_4C,RETI,DB_,LD_R_A, |
300 |
IN_D_xC,OUT_xC_D,SBC_HL_DE,LD_xWORDe_DE,DB_54,DB_55,IM_1,LD_A_I, |
301 |
IN_E_xC,OUT_xC_E,ADC_HL_DE,LD_DE_xWORDe,DB_5C,DB_5D,IM_2,LD_A_R, |
302 |
IN_H_xC,OUT_xC_H,SBC_HL_HL,LD_xWORDe_HL,DB_64,DB_65,DB_66,RRD, |
303 |
IN_L_xC,OUT_xC_L,ADC_HL_HL,LD_HL_xWORDe,DB_6C,DB_6D,DB_6E,RLD, |
304 |
IN_F_xC,DB_71,SBC_HL_SP,LD_xWORDe_SP,DB_74,DB_75,DB_76,DB_77, |
305 |
IN_A_xC,OUT_xC_A,ADC_HL_SP,LD_SP_xWORDe,DB_7C,DB_7D,DB_7E,DB_7F, |
306 |
DB_80,DB_81,DB_82,DB_83,DB_84,DB_85,DB_86,DB_87, |
307 |
DB_88,DB_89,DB_8A,DB_8B,DB_8C,DB_8D,DB_8E,DB_8F, |
308 |
DB_90,DB_91,DB_92,DB_93,DB_94,DB_95,DB_96,DB_97, |
309 |
DB_98,DB_99,DB_9A,DB_9B,DB_9C,DB_9D,DB_9E,DB_9F, |
310 |
LDI,CPI,INI,OUTI,DB_A4,DB_A5,DB_A6,DB_A7, |
311 |
LDD,CPD,IND,OUTD,DB_AC,DB_AD,DB_AE,DB_AF, |
312 |
LDIR,CPIR,INIR,OTIR,DB_B4,DB_B5,DB_B6,DB_B7, |
313 |
LDDR,CPDR,INDR,OTDR,DB_BC,DB_BD,DB_BE,DB_BF, |
314 |
DB_C0,DB_C1,DB_C2,DB_C3,DB_C4,DB_C5,DB_C6,DB_C7, |
315 |
DB_C8,DB_C9,DB_CA,DB_CB,DB_CC,DB_CD,DB_CE,DB_CF, |
316 |
DB_D0,DB_D1,DB_D2,DB_D3,DB_D4,DB_D5,DB_D6,DB_D7, |
317 |
DB_D8,DB_D9,DB_DA,DB_DB,DB_DC,DB_DD,DB_DE,DB_DF, |
318 |
DB_E0,DB_E1,DB_E2,DB_E3,DB_E4,DB_E5,DB_E6,DB_E7, |
319 |
DB_E8,DB_E9,DB_EA,DB_EB,DB_EC,DB_ED,DB_EE,DB_EF, |
320 |
DB_F0,DB_F1,DB_F2,DB_F3,DB_F4,DB_F5,DB_F6,DB_F7, |
321 |
DB_F8,DB_F9,DB_FA,DB_FB,DB_FC,DB_FD,DB_FE,DB_FF |
322 |
}; |
323 |
|
324 |
static void CodesCB(register Z80 *R) |
325 |
{ |
326 |
register byte I; |
327 |
|
328 |
I=RdZ80(R->PC.W++); |
329 |
R->ICount-=CyclesCB[I]; |
330 |
switch(I) |
331 |
{ |
332 |
#include "CodesCB.h" |
333 |
default: |
334 |
if(R->TrapBadOps) |
335 |
printf |
336 |
( |
337 |
"[Z80 %lX] Unrecognized instruction: CB %02X at PC=%04X\n", |
338 |
(long)(R->User),RdZ80(R->PC.W-1),R->PC.W-2 |
339 |
); |
340 |
} |
341 |
} |
342 |
|
343 |
static void CodesDDCB(register Z80 *R) |
344 |
{ |
345 |
register pair J; |
346 |
register byte I; |
347 |
|
348 |
#define XX IX |
349 |
J.W=R->XX.W+(offset)RdZ80(R->PC.W++); |
350 |
I=RdZ80(R->PC.W++); |
351 |
R->ICount-=CyclesXXCB[I]; |
352 |
switch(I) |
353 |
{ |
354 |
#include "CodesXCB.h" |
355 |
default: |
356 |
if(R->TrapBadOps) |
357 |
printf |
358 |
( |
359 |
"[Z80 %lX] Unrecognized instruction: DD CB %02X %02X at PC=%04X\n", |
360 |
(long)(R->User),RdZ80(R->PC.W-2),RdZ80(R->PC.W-1),R->PC.W-4 |
361 |
); |
362 |
} |
363 |
#undef XX |
364 |
} |
365 |
|
366 |
static void CodesFDCB(register Z80 *R) |
367 |
{ |
368 |
register pair J; |
369 |
register byte I; |
370 |
|
371 |
#define XX IY |
372 |
J.W=R->XX.W+(offset)RdZ80(R->PC.W++); |
373 |
I=RdZ80(R->PC.W++); |
374 |
R->ICount-=CyclesXXCB[I]; |
375 |
switch(I) |
376 |
{ |
377 |
#include "CodesXCB.h" |
378 |
default: |
379 |
if(R->TrapBadOps) |
380 |
printf |
381 |
( |
382 |
"[Z80 %lX] Unrecognized instruction: FD CB %02X %02X at PC=%04X\n", |
383 |
(long)R->User,RdZ80(R->PC.W-2),RdZ80(R->PC.W-1),R->PC.W-4 |
384 |
); |
385 |
} |
386 |
#undef XX |
387 |
} |
388 |
|
389 |
static void CodesED(register Z80 *R) |
390 |
{ |
391 |
register byte I; |
392 |
register pair J; |
393 |
|
394 |
I=RdZ80(R->PC.W++); |
395 |
R->ICount-=CyclesED[I]; |
396 |
switch(I) |
397 |
{ |
398 |
#include "CodesED.h" |
399 |
case PFX_ED: |
400 |
R->PC.W--;break; |
401 |
default: |
402 |
if(R->TrapBadOps) |
403 |
printf |
404 |
( |
405 |
"[Z80 %lX] Unrecognized instruction: ED %02X at PC=%04X\n", |
406 |
(long)R->User,RdZ80(R->PC.W-1),R->PC.W-2 |
407 |
); |
408 |
} |
409 |
} |
410 |
|
411 |
static void CodesDD(register Z80 *R) |
412 |
{ |
413 |
register byte I; |
414 |
register pair J; |
415 |
|
416 |
#define XX IX |
417 |
I=RdZ80(R->PC.W++); |
418 |
R->ICount-=CyclesXX[I]; |
419 |
switch(I) |
420 |
{ |
421 |
#include "CodesXX.h" |
422 |
case PFX_FD: |
423 |
case PFX_DD: |
424 |
R->PC.W--;break; |
425 |
case PFX_CB: |
426 |
CodesDDCB(R);break; |
427 |
default: |
428 |
if(R->TrapBadOps) |
429 |
printf |
430 |
( |
431 |
"[Z80 %lX] Unrecognized instruction: DD %02X at PC=%04X\n", |
432 |
(long)R->User,RdZ80(R->PC.W-1),R->PC.W-2 |
433 |
); |
434 |
} |
435 |
#undef XX |
436 |
} |
437 |
|
438 |
static void CodesFD(register Z80 *R) |
439 |
{ |
440 |
register byte I; |
441 |
register pair J; |
442 |
|
443 |
#define XX IY |
444 |
I=RdZ80(R->PC.W++); |
445 |
R->ICount-=CyclesXX[I]; |
446 |
switch(I) |
447 |
{ |
448 |
#include "CodesXX.h" |
449 |
case PFX_FD: |
450 |
case PFX_DD: |
451 |
R->PC.W--;break; |
452 |
case PFX_CB: |
453 |
CodesFDCB(R);break; |
454 |
default: |
455 |
printf |
456 |
( |
457 |
"Unrecognized instruction: FD %02X at PC=%04X\n", |
458 |
RdZ80(R->PC.W-1),R->PC.W-2 |
459 |
); |
460 |
} |
461 |
#undef XX |
462 |
} |
463 |
|
464 |
/** ResetZ80() ***********************************************/ |
465 |
/** This function can be used to reset the register struct **/ |
466 |
/** before starting execution with Z80(). It sets the **/ |
467 |
/** registers to their supposed initial values. **/ |
468 |
/*************************************************************/ |
469 |
void ResetZ80(Z80 *R) |
470 |
{ |
471 |
R->PC.W = 0x0000; |
472 |
R->SP.W = 0xF000; |
473 |
R->AF.W = 0x0000; |
474 |
R->BC.W = 0x0000; |
475 |
R->DE.W = 0x0000; |
476 |
R->HL.W = 0x0000; |
477 |
R->AF1.W = 0x0000; |
478 |
R->BC1.W = 0x0000; |
479 |
R->DE1.W = 0x0000; |
480 |
R->HL1.W = 0x0000; |
481 |
R->IX.W = 0x0000; |
482 |
R->IY.W = 0x0000; |
483 |
R->I = 0x00; |
484 |
R->IFF = 0x00; |
485 |
R->ICount = R->IPeriod; |
486 |
R->IRequest = INT_NONE; |
487 |
|
488 |
JumpZ80(R->PC.W); |
489 |
} |
490 |
|
491 |
/** ExecZ80() ************************************************/ |
492 |
/** This function will execute given number of Z80 cycles. **/ |
493 |
/** It will then return the number of cycles left, possibly **/ |
494 |
/** negative, and current register values in R. **/ |
495 |
/*************************************************************/ |
496 |
#ifdef EXECZ80 |
497 |
int ExecZ80(register Z80 *R,register int RunCycles) |
498 |
{ |
499 |
register byte I; |
500 |
register pair J; |
501 |
|
502 |
while(RunCycles>0) |
503 |
{ |
504 |
#ifdef DEBUG |
505 |
/* Turn tracing on when reached trap address */ |
506 |
if(R->PC.W==R->Trap) R->Trace=1; |
507 |
/* Call single-step debugger, exit if requested */ |
508 |
if(R->Trace) |
509 |
if(!DebugZ80(R)) return(RunCycles); |
510 |
#endif |
511 |
|
512 |
/* Read opcode and count cycles */ |
513 |
I=RdZ80(R->PC.W++); |
514 |
/* Count cycles */ |
515 |
RunCycles-=Cycles[I]; |
516 |
|
517 |
/* Interpret opcode */ |
518 |
switch(I) |
519 |
{ |
520 |
#include "Codes.h" |
521 |
case PFX_CB: CodesCB(R);break; |
522 |
case PFX_ED: CodesED(R);break; |
523 |
case PFX_FD: CodesFD(R);break; |
524 |
case PFX_DD: CodesDD(R);break; |
525 |
} |
526 |
} |
527 |
|
528 |
/* We are done */ |
529 |
return(RunCycles); |
530 |
} |
531 |
#endif /* EXECZ80 */ |
532 |
|
533 |
/** IntZ80() *************************************************/ |
534 |
/** This function will generate interrupt of given vector. **/ |
535 |
/*************************************************************/ |
536 |
void IntZ80(Z80 *R,word Vector) |
537 |
{ |
538 |
if((R->IFF&IFF_1)||(Vector==INT_NMI)) |
539 |
{ |
540 |
/* If HALTed, take CPU off HALT instruction */ |
541 |
if(R->IFF&IFF_HALT) { R->PC.W++;R->IFF&=~IFF_HALT; } |
542 |
|
543 |
/* Save PC on stack */ |
544 |
M_PUSH(PC); |
545 |
|
546 |
/* Automatically reset IRequest if needed */ |
547 |
if(R->IAutoReset&&(Vector==R->IRequest)) R->IRequest=INT_NONE; |
548 |
|
549 |
/* If it is NMI... */ |
550 |
if(Vector==INT_NMI) |
551 |
{ |
552 |
/* Clear IFF1 */ |
553 |
R->IFF&=~(IFF_1|IFF_EI); |
554 |
/* Jump to hardwired NMI vector */ |
555 |
R->PC.W=0x0066; |
556 |
JumpZ80(0x0066); |
557 |
/* Done */ |
558 |
return; |
559 |
} |
560 |
|
561 |
/* Further interrupts off */ |
562 |
R->IFF&=~(IFF_1|IFF_2|IFF_EI); |
563 |
|
564 |
/* If in IM2 mode... */ |
565 |
if(R->IFF&IFF_IM2) |
566 |
{ |
567 |
/* Make up the vector address */ |
568 |
Vector=(Vector&0xFF)|((word)(R->I)<<8); |
569 |
/* Read the vector */ |
570 |
R->PC.B.l=RdZ80(Vector++); |
571 |
R->PC.B.h=RdZ80(Vector); |
572 |
JumpZ80(R->PC.W); |
573 |
/* Done */ |
574 |
return; |
575 |
} |
576 |
|
577 |
/* If in IM1 mode, just jump to hardwired IRQ vector */ |
578 |
if(R->IFF&IFF_IM1) { R->PC.W=0x0038;JumpZ80(0x0038);return; } |
579 |
|
580 |
/* If in IM0 mode... */ |
581 |
|
582 |
/* Jump to a vector */ |
583 |
switch(Vector) |
584 |
{ |
585 |
case INT_RST00: R->PC.W=0x0000;JumpZ80(0x0000);break; |
586 |
case INT_RST08: R->PC.W=0x0008;JumpZ80(0x0008);break; |
587 |
case INT_RST10: R->PC.W=0x0010;JumpZ80(0x0010);break; |
588 |
case INT_RST18: R->PC.W=0x0018;JumpZ80(0x0018);break; |
589 |
case INT_RST20: R->PC.W=0x0020;JumpZ80(0x0020);break; |
590 |
case INT_RST28: R->PC.W=0x0028;JumpZ80(0x0028);break; |
591 |
case INT_RST30: R->PC.W=0x0030;JumpZ80(0x0030);break; |
592 |
case INT_RST38: R->PC.W=0x0038;JumpZ80(0x0038);break; |
593 |
} |
594 |
} |
595 |
} |
596 |
|
597 |
/** RunZ80() *************************************************/ |
598 |
/** This function will run Z80 code until an LoopZ80() call **/ |
599 |
/** returns INT_QUIT. It will return the PC at which **/ |
600 |
/** emulation stopped, and current register values in R. **/ |
601 |
/*************************************************************/ |
602 |
#ifndef EXECZ80 |
603 |
word RunZ80(Z80 *R) |
604 |
{ |
605 |
register byte I; |
606 |
register pair J; |
607 |
|
608 |
for(;;) |
609 |
{ |
610 |
#ifdef DEBUG |
611 |
/* Turn tracing on when reached trap address */ |
612 |
if(R->PC.W==R->Trap) R->Trace=1; |
613 |
/* Call single-step debugger, exit if requested */ |
614 |
if(R->Trace) |
615 |
if(!DebugZ80(R)) return(R->PC.W); |
616 |
#endif |
617 |
|
618 |
I=RdZ80(R->PC.W++); |
619 |
R->ICount-=Cycles[I]; |
620 |
switch(I) |
621 |
{ |
622 |
#include "Codes.h" |
623 |
case PFX_CB: CodesCB(R);break; |
624 |
case PFX_ED: CodesED(R);break; |
625 |
case PFX_FD: CodesFD(R);break; |
626 |
case PFX_DD: CodesDD(R);break; |
627 |
} |
628 |
|
629 |
/* If cycle counter expired... */ |
630 |
if(R->ICount<=0) |
631 |
{ |
632 |
/* If we have come after EI, get address from IRequest */ |
633 |
/* Otherwise, get it from the loop handler */ |
634 |
if(R->IFF&IFF_EI) |
635 |
{ |
636 |
R->IFF=(R->IFF&~IFF_EI)|IFF_1; /* Done with AfterEI state */ |
637 |
R->ICount+=R->IBackup-1; /* Restore the ICount */ |
638 |
|
639 |
/* Call periodic handler or set pending IRQ */ |
640 |
if(R->ICount>0) J.W=R->IRequest; |
641 |
else |
642 |
{ |
643 |
J.W=LoopZ80(R); /* Call periodic handler */ |
644 |
R->ICount+=R->IPeriod; /* Reset the cycle counter */ |
645 |
if(J.W==INT_NONE) J.W=R->IRequest; /* Pending IRQ */ |
646 |
} |
647 |
} |
648 |
else |
649 |
{ |
650 |
J.W=LoopZ80(R); /* Call periodic handler */ |
651 |
R->ICount+=R->IPeriod; /* Reset the cycle counter */ |
652 |
if(J.W==INT_NONE) J.W=R->IRequest; /* Pending IRQ */ |
653 |
} |
654 |
|
655 |
if(J.W==INT_QUIT) return(R->PC.W); /* Exit if INT_QUIT */ |
656 |
if(J.W!=INT_NONE) IntZ80(R,J.W); /* Int-pt if needed */ |
657 |
} |
658 |
} |
659 |
|
660 |
/* Execution stopped */ |
661 |
return(R->PC.W); |
662 |
} |
663 |
#endif /* !EXECZ80 */ |