1 /*
2 * Z80Ex, ZILoG Z80 CPU emulator.
3 *
4 * by Pigmaker57 aka boo_boo [pigmaker57@kahoh57.info]
5 *
6 * contains some code from the FUSE project (http://fuse-emulator.sourceforge.net)
7 * Released under GNU GPL v2
8 *
9 */
10
11 #include <assert.h>
12 #include <stdlib.h>
13 #include <string.h>
14
15 #define __Z80EX_SELF_INCLUDE
16
17 #include "typedefs.h"
18 #include "z80ex.h"
19 #include "macros.h"
20
21 #define temp_byte cpu->tmpbyte
22 #define temp_byte_s cpu->tmpbyte_s
23 #define temp_addr cpu->tmpaddr
24 #define temp_word cpu->tmpword
25
26 #include "ptables.c"
27 #include "opcodes/opcodes_base.c"
28 #include "opcodes/opcodes_dd.c"
29 #include "opcodes/opcodes_fd.c"
30 #include "opcodes/opcodes_cb.c"
31 #include "opcodes/opcodes_ed.c"
32 #include "opcodes/opcodes_ddcb.c"
33 #include "opcodes/opcodes_fdcb.c"
34
35 #define DOQUOTE(x) #x
36 #define TOSTRING(x) DOQUOTE(x)
37
38 static char revision_type[]=TOSTRING(Z80EX_RELEASE_TYPE);
39 static char ver_str[]=TOSTRING(Z80EX_VERSION_STR);
40 static Z80EX_VERSION version = {Z80EX_API_REVISION, Z80EX_VERSION_MAJOR, Z80EX_VERSION_MINOR, revision_type, ver_str};
41
z80ex_get_version()42 LIB_EXPORT Z80EX_VERSION *z80ex_get_version()
43 {
44 return(&version);
45 }
46
47 /* do one opcode (instruction or prefix) */
z80ex_step(Z80EX_CONTEXT * cpu)48 LIB_EXPORT int z80ex_step(Z80EX_CONTEXT *cpu)
49 {
50 Z80EX_BYTE opcode, d;
51 z80ex_opcode_fn ofn=NULL;
52
53 cpu->doing_opcode=1;
54 cpu->noint_once=0;
55 cpu->reset_PV_on_int=0;
56 cpu->tstate=0;
57 cpu->op_tstate=0;
58
59 opcode=READ_OP_M1(); /*fetch opcode*/
60 if(cpu->int_vector_req)
61 {
62 TSTATES(2); /*interrupt eats two extra wait-states*/
63 }
64 R++; /*R increased by one on every first M1 cycle*/
65
66 T_WAIT_UNTIL(4); /*M1 cycle eats min 4 t-states*/
67
68 if(!cpu->prefix) opcodes_base[opcode](cpu);
69 else
70 {
71 if((cpu->prefix | 0x20) == 0xFD && ((opcode | 0x20) == 0xFD || opcode == 0xED))
72 {
73 cpu->prefix=opcode;
74 cpu->noint_once=1; /*interrupts are not accepted immediately after prefix*/
75 }
76 else
77 {
78 switch(cpu->prefix)
79 {
80 case 0xDD:
81 case 0xFD:
82 if(opcode == 0xCB)
83 {
84 d=READ_OP(); /*displacement*/
85 temp_byte_s=(d & 0x80)? -(((~d) & 0x7f)+1): d;
86 opcode=READ_OP();
87 ofn = (cpu->prefix == 0xDD)? opcodes_ddcb[opcode]: opcodes_fdcb[opcode];
88 }
89 else
90 {
91 ofn = (cpu->prefix == 0xDD)? opcodes_dd[opcode]: opcodes_fd[opcode];
92 if(ofn == NULL) ofn=opcodes_base[opcode]; /*'mirrored' instructions*/
93 }
94 break;
95
96 case 0xED:
97 ofn = opcodes_ed[opcode];
98 if(ofn == NULL) ofn=opcodes_base[0x00];
99 break;
100
101 case 0xCB:
102 ofn = opcodes_cb[opcode];
103 break;
104
105 default:
106 /*this must'nt happen!*/
107 assert(0);
108 break;
109 }
110
111 ofn(cpu);
112
113 cpu->prefix=0;
114 }
115 }
116
117 cpu->doing_opcode=0;
118 return(cpu->tstate);
119 }
120
z80ex_last_op_type(Z80EX_CONTEXT * cpu)121 LIB_EXPORT Z80EX_BYTE z80ex_last_op_type(Z80EX_CONTEXT *cpu)
122 {
123 return(cpu->prefix);
124 }
125
z80ex_reset(Z80EX_CONTEXT * cpu)126 LIB_EXPORT void z80ex_reset(Z80EX_CONTEXT *cpu)
127 {
128 PC=0x0000; IFF1=IFF2=0; IM=IM0;
129 AF=SP=BC=DE=HL=IX=IY=AF_=BC_=DE_=HL_=0xffff;
130 I=R=R7=0;
131 cpu->noint_once=0; cpu->reset_PV_on_int=0; cpu->halted=0;
132 cpu->int_vector_req=0;
133 cpu->doing_opcode=0;
134 cpu->tstate=cpu->op_tstate=0;
135 cpu->prefix=0;
136 }
137
138 /**/
z80ex_create(z80ex_mread_cb mrcb_fn,void * mrcb_data,z80ex_mwrite_cb mwcb_fn,void * mwcb_data,z80ex_pread_cb prcb_fn,void * prcb_data,z80ex_pwrite_cb pwcb_fn,void * pwcb_data,z80ex_intread_cb ircb_fn,void * ircb_data)139 LIB_EXPORT Z80EX_CONTEXT *z80ex_create(
140 z80ex_mread_cb mrcb_fn, void *mrcb_data,
141 z80ex_mwrite_cb mwcb_fn, void *mwcb_data,
142 z80ex_pread_cb prcb_fn, void *prcb_data,
143 z80ex_pwrite_cb pwcb_fn, void *pwcb_data,
144 z80ex_intread_cb ircb_fn, void *ircb_data
145 )
146 {
147 Z80EX_CONTEXT *cpu;
148
149 if((cpu=(Z80EX_CONTEXT *)malloc(sizeof(Z80EX_CONTEXT))) == NULL) return(NULL);
150 memset(cpu,0x00,sizeof(Z80EX_CONTEXT));
151
152 z80ex_reset(cpu);
153
154 cpu->mread_cb=mrcb_fn;
155 cpu->mread_cb_user_data=mrcb_data;
156 cpu->mwrite_cb=mwcb_fn;
157 cpu->mwrite_cb_user_data=mwcb_data;
158 cpu->pread_cb=prcb_fn;
159 cpu->pread_cb_user_data=prcb_data;
160 cpu->pwrite_cb=pwcb_fn;
161 cpu->pwrite_cb_user_data=pwcb_data;
162 cpu->intread_cb=ircb_fn;
163 cpu->intread_cb_user_data=ircb_data;
164
165 return(cpu);
166 }
167
z80ex_destroy(Z80EX_CONTEXT * cpu)168 LIB_EXPORT void z80ex_destroy(Z80EX_CONTEXT *cpu)
169 {
170 free(cpu);
171 }
172
z80ex_set_tstate_callback(Z80EX_CONTEXT * cpu,z80ex_tstate_cb cb_fn,void * user_data)173 LIB_EXPORT void z80ex_set_tstate_callback(Z80EX_CONTEXT *cpu, z80ex_tstate_cb cb_fn, void *user_data)
174 {
175 cpu->tstate_cb=cb_fn;
176 cpu->tstate_cb_user_data=user_data;
177 }
178
z80ex_set_reti_callback(Z80EX_CONTEXT * cpu,z80ex_reti_cb cb_fn,void * user_data)179 LIB_EXPORT void z80ex_set_reti_callback(Z80EX_CONTEXT *cpu, z80ex_reti_cb cb_fn, void *user_data)
180 {
181 cpu->reti_cb=cb_fn;
182 cpu->reti_cb_user_data=user_data;
183 }
184
z80ex_set_memread_callback(Z80EX_CONTEXT * cpu,z80ex_mread_cb mrcb_fn,void * mrcb_data)185 LIB_EXPORT void z80ex_set_memread_callback(Z80EX_CONTEXT *cpu, z80ex_mread_cb mrcb_fn, void *mrcb_data)
186 {
187 cpu->mread_cb=mrcb_fn;
188 cpu->mread_cb_user_data=mrcb_data;
189 }
190
z80ex_set_memwrite_callback(Z80EX_CONTEXT * cpu,z80ex_mwrite_cb mwcb_fn,void * mwcb_data)191 LIB_EXPORT void z80ex_set_memwrite_callback(Z80EX_CONTEXT *cpu, z80ex_mwrite_cb mwcb_fn, void *mwcb_data)
192 {
193 cpu->mwrite_cb=mwcb_fn;
194 cpu->mwrite_cb_user_data=mwcb_data;
195 }
196
z80ex_set_portread_callback(Z80EX_CONTEXT * cpu,z80ex_pread_cb prcb_fn,void * prcb_data)197 LIB_EXPORT void z80ex_set_portread_callback(Z80EX_CONTEXT *cpu, z80ex_pread_cb prcb_fn, void *prcb_data)
198 {
199 cpu->pread_cb=prcb_fn;
200 cpu->pread_cb_user_data=prcb_data;
201 }
202
z80ex_set_portwrite_callback(Z80EX_CONTEXT * cpu,z80ex_pwrite_cb pwcb_fn,void * pwcb_data)203 LIB_EXPORT void z80ex_set_portwrite_callback(Z80EX_CONTEXT *cpu, z80ex_pwrite_cb pwcb_fn, void *pwcb_data)
204 {
205 cpu->pwrite_cb=pwcb_fn;
206 cpu->pwrite_cb_user_data=pwcb_data;
207 }
208
z80ex_set_intread_callback(Z80EX_CONTEXT * cpu,z80ex_intread_cb ircb_fn,void * ircb_data)209 LIB_EXPORT void z80ex_set_intread_callback(Z80EX_CONTEXT *cpu, z80ex_intread_cb ircb_fn, void *ircb_data)
210 {
211 cpu->intread_cb=ircb_fn;
212 cpu->intread_cb_user_data=ircb_data;
213 }
214
215 /*non-maskable interrupt*/
z80ex_nmi(Z80EX_CONTEXT * cpu)216 LIB_EXPORT int z80ex_nmi(Z80EX_CONTEXT *cpu)
217 {
218 if(cpu->doing_opcode || cpu->noint_once || cpu->prefix) return(0);
219
220 if(cpu->halted) { PC++; cpu->halted = 0; } /*so we met an interrupt... stop waiting*/
221
222 cpu->doing_opcode=1;
223
224 R++; /*accepting interrupt increases R by one*/
225 /*IFF2=IFF1;*/ /*contrary to zilog z80 docs, IFF2 is not modified on NMI. proved by Slava Tretiak aka restorer*/
226 IFF1=0;
227
228 TSTATES(5);
229
230 cpu->mwrite_cb(cpu, --SP, cpu->pc.b.h, cpu->mwrite_cb_user_data); /*PUSH PC -- high byte */
231 TSTATES(3);
232
233 cpu->mwrite_cb(cpu, --SP, cpu->pc.b.l, cpu->mwrite_cb_user_data); /*PUSH PC -- low byte */
234 TSTATES(3);
235
236 PC=0x0066;
237 MEMPTR=PC; /*FIXME: is that really so?*/
238
239 cpu->doing_opcode=0;
240
241 return(11); /*NMI always takes 11 t-states*/
242 }
243
244 /*maskable interrupt*/
z80ex_int(Z80EX_CONTEXT * cpu)245 LIB_EXPORT int z80ex_int(Z80EX_CONTEXT *cpu)
246 {
247 Z80EX_WORD inttemp;
248 Z80EX_BYTE iv;
249 unsigned long tt;
250
251 /*If the INT line is low and IFF1 is set, and there's no opcode executing just now,
252 a maskable interrupt is accepted, whether or not the
253 last INT routine has finished*/
254 if(!IFF1 || cpu->noint_once || cpu->doing_opcode || cpu->prefix) return(0);
255
256 cpu->tstate=0;
257 cpu->op_tstate=0;
258
259 if(cpu->halted) { PC++; cpu->halted = 0; } /*so we met an interrupt... stop waiting*/
260
261 /*When an INT is accepted, both IFF1 and IFF2 are cleared, preventing another interrupt from
262 occurring which would end up as an infinite loop*/
263 IFF1=IFF2=0;
264
265 /*original (NMOS) zilog z80 bug:*/
266 /*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.*/
267 /*(this bug was fixed in CMOS version of z80)*/
268 if(cpu->reset_PV_on_int) {F = (F & ~FLAG_P);}
269 cpu->reset_PV_on_int=0;
270
271 cpu->int_vector_req=1;
272 cpu->doing_opcode=1;
273
274 switch(IM)
275 {
276 case IM0:
277 /*note: there's no need to do R++ and WAITs here, it'll be handled by z80ex_step*/
278 tt=z80ex_step(cpu);
279
280 while(cpu->prefix) /*this is not the end?*/
281 {
282 tt+=z80ex_step(cpu);
283 }
284
285 cpu->tstate=tt;
286 break;
287
288 case IM1:
289 R++;
290 TSTATES(2); /*two extra wait-states*/
291 /*An RST 38h is executed, no matter what value is put on the bus or what
292 value the I register has. 13 t-states (2 extra + 11 for RST).*/
293 opcodes_base[0xff](cpu); /*RST38*/
294 break;
295
296 case IM2:
297 R++;
298 /*takes 19 clock periods to complete (seven to fetch the
299 lower eight bits from the interrupting device, six to save the program
300 counter, and six to obtain the jump address)*/
301 iv=READ_OP();
302 T_WAIT_UNTIL(7);
303 inttemp=(0x100*I)+iv;
304
305 PUSH(PC,7,10);
306
307 READ_MEM(PCL,inttemp++,13); READ_MEM(PCH,inttemp,16);
308 MEMPTR=PC;
309 T_WAIT_UNTIL(19);
310
311 break;
312 }
313
314 cpu->doing_opcode=0;
315 cpu->int_vector_req=0;
316
317 return(cpu->tstate);
318 }
319
z80ex_w_states(Z80EX_CONTEXT * cpu,unsigned w_states)320 LIB_EXPORT void z80ex_w_states(Z80EX_CONTEXT *cpu, unsigned w_states)
321 {
322 TSTATES(w_states);
323 }
324
z80ex_next_t_state(Z80EX_CONTEXT * cpu)325 LIB_EXPORT void z80ex_next_t_state(Z80EX_CONTEXT *cpu)
326 {
327 if(cpu->tstate_cb != NULL) cpu->tstate_cb(cpu, cpu->tstate_cb_user_data);
328 cpu->tstate++;
329 cpu->op_tstate++;
330 }
331
z80ex_get_reg(Z80EX_CONTEXT * cpu,Z80_REG_T reg)332 LIB_EXPORT Z80EX_WORD z80ex_get_reg(Z80EX_CONTEXT *cpu, Z80_REG_T reg)
333 {
334 switch(reg)
335 {
336 case regAF: return(AF);
337 case regBC: return(BC);
338 case regDE: return(DE);
339 case regHL: return(HL);
340 case regAF_: return(AF_);
341 case regBC_: return(BC_);
342 case regDE_: return(DE_);
343 case regHL_: return(HL_);
344 case regIX: return(IX);
345 case regIY: return(IY);
346 case regPC: return(PC);
347 case regSP: return(SP);
348 case regI: return(I);
349 case regR: return(R);
350 case regR7: return(R7);
351 case regIM: return(IM);
352 case regIFF1: return(IFF1);
353 case regIFF2: return(IFF2);
354 }
355
356 return(0);
357 }
358
z80ex_set_reg(Z80EX_CONTEXT * cpu,Z80_REG_T reg,Z80EX_WORD value)359 LIB_EXPORT void z80ex_set_reg(Z80EX_CONTEXT *cpu, Z80_REG_T reg, Z80EX_WORD value)
360 {
361 switch(reg)
362 {
363 case regAF: AF=value; return;
364 case regBC: BC=value; return;
365 case regDE: DE=value; return;
366 case regHL: HL=value; return;
367 case regAF_: AF_=value; return;
368 case regBC_: BC_=value; return;
369 case regDE_: DE_=value; return;
370 case regHL_: HL_=value; return;
371 case regIX: IX=value; return;
372 case regIY: IY=value; return;
373 case regPC: PC=value; return;
374 case regSP: SP=value; return;
375 case regI: I=(value & 0xff); return;
376 case regR: R=(value & 0xff); return;
377 case regR7: R7=(value & 0xff); return;
378 case regIM:
379 switch(value & 0x03)
380 {
381 case 0: IM=IM0; return;
382 case 1: IM=IM1; return;
383 case 2: IM=IM2; return;
384 }
385 case regIFF1: IFF1=(value & 0x01); return;
386 case regIFF2: IFF2=(value & 0x01); return;
387 }
388 }
389
z80ex_op_tstate(Z80EX_CONTEXT * cpu)390 LIB_EXPORT int z80ex_op_tstate(Z80EX_CONTEXT *cpu)
391 {
392 return(cpu->tstate);
393 }
394
z80ex_doing_halt(Z80EX_CONTEXT * cpu)395 LIB_EXPORT int z80ex_doing_halt(Z80EX_CONTEXT *cpu)
396 {
397 return(cpu->halted);
398 }
399
400 /*LIB_EXPORT int z80ex_get_noint_once(Z80EX_CONTEXT *cpu)
401 {
402 return(cpu->noint_once);
403 }*/
404
z80ex_int_possible(Z80EX_CONTEXT * cpu)405 LIB_EXPORT int z80ex_int_possible(Z80EX_CONTEXT *cpu)
406 {
407 return((!IFF1 || cpu->noint_once || cpu->doing_opcode || cpu->prefix)? 0 : 1);
408 }
409
z80ex_nmi_possible(Z80EX_CONTEXT * cpu)410 LIB_EXPORT int z80ex_nmi_possible(Z80EX_CONTEXT *cpu)
411 {
412 return((cpu->noint_once || cpu->doing_opcode || cpu->prefix)? 0 : 1);
413 }
414
415