1 /****************************************************************************
2 *			  real mode i286 emulator v1.4 by Fabrice Frances				*
3 *				(initial work based on David Hedley's pcemu)                *
4 ****************************************************************************/
5 
6 #include <stdio.h>
7 #include <string.h>
8 #include "host.h"
9 #include "cpuintrf.h"
10 #include "memory.h"
11 #include "mamedbg.h"
12 #include "mame.h"
13 #include "state.h"
14 
15 
16 /* All post-i286 CPUs have a 16MB address space */
17 #define AMASK	I.amask
18 
19 
20 #define i86_ICount i286_ICount
21 
22 #include "i286.h"
23 #include "i286intf.h"
24 
25 
26 static UINT8 i286_reg_layout[] = {
27 	I286_FLAGS,
28 	I286_MSW,
29 	I286_TR,
30 	I286_TR_2,
31 	I286_GDTR,
32 	I286_GDTR_2,
33 	-1,
34 	I286_AX,
35 	I286_BP,
36 	I286_LDTR,
37 	I286_LDTR_2,
38 	I286_IDTR,
39 	I286_IDTR_2,
40 	-1,
41 	I286_BX,
42 	I286_SP,
43 	I286_SS,
44 	I286_SS_2,
45 	I286_IRQ_STATE,
46 	I286_VECTOR,
47 	-1,
48 	I286_CX,
49 	I286_IP,
50 	I286_CS,
51 	I286_CS_2,
52 	I286_NMI_STATE,
53 	-1,
54 	I286_DX,
55 	I286_SI,
56 	I286_DS,
57 	I286_DS_2,
58 	-1,
59 	I286_EMPTY,
60 	I286_DI,
61 	I286_ES,
62 	I286_ES_2,
63 	0
64 };
65 
66 /* Layout of the debugger windows x,y,w,h */
67 static UINT8 i286_win_layout[] = {
68      0, 0,80, 6,    /* register window (top rows) */
69 	 0, 7,40,15,	/* disassembler window (left colums) */
70 	41, 7,39, 7,	/* memory #1 window (right, upper middle) */
71 	41,15,39, 7,	/* memory #2 window (right, lower middle) */
72      0,23,80, 1,    /* command line window (bottom rows) */
73 };
74 
75 
76 #include "i86time.c"
77 
78 /***************************************************************************/
79 /* cpu state                                                               */
80 /***************************************************************************/
81 /* I86 registers */
82 typedef union
83 {                   /* eight general registers */
84     UINT16 w[8];    /* viewed as 16 bits registers */
85     UINT8  b[16];   /* or as 8 bit registers */
86 } i286basicregs;
87 
88 typedef struct
89 {
90     i286basicregs regs;
91 	int 	amask;			/* address mask */
92     UINT32  pc;
93     UINT32  prevpc;
94 	UINT16	flags;
95 	UINT16	msw;
96 	UINT32	base[4];
97 	UINT16	sregs[4];
98 	UINT16	limit[4];
99 	UINT8 rights[4];
100 	struct {
101 		UINT32 base;
102 		UINT16 limit;
103 	} gdtr, idtr;
104 	struct {
105 		UINT16 sel;
106 		UINT32 base;
107 		UINT16 limit;
108 		UINT8 rights;
109 	} ldtr, tr;
110     int     (*irq_callback)(int irqline);
111     int     AuxVal, OverVal, SignVal, ZeroVal, CarryVal, DirVal; /* 0 or non-0 valued flags */
112     UINT8	ParityVal;
113 	UINT8	TF, IF; 	/* 0 or 1 valued flags */
114 	UINT8	int_vector;
115 	INT8	nmi_state;
116 	INT8	irq_state;
117 	int 	extra_cycles;       /* extra cycles for interrupts */
118 } i286_Regs;
119 
120 int i286_ICount;
121 
122 static i286_Regs I;
123 static unsigned prefix_base;	/* base address of the latest prefix segment */
124 static char seg_prefix;         /* prefix segment indicator */
125 
126 #define INT_IRQ 0x01
127 #define NMI_IRQ 0x02
128 
129 static UINT8 parity_table[256];
130 
131 static struct i86_timing cycles;
132 
133 /***************************************************************************/
134 
135 #define I286
136 #define PREFIX(fname) i286##fname
137 #define PREFIX86(fname) i286##fname
138 #define PREFIX186(fname) i286##fname
139 #define PREFIX286(fname) i286##fname
140 
141 #include "ea.h"
142 #include "modrm.h"
143 #include "instr86.h"
144 #include "instr186.h"
145 #include "instr286.h"
146 #include "table286.h"
147 #include "instr86.c"
148 #include "instr186.c"
149 #include "instr286.c"
150 
i286_urinit(void)151 static void i286_urinit(void)
152 {
153 	unsigned int i,j,c;
154 	BREGS reg_name[8]={ AL, CL, DL, BL, AH, CH, DH, BH };
155 
156 	for (i = 0;i < 256; i++)
157 	{
158 		for (j = i, c = 0; j > 0; j >>= 1)
159 			if (j & 1) c++;
160 
161 		parity_table[i] = !(c & 1);
162 	}
163 
164 	for (i = 0; i < 256; i++)
165 	{
166 		Mod_RM.reg.b[i] = reg_name[(i & 0x38) >> 3];
167 		Mod_RM.reg.w[i] = (WREGS) ( (i & 0x38) >> 3) ;
168 	}
169 
170 	for (i = 0xc0; i < 0x100; i++)
171 	{
172 		Mod_RM.RM.w[i] = (WREGS)( i & 7 );
173 		Mod_RM.RM.b[i] = (BREGS)reg_name[i & 7];
174 	}
175 }
176 
i286_set_address_mask(offs_t mask)177 void i286_set_address_mask(offs_t mask)
178 {
179 	I.amask=mask;
180 }
181 
i286_reset(void * param)182 void i286_reset (void *param)
183 {
184 	static int urinit=1;
185 
186 	/* in my docu not all registers are initialized! */
187 	/*memset( &I, 0, sizeof(I) );*/
188 
189 	if (urinit) {
190 		i286_urinit();
191 		urinit=0;
192 
193 		/* this function seams to be called as a result of
194 		   cpu_set_reset_line */
195 		/* If a reset parameter is given, take it as pointer to an address mask */
196 		if( param )
197 			I.amask = *(unsigned*)param;
198 		else
199 			I.amask = 0x00ffff;
200 	}
201 
202 	I.sregs[CS] = 0xf000;
203 	I.base[CS] = 0xff0000;
204 	/* temporary, until I have the right reset vector working */
205 	I.base[CS] = I.sregs[CS] << 4;
206 	I.pc = 0xffff0;
207 	I.limit[CS]=I.limit[SS]=I.limit[DS]=I.limit[ES]=0xffff;
208 	I.sregs[DS]=I.sregs[SS]=I.sregs[ES]=0;
209 	I.base[DS]=I.base[SS]=I.base[ES]=0;
210 	I.msw=0xfff0;
211 	I.flags=2;
212 	ExpandFlags(I.flags);
213 	I.idtr.base=0;I.idtr.limit=0x3ff;
214 
215 	CHANGE_PC(I.pc);
216 
217 }
218 
i286_exit(void)219 void i286_exit (void)
220 {
221 	/* nothing to do ? */
222 }
223 
224 /****************************************************************************/
225 
226 /* ASG 971222 -- added these interface functions */
227 
i286_get_context(void * dst)228 unsigned i286_get_context(void *dst)
229 {
230 	if( dst )
231 		*(i286_Regs*)dst = I;
232 	 return sizeof(i286_Regs);
233 }
234 
i286_set_context(void * src)235 void i286_set_context(void *src)
236 {
237 	if( src )
238 	{
239 		I = *(i286_Regs*)src;
240 		if (PM) {
241 
242 		} else {
243 			I.base[CS] = SegBase(CS);
244 			I.base[DS] = SegBase(DS);
245 			I.base[ES] = SegBase(ES);
246 			I.base[SS] = SegBase(SS);
247 		}
248 		CHANGE_PC(I.pc);
249 	}
250 }
251 
i286_get_reg(int regnum)252 unsigned i286_get_reg(int regnum)
253 {
254 	switch( regnum )
255 	{
256 		case REG_PC: return I.pc;
257 		case I286_IP: return I.pc - I.base[CS];
258 		case REG_SP: return I.base[SS] + I.regs.w[SP];
259 		case I286_SP: return I.regs.w[SP];
260 		case I286_FLAGS: CompressFlags(); return I.flags;
261 		case I286_AX: return I.regs.w[AX];
262 		case I286_CX: return I.regs.w[CX];
263 		case I286_DX: return I.regs.w[DX];
264 		case I286_BX: return I.regs.w[BX];
265 		case I286_BP: return I.regs.w[BP];
266 		case I286_SI: return I.regs.w[SI];
267 		case I286_DI: return I.regs.w[DI];
268 		case I286_ES: return I.sregs[ES];
269 		case I286_CS: return I.sregs[CS];
270 		case I286_SS: return I.sregs[SS];
271 		case I286_DS: return I.sregs[DS];
272 		case I286_VECTOR: return I.int_vector;
273 		case I286_PENDING: return I.irq_state;
274 		case I286_NMI_STATE: return I.nmi_state;
275 		case I286_IRQ_STATE: return I.irq_state;
276 		case REG_PREVIOUSPC: return I.prevpc;
277 		default:
278 			if( regnum <= REG_SP_CONTENTS )
279 			{
280 				unsigned offset = ((I.base[SS] + I.regs.w[SP]) & I.amask) + 2 * (REG_SP_CONTENTS - regnum);
281 				if( offset < I.amask )
282 					return cpu_readmem24( offset ) | ( cpu_readmem24( offset + 1) << 8 );
283 			}
284 	}
285 	return 0;
286 }
287 
i286_set_reg(int regnum,unsigned val)288 void i286_set_reg(int regnum, unsigned val)
289 {
290 	switch( regnum )
291 	{
292 		case REG_PC:
293 			if (PM) {
294 			} else {
295 				if (val - I.base[CS] >= 0x10000)
296 				{
297 					I.base[CS] = val & 0xffff0;
298 					I.sregs[CS] = I.base[CS] >> 4;
299 				}
300 				I.pc = val;
301 			}
302 			break;
303 		case I286_IP: I.pc = I.base[CS] + val; break;
304 		case REG_SP:
305 			if (PM) {
306 			} else {
307 				if( val - I.base[SS] < 0x10000 )
308 				{
309 					I.regs.w[SP] = val - I.base[SS];
310 				}
311 				else
312 				{
313 					I.base[SS] = val & 0xffff0;
314 					I.sregs[SS] = I.base[SS] >> 4;
315 					I.regs.w[SP] = val & 0x0000f;
316 				}
317 			}
318 			break;
319 		case I286_SP: I.regs.w[SP] = val; break;
320 		case I286_FLAGS: I.flags = val; ExpandFlags(val); break;
321 		case I286_AX: I.regs.w[AX] = val; break;
322 		case I286_CX: I.regs.w[CX] = val; break;
323 		case I286_DX: I.regs.w[DX] = val; break;
324 		case I286_BX: I.regs.w[BX] = val; break;
325 		case I286_BP: I.regs.w[BP] = val; break;
326 		case I286_SI: I.regs.w[SI] = val; break;
327 		case I286_DI: I.regs.w[DI] = val; break;
328 		case I286_ES: I.sregs[ES] = val; break;
329 		case I286_CS: I.sregs[CS] = val; break;
330 		case I286_SS: I.sregs[SS] = val; break;
331 		case I286_DS: I.sregs[DS] = val; break;
332 		case I286_VECTOR: I.int_vector = val; break;
333 		case I286_PENDING: /* obsolete */ break;
334 		case I286_NMI_STATE: i286_set_irq_line(IRQ_LINE_NMI,val); break;
335 		case I286_IRQ_STATE: i286_set_irq_line(0,val); break;
336 		default:
337 			if( regnum <= REG_SP_CONTENTS )
338 			{
339 				unsigned offset = ((I.base[SS] + I.regs.w[SP]) & I.amask) + 2 * (REG_SP_CONTENTS - regnum);
340 				if( offset < I.amask - 1 )
341 				{
342 					cpu_writemem24( offset, val & 0xff );
343 					cpu_writemem24( offset+1, (val >> 8) & 0xff );
344 				}
345 			}
346     }
347 }
348 
i286_set_irq_line(int irqline,int state)349 void i286_set_irq_line(int irqline, int state)
350 {
351 	if (irqline == IRQ_LINE_NMI)
352 	{
353 		if (I.nmi_state == state)
354 			return;
355 		I.nmi_state = state;
356 
357 		/* on a rising edge, signal the NMI */
358 		if (state != CLEAR_LINE)
359 			PREFIX(_interrupt)(I86_NMI_INT_VECTOR);
360 	}
361 	else
362 	{
363 		I.irq_state = state;
364 
365 		/* if the IF is set, signal an interrupt */
366 		if (state != CLEAR_LINE && I.IF)
367 			PREFIX(_interrupt)(-1);
368 	}
369 }
370 
i286_set_irq_callback(int (* callback)(int))371 void i286_set_irq_callback(int (*callback)(int))
372 {
373 	I.irq_callback = callback;
374 }
375 
i286_execute(int num_cycles)376 int i286_execute(int num_cycles)
377 {
378 	/* copy over the cycle counts if they're not correct */
379 	if (cycles.id != 80286)
380 		cycles = i286_cycles;
381 
382 	/* adjust for any interrupts that came in */
383 	i286_ICount = num_cycles;
384 	i286_ICount -= I.extra_cycles;
385 	I.extra_cycles = 0;
386 
387 	/* run until we're out */
388 	while(i286_ICount>0)
389 	{
390 
391 		log_cb(RETRO_LOG_DEBUG, LOGPRE "[%04x:%04x]=%02x\tF:%04x\tAX=%04x\tBX=%04x\tCX=%04x\tDX=%04x %d%d%d%d%d%d%d%d%d\n",I.sregs[CS],I.pc - I.base[CS],ReadByte(I.pc),I.flags,I.regs.w[AX],I.regs.w[BX],I.regs.w[CX],I.regs.w[DX], I.AuxVal?1:0, I.OverVal?1:0, I.SignVal?1:0, I.ZeroVal?1:0, I.CarryVal?1:0, I.ParityVal?1:0,I.TF, I.IF, I.DirVal<0?1:0);
392 
393 		CALL_MAME_DEBUG;
394 
395 		seg_prefix=FALSE;
396 		I.prevpc = I.pc;
397 
398 		TABLE286 /* call instruction*/
399     }
400 
401 	/* adjust for any interrupts that came in */
402 	i286_ICount -= I.extra_cycles;
403 	I.extra_cycles = 0;
404 
405 	return num_cycles - i286_ICount;
406 }
407 
408 /****************************************************************************
409  * Return a formatted string for a register
410  ****************************************************************************/
i286_info(void * context,int regnum)411 const char *i286_info(void *context, int regnum)
412 {
413 	static char buffer[32][63+1];
414 	static int which = 0;
415 	i286_Regs *r = context;
416 
417 	which = (which+1) % 32;
418 	buffer[which][0] = '\0';
419 	if( !context )
420 		r = &I;
421 
422 	switch( regnum )
423 	{
424 	case CPU_INFO_REG+I286_IP: sprintf(buffer[which], "IP:%04X", r->pc - r->base[CS]); break;
425 	case CPU_INFO_REG+I286_SP: sprintf(buffer[which], "SP:%04X", r->regs.w[SP]); break;
426 	case CPU_INFO_REG+I286_FLAGS: sprintf(buffer[which], "F:%04X", r->flags); break;
427 	case CPU_INFO_REG+I286_AX: sprintf(buffer[which], "AX:%04X", r->regs.w[AX]); break;
428 	case CPU_INFO_REG+I286_CX: sprintf(buffer[which], "CX:%04X", r->regs.w[CX]); break;
429 	case CPU_INFO_REG+I286_DX: sprintf(buffer[which], "DX:%04X", r->regs.w[DX]); break;
430 	case CPU_INFO_REG+I286_BX: sprintf(buffer[which], "BX:%04X", r->regs.w[BX]); break;
431 	case CPU_INFO_REG+I286_BP: sprintf(buffer[which], "BP:%04X", r->regs.w[BP]); break;
432 	case CPU_INFO_REG+I286_SI: sprintf(buffer[which], "SI:%04X", r->regs.w[SI]); break;
433 	case CPU_INFO_REG+I286_DI: sprintf(buffer[which], "DI:%04X", r->regs.w[DI]); break;
434 	case CPU_INFO_REG+I286_ES:
435 		sprintf(buffer[which], "ES:  %04X %02X", r->sregs[ES], r->rights[ES]);
436 		break;
437 	case CPU_INFO_REG+I286_ES_2:
438 		sprintf(buffer[which],"%06X %04X", r->base[ES], r->limit[ES]);
439 		break;
440 	case CPU_INFO_REG+I286_CS:
441 		sprintf(buffer[which], "CS:  %04X %02X", r->sregs[CS], r->rights[CS]);
442 		break;
443 	case CPU_INFO_REG+I286_CS_2:
444 		sprintf(buffer[which],"%06X %04X", r->base[CS], r->limit[CS]);
445 		break;
446 	case CPU_INFO_REG+I286_SS:
447 		sprintf(buffer[which], "SS:  %04X %02X", r->sregs[SS], r->rights[SS]);
448 		break;
449 	case CPU_INFO_REG+I286_SS_2:
450 		sprintf(buffer[which],"%06X %04X", r->base[SS], r->limit[SS]);
451 		break;
452 	case CPU_INFO_REG+I286_DS:
453 		sprintf(buffer[which], "DS:  %04X %02X", r->sregs[DS], r->rights[DS]);
454 		break;
455 	case CPU_INFO_REG+I286_DS_2:
456 		sprintf(buffer[which],"%06X %04X", r->base[DS], r->limit[DS]);
457 		break;
458 	case CPU_INFO_REG+I286_MSW: sprintf(buffer[which],"MSW:%04X", r->msw); break;
459 	case CPU_INFO_REG+I286_GDTR: sprintf(buffer[which],"GDTR: %06X", r->gdtr.base); break;
460 	case CPU_INFO_REG+I286_GDTR_2: sprintf(buffer[which],"%04X", r->gdtr.limit); break;
461 	case CPU_INFO_REG+I286_IDTR: sprintf(buffer[which],"IDTR: %06X", r->idtr.base); break;
462 	case CPU_INFO_REG+I286_IDTR_2: sprintf(buffer[which],"%04X", r->idtr.limit); break;
463 	case CPU_INFO_REG+I286_LDTR:
464 		sprintf(buffer[which],"LDTR:%04X %02X", r->ldtr.sel, r->ldtr.rights);
465 		break;
466 	case CPU_INFO_REG+I286_LDTR_2:
467 		sprintf(buffer[which],"%06X %04X", r->ldtr.base, r->ldtr.limit);
468 		break;
469 	case CPU_INFO_REG+I286_TR:
470 		sprintf(buffer[which],"TR:  %04X %02X", r->tr.sel, r->tr.rights);
471 		break;
472 	case CPU_INFO_REG+I286_TR_2:
473 		sprintf(buffer[which],"%06X %04X", r->tr.base, r->tr.limit);
474 		break;
475 	case CPU_INFO_REG+I286_VECTOR: sprintf(buffer[which], "V:%02X", r->int_vector); break;
476 	case CPU_INFO_REG+I286_PENDING: sprintf(buffer[which], "P:%X", r->irq_state); break;
477 	case CPU_INFO_REG+I286_NMI_STATE: sprintf(buffer[which], "NMI:%X", r->nmi_state); break;
478 	case CPU_INFO_REG+I286_IRQ_STATE: sprintf(buffer[which], "IRQ:%X", r->irq_state); break;
479 	case CPU_INFO_FLAGS:
480 		r->flags = CompressFlags();
481 		sprintf(buffer[which], "%c%c %c%c%c%c%c%c%c%c%c%c%c%c%c",
482 				r->flags & 0x8000 ? '?':'.',
483 				r->flags & 0x4000 ? '?':'.',
484 				((r->flags & 0x3000)>>12)+'0',
485 				r->flags & 0x0800 ? 'O':'.',
486 				r->flags & 0x0400 ? 'D':'.',
487 				r->flags & 0x0200 ? 'I':'.',
488 				r->flags & 0x0100 ? 'T':'.',
489 				r->flags & 0x0080 ? 'S':'.',
490 				r->flags & 0x0040 ? 'Z':'.',
491 				r->flags & 0x0020 ? '?':'.',
492 				r->flags & 0x0010 ? 'A':'.',
493 				r->flags & 0x0008 ? '?':'.',
494 				r->flags & 0x0004 ? 'P':'.',
495 				r->flags & 0x0002 ? 'N':'.',
496 				r->flags & 0x0001 ? 'C':'.');
497 		break;
498 	case CPU_INFO_REG+I286_EMPTY: sprintf(buffer[which]," ");break;
499 	case CPU_INFO_NAME: return "I80286";
500 	case CPU_INFO_FAMILY: return "Intel 80286";
501 	case CPU_INFO_VERSION: return "1.4";
502 	case CPU_INFO_FILE: return __FILE__;
503 	case CPU_INFO_CREDITS: return "Real mode i286 emulator v1.4 by Fabrice Frances\n(initial work I.based on David Hedley's pcemu)";
504 	case CPU_INFO_REG_LAYOUT: return (const char*)i286_reg_layout;
505 	case CPU_INFO_WIN_LAYOUT: return (const char*)i286_win_layout;
506 	}
507 	return buffer[which];
508 }
509 
i286_dasm(char * buffer,unsigned pc)510 unsigned i286_dasm(char *buffer, unsigned pc)
511 {
512 #ifdef MAME_DEBUG
513     return DasmI286(buffer,pc);
514 #else
515 	sprintf( buffer, "$%02X", cpu_readop(pc) );
516 	return 1;
517 #endif
518 }
519 
i286_init(void)520 void i286_init(void)
521 {
522 	int cpu = cpu_getactivecpu();
523 	const char *type = "I286";
524 	state_save_register_UINT16(type, cpu, "REGS",			I.regs.w, 8);
525 	state_save_register_int(   type, cpu, "AMASK",			&I.amask);
526 	state_save_register_UINT32(type, cpu, "PC",				&I.pc, 1);
527 	state_save_register_UINT32(type, cpu, "PREVPC",			&I.prevpc, 1);
528 	state_save_register_UINT16(type, cpu, "MSW",			&I.msw, 1);
529 	state_save_register_UINT32(type, cpu, "BASE",			I.base, 4);
530 	state_save_register_UINT16(type, cpu, "SREGS",			I.sregs, 4);
531 	state_save_register_UINT16(type, cpu, "LIMIT",			I.limit, 4);
532 	state_save_register_UINT8 (type, cpu, "RIGHTS",			I.rights, 4);
533 	state_save_register_UINT32(type, cpu, "GDTR_BASE",		&I.gdtr.base, 1);
534 	state_save_register_UINT16(type, cpu, "GDTR_LIMIT",		&I.gdtr.limit, 1);
535 	state_save_register_UINT32(type, cpu, "IDTR_BASE",		&I.idtr.base, 1);
536 	state_save_register_UINT16(type, cpu, "IDTR_LIMIT",		&I.idtr.limit, 1);
537 	state_save_register_UINT16(type, cpu, "LDTR_SEL",		&I.ldtr.sel, 1);
538 	state_save_register_UINT32(type, cpu, "LDTR_BASE",		&I.ldtr.base, 1);
539 	state_save_register_UINT16(type, cpu, "LDTR_LIMIT",		&I.ldtr.limit, 1);
540 	state_save_register_UINT8 (type, cpu, "LDTR_RIGHTS",	&I.ldtr.rights, 1);
541 	state_save_register_UINT16(type, cpu, "TR_SEL",			&I.tr.sel, 1);
542 	state_save_register_UINT32(type, cpu, "TR_BASE",		&I.tr.base, 1);
543 	state_save_register_UINT16(type, cpu, "TR_LIMIT",		&I.tr.limit, 1);
544 	state_save_register_UINT8 (type, cpu, "TR_RIGHTS",		&I.tr.rights, 1);
545 	state_save_register_int(   type, cpu, "AUXVAL",			&I.AuxVal);
546 	state_save_register_int(   type, cpu, "OVERVAL",		&I.OverVal);
547 	state_save_register_int(   type, cpu, "SIGNVAL",		&I.SignVal);
548 	state_save_register_int(   type, cpu, "ZEROVAL",		&I.ZeroVal);
549 	state_save_register_int(   type, cpu, "CARRYVAL",		&I.CarryVal);
550 	state_save_register_int(   type, cpu, "DIRVAL",			&I.DirVal);
551 	state_save_register_UINT8( type, cpu, "PARITYVAL",		&I.ParityVal, 1);
552 	state_save_register_UINT8( type, cpu, "TF",				&I.TF, 1);
553 	state_save_register_UINT8( type, cpu, "IF",				&I.IF, 1);
554 	state_save_register_UINT8( type, cpu, "INT_VECTOR",		&I.int_vector, 1);
555 	state_save_register_INT8(  type, cpu, "NMI_STATE",		&I.nmi_state, 1);
556 	state_save_register_INT8(  type, cpu, "IRQ_STATE",		&I.irq_state, 1);
557 	state_save_register_int(   type, cpu, "EXTRA_CYCLES",	&I.extra_cycles);
558 }
559