Xemu [doxygen]  hyppo 0a42be3a057156924bc1b626a687bd6e27349c45 @ Sat 19 Mar 02:15:11 CET 2022
z80ex.c
Go to the documentation of this file.
1 /*
2  * Z80Ex, ZILoG Z80 CPU emulator.
3  *
4  * by Pigmaker57 aka boo_boo [pigmaker57@kahoh57.info]
5  * modified by Gabor Lenart LGB [lgblgblgb@gmail.com] for Xep128 project
6  * used by Gabor Lenart LGB [lgblgblgb@gmail.com] in Xemu project
7  * my modifications (C)2015,2016,2017
8  *
9  * contains some code from the FUSE project (http://fuse-emulator.sourceforge.net)
10  * Released under GNU GPL v2
11  *
12  */
13 
14 #include <assert.h>
15 #include <stdlib.h>
16 #include <string.h>
17 
18 #include "xemu/z80ex/z80ex.h"
19 #include "xemu/z80ex/macros.h"
20 
22 
23 #define temp_byte z80ex.tmpbyte
24 #define temp_byte_s z80ex.tmpbyte_s
25 #define temp_addr z80ex.tmpaddr
26 #define temp_word z80ex.tmpword
27 
28 typedef void (*z80ex_opcode_fn) (void);
29 
30 #ifdef Z80EX_Z180_BY_DEFAULT
31 #define Z180_LIKELY XEMU_LIKELY
32 #else
33 #define Z180_LIKELY XEMU_UNLIKELY
34 #endif
35 
36 #include "xemu/z80ex/ptables.c"
38 #include "xemu/z80ex/opcodes_dd.c"
39 #include "xemu/z80ex/opcodes_fd.c"
40 #include "xemu/z80ex/opcodes_cb.c"
41 #include "xemu/z80ex/opcodes_ed.c"
44 #include "xemu/z80ex/z180ex.c"
45 
46 /* do one opcode (instruction or prefix) */
47 int z80ex_step(void)
48 {
49  Z80EX_BYTE opcode, d;
50  z80ex_opcode_fn ofn = NULL;
51 
52  z80ex.doing_opcode = 1;
53  z80ex.noint_once = 0;
55  z80ex.tstate = 0;
56  z80ex.op_tstate = 0;
57 
58  opcode = READ_OP_M1(); /* fetch opcode */
60  {
61  TSTATES(2); /* interrupt eats two extra wait-states */
62  }
63  R++; /* R increased by one on every first M1 cycle */
64 
65  T_WAIT_UNTIL(4); /* M1 cycle eats min 4 t-states */
66 
67  if (!z80ex.prefix)
68  opcodes_base[opcode]();
69  else {
70  if ((z80ex.prefix | 0x20) == 0xFD && ((opcode | 0x20) == 0xFD || opcode == 0xED)) {
71  z80ex.prefix = opcode;
72  z80ex.noint_once = 1; /* interrupts are not accepted immediately after prefix */
73  } else {
74  switch (z80ex.prefix) {
75  case 0xDD:
76  case 0xFD:
77  if (opcode == 0xCB) { /* FD/DD prefixed CB opcodes */
78  d = READ_OP(); /* displacement */
79  temp_byte_s = (d & 0x80)? -(((~d) & 0x7f)+1): d;
80  opcode = READ_OP();
81 #ifdef Z80EX_Z180_SUPPORT
82  if (Z180_LIKELY(z80ex.z180)) {
83  if (XEMU_UNLIKELY((opcode & 7) != 6 || opcode == 0x36))
84  ofn = trapping(z80ex.prefix, 0xCB, opcode, ITC_B3);
85  else
86  ofn = (z80ex.prefix == 0xDD) ? opcodes_ddcb[opcode] : opcodes_fdcb[opcode];
87  } else
88 #endif
89  ofn = (z80ex.prefix == 0xDD) ? opcodes_ddcb[opcode] : opcodes_fdcb[opcode];
90  } else { /* FD/DD prefixed base opcodes */
91 #ifdef Z80EX_Z180_SUPPORT
92  if (XEMU_UNLIKELY(z80ex.z180 && opcodes_ddfd_bad_for_z180[opcode])) {
93  ofn = trapping(z80ex.prefix, 0x00, opcode, ITC_B2);
94  } else {
95 #endif
96  ofn = (z80ex.prefix == 0xDD) ? opcodes_dd[opcode] : opcodes_fd[opcode];
97  if (XEMU_UNLIKELY(ofn == NULL)) ofn = opcodes_base[opcode]; /* 'mirrored' instructions NOTE: this should NOT happen with Z180! */
98 #ifdef Z80EX_Z180_SUPPORT
99  }
100 #endif
101  }
102  break;
103 
104  case 0xED: /* ED opcodes */
105 #ifdef Z80EX_ED_TRAPPING_SUPPORT
106  if (XEMU_UNLIKELY(opcode > 0xBB)) {
107  /* check if ED-trap emu func accepted the opcode as its own "faked" */
108  if (z80ex_ed_cb(opcode)) {
109  ofn = opcodes_base[0x00];
110  break;
111  }
112  }
113 #endif
114 #ifdef Z80EX_Z180_SUPPORT
115  if (Z180_LIKELY(z80ex.z180))
116  ofn = opcodes_ed_z180[opcode];
117  else
118 #endif
119  ofn = opcodes_ed[opcode];
120  if (ofn == NULL) {
121 #ifdef Z80EX_Z180_SUPPORT
122  if (XEMU_UNLIKELY(z80ex.z180))
123  ofn = trapping(0x00, 0xED, opcode, ITC_B2);
124  else
125 #endif
126  ofn = opcodes_base[0x00];
127  }
128  break;
129 
130  case 0xCB: /* CB opcodes */
131 #ifdef Z80EX_Z180_SUPPORT
132  if (XEMU_UNLIKELY(z80ex.z180 && (opcode & 0xF8) == 0x30))
133  ofn = trapping(0x00, 0xCB, opcode, ITC_B2);
134  else
135 #endif
136  ofn = opcodes_cb[opcode];
137  break;
138 
139  default:
140  /* this must'nt happen! */
141  assert(0);
142  break;
143  }
144 
145  ofn();
146 
147  z80ex.prefix = 0;
148  }
149  }
150 
151  z80ex.doing_opcode = 0;
152  return z80ex.tstate;
153 }
154 
155 
156 void z80ex_reset ( void )
157 {
158  PC = 0x0000; IFF1 = IFF2 = 0; IM = IM0;
159  AF= SP = BC = DE = HL = IX = IY = AF_ = BC_ = DE_ = HL_ = 0xffff;
160  I = R = R7 = 0;
162  z80ex.int_vector_req = 0;
163  z80ex.doing_opcode = 0;
164  z80ex.tstate = z80ex.op_tstate = 0;
165  z80ex.prefix = 0;
166 #ifdef Z80EX_Z180_SUPPORT
167  z80ex.internal_int_disable = 0;
168 #endif
169 }
170 
171 
172 
173 
174 
175 void z80ex_init ( void )
176 {
177  memset(&z80ex, 0x00, sizeof(Z80EX_CONTEXT));
178 
179  z80ex_reset();
180 
181  z80ex.nmos = 1;
182 #ifdef Z80EX_HAVE_TSTATE_CB_VAR
183  z80ex.tstate_cb = 0;
184 #endif
185 #ifdef Z80EX_Z180_SUPPORT
186  z80ex.internal_int_disable = 0;
187  z80ex.z180 = 0;
188 #endif
189 }
190 
191 /*non-maskable interrupt*/
192 int z80ex_nmi(void)
193 {
194  if (z80ex.doing_opcode || z80ex.noint_once || z80ex.prefix) return 0;
195 
196  if (z80ex.halted) {
197  /*so we met an interrupt... stop waiting*/
198  PC++;
199  z80ex.halted = 0;
200  }
201 
202  z80ex.doing_opcode = 1;
203 
204  R++; /* accepting interrupt increases R by one */
205  /*IFF2=IFF1;*/ /* contrary to zilog z80 docs, IFF2 is not modified on NMI. proved by Slava Tretiak aka restorer */
206  IFF1 = 0;
207 
208  TSTATES(5);
209 
210  z80ex_mwrite_cb(--SP, z80ex.pc.b.h); /* PUSH PC -- high byte */
211  TSTATES(3);
212 
213  z80ex_mwrite_cb(--SP, z80ex.pc.b.l); /* PUSH PC -- low byte */
214  TSTATES(3);
215 
216  PC = 0x0066;
217  MEMPTR = PC; /* FIXME: is that really so? */
218 
219  z80ex.doing_opcode = 0;
220 
221  return 11; /* NMI always takes 11 t-states */
222 }
223 
224 /*maskable interrupt*/
225 int z80ex_int(void)
226 {
227  Z80EX_WORD inttemp;
228  Z80EX_BYTE iv;
229  unsigned long tt;
230 
231  /* If the INT line is low and IFF1 is set, and there's no opcode executing just now,
232  a maskable interrupt is accepted, whether or not the
233  last INT routine has finished */
234  if (
236 #ifdef Z80EX_Z180_SUPPORT
237  || z80ex.internal_int_disable
238 #endif
239  ) return 0;
240 
241  z80ex.tstate = 0;
242  z80ex.op_tstate = 0;
243 
244  if (z80ex.halted) {
245  /* so we met an interrupt... stop waiting */
246  PC++;
247  z80ex.halted = 0;
248  }
249 
250  /* When an INT is accepted, both IFF1 and IFF2 are cleared, preventing another interrupt from
251  occurring which would end up as an infinite loop */
252  IFF1 = IFF2 = 0;
253 
254  /* original (NMOS) zilog z80 bug: */
255  /* If a LD A,I or LD A,R (which copy IFF2 to the P/V flag) is interrupted, then the P/V flag is reset, even if interrupts were enabled beforehand. */
256  /* (this bug was fixed in CMOS version of z80) */
257  if (z80ex.reset_PV_on_int) {
258  F = (F & ~FLAG_P);
259  }
261 
262  z80ex.int_vector_req = 1;
263  z80ex.doing_opcode = 1;
264 
265  switch (IM) {
266  case IM0:
267  /* note: there's no need to do R++ and WAITs here, it'll be handled by z80ex_step */
268  tt = z80ex_step();
269  while(z80ex.prefix) { /* this is not the end? */
270  tt+=z80ex_step();
271  }
272  z80ex.tstate = tt;
273  break;
274 
275  case IM1:
276  R++;
277  TSTATES(2); /* two extra wait-states */
278  /* An RST 38h is executed, no matter what value is put on the bus or what
279  value the I register has. 13 t-states (2 extra + 11 for RST). */
280  opcodes_base[0xff](); /* RST 38 */
281  break;
282 
283  case IM2:
284  R++;
285  /* takes 19 clock periods to complete (seven to fetch the
286  lower eight bits from the interrupting device, six to save the program
287  counter, and six to obtain the jump address) */
288  iv=READ_OP();
289  T_WAIT_UNTIL(7);
290  inttemp = (0x100 * I) + iv;
291 
292  PUSH(PC, 7, 10);
293 
294  READ_MEM(PCL, inttemp++, 13); READ_MEM(PCH, inttemp, 16);
295  MEMPTR = PC;
296  T_WAIT_UNTIL(19);
297 
298  break;
299  }
300 
301  z80ex.doing_opcode = 0;
302  z80ex.int_vector_req = 0;
303 
304  return z80ex.tstate;
305 }
306 
307 void z80ex_w_states(unsigned w_states)
308 {
309  TSTATES(w_states);
310 }
311 
313 {
314 #ifdef Z80EX_TSTATE_CALLBACK
316 #endif
317  z80ex.tstate++;
318  z80ex.op_tstate++;
319 }
320 
321 /*int z80ex_get_noint_once(Z80EX_CONTEXT *cpu)
322 {
323  return z80ex.noint_once;
324 }*/
325 
326 /*returns 1 if maskable interrupts are possible in current z80 state*/
328 {
329  return ((!IFF1 || z80ex.noint_once || z80ex.doing_opcode || z80ex.prefix) ? 0 : 1);
330 }
331 
332 /*returns 1 if non-maskable interrupts are possible in current z80 state*/
334 {
335  return ((z80ex.noint_once || z80ex.doing_opcode || z80ex.prefix) ? 0 : 1);
336 }
337 
Z80EX_Z180_SUPPORT
#define Z80EX_Z180_SUPPORT
Definition: xemu-target.h:6
z80ex_ed_cb
int z80ex_ed_cb(Z80EX_BYTE opcode)
Definition: cpu.c:586
z80ex_init
void z80ex_init(void)
Definition: z80ex.c:175
FLAG_P
#define FLAG_P
Definition: macros.h:81
PCL
#define PCL
Definition: macros.h:62
z80ex_w_states
void z80ex_w_states(unsigned w_states)
Definition: z80ex.c:307
BC_
#define BC_
Definition: macros.h:39
_z80_cpu_context::nmos
int nmos
Definition: z80ex.h:175
R
#define R
Definition: macros.h:66
Z80EX_REGPAIR_T::b
struct Z80EX_REGPAIR_T::@66 b
BC
#define BC
Definition: macros.h:23
IS_TSTATE_CB
#define IS_TSTATE_CB
Definition: z80ex.h:23
z80ex_step
int z80ex_step(void)
Definition: z80ex.c:47
opcodes_ed.c
z80ex.h
T_WAIT_UNTIL
#define T_WAIT_UNTIL(t_state)
Definition: macros.h:119
z80ex_mwrite_cb
void z80ex_mwrite_cb(Z80EX_WORD addr, Z80EX_BYTE value)
Definition: cpu.c:278
IM2
@ IM2
Definition: z80ex.h:67
macros.h
F
#define F
Definition: macros.h:18
opcodes_fd.c
AF_
#define AF_
Definition: macros.h:35
_z80_cpu_context::doing_opcode
int doing_opcode
Definition: z80ex.h:161
_z80_cpu_context::tstate
unsigned long tstate
Definition: z80ex.h:156
PUSH
#define PUSH(rp, wr1, wr2)
Definition: macros.h:432
Z180_LIKELY
#define Z180_LIKELY
Definition: z80ex.c:33
z80ex_int
int z80ex_int(void)
Definition: z80ex.c:225
Z80EX_WORD
unsigned short Z80EX_WORD
Definition: z80ex.h:51
z80ex_reset
void z80ex_reset(void)
Definition: z80ex.c:156
IFF1
#define IFF1
Definition: macros.h:69
_z80_cpu_context
Definition: z80ex.h:143
Z80EX_REGPAIR_T::h
Z80EX_BYTE h
Definition: z80ex.h:62
opcodes_ddcb.c
HL_
#define HL_
Definition: macros.h:47
HL
#define HL
Definition: macros.h:31
ptables.c
SP
#define SP
Definition: macros.h:59
emutools_basicdefs.h
IM0
@ IM0
Definition: z80ex.h:67
_z80_cpu_context::halted
int halted
Definition: z80ex.h:154
_z80_cpu_context::reset_PV_on_int
int reset_PV_on_int
Definition: z80ex.h:160
z80ex_next_t_state
void z80ex_next_t_state(void)
Definition: z80ex.c:312
DE_
#define DE_
Definition: macros.h:43
z80ex_opcode_fn
void(* z80ex_opcode_fn)(void)
Definition: z80ex.c:28
Z80EX_BYTE
unsigned char Z80EX_BYTE
Definition: z80ex.h:49
IX
#define IX
Definition: macros.h:51
IM
#define IM
Definition: macros.h:71
Z80EX_REGPAIR_T::l
Z80EX_BYTE l
Definition: z80ex.h:62
_z80_cpu_context::prefix
Z80EX_BYTE prefix
Definition: z80ex.h:163
TSTATES
#define TSTATES(amount)
Definition: macros.h:143
READ_OP
#define READ_OP()
Definition: macros.h:93
MEMPTR
#define MEMPTR
Definition: macros.h:75
z180ex.c
PCH
#define PCH
Definition: macros.h:61
opcodes_fdcb.c
_z80_cpu_context::int_vector_req
char int_vector_req
Definition: z80ex.h:162
R7
#define R7
Definition: macros.h:67
I
#define I
Definition: macros.h:65
DE
#define DE
Definition: macros.h:27
AF
#define AF
Definition: macros.h:19
temp_byte_s
#define temp_byte_s
Definition: z80ex.c:24
z80ex_nmi_possible
int z80ex_nmi_possible(void)
Definition: z80ex.c:333
opcodes_dd.c
READ_OP_M1
#define READ_OP_M1()
Definition: macros.h:90
PC
#define PC
Definition: macros.h:63
_z80_cpu_context::op_tstate
unsigned char op_tstate
Definition: z80ex.h:157
IM1
@ IM1
Definition: z80ex.h:67
IY
#define IY
Definition: macros.h:55
z80ex_int_possible
int z80ex_int_possible(void)
Definition: z80ex.c:327
opcodes_cb.c
z80ex
Z80EX_CONTEXT z80ex
Definition: primo.c:37
z80ex_nmi
int z80ex_nmi(void)
Definition: z80ex.c:192
_z80_cpu_context::pc
Z80EX_REGPAIR_T pc
Definition: z80ex.h:150
IFF2
#define IFF2
Definition: macros.h:70
_z80_cpu_context::noint_once
int noint_once
Definition: z80ex.h:159
READ_MEM
#define READ_MEM(result, addr, t_state)
Definition: macros.h:147
XEMU_UNLIKELY
#define XEMU_UNLIKELY(__x__)
Definition: emutools_basicdefs.h:125
z80ex_tstate_cb
void z80ex_tstate_cb(void)
Definition: spectrum.c:113
opcodes_base.c