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