1 // license:BSD-3-Clause
2 // copyright-holders:Ville Linde, Barry Rodewald, Carl, Philp Bennett
3 // Intel 486+ specific opcodes
5 static void I486OP(cpuid)(i386_state *cpustate) // Opcode 0x0F A2
7 if (cpustate->cpuid_id0 == 0)
9 // this 486 doesn't support the CPUID instruction
10 logerror("CPUID not supported at %08x!\n", cpustate->eip);
11 i386_trap(cpustate, 6, 0, 0);
19 REG32(EAX) = cpustate->cpuid_max_input_value_eax;
20 REG32(EBX) = cpustate->cpuid_id0;
21 REG32(ECX) = cpustate->cpuid_id2;
22 REG32(EDX) = cpustate->cpuid_id1;
23 CYCLES(cpustate,CYCLES_CPUID);
29 REG32(EAX) = cpustate->cpu_version;
30 REG32(EDX) = cpustate->feature_flags;
31 CYCLES(cpustate,CYCLES_CPUID_EAX1);
38 static void I486OP(invd)(i386_state *cpustate) // Opcode 0x0f 08
41 CYCLES(cpustate,CYCLES_INVD);
44 static void I486OP(wbinvd)(i386_state *cpustate) // Opcode 0x0f 09
49 static void I486OP(cmpxchg_rm8_r8)(i386_state *cpustate) // Opcode 0x0f b0
51 UINT8 modrm = FETCH(cpustate);
53 UINT8 dst = LOAD_RM8(modrm);
54 UINT8 src = LOAD_REG8(modrm);
56 if( REG8(AL) == dst ) {
57 STORE_RM8(modrm, src);
59 CYCLES(cpustate,CYCLES_CMPXCHG_REG_REG_T);
63 CYCLES(cpustate,CYCLES_CMPXCHG_REG_REG_F);
66 // TODO: Check write if needed
67 UINT32 ea = GetEA(cpustate,modrm,0);
68 UINT8 dst = READ8(cpustate,ea);
69 UINT8 src = LOAD_REG8(modrm);
71 if( REG8(AL) == dst ) {
72 WRITE8(cpustate,ea, src);
74 CYCLES(cpustate,CYCLES_CMPXCHG_REG_MEM_T);
78 CYCLES(cpustate,CYCLES_CMPXCHG_REG_MEM_F);
83 static void I486OP(cmpxchg_rm16_r16)(i386_state *cpustate) // Opcode 0x0f b1
85 UINT8 modrm = FETCH(cpustate);
87 UINT16 dst = LOAD_RM16(modrm);
88 UINT16 src = LOAD_REG16(modrm);
90 if( REG16(AX) == dst ) {
91 STORE_RM16(modrm, src);
93 CYCLES(cpustate,CYCLES_CMPXCHG_REG_REG_T);
97 CYCLES(cpustate,CYCLES_CMPXCHG_REG_REG_F);
100 UINT32 ea = GetEA(cpustate,modrm,0);
101 UINT16 dst = READ16(cpustate,ea);
102 UINT16 src = LOAD_REG16(modrm);
104 if( REG16(AX) == dst ) {
105 WRITE16(cpustate,ea, src);
107 CYCLES(cpustate,CYCLES_CMPXCHG_REG_MEM_T);
111 CYCLES(cpustate,CYCLES_CMPXCHG_REG_MEM_F);
116 static void I486OP(cmpxchg_rm32_r32)(i386_state *cpustate) // Opcode 0x0f b1
118 UINT8 modrm = FETCH(cpustate);
119 if( modrm >= 0xc0 ) {
120 UINT32 dst = LOAD_RM32(modrm);
121 UINT32 src = LOAD_REG32(modrm);
123 if( REG32(EAX) == dst ) {
124 STORE_RM32(modrm, src);
126 CYCLES(cpustate,CYCLES_CMPXCHG_REG_REG_T);
130 CYCLES(cpustate,CYCLES_CMPXCHG_REG_REG_F);
133 UINT32 ea = GetEA(cpustate,modrm,0);
134 UINT32 dst = READ32(cpustate,ea);
135 UINT32 src = LOAD_REG32(modrm);
137 if( REG32(EAX) == dst ) {
138 WRITE32(cpustate,ea, src);
140 CYCLES(cpustate,CYCLES_CMPXCHG_REG_MEM_T);
144 CYCLES(cpustate,CYCLES_CMPXCHG_REG_MEM_F);
149 static void I486OP(xadd_rm8_r8)(i386_state *cpustate) // Opcode 0x0f c0
151 UINT8 modrm = FETCH(cpustate);
152 if( modrm >= 0xc0 ) {
153 UINT8 dst = LOAD_RM8(modrm);
154 UINT8 src = LOAD_REG8(modrm);
155 STORE_REG8(modrm, dst);
156 STORE_RM8(modrm, dst + src);
157 CYCLES(cpustate,CYCLES_XADD_REG_REG);
159 UINT32 ea = GetEA(cpustate,modrm,1);
160 UINT8 dst = READ8(cpustate,ea);
161 UINT8 src = LOAD_REG8(modrm);
162 WRITE8(cpustate,ea, dst + src);
163 STORE_REG8(modrm, dst);
164 CYCLES(cpustate,CYCLES_XADD_REG_MEM);
168 static void I486OP(xadd_rm16_r16)(i386_state *cpustate) // Opcode 0x0f c1
170 UINT8 modrm = FETCH(cpustate);
171 if( modrm >= 0xc0 ) {
172 UINT16 dst = LOAD_RM16(modrm);
173 UINT16 src = LOAD_REG16(modrm);
174 STORE_REG16(modrm, dst);
175 STORE_RM16(modrm, dst + src);
176 CYCLES(cpustate,CYCLES_XADD_REG_REG);
178 UINT32 ea = GetEA(cpustate,modrm,1);
179 UINT16 dst = READ16(cpustate,ea);
180 UINT16 src = LOAD_REG16(modrm);
181 WRITE16(cpustate,ea, dst + src);
182 STORE_REG16(modrm, dst);
183 CYCLES(cpustate,CYCLES_XADD_REG_MEM);
187 static void I486OP(xadd_rm32_r32)(i386_state *cpustate) // Opcode 0x0f c1
189 UINT8 modrm = FETCH(cpustate);
190 if( modrm >= 0xc0 ) {
191 UINT32 dst = LOAD_RM32(modrm);
192 UINT32 src = LOAD_REG32(modrm);
193 STORE_REG32(modrm, dst);
194 STORE_RM32(modrm, dst + src);
195 CYCLES(cpustate,CYCLES_XADD_REG_REG);
197 UINT32 ea = GetEA(cpustate,modrm,1);
198 UINT32 dst = READ32(cpustate,ea);
199 UINT32 src = LOAD_REG32(modrm);
200 WRITE32(cpustate,ea, dst + src);
201 STORE_REG32(modrm, dst);
202 CYCLES(cpustate,CYCLES_XADD_REG_MEM);
206 static void I486OP(group0F01_16)(i386_state *cpustate) // Opcode 0x0f 01
208 UINT8 modrm = FETCH(cpustate);
212 switch( (modrm >> 3) & 0x7 )
216 if( modrm >= 0xc0 ) {
217 address = LOAD_RM16(modrm);
218 ea = i386_translate( cpustate, CS, address, 1 );
220 ea = GetEA(cpustate,modrm,1);
222 WRITE16(cpustate,ea, cpustate->gdtr.limit);
223 WRITE32(cpustate,ea + 2, cpustate->gdtr.base & 0xffffff);
224 CYCLES(cpustate,CYCLES_SGDT);
231 address = LOAD_RM16(modrm);
232 ea = i386_translate( cpustate, CS, address, 1 );
236 ea = GetEA(cpustate,modrm,1);
238 WRITE16(cpustate,ea, cpustate->idtr.limit);
239 WRITE32(cpustate,ea + 2, cpustate->idtr.base & 0xffffff);
240 CYCLES(cpustate,CYCLES_SIDT);
245 if(PROTECTED_MODE && cpustate->CPL)
247 if( modrm >= 0xc0 ) {
248 address = LOAD_RM16(modrm);
249 ea = i386_translate( cpustate, CS, address, 0 );
251 ea = GetEA(cpustate,modrm,0);
253 cpustate->gdtr.limit = READ16(cpustate,ea);
254 cpustate->gdtr.base = READ32(cpustate,ea + 2) & 0xffffff;
255 CYCLES(cpustate,CYCLES_LGDT);
260 if(PROTECTED_MODE && cpustate->CPL)
262 if( modrm >= 0xc0 ) {
263 address = LOAD_RM16(modrm);
264 ea = i386_translate( cpustate, CS, address, 0 );
266 ea = GetEA(cpustate,modrm,0);
268 cpustate->idtr.limit = READ16(cpustate,ea);
269 cpustate->idtr.base = READ32(cpustate,ea + 2) & 0xffffff;
270 CYCLES(cpustate,CYCLES_LIDT);
275 if( modrm >= 0xc0 ) {
276 STORE_RM16(modrm, cpustate->cr[0]);
277 CYCLES(cpustate,CYCLES_SMSW_REG);
279 ea = GetEA(cpustate,modrm,1);
280 WRITE16(cpustate,ea, cpustate->cr[0]);
281 CYCLES(cpustate,CYCLES_SMSW_MEM);
288 if(PROTECTED_MODE && cpustate->CPL)
290 if( modrm >= 0xc0 ) {
291 b = LOAD_RM16(modrm);
292 CYCLES(cpustate,CYCLES_LMSW_REG);
294 ea = GetEA(cpustate,modrm,0);
295 CYCLES(cpustate,CYCLES_LMSW_MEM);
296 b = READ16(cpustate,ea);
299 b |= 0x0001; // cannot return to real mode using this instruction.
300 cpustate->cr[0] &= ~0x0000000f;
301 cpustate->cr[0] |= b & 0x0000000f;
306 if(PROTECTED_MODE && cpustate->CPL)
310 logerror("i486: invlpg with modrm %02X\n", modrm);
313 ea = GetEA(cpustate,modrm,-1);
314 CYCLES(cpustate,25); // TODO: add to cycles.h
315 vtlb_flush_address(cpustate->vtlb, ea);
319 report_invalid_modrm(cpustate, "group0F01_16", modrm);
324 static void I486OP(group0F01_32)(i386_state *cpustate) // Opcode 0x0f 01
326 UINT8 modrm = FETCH(cpustate);
329 switch( (modrm >> 3) & 0x7 )
333 if( modrm >= 0xc0 ) {
334 address = LOAD_RM32(modrm);
335 ea = i386_translate( cpustate, CS, address, 1 );
337 ea = GetEA(cpustate,modrm,1);
339 WRITE16(cpustate,ea, cpustate->gdtr.limit);
340 WRITE32(cpustate,ea + 2, cpustate->gdtr.base);
341 CYCLES(cpustate,CYCLES_SGDT);
348 address = LOAD_RM32(modrm);
349 ea = i386_translate( cpustate, CS, address, 1 );
353 ea = GetEA(cpustate,modrm,1);
355 WRITE16(cpustate,ea, cpustate->idtr.limit);
356 WRITE32(cpustate,ea + 2, cpustate->idtr.base);
357 CYCLES(cpustate,CYCLES_SIDT);
362 if(PROTECTED_MODE && cpustate->CPL)
364 if( modrm >= 0xc0 ) {
365 address = LOAD_RM32(modrm);
366 ea = i386_translate( cpustate, CS, address, 0 );
368 ea = GetEA(cpustate,modrm,0);
370 cpustate->gdtr.limit = READ16(cpustate,ea);
371 cpustate->gdtr.base = READ32(cpustate,ea + 2);
372 CYCLES(cpustate,CYCLES_LGDT);
377 if(PROTECTED_MODE && cpustate->CPL)
379 if( modrm >= 0xc0 ) {
380 address = LOAD_RM32(modrm);
381 ea = i386_translate( cpustate, CS, address, 0 );
383 ea = GetEA(cpustate,modrm,0);
385 cpustate->idtr.limit = READ16(cpustate,ea);
386 cpustate->idtr.base = READ32(cpustate,ea + 2);
387 CYCLES(cpustate,CYCLES_LIDT);
392 if( modrm >= 0xc0 ) {
393 STORE_RM32(modrm, cpustate->cr[0] & 0xffff);
394 CYCLES(cpustate,CYCLES_SMSW_REG);
396 /* always 16-bit memory operand */
397 ea = GetEA(cpustate,modrm,1);
398 WRITE16(cpustate,ea, cpustate->cr[0]);
399 CYCLES(cpustate,CYCLES_SMSW_MEM);
405 if(PROTECTED_MODE && cpustate->CPL)
408 if( modrm >= 0xc0 ) {
409 b = LOAD_RM16(modrm);
410 CYCLES(cpustate,CYCLES_LMSW_REG);
412 ea = GetEA(cpustate,modrm,0);
413 CYCLES(cpustate,CYCLES_LMSW_MEM);
414 b = READ16(cpustate,ea);
417 b |= 0x0001; // cannot return to real mode using this instruction.
418 cpustate->cr[0] &= ~0x0000000f;
419 cpustate->cr[0] |= b & 0x0000000f;
424 if(PROTECTED_MODE && cpustate->CPL)
428 logerror("i486: invlpg with modrm %02X\n", modrm);
431 ea = GetEA(cpustate,modrm,-1);
432 CYCLES(cpustate,25); // TODO: add to cycles.h
433 vtlb_flush_address(cpustate->vtlb, ea);
437 report_invalid_modrm(cpustate, "group0F01_32", modrm);
442 static void I486OP(bswap_eax)(i386_state *cpustate) // Opcode 0x0f 38
444 REG32(EAX) = SWITCH_ENDIAN_32(REG32(EAX));
445 CYCLES(cpustate,1); // TODO
448 static void I486OP(bswap_ecx)(i386_state *cpustate) // Opcode 0x0f 39
450 REG32(ECX) = SWITCH_ENDIAN_32(REG32(ECX));
451 CYCLES(cpustate,1); // TODO
454 static void I486OP(bswap_edx)(i386_state *cpustate) // Opcode 0x0f 3A
456 REG32(EDX) = SWITCH_ENDIAN_32(REG32(EDX));
457 CYCLES(cpustate,1); // TODO
460 static void I486OP(bswap_ebx)(i386_state *cpustate) // Opcode 0x0f 3B
462 REG32(EBX) = SWITCH_ENDIAN_32(REG32(EBX));
463 CYCLES(cpustate,1); // TODO
466 static void I486OP(bswap_esp)(i386_state *cpustate) // Opcode 0x0f 3C
468 REG32(ESP) = SWITCH_ENDIAN_32(REG32(ESP));
469 CYCLES(cpustate,1); // TODO
472 static void I486OP(bswap_ebp)(i386_state *cpustate) // Opcode 0x0f 3D
474 REG32(EBP) = SWITCH_ENDIAN_32(REG32(EBP));
475 CYCLES(cpustate,1); // TODO
478 static void I486OP(bswap_esi)(i386_state *cpustate) // Opcode 0x0f 3E
480 REG32(ESI) = SWITCH_ENDIAN_32(REG32(ESI));
481 CYCLES(cpustate,1); // TODO
484 static void I486OP(bswap_edi)(i386_state *cpustate) // Opcode 0x0f 3F
486 REG32(EDI) = SWITCH_ENDIAN_32(REG32(EDI));
487 CYCLES(cpustate,1); // TODO
490 static void I486OP(mov_cr_r32)(i386_state *cpustate) // Opcode 0x0f 22
492 if(PROTECTED_MODE && cpustate->CPL)
494 UINT8 modrm = FETCH(cpustate);
495 UINT8 cr = (modrm >> 3) & 0x7;
496 UINT32 oldcr = cpustate->cr[cr];
497 UINT32 data = LOAD_RM32(modrm);
501 CYCLES(cpustate,CYCLES_MOV_REG_CR0);
502 if((oldcr ^ cpustate->cr[cr]) & 0x80010000)
503 vtlb_flush_dynamic(cpustate->vtlb);
505 case 2: CYCLES(cpustate,CYCLES_MOV_REG_CR2); break;
507 CYCLES(cpustate,CYCLES_MOV_REG_CR3);
508 vtlb_flush_dynamic(cpustate->vtlb);
510 case 4: CYCLES(cpustate,1); break; // TODO
512 logerror("i386: mov_cr_r32 CR%d!\n", cr);
515 cpustate->cr[cr] = data;