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