1 // license:BSD-3-Clause
2 // copyright-holders:Ville Linde, Barry Rodewald, Carl, Philip 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,1);
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,2);
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,4);
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 UINT8 sum = ADD8(cpustate, dst, src);
156 STORE_REG8(modrm, dst);
157 STORE_RM8(modrm, sum);
158 CYCLES(cpustate,CYCLES_XADD_REG_REG);
160 UINT32 ea = GetEA(cpustate,modrm,1,1);
161 UINT8 dst = READ8(cpustate,ea);
162 UINT8 src = LOAD_REG8(modrm);
163 UINT8 sum = ADD8(cpustate, dst, src);
164 WRITE8(cpustate,ea, sum);
165 STORE_REG8(modrm, dst);
166 CYCLES(cpustate,CYCLES_XADD_REG_MEM);
170 static void I486OP(xadd_rm16_r16)(i386_state *cpustate) // Opcode 0x0f c1
172 UINT8 modrm = FETCH(cpustate);
173 if( modrm >= 0xc0 ) {
174 UINT16 dst = LOAD_RM16(modrm);
175 UINT16 src = LOAD_REG16(modrm);
176 UINT16 sum = ADD16(cpustate, dst, src);
177 STORE_REG16(modrm, dst);
178 STORE_RM16(modrm, sum);
179 CYCLES(cpustate,CYCLES_XADD_REG_REG);
181 UINT32 ea = GetEA(cpustate,modrm,1,2);
182 UINT16 dst = READ16(cpustate,ea);
183 UINT16 src = LOAD_REG16(modrm);
184 UINT16 sum = ADD16(cpustate, dst, src);
185 WRITE16(cpustate,ea, sum);
186 STORE_REG16(modrm, dst);
187 CYCLES(cpustate,CYCLES_XADD_REG_MEM);
191 static void I486OP(xadd_rm32_r32)(i386_state *cpustate) // Opcode 0x0f c1
193 UINT8 modrm = FETCH(cpustate);
194 if( modrm >= 0xc0 ) {
195 UINT32 dst = LOAD_RM32(modrm);
196 UINT32 src = LOAD_REG32(modrm);
197 UINT32 sum = ADD32(cpustate, dst, src);
198 STORE_REG32(modrm, dst);
199 STORE_RM32(modrm, sum);
200 CYCLES(cpustate,CYCLES_XADD_REG_REG);
202 UINT32 ea = GetEA(cpustate,modrm,1,4);
203 UINT32 dst = READ32(cpustate,ea);
204 UINT32 src = LOAD_REG32(modrm);
205 UINT32 sum = ADD32(cpustate, dst, src);
206 WRITE32(cpustate,ea, sum);
207 STORE_REG32(modrm, dst);
208 CYCLES(cpustate,CYCLES_XADD_REG_MEM);
212 static void I486OP(group0F01_16)(i386_state *cpustate) // Opcode 0x0f 01
214 UINT8 modrm = FETCH(cpustate);
218 switch( (modrm >> 3) & 0x7 )
222 if( modrm >= 0xc0 ) {
223 address = LOAD_RM16(modrm);
224 ea = i386_translate( cpustate, CS, address, 1, 6 );
226 ea = GetEA(cpustate,modrm,1,6);
228 WRITE16(cpustate,ea, cpustate->gdtr.limit);
229 WRITE32(cpustate,ea + 2, cpustate->gdtr.base);
230 CYCLES(cpustate,CYCLES_SGDT);
237 address = LOAD_RM16(modrm);
238 ea = i386_translate( cpustate, CS, address, 1, 6 );
242 ea = GetEA(cpustate,modrm,1,6);
244 WRITE16(cpustate,ea, cpustate->idtr.limit);
245 WRITE32(cpustate,ea + 2, cpustate->idtr.base);
246 CYCLES(cpustate,CYCLES_SIDT);
251 if(PROTECTED_MODE && cpustate->CPL)
253 if( modrm >= 0xc0 ) {
254 address = LOAD_RM16(modrm);
255 ea = i386_translate( cpustate, CS, address, 0, 6 );
257 ea = GetEA(cpustate,modrm,0,6);
259 cpustate->gdtr.limit = READ16(cpustate,ea);
260 cpustate->gdtr.base = READ32(cpustate,ea + 2) & 0xffffff;
261 CYCLES(cpustate,CYCLES_LGDT);
266 if(PROTECTED_MODE && cpustate->CPL)
268 if( modrm >= 0xc0 ) {
269 address = LOAD_RM16(modrm);
270 ea = i386_translate( cpustate, CS, address, 0, 6 );
272 ea = GetEA(cpustate,modrm,0,6);
274 cpustate->idtr.limit = READ16(cpustate,ea);
275 cpustate->idtr.base = READ32(cpustate,ea + 2) & 0xffffff;
276 CYCLES(cpustate,CYCLES_LIDT);
281 if( modrm >= 0xc0 ) {
282 STORE_RM16(modrm, cpustate->cr[0]);
283 CYCLES(cpustate,CYCLES_SMSW_REG);
285 ea = GetEA(cpustate,modrm,1,2);
286 WRITE16(cpustate,ea, cpustate->cr[0]);
287 CYCLES(cpustate,CYCLES_SMSW_MEM);
293 if(PROTECTED_MODE && cpustate->CPL)
296 if( modrm >= 0xc0 ) {
297 b = LOAD_RM16(modrm);
298 CYCLES(cpustate,CYCLES_LMSW_REG);
300 ea = GetEA(cpustate,modrm,0,2);
301 CYCLES(cpustate,CYCLES_LMSW_MEM);
302 b = READ16(cpustate,ea);
305 b |= 0x0001; // cannot return to real mode using this instruction.
306 cpustate->cr[0] &= ~0x0000000f;
307 cpustate->cr[0] |= b & 0x0000000f;
312 if(PROTECTED_MODE && cpustate->CPL)
316 logerror("i486: invlpg with modrm %02X\n", modrm);
319 ea = GetEA(cpustate,modrm,-1,1);
320 CYCLES(cpustate,25); // TODO: add to cycles.h
321 vtlb_flush_address(cpustate->vtlb, ea);
325 report_invalid_modrm(cpustate, "group0F01_16", modrm);
330 static void I486OP(group0F01_32)(i386_state *cpustate) // Opcode 0x0f 01
332 UINT8 modrm = FETCH(cpustate);
335 switch( (modrm >> 3) & 0x7 )
339 if( modrm >= 0xc0 ) {
340 address = LOAD_RM32(modrm);
341 ea = i386_translate( cpustate, CS, address, 1, 6 );
343 ea = GetEA(cpustate,modrm,1,6);
345 WRITE16(cpustate,ea, cpustate->gdtr.limit);
346 WRITE32(cpustate,ea + 2, cpustate->gdtr.base);
347 CYCLES(cpustate,CYCLES_SGDT);
354 address = LOAD_RM32(modrm);
355 ea = i386_translate( cpustate, CS, address, 1, 6 );
359 ea = GetEA(cpustate,modrm,1,6);
361 WRITE16(cpustate,ea, cpustate->idtr.limit);
362 WRITE32(cpustate,ea + 2, cpustate->idtr.base);
363 CYCLES(cpustate,CYCLES_SIDT);
368 if(PROTECTED_MODE && cpustate->CPL)
370 if( modrm >= 0xc0 ) {
371 address = LOAD_RM32(modrm);
372 ea = i386_translate( cpustate, CS, address, 0, 6 );
374 ea = GetEA(cpustate,modrm,0,6);
376 cpustate->gdtr.limit = READ16(cpustate,ea);
377 cpustate->gdtr.base = READ32(cpustate,ea + 2);
378 CYCLES(cpustate,CYCLES_LGDT);
383 if(PROTECTED_MODE && cpustate->CPL)
385 if( modrm >= 0xc0 ) {
386 address = LOAD_RM32(modrm);
387 ea = i386_translate( cpustate, CS, address, 0, 6 );
389 ea = GetEA(cpustate,modrm,0,6);
391 cpustate->idtr.limit = READ16(cpustate,ea);
392 cpustate->idtr.base = READ32(cpustate,ea + 2);
393 CYCLES(cpustate,CYCLES_LIDT);
398 if( modrm >= 0xc0 ) {
399 STORE_RM32(modrm, cpustate->cr[0] & 0xffff);
400 CYCLES(cpustate,CYCLES_SMSW_REG);
402 /* always 16-bit memory operand */
403 ea = GetEA(cpustate,modrm,1,2);
404 WRITE16(cpustate,ea, cpustate->cr[0]);
405 CYCLES(cpustate,CYCLES_SMSW_MEM);
411 if(PROTECTED_MODE && cpustate->CPL)
414 if( modrm >= 0xc0 ) {
415 b = LOAD_RM16(modrm);
416 CYCLES(cpustate,CYCLES_LMSW_REG);
418 ea = GetEA(cpustate,modrm,0,2);
419 CYCLES(cpustate,CYCLES_LMSW_MEM);
420 b = READ16(cpustate,ea);
423 b |= 0x0001; // cannot return to real mode using this instruction.
424 cpustate->cr[0] &= ~0x0000000f;
425 cpustate->cr[0] |= b & 0x0000000f;
430 if(PROTECTED_MODE && cpustate->CPL)
434 logerror("i486: invlpg with modrm %02X\n", modrm);
437 ea = GetEA(cpustate,modrm,-1,1);
438 CYCLES(cpustate,25); // TODO: add to cycles.h
439 vtlb_flush_address(cpustate->vtlb, ea);
443 report_invalid_modrm(cpustate, "group0F01_32", modrm);
448 static void I486OP(bswap_eax)(i386_state *cpustate) // Opcode 0x0f 38
450 REG32(EAX) = SWITCH_ENDIAN_32(REG32(EAX));
451 CYCLES(cpustate,1); // TODO
454 static void I486OP(bswap_ecx)(i386_state *cpustate) // Opcode 0x0f 39
456 REG32(ECX) = SWITCH_ENDIAN_32(REG32(ECX));
457 CYCLES(cpustate,1); // TODO
460 static void I486OP(bswap_edx)(i386_state *cpustate) // Opcode 0x0f 3A
462 REG32(EDX) = SWITCH_ENDIAN_32(REG32(EDX));
463 CYCLES(cpustate,1); // TODO
466 static void I486OP(bswap_ebx)(i386_state *cpustate) // Opcode 0x0f 3B
468 REG32(EBX) = SWITCH_ENDIAN_32(REG32(EBX));
469 CYCLES(cpustate,1); // TODO
472 static void I486OP(bswap_esp)(i386_state *cpustate) // Opcode 0x0f 3C
474 REG32(ESP) = SWITCH_ENDIAN_32(REG32(ESP));
475 CYCLES(cpustate,1); // TODO
478 static void I486OP(bswap_ebp)(i386_state *cpustate) // Opcode 0x0f 3D
480 REG32(EBP) = SWITCH_ENDIAN_32(REG32(EBP));
481 CYCLES(cpustate,1); // TODO
484 static void I486OP(bswap_esi)(i386_state *cpustate) // Opcode 0x0f 3E
486 REG32(ESI) = SWITCH_ENDIAN_32(REG32(ESI));
487 CYCLES(cpustate,1); // TODO
490 static void I486OP(bswap_edi)(i386_state *cpustate) // Opcode 0x0f 3F
492 REG32(EDI) = SWITCH_ENDIAN_32(REG32(EDI));
493 CYCLES(cpustate,1); // TODO
496 static void I486OP(mov_cr_r32)(i386_state *cpustate) // Opcode 0x0f 22
498 if(PROTECTED_MODE && cpustate->CPL)
500 UINT8 modrm = FETCH(cpustate);
501 UINT8 cr = (modrm >> 3) & 0x7;
502 UINT32 oldcr = cpustate->cr[cr];
503 UINT32 data = LOAD_RM32(modrm);
507 CYCLES(cpustate,CYCLES_MOV_REG_CR0);
508 if((oldcr ^ cpustate->cr[cr]) & 0x80010000)
509 vtlb_flush_dynamic(cpustate->vtlb);
510 // if (PROTECTED_MODE != BIT(data, 0))
511 // debugger_privilege_hook();
513 case 2: CYCLES(cpustate,CYCLES_MOV_REG_CR2); break;
515 CYCLES(cpustate,CYCLES_MOV_REG_CR3);
516 vtlb_flush_dynamic(cpustate->vtlb);
518 case 4: CYCLES(cpustate,1); break; // TODO
520 logerror("i386: mov_cr_r32 CR%d!\n", cr);
523 cpustate->cr[cr] = data;