1 // license:BSD-3-Clause
2 // copyright-holders:Carl
3 #include "emu.h"
4 #include "i286.h"
5 #include "debugger.h"
6 #include "i86inline.h"
7
8 /*
9 * Descriptor format
10 * Data Segment
11 * 48. . . . . . .40. . . . . . .32. . . . . . .24. . . . . . .16. . . . . . . 8. . . . . . . 0
12 * P|DPL|1|0|E|W|A| BASE 23-16 | BASE 15-0 | LIMIT |
13 * Code Segment
14 * 48. . . . . . .40. . . . . . .32. . . . . . .24. . . . . . .16. . . . . . . 8. . . . . . . 0
15 * P|DPL|1|1|C|R|A| BASE 23-16 | BASE 15-0 | LIMIT |
16 * System
17 * 48. . . . . . .40. . . . . . .32. . . . . . .24. . . . . . .16. . . . . . . 8. . . . . . . 0
18 * P|DPL|0| TYPE | BASE 23-16 | BASE 15-0 | LIMIT |
19 *
20 * P == Present
21 * A == Accessed
22 * E == Expand Down
23 * W == Read/Write
24 * C == Conforming
25 * R == Readable
26 * DPL == Descriptor Privilege Level
27 *
28 * Bits 48-64 are ignored but reserved for the 80386
29 */
30
31 #define LIMIT(desc) (desc[0]&0xffff)
32 #define BASE(desc) ((desc[1]&0xffff)|((desc[2]&0xff)<<16))
33 #define RIGHTS(desc) ((desc[2]>>8)&0xff)
34
35 #define ACCESS(r) (r&1)
36 #define SET_ACC(desc) (desc[2]|=0x100)
37 #define RW(r) ((r>>1)&1)
38 #define READ(r) ((r>>1)&1)
39 #define CONF(r) ((r>>2)&1)
40 #define EXPDOWN(r) ((r>>2)&1)
41 #define CODE(r) ((r>>3)&1)
42 #define SEGDESC(r) ((r>>4)&1)
43 #define DPL(r) ((r>>5)&3)
44 #define PRES(r) ((r>>7)&1)
45 #define GATE(r) (r&31)
46 #define GATESEL(desc) (desc[1])
47 #define GATEOFF(desc) (desc[0])
48 #define GATECNT(desc) (desc[2]&31)
49
50 #define RPL(s) (s&3)
51 #define IDX(s) (s&(~7))
52 #define IDXTBL(s) (s&(~3))
53 #define TBL(s) (s&4)
54
55 #define TSSDESCIDLE 1
56 #define LDTDESC 2
57 #define TSSDESCBUSY 3
58 #define CALLGATE 4
59 #define TASKGATE 5
60 #define INTGATE 6
61 #define TRAPGATE 7
62
63 #define TSS_BACK 0
64 #define TSS_SP0 1
65 #define TSS_SS0 2
66 #define TSS_SP1 3
67 #define TSS_SS1 4
68 #define TSS_SP2 5
69 #define TSS_SS2 6
70 #define TSS_IP 7
71 #define TSS_FLAG 8
72 #define TSS_AX 9
73 #define TSS_CX 10
74 #define TSS_DX 11
75 #define TSS_BX 12
76 #define TSS_SP 13
77 #define TSS_BP 14
78 #define TSS_SI 15
79 #define TSS_DI 16
80 #define TSS_ES 17
81 #define TSS_CS 18
82 #define TSS_SS 19
83 #define TSS_DS 20
84 #define TSS_LDT 21
85
86 #define PMAX(a,b) ((a<b)?b:a)
87 #define CPL DPL(m_rights[SS])
88 #define PM (m_msw&1)
89
90 #define NT_IRET 0
91 #define NT_JMP 1
92 #define NT_CALL 2
93
94 /* these come from the 80286 timings in OPCODE.LST */
95 /* many of these numbers are suspect TODO: add protmode insns*/
96 const uint8_t i80286_cpu_device::m_i80286_timing[] =
97 {
98 23,17, /* exception, IRET */
99 0, 2, 3, 1, /* INTs */
100 2, /* segment overrides */
101 2, 2, 2, /* flag operations */
102 3, 3,16,14, /* arithmetic adjusts */
103 3, 3, /* decimal adjusts */
104 2, 2, /* sign extension */
105 2, 7, 3, 3, 3, 5, /* misc */
106
107 7, 7,11, /* direct JMPs */
108 7,11,26, /* indirect JMPs */
109 7,13, /* direct CALLs */
110 7,11,29, /* indirect CALLs */
111 11,15,11,15, /* returns */
112 3, 7, 4, 8, /* conditional JMPs */
113 4, 8, 4, 8, /* loops */
114
115 5, 5, 5, 5, /* port reads */
116 3, 3, 3, 3, /* port writes */
117
118 2, 3, 3, /* move, 8-bit */
119 2, 3, /* move, 8-bit immediate */
120 2, 3, 3, /* move, 16-bit */
121 2, 3, /* move, 16-bit immediate */
122 5, 5, 3, 3, /* move, AL/AX memory */
123 2, 5, 2, 3, /* move, segment registers */
124 3, 5, /* exchange, 8-bit */
125 3, 5, 3, /* exchange, 16-bit */
126
127 5, 5, 3, 3, /* pushes */
128 5, 5, 5, 5, /* pops */
129
130 2, 7, 7, /* ALU ops, 8-bit */
131 3, 7, 7, /* ALU ops, 8-bit immediate */
132 2, 7, 7, /* ALU ops, 16-bit */
133 3, 7, 7, /* ALU ops, 16-bit immediate */
134 3, 7, 7, /* ALU ops, 16-bit w/8-bit immediate */
135 13,21,16,24, /* MUL */
136 13,21,16,24, /* IMUL */
137 14,22,17,25, /* DIV */
138 17,25,20,28, /* IDIV */
139 2, 2, 7, 7, /* INC/DEC */
140 2, 2, 7, 7, /* NEG/NOT */
141
142 2, 5, 1, /* reg shift/rotate */
143 7, 8, 1, /* m8 shift/rotate */
144 7, 8, 1, /* m16 shift/rotate */
145
146 13, 5,12, /* CMPS 8-bit */
147 13, 5,12, /* CMPS 16-bit */
148 9, 5, 8, /* SCAS 8-bit */
149 9, 5, 8, /* SCAS 16-bit */
150 5, 5, 4, /* LODS 8-bit */
151 5, 5, 4, /* LODS 16-bit */
152 4, 4, 3, /* STOS 8-bit */
153 4, 4, 3, /* STOS 16-bit */
154 5, 5, 4, /* MOVS 8-bit */
155 5, 5, 4, /* MOVS 16-bit */
156
157 5, 5, 4, /* (80186) INS 8-bit */
158 5, 5, 4, /* (80186) INS 16-bit */
159 5, 5, 4, /* (80186) OUTS 8-bit */
160 5, 5, 4, /* (80186) OUTS 16-bit */
161 3,17,19, /* (80186) PUSH immediate, PUSHA/POPA */
162 21,24, /* (80186) IMUL immediate 8-bit */
163 21,24, /* (80186) IMUL immediate 16-bit */
164 11,15,12, 4, 5, /* (80186) ENTER/LEAVE */
165 13, /* (80186) BOUND */
166 };
167
168 DEFINE_DEVICE_TYPE(I80286, i80286_cpu_device, "i80286", "Intel 80286")
169
i80286_cpu_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)170 i80286_cpu_device::i80286_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
171 : i8086_common_cpu_device(mconfig, I80286, tag, owner, clock)
172 , m_program_config("program", ENDIANNESS_LITTLE, 16, 24, 0)
173 , m_opcodes_config("opcodes", ENDIANNESS_LITTLE, 16, 24, 0)
174 , m_io_config("io", ENDIANNESS_LITTLE, 16, 16, 0)
175 , m_out_shutdown_func(*this)
176 {
177 memcpy(m_timing, m_i80286_timing, sizeof(m_i80286_timing));
178 m_amask = 0xffffff;
179 memset(m_sregs, 0x00, sizeof(m_sregs));
180 m_sregs[CS] = 0xf000;
181 memset(m_base, 0x00, sizeof(m_base));
182 m_base[CS] = 0xff0000;
183 memset(m_limit, 0x00, sizeof(m_limit));
184 m_limit[CS] = m_limit[SS] = m_limit[DS] = m_limit[ES] = 0xffff;
185 memset(m_rights, 0x00, sizeof(m_rights));
186 m_rights[DS] = m_rights[SS] = m_rights[ES] = 0x93;
187 memset(&m_gdtr, 0x00, sizeof(m_gdtr));
188 memset(&m_idtr, 0x00, sizeof(m_idtr));
189 m_idtr.limit = 0x3ff;
190 memset(&m_ldtr, 0x00, sizeof(m_ldtr));
191 memset(&m_tr, 0x00, sizeof(m_tr));
192 m_msw = 0xfff0;
193 }
194
device_reset()195 void i80286_cpu_device::device_reset()
196 {
197 i8086_common_cpu_device::device_reset();
198 m_MF = 0;
199 m_NT = 0;
200 m_IOPL = 0;
201 m_msw = 0xfff0;
202 m_limit[CS] = m_limit[SS] = m_limit[DS] = m_limit[ES] = 0xffff;
203 m_sregs[DS] = m_sregs[SS] = m_sregs[ES] = 0;
204 m_base[DS] = m_base[SS] = m_base[ES] = 0;
205 m_rights[DS] = m_rights[SS] = m_rights[ES] = 0x93;
206 m_rights[CS] = 0x93;
207 m_valid[CS] = m_valid[SS] = m_valid[DS] = m_valid[ES] = true;
208 m_idtr.base = 0;
209 m_idtr.limit = 0x3ff;
210 m_gdtr.base = m_ldtr.base = m_tr.base = 0;
211 m_gdtr.limit = m_ldtr.limit = m_tr.limit = 0;
212 m_ldtr.rights = m_tr.rights = 0;
213 m_ldtr.sel = m_tr.sel = 0;
214 m_sregs[CS] = 0xf000;
215 m_base[CS] = 0xff0000;
216 m_ip = 0xfff0;
217 m_trap_level = 0;
218 m_shutdown = false;
219 m_out_shutdown_func(false);
220 }
221
device_start()222 void i80286_cpu_device::device_start()
223 {
224 i8086_common_cpu_device::device_start();
225 save_item(NAME(m_trap_level));
226 save_item(NAME(m_msw));
227 save_item(NAME(m_base));
228 save_item(NAME(m_limit));
229 save_item(NAME(m_rights));
230 save_item(NAME(m_valid));
231 save_item(NAME(m_gdtr.base));
232 save_item(NAME(m_gdtr.limit));
233 save_item(NAME(m_idtr.base));
234 save_item(NAME(m_idtr.limit));
235 save_item(NAME(m_ldtr.sel));
236 save_item(NAME(m_ldtr.base));
237 save_item(NAME(m_ldtr.limit));
238 save_item(NAME(m_ldtr.rights));
239 save_item(NAME(m_tr.sel));
240 save_item(NAME(m_tr.base));
241 save_item(NAME(m_tr.limit));
242 save_item(NAME(m_tr.rights));
243 save_item(NAME(m_amask));
244 save_item(NAME(m_shutdown));
245
246 state_add( I286_ES, "ES", m_sregs[ES] ).formatstr("%04X");
247 state_add( I286_ES_BASE, "ESBASE", m_base[ES]).formatstr("%06X");
248 state_add( I286_ES_LIMIT, "ESLIMIT", m_limit[ES]).formatstr("%04X");
249 state_add( I286_ES_FLAGS, "ESFLAGS", m_rights[ES]).formatstr("%02X");
250 state_add( I286_CS, "CS", m_sregs[CS] ).callimport().formatstr("%04X");
251 state_add( I286_CS_BASE, "CSBASE", m_base[CS]).callimport().formatstr("%06X");
252 state_add( I286_CS_LIMIT, "CSLIMIT", m_limit[CS]).formatstr("%04X");
253 state_add( I286_CS_FLAGS, "CSFLAGS", m_rights[CS]).formatstr("%02X");
254 state_add( I286_SS, "SS", m_sregs[SS] ).formatstr("%04X");
255 state_add( I286_SS_BASE, "SSBASE", m_base[SS]).formatstr("%06X");
256 state_add( I286_SS_LIMIT, "SSLIMIT", m_limit[SS]).formatstr("%04X");
257 state_add( I286_SS_FLAGS, "SSFLAGS", m_rights[SS]).formatstr("%02X");
258 state_add( I286_DS, "DS", m_sregs[DS] ).formatstr("%04X");
259 state_add( I286_DS_BASE, "DSBASE", m_base[DS]).formatstr("%06X");
260 state_add( I286_DS_LIMIT, "DSLIMIT", m_limit[DS]).formatstr("%04X");
261 state_add( I286_DS_FLAGS, "DSFLAGS", m_rights[DS]).formatstr("%02X");
262 state_add( I286_GDTR_BASE, "GDTRBASE", m_gdtr.base).formatstr("%06X");
263 state_add( I286_GDTR_LIMIT, "GDTRLIMIT", m_gdtr.limit).formatstr("%04X");
264 state_add( I286_IDTR_BASE, "IDTRBASE", m_idtr.base).formatstr("%06X");
265 state_add( I286_IDTR_LIMIT, "IDTRLIMIT", m_idtr.limit).formatstr("%04X");
266 state_add( I286_LDTR, "LDTR", m_ldtr.sel ).formatstr("%04X");
267 state_add( I286_LDTR_BASE, "LDTRBASE", m_ldtr.base).formatstr("%06X");
268 state_add( I286_LDTR_LIMIT, "LDTRLIMIT", m_ldtr.limit).formatstr("%04X");
269 state_add( I286_LDTR_FLAGS, "LDTRFLAGS", m_ldtr.rights).formatstr("%02X");
270 state_add( I286_TR, "TR", m_tr.sel ).formatstr("%04X");
271 state_add( I286_TR_BASE, "TRBASE", m_tr.base).formatstr("%06X");
272 state_add( I286_TR_LIMIT, "TRLIMIT", m_tr.limit).formatstr("%04X");
273 state_add( I286_TR_FLAGS, "TRFLAGS", m_tr.rights).formatstr("%02X");
274 state_add( I286_MSW, "MSW", m_msw ).formatstr("%04X");
275 state_add( I286_VECTOR, "V", m_int_vector).formatstr("%02X");
276
277 state_add( I286_PC, "PC", m_pc).callimport().formatstr("%06X");
278 state_add<uint32_t>( STATE_GENPCBASE, "CURPC", [this] { return m_base[CS] + m_prev_ip; }).mask(0xffffff).noshow();
279 state_add( I8086_HALT, "HALT", m_halt ).mask(1);
280
281 m_out_shutdown_func.resolve_safe();
282 }
283
memory_space_config() const284 device_memory_interface::space_config_vector i80286_cpu_device::memory_space_config() const
285 {
286 if(has_configured_map(AS_OPCODES))
287 return space_config_vector {
288 std::make_pair(AS_PROGRAM, &m_program_config),
289 std::make_pair(AS_OPCODES, &m_opcodes_config),
290 std::make_pair(AS_IO, &m_io_config)
291 };
292 else
293 return space_config_vector {
294 std::make_pair(AS_PROGRAM, &m_program_config),
295 std::make_pair(AS_IO, &m_io_config)
296 };
297 }
298
299
300 //-------------------------------------------------
301 // state_import - import state into the device,
302 // after it has been set
303 //-------------------------------------------------
304
state_import(const device_state_entry & entry)305 void i80286_cpu_device::state_import(const device_state_entry &entry)
306 {
307 switch (entry.index())
308 {
309 case I286_IP:
310 case I286_CS_BASE:
311 m_pc = m_base[CS] + m_ip;
312 break;
313
314 case I286_CS:
315 // TODO: should this call data_descriptor to update the current segment?
316 break;
317
318 case STATE_GENPC:
319 if (m_pc - m_base[CS] > m_limit[CS])
320 {
321 // TODO: should this call data_descriptor instead of ignoring jumps outside the current segment?
322 if (PM)
323 {
324 m_pc = m_base[CS] + m_ip;
325 }
326 else
327 {
328 m_sregs[CS] = m_pc >> 4;
329 m_base[CS] = m_sregs[CS] << 4;
330 }
331 }
332 m_ip = m_pc - m_base[CS];
333 m_prev_ip = m_ip;
334 break;
335 }
336 }
337
338
339 //-------------------------------------------------
340 // state_string_export - export state as a string
341 // for the debugger
342 //-------------------------------------------------
343
state_string_export(const device_state_entry & entry,std::string & str) const344 void i80286_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) const
345 {
346 switch (entry.index())
347 {
348 case STATE_GENFLAGS:
349 {
350 uint16_t flags = CompressFlags();
351 str = string_format("%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
352 flags & 0x8000 ? '0':'.',
353 flags & 0x4000 ? 'N':'.',
354 flags & 0x2000 ? 'I':'.',
355 flags & 0x1000 ? 'I':'.',
356 flags & 0x0800 ? 'O':'.',
357 flags & 0x0400 ? 'D':'.',
358 flags & 0x0200 ? 'I':'.',
359 flags & 0x0100 ? 'T':'.',
360 flags & 0x0080 ? 'S':'.',
361 flags & 0x0040 ? 'Z':'.',
362 flags & 0x0020 ? '0':'.',
363 flags & 0x0010 ? 'A':'.',
364 flags & 0x0008 ? '0':'.',
365 flags & 0x0004 ? 'P':'.',
366 flags & 0x0002 ? '1':'.',
367 flags & 0x0001 ? 'C':'.');
368 }
369 break;
370 }
371 }
372
memory_translate(int spacenum,int intention,offs_t & address)373 bool i80286_cpu_device::memory_translate(int spacenum, int intention, offs_t &address)
374 {
375 if(spacenum == AS_PROGRAM)
376 address &= m_amask;
377
378 return true;
379 }
380
execute_set_input(int inptnum,int state)381 void i80286_cpu_device::execute_set_input(int inptnum, int state)
382 {
383 if(inptnum == INPUT_LINE_NMI)
384 {
385 if(m_nmi_state == state)
386 {
387 return;
388 }
389 m_nmi_state = state;
390 if(state != CLEAR_LINE)
391 {
392 m_pending_irq |= NMI_IRQ;
393 }
394 }
395 else if(inptnum == INPUT_LINE_A20)
396 m_amask = m_a20_callback.isnull() ? 0xffffff : m_a20_callback(state);
397 else
398 {
399 m_irq_state = state;
400 if(state == CLEAR_LINE)
401 {
402 m_pending_irq &= ~INT_IRQ;
403 }
404 else
405 {
406 m_pending_irq |= INT_IRQ;
407 }
408 }
409 }
410 // when a cpu reset happens on a AT the bios checks for 9 in byte 0xf
411 // of the nvram. if yes, after init, it sets the stack pointer to the value in 0040:0067
412 // in the bios data segment then pops es and ds off that stack, does popa then a far ret.
413
trap(uint32_t error)414 void i80286_cpu_device::trap(uint32_t error)
415 {
416 int error_code = error & 0xffff;
417 uint16_t number = error >> 16;
418 if(error_code == 0xffff)
419 error_code = -1;
420 m_ip = m_prev_ip;
421 try
422 {
423 switch(number)
424 {
425 case FAULT_DE:
426 case FAULT_TS:
427 case FAULT_NP:
428 case FAULT_SS:
429 case FAULT_GP:
430 m_trap_level++;
431 if(m_trap_level == 2)
432 throw TRAP(FAULT_DF,0);
433 if(m_trap_level == 3)
434 break;
435 interrupt_descriptor(number,1,error_code);
436 break;
437 case FAULT_DF:
438 interrupt_descriptor(number,1,0);
439 break;
440 default:
441 interrupt_descriptor(number,1,-1);
442 }
443 }
444 catch(uint32_t e)
445 {
446 trap(e);
447 }
448 if(m_trap_level == 3)
449 {
450 m_shutdown = true;
451 m_out_shutdown_func(true);
452 }
453 m_trap_level = 0;
454 }
455
selector_address(uint16_t sel)456 uint32_t i80286_cpu_device::selector_address(uint16_t sel)
457 {
458 uint32_t base;
459 uint16_t limit;
460 if(TBL(sel))
461 {
462 base = m_ldtr.base;
463 limit = m_ldtr.limit;
464 }
465 else
466 {
467 base = m_gdtr.base;
468 limit = m_gdtr.limit;
469 }
470 return ((IDX(sel) >= limit) || !IDXTBL(sel) ? -1 : base + IDX(sel));
471 }
472
verify(uint16_t selector,int operation,uint8_t rights,bool valid)473 int i80286_cpu_device::verify(uint16_t selector, int operation, uint8_t rights, bool valid)
474 {
475 if(!IDXTBL(selector) && !valid)
476 return FAULT_GP;
477 if(!SEGDESC(rights))
478 return FAULT_GP;
479
480 switch (operation)
481 {
482 case I8086_READ:
483 if(CODE(rights) && !READ(rights))
484 return FAULT_GP;
485 break;
486 case I8086_WRITE:
487 if(CODE(rights) || !RW(rights))
488 return FAULT_GP;
489 break;
490 case I8086_FETCH:
491 if(!CODE(rights))
492 return FAULT_GP;
493 break;
494 }
495 return 0;
496 }
497
pop_seg(int reg)498 void i80286_cpu_device::pop_seg(int reg)
499 {
500 uint16_t sel;
501 if(PM)
502 check_permission(SS, m_regs.w[SP], 2, I8086_READ);
503 sel = read_word(m_base[SS] + m_regs.w[SP]);
504 data_descriptor(reg, sel);
505 m_regs.w[SP] += 2;
506 }
507
data_descriptor(int reg,uint16_t selector,int cpl,uint32_t trap,uint16_t offset,int size)508 void i80286_cpu_device::data_descriptor(int reg, uint16_t selector, int cpl, uint32_t trap, uint16_t offset, int size)
509 {
510 if(PM)
511 {
512 uint16_t desc[3];
513 uint8_t r;
514 uint32_t addr;
515 if((reg != SS) && !IDXTBL(selector))
516 {
517 m_sregs[reg] = 0;
518 m_limit[reg] = 0;
519 m_base[reg] = 0;
520 m_rights[reg] = 0;
521 m_valid[reg] = 0;
522 return;
523 }
524
525 if((addr = selector_address(selector)) == -1)
526 throw trap;
527
528 desc[0] = read_word(addr);
529 desc[1] = read_word(addr + 2);
530 desc[2] = read_word(addr + 4);
531 r = RIGHTS(desc);
532
533 if(!SEGDESC(r))
534 throw trap;
535
536 if(reg == SS)
537 {
538 if(!IDXTBL(selector))
539 throw trap;
540 if(DPL(r) != cpl)
541 throw trap;
542 if(RPL(selector) != cpl)
543 throw trap;
544 if(!RW(r) || CODE(r))
545 throw trap;
546 if(!PRES(r))
547 throw TRAP(FAULT_SS, (IDXTBL(selector) + (trap & 1)));
548 }
549 else
550 {
551 if((DPL(r) < PMAX(cpl, RPL(selector))) && (!CODE(r) || (CODE(r) && !CONF(r))))
552 throw trap;
553 if(CODE(r) && !READ(r))
554 throw trap;
555 if(!PRES(r))
556 throw TRAP(FAULT_NP, (IDXTBL(selector) + (trap & 1)));
557 }
558
559 if(offset + size)
560 {
561 if((CODE(r) || !EXPDOWN(r)) && ((offset + size - 1) > LIMIT(desc)))
562 throw (reg==SS) ? TRAP(FAULT_SS, (trap & 1)) : trap;
563
564 if(!CODE(r) && EXPDOWN(r) && ((offset <= LIMIT(desc)) || ((offset + size - 1) > 0xffff)))
565 throw (reg==SS) ? TRAP(FAULT_SS, (trap & 1)) : trap;
566 }
567
568 SET_ACC(desc);
569 write_word(addr + 4, desc[2]);
570 m_sregs[reg] = selector;
571 m_limit[reg] = LIMIT(desc);
572 m_base[reg] = BASE(desc);
573 m_rights[reg] = RIGHTS(desc);
574 }
575 else
576 {
577 m_sregs[reg] = selector;
578 m_base[reg] = selector << 4;
579 }
580 m_valid[reg] = 1;
581 }
582
data_descriptor(int reg,uint16_t selector)583 void i80286_cpu_device::data_descriptor(int reg, uint16_t selector)
584 {
585 data_descriptor(reg, selector, CPL, TRAP(FAULT_GP,IDXTBL(selector)));
586 }
587
switch_task(uint16_t ntask,int type)588 void i80286_cpu_device::switch_task(uint16_t ntask, int type)
589 {
590 uint16_t ndesc[3], desc[3], ntss[22], otss[22], flags;
591 uint8_t r, lr;
592 uint32_t naddr, oaddr, ldtaddr;
593 int i;
594 logerror("i286: %06x This program uses TSSs, how rare. Please report this to the developers.\n", m_pc);
595
596 if(TBL(ntask))
597 throw TRAP(FAULT_TS, IDXTBL(ntask));
598
599 if((naddr = selector_address(ntask)) == -1)
600 throw TRAP(FAULT_TS, IDXTBL(ntask));
601
602 oaddr = selector_address(m_tr.sel);
603 ndesc[0] = read_word(naddr);
604 ndesc[1] = read_word(naddr + 2);
605 ndesc[2] = read_word(naddr + 4);
606 desc[2] = read_word(oaddr + 4);
607 r = RIGHTS(ndesc);
608
609 if(SEGDESC(r) || ((GATE(r) & ~2) != TSSDESCIDLE))
610 throw TRAP(FAULT_GP, IDXTBL(ntask));
611
612 if(!PRES(r))
613 throw TRAP(FAULT_NP, IDXTBL(ntask));
614
615 if(LIMIT(ndesc) < 43)
616 throw TRAP(FAULT_TS, IDXTBL(ntask));
617
618 flags = CompressFlags();
619
620 if(type == NT_CALL)
621 write_word(BASE(ndesc) + TSS_BACK * 2, m_tr.sel);
622
623 if(type == NT_IRET)
624 flags &= ~0x4000;
625
626 otss[TSS_IP] = m_ip;
627 otss[TSS_FLAG] = flags;
628 otss[TSS_AX] = m_regs.w[AX];
629 otss[TSS_CX] = m_regs.w[CX];
630 otss[TSS_DX] = m_regs.w[DX];
631 otss[TSS_BX] = m_regs.w[BX];
632 otss[TSS_SP] = m_regs.w[SP];
633 otss[TSS_BP] = m_regs.w[BP];
634 otss[TSS_SI] = m_regs.w[SI];
635 otss[TSS_DI] = m_regs.w[DI];
636 otss[TSS_ES] = m_sregs[ES];
637 otss[TSS_CS] = m_sregs[CS];
638 otss[TSS_SS] = m_sregs[SS];
639 otss[TSS_DS] = m_sregs[DS];
640
641 for (i = 14; i < 42; i += 2)
642 write_word(m_tr.base + i, otss[i / 2]);
643
644 for (i = 0; i < 44; i += 2)
645 ntss[i / 2] = read_word(BASE(ndesc) + i);
646
647 // jmp does both
648 if(type != NT_CALL)
649 {
650 desc[2] &= ~0x200; // mark idle
651 write_word(oaddr + 4, desc[2]);
652 }
653
654 if(type != NT_IRET)
655 {
656 ndesc[2] |= 0x200;
657 write_word(naddr + 4, ndesc[2]);
658 }
659
660 m_tr.sel = ntask;
661 m_tr.limit = LIMIT(ndesc);
662 m_tr.base = BASE(ndesc);
663 m_tr.rights = RIGHTS(ndesc);
664
665 load_flags(ntss[TSS_FLAG], 0);
666 m_regs.w[AX] = ntss[TSS_AX];
667 m_regs.w[CX] = ntss[TSS_CX];
668 m_regs.w[DX] = ntss[TSS_DX];
669 m_regs.w[BX] = ntss[TSS_BX];
670 m_regs.w[SP] = ntss[TSS_SP];
671 m_regs.w[BP] = ntss[TSS_BP];
672 m_regs.w[SI] = ntss[TSS_SI];
673 m_regs.w[DI] = ntss[TSS_DI];
674
675 if(TBL(ntss[TSS_LDT]))
676 throw TRAP(FAULT_TS, IDXTBL(ntss[TSS_LDT]));
677
678 if(IDXTBL(ntss[TSS_LDT]))
679 {
680 if((ldtaddr = selector_address(ntss[TSS_LDT])) == -1)
681 throw TRAP(FAULT_TS, IDXTBL(ntss[TSS_LDT]));
682
683 desc[0] = read_word(ldtaddr);
684 desc[1] = read_word(ldtaddr + 2);
685 desc[2] = read_word(ldtaddr + 4);
686 lr = RIGHTS(desc);
687
688 if(SEGDESC(lr) || (GATE(lr) != LDTDESC))
689 throw TRAP(FAULT_TS, IDXTBL(ntss[TSS_LDT]));
690
691 if(!PRES(lr))
692 throw TRAP(FAULT_TS, IDXTBL(ntss[TSS_LDT]));
693
694 m_ldtr.sel = ntss[TSS_LDT];
695 m_ldtr.limit = LIMIT(desc);
696 m_ldtr.base = BASE(desc);
697 m_ldtr.rights = RIGHTS(desc);
698 }
699 else
700 {
701 m_ldtr.sel = 0;
702 m_ldtr.limit = 0;
703 m_ldtr.base = 0;
704 m_ldtr.rights = 0;
705 }
706
707 if(type == NT_CALL)
708 m_NT = 1;
709
710 m_msw |= 8;
711 // Docs explicitly say SS is loaded first. Why? Because the DPL
712 // of the TSS is compared to the DPL of SS which is CPL
713 data_descriptor(SS, ntss[TSS_SS], RPL(ntss[TSS_CS]), TRAP(FAULT_TS, IDXTBL(ntss[TSS_SS])));
714
715 try
716 {
717 code_descriptor(ntss[TSS_CS], ntss[TSS_IP], 0);
718 }
719 catch (uint32_t e)
720 {
721 int error_code = e & 0xffff;
722 if(error_code == FAULT_GP)
723 e = TRAP(FAULT_TS, (e >> 16)); // #NP fault is correct
724 throw e;
725 }
726
727 data_descriptor(ES, ntss[TSS_ES], CPL, TRAP(FAULT_TS, IDXTBL(ntss[TSS_ES])));
728 data_descriptor(DS, ntss[TSS_DS], CPL, TRAP(FAULT_TS, IDXTBL(ntss[TSS_DS])));
729 }
730
code_descriptor(uint16_t selector,uint16_t offset,int gate)731 void i80286_cpu_device::code_descriptor(uint16_t selector, uint16_t offset, int gate)
732 {
733 if(PM)
734 {
735 uint16_t desc[3];
736 uint8_t r;
737 uint32_t addr;
738 if((addr = selector_address(selector)) == -1)
739 throw TRAP(FAULT_GP, IDXTBL(selector));
740
741 desc[0] = read_word(addr);
742 desc[1] = read_word(addr + 2);
743 desc[2] = read_word(addr + 4);
744 r = RIGHTS(desc);
745
746 if(SEGDESC(r))
747 {
748 if(!CODE(r))
749 throw TRAP(FAULT_GP, IDXTBL(selector));
750
751 if(CONF(r))
752 {
753 if(DPL(r) > CPL)
754 throw TRAP(FAULT_GP, IDXTBL(selector));
755 }
756 else
757 if((RPL(selector) > CPL) || (DPL(r) != CPL))
758 throw TRAP(FAULT_GP, IDXTBL(selector));
759
760 if(!PRES(r))
761 throw TRAP(FAULT_NP, IDXTBL(selector)); // this order is important
762
763 if(offset > LIMIT(desc))
764 throw TRAP(FAULT_GP, 0);
765
766 SET_ACC(desc);
767 write_word(addr + 4, desc[2]);
768 m_sregs[CS] = IDXTBL(selector) | CPL;
769 m_limit[CS] = LIMIT(desc);
770 m_base[CS] = BASE(desc);
771 m_rights[CS] = RIGHTS(desc);
772 m_prev_ip = m_ip = offset;
773 }
774 else
775 { // systemdescriptor
776 uint16_t gatesel = GATESEL(desc);
777
778 if(!gate)
779 throw TRAP(FAULT_GP, IDXTBL(selector)); // tss cs must be segment
780 if(DPL(r) < PMAX(CPL,RPL(selector)))
781 throw TRAP(FAULT_GP, IDXTBL(selector));
782 if(!PRES(r))
783 throw TRAP(FAULT_NP, IDXTBL(selector));
784
785 switch (GATE(r))
786 {
787 case CALLGATE:
788 {
789 uint16_t gatedesc[3];
790 if((addr = selector_address(gatesel)) == -1)
791 throw TRAP(FAULT_GP, IDXTBL(gatesel));
792
793 gatedesc[0] = read_word(addr);
794 gatedesc[1] = read_word(addr + 2);
795 gatedesc[2] = read_word(addr + 4);
796 r = RIGHTS(gatedesc);
797
798 if(!CODE(r) || !SEGDESC(r))
799 throw TRAP(FAULT_GP, IDXTBL(gatesel));
800 if(DPL(r) > CPL)
801 throw TRAP(FAULT_GP, IDXTBL(gatesel));
802 if(!PRES(r))
803 throw TRAP(FAULT_NP, IDXTBL(gatesel));
804
805 if(GATEOFF(desc) > LIMIT(gatedesc))
806 throw TRAP(FAULT_GP,0);
807
808 if (!CONF(r) && (DPL(r) < CPL))
809 {
810 // inner call
811 uint16_t tss_ss, tss_sp, oldss, oldsp;
812 uint32_t oldstk;
813 int i;
814 if(gate == NT_JMP)
815 throw TRAP(FAULT_GP, IDXTBL(gatesel)); // can't jmp to inner
816
817 tss_ss = read_word(m_tr.base+TSS_SS0*2+(DPL(r)*4));
818 tss_sp = read_word(m_tr.base+TSS_SP0*2+(DPL(r)*4));
819
820 oldss = m_sregs[SS];
821 oldsp = m_regs.w[SP];
822 oldstk = m_base[SS] + oldsp;
823 data_descriptor(SS, tss_ss, DPL(r), TRAP(FAULT_TS,IDXTBL(tss_ss)), tss_sp-8-(GATECNT(desc)*2), 8+(GATECNT(desc)*2));
824 m_regs.w[SP] = tss_sp;
825 PUSH(oldss);
826 PUSH(oldsp);
827 for(i = GATECNT(desc)-1; i >= 0; i--)
828 PUSH(read_word(oldstk+(i*2)));
829 }
830 else
831 check_permission(SS, m_regs.w[SP]-4, 4, I8086_READ);
832
833 SET_ACC(gatedesc);
834 write_word(addr+4, gatedesc[2]);
835 m_sregs[CS]=IDXTBL(gatesel) | DPL(r);
836 m_limit[CS]=LIMIT(gatedesc);
837 m_base[CS]=BASE(gatedesc);
838 m_rights[CS]=RIGHTS(gatedesc);
839 m_ip=GATEOFF(desc);
840 break;
841 }
842
843 case TASKGATE:
844 selector = gatesel;
845 if((addr = selector_address(selector)) == -1)
846 throw TRAP(FAULT_GP, IDXTBL(selector));
847
848 desc[2] = read_word(addr+4);
849 r = RIGHTS(desc);
850 if (SEGDESC(r) || (GATE(r) != TSSDESCIDLE))
851 throw TRAP(FAULT_GP,IDXTBL(selector));
852
853 case TSSDESCIDLE:
854 switch_task(selector, gate);
855 load_flags(CompressFlags(), CPL);
856 break;
857
858 default:
859 throw TRAP(FAULT_GP,IDXTBL(selector));
860 }
861 }
862 }
863 else
864 {
865 m_prev_ip = m_ip = offset;
866 m_sregs[CS]=selector;
867 m_base[CS]=selector<<4;
868 m_rights[CS]=0x93;
869 m_limit[CS]=0xffff;
870 }
871 }
872
interrupt_descriptor(int number,int hwint,int error)873 void i80286_cpu_device::interrupt_descriptor(int number, int hwint, int error)
874 {
875 uint16_t desc[3], gatesel, flags = CompressFlags();
876 uint8_t r;
877 hwint = hwint ? 1 : 0;
878
879 if(number == -1)
880 {
881 number = standard_irq_callback(0);
882
883 hwint = 1;
884 }
885
886 debugger_exception_hook(number);
887
888 if(!PM)
889 {
890 PUSH(flags & ~0xf000);
891 m_TF = m_IF = 0;
892
893 uint16_t dest_off = read_word(number * 4 + 0);
894 uint16_t dest_seg = read_word(number * 4 + 2);
895
896 PUSH(m_sregs[CS]);
897 PUSH(m_ip);
898 code_descriptor(dest_seg, dest_off, 0);
899 return;
900 }
901
902 if((number << 3) >= m_idtr.limit)
903 throw TRAP(FAULT_GP, (number * 8 + 2 + hwint));
904
905 desc[0] = read_word(m_idtr.base + (number << 3));
906 desc[1] = read_word(m_idtr.base + (number << 3) + 2);
907 desc[2] = read_word(m_idtr.base + (number << 3) + 4);
908
909 r = RIGHTS(desc);
910 if(!hwint && (DPL(r) < CPL))
911 throw TRAP(FAULT_GP, (number * 8 + 2 + hwint));
912 if(!PRES(r))
913 throw TRAP(FAULT_NP, (number * 8 + 2 + hwint));
914 gatesel = GATESEL(desc);
915
916 switch (GATE(r))
917 {
918 case TASKGATE:
919 try
920 {
921 switch_task(gatesel, NT_CALL);
922 }
923 catch (uint32_t e)
924 {
925 throw e + hwint;
926 }
927 if((hwint == 1) && (error != -1))
928 PUSH(error);
929 load_flags(CompressFlags(), CPL); // new flags
930 break;
931
932 case INTGATE:
933 case TRAPGATE:
934 {
935 uint16_t gatedesc[3];
936 uint32_t addr;
937
938 if((addr = selector_address(gatesel)) == -1)
939 throw TRAP(FAULT_GP, (IDXTBL(gatesel) + hwint));
940
941 gatedesc[0] = read_word(addr);
942 gatedesc[1] = read_word(addr + 2);
943 gatedesc[2] = read_word(addr + 4);
944 r = RIGHTS(gatedesc);
945 if(!CODE(r) || !SEGDESC(r))
946 throw TRAP(FAULT_GP, (IDXTBL(gatesel) + hwint));
947 if(DPL(r) > CPL)
948 throw TRAP(FAULT_GP, (IDXTBL(gatesel) + hwint));
949 if(!PRES(r))
950 throw TRAP(FAULT_NP, (IDXTBL(gatesel) + hwint));
951 if(GATEOFF(desc) > LIMIT(gatedesc))
952 throw TRAP(FAULT_GP, hwint);
953
954 if(!CONF(r) && (DPL(r) < CPL))
955 {
956 // inner call
957 uint16_t tss_ss, tss_sp, oldss, oldsp;
958 tss_ss = read_word(m_tr.base + TSS_SS0 * 2 + (DPL(r) * 4));
959 tss_sp = read_word(m_tr.base + TSS_SP0 * 2 + (DPL(r) * 4));
960
961 oldss = m_sregs[SS];
962 oldsp = m_regs.w[SP];
963 data_descriptor(SS, tss_ss, DPL(r), TRAP(FAULT_TS, (IDXTBL(tss_ss) + hwint)), tss_sp - ((error != -1) ? 12 : 10), (error != -1) ? 12 : 10);
964 m_regs.w[SP] = tss_sp;
965 PUSH(oldss);
966 PUSH(oldsp);
967 }
968 else
969 check_permission(SS, m_regs.w[SP] - ((error != -1) ? 8 : 6), (error != -1) ? 8 : 6, I8086_READ);
970
971 SET_ACC(gatedesc);
972 write_word(addr + 4, gatedesc[2]);
973 PUSH(flags);
974 PUSH(m_sregs[CS]);
975 PUSH(m_ip);
976 if((hwint == 1) && (error != -1))
977 PUSH(error);
978 m_sregs[CS] = IDXTBL(gatesel) | DPL(r);
979 m_limit[CS] = LIMIT(gatedesc);
980 m_base[CS] = BASE(gatedesc);
981 m_rights[CS] = RIGHTS(gatedesc);
982 m_prev_ip = m_ip = GATEOFF(desc);
983 m_TF = 0;
984 m_NT = 0;
985 if(GATE(RIGHTS(desc)) == INTGATE)
986 m_IF = 0;
987 break;
988 }
989 default:
990 throw TRAP(FAULT_GP, (number * 8 + 2 + hwint));
991 }
992 }
993
read_port_byte(uint16_t port)994 uint8_t i80286_cpu_device::read_port_byte(uint16_t port)
995 {
996 if(PM && (CPL > m_IOPL))
997 throw TRAP(FAULT_GP, 0);
998 return m_io->read_byte(port);
999 }
1000
read_port_word(uint16_t port)1001 uint16_t i80286_cpu_device::read_port_word(uint16_t port)
1002 {
1003 if(PM && (CPL > m_IOPL))
1004 throw TRAP(FAULT_GP, 0);
1005 return m_io->read_word_unaligned(port);
1006 }
1007
write_port_byte(uint16_t port,uint8_t data)1008 void i80286_cpu_device::write_port_byte(uint16_t port, uint8_t data)
1009 {
1010 if(PM && (CPL > m_IOPL))
1011 throw TRAP(FAULT_GP, 0);
1012 m_io->write_byte(port, data);
1013 }
1014
write_port_word(uint16_t port,uint16_t data)1015 void i80286_cpu_device::write_port_word(uint16_t port, uint16_t data)
1016 {
1017 if(PM && (CPL > m_IOPL))
1018 throw TRAP(FAULT_GP, 0);
1019 m_io->write_word_unaligned(port, data);
1020 }
1021
fetch()1022 uint8_t i80286_cpu_device::fetch()
1023 {
1024 uint8_t data;
1025 if(m_ip > m_limit[CS])
1026 throw TRAP(FAULT_GP, 0);
1027
1028 data = m_or8(update_pc() & m_amask);
1029 m_ip++;
1030 return data;
1031 }
1032
calc_addr(int seg,uint16_t offset,int size,int op,bool override)1033 uint32_t i80286_cpu_device::calc_addr(int seg, uint16_t offset, int size, int op, bool override)
1034 {
1035 seg = (m_seg_prefix && (seg==DS || seg==SS) && override) ? m_prefix_seg : seg;
1036 if(op != I8086_NONE)
1037 check_permission(seg, offset, size, op);
1038
1039 return (m_base[seg] + offset) & (op != I8086_NONE ? m_amask : 0xffffff);
1040 }
1041
execute_run()1042 void i80286_cpu_device::execute_run()
1043 {
1044 while(m_icount > 0 )
1045 {
1046 try
1047 {
1048 if ( m_seg_prefix_next )
1049 {
1050 m_seg_prefix = true;
1051 m_seg_prefix_next = false;
1052 }
1053 else
1054 {
1055 m_prev_ip = m_ip;
1056 m_seg_prefix = false;
1057
1058 /* Dispatch IRQ */
1059 if ( m_pending_irq && m_no_interrupt == 0 )
1060 {
1061 if ( m_pending_irq & NMI_IRQ )
1062 {
1063 interrupt_descriptor(NMI, 1, -1);
1064 m_pending_irq &= ~NMI_IRQ;
1065 m_halt = false;
1066 m_shutdown = false;
1067 m_out_shutdown_func(false);
1068 }
1069 else if ( m_IF )
1070 {
1071 interrupt_descriptor(-1, 1, -1);
1072 m_halt = false;
1073 }
1074 }
1075
1076 if(m_halt || m_shutdown)
1077 {
1078 m_icount = 0;
1079 return;
1080 }
1081
1082 /* No interrupt allowed between last instruction and this one */
1083 if ( m_no_interrupt )
1084 {
1085 m_no_interrupt--;
1086 }
1087
1088 /* trap should allow one instruction to be executed */
1089 if ( m_fire_trap )
1090 {
1091 if ( m_fire_trap >= 2 )
1092 {
1093 interrupt(1);
1094 m_fire_trap = 0;
1095 }
1096 else
1097 {
1098 m_fire_trap++;
1099 }
1100 }
1101 }
1102
1103 debugger_instruction_hook( update_pc() & m_amask );
1104
1105 uint8_t op = fetch_op();
1106
1107 switch(op)
1108 {
1109 case 0x07: // i_pop_es
1110 pop_seg(ES);
1111 CLK(POP_SEG);
1112 break;
1113
1114 case 0x0f:
1115 {
1116 unsigned next = fetch_op();
1117 uint16_t desc[3], tmp, msw, sel;
1118 uint8_t r;
1119 uint32_t addr;
1120
1121 switch (next)
1122 {
1123 case 0:
1124 if(!PM)
1125 throw TRAP(FAULT_UD, (uint16_t)-1);
1126 m_modrm = fetch();
1127 switch (m_modrm & 0x38)
1128 {
1129 case 0: /* sldt */
1130 PutRMWord(m_ldtr.sel);
1131 break;
1132
1133 case 8: /* str */
1134 PutRMWord(m_tr.sel);
1135 break;
1136
1137 case 0x10: /* lldt */
1138 if(CPL != 0)
1139 throw TRAP(FAULT_GP, 0);
1140 sel = GetRMWord();
1141 if(TBL(sel))
1142 throw TRAP(FAULT_GP, IDXTBL(sel));
1143 if(IDXTBL(sel))
1144 {
1145 if(IDX(sel) >= m_gdtr.limit)
1146 throw TRAP(FAULT_GP, IDXTBL(sel));
1147 addr = m_gdtr.base + IDX(sel);
1148 desc[0] = read_word(addr);
1149 desc[1] = read_word(addr + 2);
1150 desc[2] = read_word(addr + 4);
1151 r = RIGHTS(desc);
1152 if(SEGDESC(r) || (GATE(r) != LDTDESC))
1153 throw TRAP(FAULT_GP, IDXTBL(sel));
1154 if(!PRES(r))
1155 throw TRAP(FAULT_NP, IDXTBL(sel));
1156 }
1157 else
1158 {
1159 desc[0] = 0;
1160 desc[1] = 0;
1161 desc[2] = 0;
1162 }
1163 m_ldtr.sel = sel;
1164 m_ldtr.limit = LIMIT(desc);
1165 m_ldtr.base = BASE(desc);
1166 m_ldtr.rights = RIGHTS(desc);
1167 break;
1168
1169 case 0x18: /* ltr */
1170 if(CPL != 0)
1171 throw TRAP(FAULT_GP, 0);
1172 sel = GetRMWord();
1173 if((addr = selector_address(sel)) == -1)
1174 throw TRAP(FAULT_GP, IDXTBL(sel));
1175 desc[0] = read_word(addr);
1176 desc[1] = read_word(addr + 2);
1177 desc[2] = read_word(addr + 4);
1178 r = RIGHTS(desc);
1179 if(SEGDESC(r) || (GATE(r) != TSSDESCIDLE))
1180 throw TRAP(FAULT_GP, IDXTBL(sel));
1181 if(!PRES(r))
1182 throw TRAP(FAULT_NP, IDXTBL(sel));
1183 desc[2] |= 0x200; // mark busy
1184 write_word(addr + 4, desc[2]);
1185 m_tr.sel = sel;
1186 m_tr.limit = LIMIT(desc);
1187 m_tr.base = BASE(desc);
1188 m_tr.rights = RIGHTS(desc);
1189 break;
1190
1191 case 0x20: /* verr */
1192 tmp = GetRMWord();
1193 if((addr = selector_address(tmp)) == -1)
1194 m_ZeroVal = 1;
1195 else
1196 {
1197 desc[2] = read_word(addr + 4);
1198 r = RIGHTS(desc);
1199 m_ZeroVal = verify(tmp, I8086_READ, RIGHTS(desc), 0);
1200 m_ZeroVal = m_ZeroVal || (CODE(r) && CONF(r) ? 0 : (DPL(r) < PMAX(RPL(tmp),CPL)));
1201 }
1202 break;
1203
1204 case 0x28: /* verw */
1205 tmp = GetRMWord();
1206 if((addr = selector_address(tmp)) == -1)
1207 m_ZeroVal = 1;
1208 else
1209 {
1210 desc[2] = read_word(addr + 4);
1211 r = RIGHTS(desc);
1212 m_ZeroVal = verify(tmp, I8086_WRITE, RIGHTS(desc), 0);
1213 m_ZeroVal = m_ZeroVal || (DPL(r) < PMAX(RPL(tmp),CPL));
1214 }
1215 break;
1216
1217 default:
1218 throw TRAP(FAULT_UD, (uint16_t)-1);
1219 }
1220 break;
1221 case 1:
1222 {
1223 uint32_t ea;
1224 m_modrm = fetch();
1225 if((m_modrm >= 0xc0) && (m_modrm < 0xe0))
1226 throw TRAP(FAULT_UD, (uint16_t)-1);
1227 switch (m_modrm & 0x38)
1228 {
1229 case 0: /* sgdt */
1230 ea = get_ea(6, I8086_WRITE);
1231 write_word(ea, m_gdtr.limit);
1232 write_word(ea + 2, m_gdtr.base & 0xffff);
1233 write_word(ea + 4, 0xff00 | m_gdtr.base >> 16);
1234 break;
1235 case 8: /* sidt */
1236 ea = get_ea(6, I8086_WRITE);
1237 write_word(ea, m_idtr.limit);
1238 write_word(ea + 2, m_idtr.base & 0xffff);
1239 write_word(ea + 4, 0xff00 | m_idtr.base >> 16);
1240 break;
1241 case 0x10: /* lgdt */
1242 if(PM && (CPL != 0))
1243 throw TRAP(FAULT_GP, 0);
1244 ea = get_ea(6, I8086_READ);
1245 m_gdtr.limit = read_word(ea);
1246 m_gdtr.base = read_word(ea + 2) | (read_byte(ea + 4) << 16);
1247 break;
1248 case 0x18: /* lidt */
1249 if(PM && (CPL != 0))
1250 throw TRAP(FAULT_GP, 0);
1251 ea = get_ea(6, I8086_READ);
1252 m_idtr.limit = read_word(ea);
1253 m_idtr.base = read_word(ea + 2) | (read_byte(ea + 4) << 16);
1254 break;
1255 case 0x20: /* smsw */
1256 PutRMWord(m_msw);
1257 break;
1258 case 0x30: /* lmsw */
1259 if(PM && (CPL != 0))
1260 throw TRAP(FAULT_GP, 0);
1261 msw = GetRMWord();
1262 m_msw = (m_msw & 1) | msw;
1263 break;
1264 default:
1265 throw TRAP(FAULT_UD, (uint16_t)-1);
1266 }
1267 break;
1268 }
1269 case 2: /* LAR */
1270 if(!PM)
1271 throw TRAP(FAULT_UD, (uint16_t)-1);
1272 m_modrm = fetch_op();
1273 tmp = GetRMWord();
1274 if((addr = selector_address(tmp)) == -1)
1275 m_ZeroVal = 1;
1276 else
1277 {
1278 desc[2] = read_word(addr + 4);
1279 r = RIGHTS(desc);
1280 if(!SEGDESC(r) && ((GATE(r) > TRAPGATE) || !GATE(r)))
1281 m_ZeroVal = 1;
1282 else if(DPL(r) >= PMAX(RPL(tmp),CPL) || (SEGDESC(r) && CODE(r) && CONF(r)))
1283 {
1284 m_ZeroVal = 0;
1285 // rights are expected to be in upper byte
1286 RegWord(r << 8);
1287 }
1288 else
1289 m_ZeroVal = 1;
1290 }
1291 break;
1292 case 3: /* LSL */
1293 if(!PM)
1294 throw TRAP(FAULT_UD, (uint16_t)-1);
1295 m_modrm = fetch_op();
1296 tmp = GetRMWord();
1297 if((addr = selector_address(tmp)) == -1)
1298 m_ZeroVal = 1;
1299 else
1300 {
1301 desc[2] = read_word(addr + 4);
1302 r = RIGHTS(desc);
1303 if(!SEGDESC(r) && ((GATE(r) >= CALLGATE) || !GATE(r)))
1304 m_ZeroVal = 1; // not valid for gates
1305 else if(DPL(r) >= PMAX(RPL(tmp),CPL) || (SEGDESC(r) && CODE(r) && CONF(r)))
1306 {
1307 m_ZeroVal = 0;
1308 RegWord(read_word(addr));
1309 }
1310 else
1311 m_ZeroVal = 1;
1312 }
1313 break;
1314 case 5: /* loadall */
1315 if(PM && (CPL != 0))
1316 throw TRAP(FAULT_GP, 0);
1317 m_msw = (m_msw & 1) | read_word(0x806);
1318 m_tr.sel = read_word(0x816);
1319 ExpandFlags(read_word(0x818));
1320 m_ip = read_word(0x81a);
1321 m_ldtr.sel = read_word(0x81c);
1322 m_sregs[DS] = read_word(0x81e);
1323 m_sregs[SS] = read_word(0x820);
1324 m_sregs[CS] = read_word(0x822);
1325 m_sregs[ES] = read_word(0x824);
1326 m_regs.w[DI] = read_word(0x826);
1327 m_regs.w[SI] = read_word(0x828);
1328 m_regs.w[BP] = read_word(0x82a);
1329 m_regs.w[SP] = read_word(0x82c);
1330 m_regs.w[BX] = read_word(0x82e);
1331 m_regs.w[DX] = read_word(0x830);
1332 m_regs.w[CX] = read_word(0x832);
1333 m_regs.w[AX] = read_word(0x834);
1334 // loadall uses base-rights-limit order
1335 #define LOADDESC(addr, sreg) { desc[1] = read_word(addr); desc[2] = read_word(addr+2); desc[0] = read_word(addr+4); \
1336 m_base[sreg] = BASE(desc); m_rights[sreg] = RIGHTS(desc); \
1337 m_limit[sreg] = LIMIT(desc); }
1338 LOADDESC(0x836, ES);
1339 LOADDESC(0x83C, CS);
1340 LOADDESC(0x842, SS);
1341 LOADDESC(0x848, DS);
1342 #undef LOADDESC
1343 // void cast supresses warning
1344 #define LOADDESC(addr, reg, r) { desc[1] = read_word(addr); desc[2] = read_word(addr + 2); desc[0] = read_word(addr + 4); \
1345 reg.base = BASE(desc); (void)(r); reg.limit = LIMIT(desc); }
1346 LOADDESC(0x84e, m_gdtr, 1);
1347 LOADDESC(0x854, m_ldtr, m_ldtr.rights = RIGHTS(desc));
1348 LOADDESC(0x85a, m_idtr, 1);
1349 LOADDESC(0x860, m_tr, m_tr.rights = RIGHTS(desc));
1350 #undef LOADDESC
1351 break;
1352
1353 case 6: /* clts */
1354 if(PM && (CPL != 0))
1355 throw TRAP(FAULT_GP, 0);
1356 m_msw &= ~8;
1357 break;
1358 default:
1359 throw TRAP(FAULT_UD, (uint16_t)-1);
1360 }
1361 break;
1362 }
1363
1364 case 0x17: // i_pop_ss
1365 pop_seg(SS);
1366 CLK(POP_SEG);
1367 m_no_interrupt = 1;
1368 break;
1369
1370 case 0x1f: // i_pop_ds
1371 pop_seg(DS);
1372 CLK(POP_SEG);
1373 break;
1374
1375 case 0x54: // i_push_sp
1376 PUSH(m_regs.w[SP]);
1377 CLK(PUSH_R16);
1378 break;
1379
1380 case 0x60: // i_pusha
1381 {
1382 check_permission(SS, m_regs.w[SP]-16, 16, I8086_WRITE);
1383 uint32_t tmp = m_regs.w[SP];
1384 PUSH(m_regs.w[AX]);
1385 PUSH(m_regs.w[CX]);
1386 PUSH(m_regs.w[DX]);
1387 PUSH(m_regs.w[BX]);
1388 PUSH(tmp);
1389 PUSH(m_regs.w[BP]);
1390 PUSH(m_regs.w[SI]);
1391 PUSH(m_regs.w[DI]);
1392 CLK(PUSHA);
1393 }
1394 break;
1395
1396 case 0x61: // i_popa
1397 check_permission(SS, m_regs.w[SP], 16, I8086_READ);
1398 m_regs.w[DI] = POP();
1399 m_regs.w[SI] = POP();
1400 m_regs.w[BP] = POP();
1401 POP();
1402 m_regs.w[BX] = POP();
1403 m_regs.w[DX] = POP();
1404 m_regs.w[CX] = POP();
1405 m_regs.w[AX] = POP();
1406 CLK(POPA);
1407 break;
1408
1409 case 0x62: // i_bound
1410 {
1411 uint32_t low,high,tmp;
1412 m_modrm = fetch();
1413 low = GetRMWord();
1414 high = GetnextRMWord();
1415 tmp = RegWord();
1416 if (tmp<low || tmp>high)
1417 interrupt(5);
1418 CLK(BOUND);
1419 logerror("%06x: bound %04x high %04x low %04x tmp\n", m_pc, high, low, tmp);
1420 }
1421 break;
1422
1423 case 0x63: // arpl
1424 {
1425 uint16_t tmp, source;
1426 if (!PM) throw TRAP(FAULT_UD,(uint16_t)-1);
1427
1428 m_modrm=fetch_op();
1429 tmp=GetRMWord();
1430 source=RegWord();
1431
1432 if (RPL(tmp)<RPL(source))
1433 {
1434 m_ZeroVal = 0;
1435 PutbackRMWord(IDXTBL(tmp)|RPL(source));
1436 }
1437 else
1438 m_ZeroVal = 1;
1439 break;
1440 }
1441
1442 case 0x68: // i_push_d16
1443 PUSH( fetch_word() );
1444 CLK(PUSH_IMM);
1445 break;
1446
1447 case 0x69: // i_imul_d16
1448 {
1449 uint32_t tmp;
1450 DEF_r16w();
1451 tmp = fetch_word();
1452 m_dst = (int32_t)((int16_t)m_src)*(int32_t)((int16_t)tmp);
1453 m_CarryVal = m_OverVal = (((int32_t)m_dst) >> 15 != 0) && (((int32_t)m_dst) >> 15 != -1);
1454 RegWord(m_dst);
1455 CLKM(IMUL_RRI16, IMUL_RMI16);
1456 }
1457 break;
1458
1459 case 0x6a: // i_push_d8
1460 PUSH( (uint16_t)((int16_t)((int8_t)fetch())) );
1461 CLK(PUSH_IMM);
1462 break;
1463
1464 case 0x6b: // i_imul_d8
1465 {
1466 uint32_t src2;
1467 DEF_r16w();
1468 src2= (uint16_t)((int16_t)((int8_t)fetch()));
1469 m_dst = (int32_t)((int16_t)m_src)*(int32_t)((int16_t)src2);
1470 m_CarryVal = m_OverVal = (((int32_t)m_dst) >> 15 != 0) && (((int32_t)m_dst) >> 15 != -1);
1471 RegWord(m_dst);
1472 CLKM(IMUL_RRI8, IMUL_RMI8);
1473 }
1474 break;
1475
1476 case 0x6c: // i_insb
1477 i_insb();
1478 break;
1479
1480 case 0x6d: // i_insw
1481 i_insw();
1482 break;
1483
1484 case 0x6e: // i_outsb
1485 i_outsb();
1486 break;
1487
1488 case 0x6f: // i_outsw
1489 i_outsw();
1490 break;
1491
1492 case 0x8c: // i_mov_wsreg
1493 m_modrm = fetch();
1494 if((m_modrm & 0x38) > 0x18)
1495 {
1496 logerror("%06x: Mov Sreg - Invalid register\n", m_pc);
1497 throw TRAP(FAULT_UD, (uint16_t)-1);
1498 }
1499 PutRMWord(m_sregs[(m_modrm & 0x38) >> 3]);
1500 CLKM(MOV_RS,MOV_MS);
1501 break;
1502
1503 case 0x8e: // i_mov_sregw
1504 m_modrm = fetch();
1505 m_src = GetRMWord();
1506 CLKM(MOV_SR,MOV_SM);
1507 switch (m_modrm & 0x38)
1508 {
1509 case 0x00: /* mov es,ew */
1510 data_descriptor(ES, m_src);
1511 break;
1512 case 0x10: /* mov ss,ew */
1513 data_descriptor(SS, m_src);
1514 m_no_interrupt = 1;
1515 break;
1516 case 0x18: /* mov ds,ew */
1517 data_descriptor(DS, m_src);
1518 break;
1519 default:
1520 logerror("%06x: Mov Sreg - Invalid register\n", m_pc);
1521 throw TRAP(FAULT_UD, (uint16_t)-1);
1522 }
1523 break;
1524
1525 case 0x8f: // i_popw
1526 {
1527 m_modrm = fetch();
1528 uint16_t tmp = read_word(calc_addr(SS, m_regs.w[SP], 2, I8086_READ, false));
1529 PutRMWord( tmp );
1530 m_regs.w[SP] += 2;
1531 CLKM(POP_R16,POP_M16);
1532 break;
1533 }
1534
1535 case 0x9a: // i_call_far
1536 {
1537 uint16_t cs = m_sregs[CS];
1538 uint16_t tmp = fetch_word();
1539 uint16_t tmp2 = fetch_word();
1540 uint16_t ip = m_ip;
1541 code_descriptor(tmp2, tmp, NT_CALL);
1542 PUSH(cs);
1543 PUSH(ip);
1544 CLK(CALL_FAR);
1545 }
1546 break;
1547
1548 case 0x9b: // i_wait
1549 if((m_msw & 0x0a) == 0x0a)
1550 throw TRAP(FAULT_NM, (uint16_t)-1);
1551 CLK(WAIT);
1552 break;
1553
1554 case 0x9c: // pushf
1555 {
1556 uint16_t flags = CompressFlags();
1557 if(!PM)
1558 flags &= ~0xf000;
1559 PUSH(flags);
1560 CLK(PUSHF);
1561 break;
1562 }
1563
1564 case 0x9d: // popf
1565 {
1566 uint16_t flags;
1567 flags = POP();
1568 CLK(POPF);
1569 load_flags(flags, CPL);
1570 break;
1571 }
1572
1573 case 0xc0: // i_rotshft_bd8
1574 {
1575 uint8_t c;
1576 m_modrm = fetch();
1577 m_src = GetRMByte();
1578 m_dst = m_src;
1579 c = fetch() & 0x1f;
1580 CLKM(ROT_REG_BASE,ROT_M8_BASE);
1581 m_icount -= m_timing[ROT_REG_BIT] * c;
1582 if (c)
1583 {
1584 switch ( m_modrm & 0x38 )
1585 {
1586 case 0x00: do { ROL_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break;
1587 case 0x08: do { ROR_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break;
1588 case 0x10: do { ROLC_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break;
1589 case 0x18: do { RORC_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break;
1590 case 0x30:
1591 case 0x20: SHL_BYTE(c); break;
1592 case 0x28: SHR_BYTE(c); break;
1593 case 0x38: SHRA_BYTE(c); break;
1594 }
1595 }
1596 }
1597 break;
1598
1599 case 0xc1: // i_rotshft_wd8
1600 {
1601 uint8_t c;
1602 m_modrm = fetch();
1603 m_src = GetRMWord();
1604 m_dst = m_src;
1605 c = fetch() & 0x1f;
1606 CLKM(ROT_REG_BASE,ROT_M16_BASE);
1607 m_icount -= m_timing[ROT_REG_BIT] * c;
1608 if (c)
1609 {
1610 switch ( m_modrm & 0x38 )
1611 {
1612 case 0x00: do { ROL_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break;
1613 case 0x08: do { ROR_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break;
1614 case 0x10: do { ROLC_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break;
1615 case 0x18: do { RORC_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break;
1616 case 0x30:
1617 case 0x20: SHL_WORD(c); break;
1618 case 0x28: SHR_WORD(c); break;
1619 case 0x38: SHRA_WORD(c); break;
1620 }
1621 }
1622 }
1623 break;
1624
1625 case 0xc4: // i_les_dw
1626 {
1627 m_modrm = fetch();
1628 if(m_modrm >= 0xc0)
1629 throw TRAP(FAULT_UD, (uint16_t)-1);
1630 uint16_t tmp = GetRMWord();
1631 data_descriptor(ES, GetnextRMWord());
1632 RegWord(tmp);
1633 CLK(LOAD_PTR);
1634 break;
1635 }
1636
1637 case 0xc5: // i_lds_dw
1638 {
1639 m_modrm = fetch();
1640 if(m_modrm >= 0xc0)
1641 throw TRAP(FAULT_UD, (uint16_t)-1);
1642 uint16_t tmp = GetRMWord();
1643 data_descriptor(DS, GetnextRMWord());
1644 RegWord(tmp);
1645 CLK(LOAD_PTR);
1646 break;
1647 }
1648
1649 case 0xc8: // i_enter
1650 {
1651 uint16_t nb = fetch();
1652 uint32_t level;
1653
1654 nb |= fetch() << 8;
1655 level = fetch();
1656 CLK(!level ? ENTER0 : (level == 1) ? ENTER1 : ENTER_BASE);
1657 if(level > 1)
1658 m_icount -= level * m_timing[ENTER_COUNT];
1659 PUSH(m_regs.w[BP]);
1660 m_regs.w[BP] = m_regs.w[SP];
1661 m_regs.w[SP] -= nb;
1662 for (int i=1; i<level; i++)
1663 {
1664 PUSH( GetMemW(SS,m_regs.w[BP] - i*2) );
1665 }
1666 if (level)
1667 {
1668 PUSH(m_regs.w[BP]);
1669 }
1670 }
1671 break;
1672
1673 case 0xc9: // i_leave
1674 m_regs.w[SP] = m_regs.w[BP];
1675 m_regs.w[BP] = POP();
1676 CLK(LEAVE);
1677 break;
1678
1679 case 0xca: // ret far imm
1680 {
1681 unsigned count = fetch_word();
1682 far_return(0, count);
1683 CLK(RET_FAR_IMM);
1684 break;
1685 }
1686 case 0xcb: // ret far
1687 far_return(0, 0);
1688 CLK(RET_FAR);
1689 break;
1690
1691 case 0xcf: // iret
1692 {
1693 int oldcpl = (PM) ? CPL : 0;
1694 uint16_t flags = far_return(1, 0);
1695 CLK(IRET);
1696 load_flags(flags, oldcpl);
1697 break;
1698 }
1699
1700 case 0xd2: // i_rotshft_bcl
1701 {
1702 uint8_t c;
1703
1704 m_modrm = fetch();
1705 m_src = GetRMByte();
1706 m_dst = m_src;
1707 c = m_regs.b[CL] & 0x1f;
1708 CLKM(ROT_REG_BASE,ROT_M16_BASE);
1709 m_icount -= m_timing[ROT_REG_BIT] * c;
1710 if (c)
1711 {
1712 switch ( m_modrm & 0x38 )
1713 {
1714 case 0x00: do { ROL_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break;
1715 case 0x08: do { ROR_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break;
1716 case 0x10: do { ROLC_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break;
1717 case 0x18: do { RORC_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break;
1718 case 0x30:
1719 case 0x20: SHL_BYTE(c); break;
1720 case 0x28: SHR_BYTE(c); break;
1721 case 0x38: SHRA_BYTE(c); break;
1722 }
1723 }
1724 }
1725 break;
1726
1727 case 0xd3: // i_rotshft_wcl
1728 {
1729 uint8_t c;
1730
1731 m_modrm = fetch();
1732 m_src = GetRMWord();
1733 m_dst = m_src;
1734 c = m_regs.b[CL] & 0x1f;
1735 CLKM(ROT_REG_BASE,ROT_M16_BASE);
1736 m_icount -= m_timing[ROT_REG_BIT] * c;
1737 if (c)
1738 {
1739 switch ( m_modrm & 0x38 )
1740 {
1741 case 0x00: do { ROL_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break;
1742 case 0x08: do { ROR_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break;
1743 case 0x10: do { ROLC_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break;
1744 case 0x18: do { RORC_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break;
1745 case 0x30:
1746 case 0x20: SHL_WORD(c); break;
1747 case 0x28: SHR_WORD(c); break;
1748 case 0x38: SHRA_WORD(c); break;
1749 }
1750 }
1751 }
1752 break;
1753
1754 case 0xd8: // i_esc
1755 case 0xd9:
1756 case 0xda:
1757 case 0xdb:
1758 case 0xdc:
1759 case 0xdd:
1760 case 0xde:
1761 case 0xdf:
1762 if((m_msw & 8) || (m_msw & 4))
1763 throw TRAP(FAULT_NM, (uint16_t)-1);
1764 m_modrm = fetch();
1765 GetRMByte();
1766 CLK(NOP);
1767 if((m_modrm == 0xe0) && (op == 0xdf))
1768 m_regs.w[AX] = 0xffff; // FPU not present
1769 break;
1770
1771 case 0xea: // i_jmp_far
1772 {
1773 uint16_t tmp = fetch_word();
1774 uint16_t tmp1 = fetch_word();
1775 code_descriptor(tmp1, tmp, NT_JMP);
1776 CLK(JMP_FAR);
1777 break;
1778 }
1779
1780 case 0xf0: // i_lock
1781 if(PM && (CPL > m_IOPL))
1782 throw TRAP(FAULT_GP, 0);
1783 logerror("%06x: Warning - BUSLOCK\n", m_pc);
1784 m_no_interrupt = 1;
1785 CLK(NOP);
1786 break;
1787
1788 case 0xf4: // i_hlt
1789 if(PM && CPL)
1790 throw TRAP(FAULT_GP, 0);
1791 m_icount = 0;
1792 m_halt = true;
1793 break;
1794
1795 case 0xfa: // i_cli
1796 if(PM && (CPL > m_IOPL))
1797 throw TRAP(FAULT_GP, 0);
1798 m_IF = 0;
1799 CLK(FLAG_OPS);
1800 break;
1801
1802 case 0xfb: // i_sti
1803 if(PM && (CPL > m_IOPL))
1804 throw TRAP(FAULT_GP, 0);
1805 m_IF = 1;
1806 CLK(FLAG_OPS);
1807 break;
1808
1809 case 0xff: // i_ffpre
1810 {
1811 uint32_t tmp, tmp1;
1812 m_modrm = fetch();
1813 tmp = GetRMWord();
1814 switch ( m_modrm & 0x38 )
1815 {
1816 case 0x00: /* INC */
1817 tmp1 = tmp+1;
1818 m_OverVal = (tmp==0x7fff);
1819 set_AF(tmp1,tmp,1);
1820 set_SZPF_Word(tmp1);
1821 PutbackRMWord(tmp1);
1822 CLKM(INCDEC_R16,INCDEC_M16);
1823 break;
1824 case 0x08: /* DEC */
1825 tmp1 = tmp-1;
1826 m_OverVal = (tmp==0x8000);
1827 set_AF(tmp1,tmp,1);
1828 set_SZPF_Word(tmp1);
1829 PutbackRMWord(tmp1);
1830 CLKM(INCDEC_R16,INCDEC_M16);
1831 break;
1832 case 0x10: /* CALL */
1833 PUSH(m_ip);
1834 m_ip = tmp;
1835 CLKM(CALL_R16,CALL_M16);
1836 break;
1837 case 0x18: /* CALL FAR */
1838 {
1839 uint16_t ip = m_ip;
1840 tmp1 = m_sregs[CS];
1841 code_descriptor(GetnextRMWord(), tmp, NT_CALL);
1842 PUSH(tmp1);
1843 PUSH(ip);
1844 CLK(CALL_M32);
1845 break;
1846 }
1847 case 0x20: /* JMP */
1848 m_ip = tmp;
1849 CLKM(JMP_R16,JMP_M16);
1850 break;
1851 case 0x28: /* JMP FAR */
1852 code_descriptor(GetnextRMWord(), tmp, NT_JMP);
1853 CLK(JMP_M32);
1854 break;
1855 case 0x30:
1856 PUSH(tmp);
1857 CLKM(PUSH_R16,PUSH_M16);
1858 break;
1859 default:
1860 logerror("%06x: FF Pre with unimplemented mod\n", m_pc);
1861 throw TRAP(FAULT_UD,(uint16_t)-1);
1862 }
1863 }
1864 break;
1865
1866 case 0xf2: // i_repne
1867 case 0xf3:
1868 {
1869 bool pass = false;
1870 uint8_t next = repx_op();
1871 uint16_t c = m_regs.w[CX];
1872
1873 switch (next)
1874 {
1875 case 0x6c: CLK(OVERRIDE); if (c) do { i_insb(); c--; } while (c>0 && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break;
1876 case 0x6d: CLK(OVERRIDE); if (c) do { i_insw(); c--; } while (c>0 && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break;
1877 case 0x6e: CLK(OVERRIDE); if (c) do { i_outsb(); c--; } while (c>0 && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break;
1878 case 0x6f: CLK(OVERRIDE); if (c) do { i_outsw(); c--; } while (c>0 && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break;
1879 default:
1880 // Decrement IP and pass on
1881 m_ip -= 1 + (m_seg_prefix_next ? 1 : 0);
1882 pass = true;
1883 }
1884 if(!pass)
1885 {
1886 if(c)
1887 m_ip = m_prev_ip;
1888 break;
1889 }
1890 }
1891
1892 default:
1893 if(!common_op(op))
1894 {
1895 m_icount -= 10; // UD fault timing?
1896 logerror("%06x: Invalid Opcode %02x\n", m_pc, op);
1897 m_ip = m_prev_ip;
1898 throw TRAP(FAULT_UD, (uint16_t)-1);
1899 }
1900 break;
1901 }
1902 }
1903 catch(uint32_t e)
1904 {
1905 trap(e);
1906 }
1907 }
1908 }
1909
1910
load_flags(uint16_t flags,int cpl)1911 void i80286_cpu_device::load_flags(uint16_t flags, int cpl)
1912 {
1913 uint16_t oldflags = CompressFlags();
1914 flags &= ~0x8000;
1915 if(PM && cpl)
1916 {
1917 uint16_t mask = 0x3000;
1918 if(cpl > m_IOPL)
1919 mask |= 0x200;
1920 flags &= ~mask;
1921 flags |= (oldflags & mask);
1922 }
1923 else if(!PM)
1924 (flags &= ~0xf000);
1925 ExpandFlags(flags);
1926
1927 if(m_TF)
1928 m_fire_trap = 1;
1929 }
1930
far_return(int iret,int bytes)1931 uint16_t i80286_cpu_device::far_return(int iret, int bytes)
1932 {
1933 uint16_t sel, off, flags = 0;
1934 int spaddr;
1935
1936 if(PM && m_NT && iret)
1937 {
1938 switch_task(read_word(m_tr.base + TSS_BACK * 2), NT_IRET);
1939 return CompressFlags();
1940 }
1941
1942 // must be restartable
1943 if(PM)
1944 check_permission(SS, m_regs.w[SP], (iret ? 6 : 4), I8086_READ);
1945
1946 spaddr = (m_base[SS] + m_regs.w[SP]) & m_amask;
1947 off = read_word(spaddr);
1948 sel = read_word(spaddr + 2);
1949 if(iret)
1950 flags = read_word(spaddr + 4);
1951
1952 if(PM)
1953 {
1954 uint16_t desc[3], newsp, newss;
1955 int addr, r;
1956
1957 if((addr = selector_address(sel)) == -1)
1958 throw TRAP(FAULT_GP, IDXTBL(sel));
1959
1960 if(RPL(sel) < CPL)
1961 throw TRAP(FAULT_GP, IDXTBL(sel));
1962 desc[0] = read_word(addr);
1963 desc[1] = read_word(addr + 2);
1964 desc[2] = read_word(addr + 4);
1965 r = RIGHTS(desc);
1966
1967 if(!CODE(r) || !SEGDESC(r))
1968 throw TRAP(FAULT_GP, IDXTBL(sel));
1969 if(CONF(r))
1970 {
1971 if(DPL(r) > RPL(sel))
1972 throw TRAP(FAULT_GP, IDXTBL(sel));
1973 }
1974 else if(DPL(r) != RPL(sel))
1975 throw TRAP(FAULT_GP, IDXTBL(sel));
1976
1977 if(!PRES(r))
1978 throw TRAP(FAULT_NP, IDXTBL(sel));
1979 if(off > LIMIT(desc))
1980 throw TRAP(FAULT_GP, 0);
1981 if(CPL < RPL(sel))
1982 {
1983 check_permission(SS, m_regs.w[SP] + (iret ? 6 : 4) + bytes, 4, I8086_READ);
1984 newsp = read_word(spaddr + ((iret ? 6 : 4) + bytes));
1985 newss = read_word(spaddr + ((iret ? 8 : 6) + bytes));
1986 data_descriptor(SS, newss, RPL(sel), TRAP(FAULT_GP, IDXTBL(newss)));
1987 m_regs.w[SP] = newsp + bytes;
1988 }
1989 else
1990 m_regs.w[SP] += (iret ? 6 : 4) + bytes;
1991 SET_ACC(desc);
1992 write_word(addr + 4, desc[2]);
1993 m_sregs[CS] = sel;
1994 m_limit[CS] = LIMIT(desc);
1995 m_base[CS] = BASE(desc);
1996 m_rights[CS] = RIGHTS(desc);
1997 m_ip = off;
1998
1999 // docs say check rpl but windows doesn't like it
2000 r = m_rights[DS];
2001 if(verify(m_sregs[DS], I8086_READ, r, 0) || (CODE(r) && CONF(r) ? 0 : (DPL(r) < CPL)))
2002 data_descriptor(DS, 0);
2003 r = m_rights[ES];
2004 if(verify(m_sregs[ES], I8086_READ, r, 0) || (CODE(r) && CONF(r) ? 0 : (DPL(r) < CPL)))
2005 data_descriptor(ES, 0);
2006 }
2007 else
2008 {
2009 m_regs.w[SP] += (iret ? 6 : 4) + bytes;
2010 m_sregs[CS] = sel;
2011 m_base[CS] = sel << 4;
2012 m_rights[CS] = 0x93;
2013 m_limit[CS] = 0xffff;
2014 m_ip = off;
2015 }
2016
2017 return flags;
2018 }
2019
check_permission(uint8_t check_seg,uint32_t offset,uint16_t size,int operation)2020 void i80286_cpu_device::check_permission(uint8_t check_seg, uint32_t offset, uint16_t size, int operation)
2021 {
2022 int trap;
2023 uint8_t rights;
2024 if(PM)
2025 {
2026 rights = m_rights[check_seg];
2027 trap = verify(m_sregs[check_seg], operation, rights, m_valid[check_seg]);
2028 if((CODE(rights) || !EXPDOWN(rights)) && ((offset+size-1) > m_limit[check_seg]))
2029 trap = FAULT_GP;
2030 if(!CODE(rights) && EXPDOWN(rights) && ((offset <= m_limit[check_seg]) || ((offset + size - 1) > 0xffff)))
2031 trap = FAULT_GP;
2032
2033 if((trap == FAULT_GP) && (check_seg == SS))
2034 trap = FAULT_SS;
2035 if(trap)
2036 throw TRAP(trap, 0);
2037 }
2038 }
2039