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