OSDN Git Service

[VM][I386] Merge Upstream 2017-05-28.
[csp-qt/common_source_project-fm7.git] / source / src / vm / mame / emu / cpu / i386 / i486ops.c
1 // license:BSD-3-Clause
2 // copyright-holders:Ville Linde, Barry Rodewald, Carl, Philp Bennett
3 // Intel 486+ specific opcodes
4
5 static void I486OP(cpuid)(i386_state *cpustate)             // Opcode 0x0F A2
6 {
7         if (cpustate->cpuid_id0 == 0)
8         {
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);
12         }
13         else
14         {
15                 switch (REG32(EAX))
16                 {
17                         case 0:
18                         {
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);
24                                 break;
25                         }
26
27                         case 1:
28                         {
29                                 REG32(EAX) = cpustate->cpu_version;
30                                 REG32(EDX) = cpustate->feature_flags;
31                                 CYCLES(cpustate,CYCLES_CPUID_EAX1);
32                                 break;
33                         }
34                 }
35         }
36 }
37
38 static void I486OP(invd)(i386_state *cpustate)              // Opcode 0x0f 08
39 {
40         // Nothing to do ?
41         CYCLES(cpustate,CYCLES_INVD);
42 }
43
44 static void I486OP(wbinvd)(i386_state *cpustate)            // Opcode 0x0f 09
45 {
46         // Nothing to do ?
47 }
48
49 static void I486OP(cmpxchg_rm8_r8)(i386_state *cpustate)    // Opcode 0x0f b0
50 {
51         UINT8 modrm = FETCH(cpustate);
52         if( modrm >= 0xc0 ) {
53                 UINT8 dst = LOAD_RM8(modrm);
54                 UINT8 src = LOAD_REG8(modrm);
55
56                 if( REG8(AL) == dst ) {
57                         STORE_RM8(modrm, src);
58                         cpustate->ZF = 1;
59                         CYCLES(cpustate,CYCLES_CMPXCHG_REG_REG_T);
60                 } else {
61                         REG8(AL) = dst;
62                         cpustate->ZF = 0;
63                         CYCLES(cpustate,CYCLES_CMPXCHG_REG_REG_F);
64                 }
65         } else {
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);
70
71                 if( REG8(AL) == dst ) {
72                         WRITE8(cpustate,ea, src);
73                         cpustate->ZF = 1;
74                         CYCLES(cpustate,CYCLES_CMPXCHG_REG_MEM_T);
75                 } else {
76                         REG8(AL) = dst;
77                         cpustate->ZF = 0;
78                         CYCLES(cpustate,CYCLES_CMPXCHG_REG_MEM_F);
79                 }
80         }
81 }
82
83 static void I486OP(cmpxchg_rm16_r16)(i386_state *cpustate)  // Opcode 0x0f b1
84 {
85         UINT8 modrm = FETCH(cpustate);
86         if( modrm >= 0xc0 ) {
87                 UINT16 dst = LOAD_RM16(modrm);
88                 UINT16 src = LOAD_REG16(modrm);
89
90                 if( REG16(AX) == dst ) {
91                         STORE_RM16(modrm, src);
92                         cpustate->ZF = 1;
93                         CYCLES(cpustate,CYCLES_CMPXCHG_REG_REG_T);
94                 } else {
95                         REG16(AX) = dst;
96                         cpustate->ZF = 0;
97                         CYCLES(cpustate,CYCLES_CMPXCHG_REG_REG_F);
98                 }
99         } else {
100                 UINT32 ea = GetEA(cpustate,modrm,0);
101                 UINT16 dst = READ16(cpustate,ea);
102                 UINT16 src = LOAD_REG16(modrm);
103
104                 if( REG16(AX) == dst ) {
105                         WRITE16(cpustate,ea, src);
106                         cpustate->ZF = 1;
107                         CYCLES(cpustate,CYCLES_CMPXCHG_REG_MEM_T);
108                 } else {
109                         REG16(AX) = dst;
110                         cpustate->ZF = 0;
111                         CYCLES(cpustate,CYCLES_CMPXCHG_REG_MEM_F);
112                 }
113         }
114 }
115
116 static void I486OP(cmpxchg_rm32_r32)(i386_state *cpustate)  // Opcode 0x0f b1
117 {
118         UINT8 modrm = FETCH(cpustate);
119         if( modrm >= 0xc0 ) {
120                 UINT32 dst = LOAD_RM32(modrm);
121                 UINT32 src = LOAD_REG32(modrm);
122
123                 if( REG32(EAX) == dst ) {
124                         STORE_RM32(modrm, src);
125                         cpustate->ZF = 1;
126                         CYCLES(cpustate,CYCLES_CMPXCHG_REG_REG_T);
127                 } else {
128                         REG32(EAX) = dst;
129                         cpustate->ZF = 0;
130                         CYCLES(cpustate,CYCLES_CMPXCHG_REG_REG_F);
131                 }
132         } else {
133                 UINT32 ea = GetEA(cpustate,modrm,0);
134                 UINT32 dst = READ32(cpustate,ea);
135                 UINT32 src = LOAD_REG32(modrm);
136
137                 if( REG32(EAX) == dst ) {
138                         WRITE32(cpustate,ea, src);
139                         cpustate->ZF = 1;
140                         CYCLES(cpustate,CYCLES_CMPXCHG_REG_MEM_T);
141                 } else {
142                         REG32(EAX) = dst;
143                         cpustate->ZF = 0;
144                         CYCLES(cpustate,CYCLES_CMPXCHG_REG_MEM_F);
145                 }
146         }
147 }
148
149 static void I486OP(xadd_rm8_r8)(i386_state *cpustate)   // Opcode 0x0f c0
150 {
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);
158         } else {
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);
165         }
166 }
167
168 static void I486OP(xadd_rm16_r16)(i386_state *cpustate) // Opcode 0x0f c1
169 {
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);
177         } else {
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);
184         }
185 }
186
187 static void I486OP(xadd_rm32_r32)(i386_state *cpustate) // Opcode 0x0f c1
188 {
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);
196         } else {
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);
203         }
204 }
205
206 static void I486OP(group0F01_16)(i386_state *cpustate)      // Opcode 0x0f 01
207 {
208         UINT8 modrm = FETCH(cpustate);
209         UINT16 address;
210         UINT32 ea;
211
212         switch( (modrm >> 3) & 0x7 )
213         {
214                 case 0:         /* SGDT */
215                         {
216                                 if( modrm >= 0xc0 ) {
217                                         address = LOAD_RM16(modrm);
218                                         ea = i386_translate( cpustate, CS, address, 1 );
219                                 } else {
220                                         ea = GetEA(cpustate,modrm,1);
221                                 }
222                                 WRITE16(cpustate,ea, cpustate->gdtr.limit);
223                                 WRITE32(cpustate,ea + 2, cpustate->gdtr.base & 0xffffff);
224                                 CYCLES(cpustate,CYCLES_SGDT);
225                                 break;
226                         }
227                 case 1:         /* SIDT */
228                         {
229                                 if (modrm >= 0xc0)
230                                 {
231                                         address = LOAD_RM16(modrm);
232                                         ea = i386_translate( cpustate, CS, address, 1 );
233                                 }
234                                 else
235                                 {
236                                         ea = GetEA(cpustate,modrm,1);
237                                 }
238                                 WRITE16(cpustate,ea, cpustate->idtr.limit);
239                                 WRITE32(cpustate,ea + 2, cpustate->idtr.base & 0xffffff);
240                                 CYCLES(cpustate,CYCLES_SIDT);
241                                 break;
242                         }
243                 case 2:         /* LGDT */
244                         {
245                                 if(PROTECTED_MODE && cpustate->CPL)
246                                         FAULT(FAULT_GP,0)
247                                 if( modrm >= 0xc0 ) {
248                                         address = LOAD_RM16(modrm);
249                                         ea = i386_translate( cpustate, CS, address, 0 );
250                                 } else {
251                                         ea = GetEA(cpustate,modrm,0);
252                                 }
253                                 cpustate->gdtr.limit = READ16(cpustate,ea);
254                                 cpustate->gdtr.base = READ32(cpustate,ea + 2) & 0xffffff;
255                                 CYCLES(cpustate,CYCLES_LGDT);
256                                 break;
257                         }
258                 case 3:         /* LIDT */
259                         {
260                                 if(PROTECTED_MODE && cpustate->CPL)
261                                         FAULT(FAULT_GP,0)
262                                 if( modrm >= 0xc0 ) {
263                                         address = LOAD_RM16(modrm);
264                                         ea = i386_translate( cpustate, CS, address, 0 );
265                                 } else {
266                                         ea = GetEA(cpustate,modrm,0);
267                                 }
268                                 cpustate->idtr.limit = READ16(cpustate,ea);
269                                 cpustate->idtr.base = READ32(cpustate,ea + 2) & 0xffffff;
270                                 CYCLES(cpustate,CYCLES_LIDT);
271                                 break;
272                         }
273                 case 4:         /* SMSW */
274                         {
275                                 if( modrm >= 0xc0 ) {
276                                         STORE_RM16(modrm, cpustate->cr[0]);
277                                         CYCLES(cpustate,CYCLES_SMSW_REG);
278                                 } else {
279                                         ea = GetEA(cpustate,modrm,1);
280                                         WRITE16(cpustate,ea, cpustate->cr[0]);
281                                         CYCLES(cpustate,CYCLES_SMSW_MEM);
282                                 }
283                                 break;
284                         }
285                 case 6:         /* LMSW */
286                         {
287                                 UINT16 b;
288                                 if(PROTECTED_MODE && cpustate->CPL)
289                                         FAULT(FAULT_GP,0)
290                                 if( modrm >= 0xc0 ) {
291                                         b = LOAD_RM16(modrm);
292                                         CYCLES(cpustate,CYCLES_LMSW_REG);
293                                 } else {
294                                         ea = GetEA(cpustate,modrm,0);
295                                         CYCLES(cpustate,CYCLES_LMSW_MEM);
296                                         b = READ16(cpustate,ea);
297                                 }
298                                 if(PROTECTED_MODE)
299                                         b |= 0x0001;  // cannot return to real mode using this instruction.
300                                 cpustate->cr[0] &= ~0x0000000f;
301                                 cpustate->cr[0] |= b & 0x0000000f;
302                                 break;
303                         }
304                 case 7:         /* INVLPG */
305                         {
306                                 if(PROTECTED_MODE && cpustate->CPL)
307                                         FAULT(FAULT_GP,0)
308                                 if(modrm >= 0xc0)
309                                 {
310                                         logerror("i486: invlpg with modrm %02X\n", modrm);
311                                         FAULT(FAULT_UD,0)
312                                 }
313                                 ea = GetEA(cpustate,modrm,-1);
314                                 CYCLES(cpustate,25); // TODO: add to cycles.h
315                                 vtlb_flush_address(cpustate->vtlb, ea);
316                                 break;
317                         }
318                 default:
319                         report_invalid_modrm(cpustate, "group0F01_16", modrm);
320                         break;
321         }
322 }
323
324 static void I486OP(group0F01_32)(i386_state *cpustate)      // Opcode 0x0f 01
325 {
326         UINT8 modrm = FETCH(cpustate);
327         UINT32 address, ea;
328
329         switch( (modrm >> 3) & 0x7 )
330         {
331                 case 0:         /* SGDT */
332                         {
333                                 if( modrm >= 0xc0 ) {
334                                         address = LOAD_RM32(modrm);
335                                         ea = i386_translate( cpustate, CS, address, 1 );
336                                 } else {
337                                         ea = GetEA(cpustate,modrm,1);
338                                 }
339                                 WRITE16(cpustate,ea, cpustate->gdtr.limit);
340                                 WRITE32(cpustate,ea + 2, cpustate->gdtr.base);
341                                 CYCLES(cpustate,CYCLES_SGDT);
342                                 break;
343                         }
344                 case 1:         /* SIDT */
345                         {
346                                 if (modrm >= 0xc0)
347                                 {
348                                         address = LOAD_RM32(modrm);
349                                         ea = i386_translate( cpustate, CS, address, 1 );
350                                 }
351                                 else
352                                 {
353                                         ea = GetEA(cpustate,modrm,1);
354                                 }
355                                 WRITE16(cpustate,ea, cpustate->idtr.limit);
356                                 WRITE32(cpustate,ea + 2, cpustate->idtr.base);
357                                 CYCLES(cpustate,CYCLES_SIDT);
358                                 break;
359                         }
360                 case 2:         /* LGDT */
361                         {
362                                 if(PROTECTED_MODE && cpustate->CPL)
363                                         FAULT(FAULT_GP,0)
364                                 if( modrm >= 0xc0 ) {
365                                         address = LOAD_RM32(modrm);
366                                         ea = i386_translate( cpustate, CS, address, 0 );
367                                 } else {
368                                         ea = GetEA(cpustate,modrm,0);
369                                 }
370                                 cpustate->gdtr.limit = READ16(cpustate,ea);
371                                 cpustate->gdtr.base = READ32(cpustate,ea + 2);
372                                 CYCLES(cpustate,CYCLES_LGDT);
373                                 break;
374                         }
375                 case 3:         /* LIDT */
376                         {
377                                 if(PROTECTED_MODE && cpustate->CPL)
378                                         FAULT(FAULT_GP,0)
379                                 if( modrm >= 0xc0 ) {
380                                         address = LOAD_RM32(modrm);
381                                         ea = i386_translate( cpustate, CS, address, 0 );
382                                 } else {
383                                         ea = GetEA(cpustate,modrm,0);
384                                 }
385                                 cpustate->idtr.limit = READ16(cpustate,ea);
386                                 cpustate->idtr.base = READ32(cpustate,ea + 2);
387                                 CYCLES(cpustate,CYCLES_LIDT);
388                                 break;
389                         }
390                 case 4:         /* SMSW */
391                         {
392                                 if( modrm >= 0xc0 ) {
393                                         STORE_RM32(modrm, cpustate->cr[0] & 0xffff);
394                                         CYCLES(cpustate,CYCLES_SMSW_REG);
395                                 } else {
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);
400                                 }
401                                 break;
402                         }
403                 case 6:         /* LMSW */
404                         {
405                                 if(PROTECTED_MODE && cpustate->CPL)
406                                         FAULT(FAULT_GP,0)
407                                 UINT16 b;
408                                 if( modrm >= 0xc0 ) {
409                                         b = LOAD_RM16(modrm);
410                                         CYCLES(cpustate,CYCLES_LMSW_REG);
411                                 } else {
412                                         ea = GetEA(cpustate,modrm,0);
413                                         CYCLES(cpustate,CYCLES_LMSW_MEM);
414                                 b = READ16(cpustate,ea);
415                                 }
416                                 if(PROTECTED_MODE)
417                                         b |= 0x0001;  // cannot return to real mode using this instruction.
418                                 cpustate->cr[0] &= ~0x0000000f;
419                                 cpustate->cr[0] |= b & 0x0000000f;
420                                 break;
421                         }
422                 case 7:         /* INVLPG */
423                         {
424                                 if(PROTECTED_MODE && cpustate->CPL)
425                                         FAULT(FAULT_GP,0)
426                                 if(modrm >= 0xc0)
427                                 {
428                                         logerror("i486: invlpg with modrm %02X\n", modrm);
429                                         FAULT(FAULT_UD,0)
430                                 }
431                                 ea = GetEA(cpustate,modrm,-1);
432                                 CYCLES(cpustate,25); // TODO: add to cycles.h
433                                 vtlb_flush_address(cpustate->vtlb, ea);
434                                 break;
435                         }
436                 default:
437                         report_invalid_modrm(cpustate, "group0F01_32", modrm);
438                         break;
439         }
440 }
441
442 static void I486OP(bswap_eax)(i386_state *cpustate)     // Opcode 0x0f 38
443 {
444         REG32(EAX) = SWITCH_ENDIAN_32(REG32(EAX));
445         CYCLES(cpustate,1);     // TODO
446 }
447
448 static void I486OP(bswap_ecx)(i386_state *cpustate)     // Opcode 0x0f 39
449 {
450         REG32(ECX) = SWITCH_ENDIAN_32(REG32(ECX));
451         CYCLES(cpustate,1);     // TODO
452 }
453
454 static void I486OP(bswap_edx)(i386_state *cpustate)     // Opcode 0x0f 3A
455 {
456         REG32(EDX) = SWITCH_ENDIAN_32(REG32(EDX));
457         CYCLES(cpustate,1);     // TODO
458 }
459
460 static void I486OP(bswap_ebx)(i386_state *cpustate)     // Opcode 0x0f 3B
461 {
462         REG32(EBX) = SWITCH_ENDIAN_32(REG32(EBX));
463         CYCLES(cpustate,1);     // TODO
464 }
465
466 static void I486OP(bswap_esp)(i386_state *cpustate)     // Opcode 0x0f 3C
467 {
468         REG32(ESP) = SWITCH_ENDIAN_32(REG32(ESP));
469         CYCLES(cpustate,1);     // TODO
470 }
471
472 static void I486OP(bswap_ebp)(i386_state *cpustate)     // Opcode 0x0f 3D
473 {
474         REG32(EBP) = SWITCH_ENDIAN_32(REG32(EBP));
475         CYCLES(cpustate,1);     // TODO
476 }
477
478 static void I486OP(bswap_esi)(i386_state *cpustate)     // Opcode 0x0f 3E
479 {
480         REG32(ESI) = SWITCH_ENDIAN_32(REG32(ESI));
481         CYCLES(cpustate,1);     // TODO
482 }
483
484 static void I486OP(bswap_edi)(i386_state *cpustate)     // Opcode 0x0f 3F
485 {
486         REG32(EDI) = SWITCH_ENDIAN_32(REG32(EDI));
487         CYCLES(cpustate,1);     // TODO
488 }
489
490 static void I486OP(mov_cr_r32)(i386_state *cpustate)        // Opcode 0x0f 22
491 {
492         if(PROTECTED_MODE && cpustate->CPL)
493                 FAULT(FAULT_GP, 0);
494         UINT8 modrm = FETCH(cpustate);
495         UINT8 cr = (modrm >> 3) & 0x7;
496         UINT32 oldcr = cpustate->cr[cr];
497         UINT32 data = LOAD_RM32(modrm);
498         switch(cr)
499         {
500                 case 0:
501                         CYCLES(cpustate,CYCLES_MOV_REG_CR0);
502                         if((oldcr ^ cpustate->cr[cr]) & 0x80010000)
503                                 vtlb_flush_dynamic(cpustate->vtlb);
504                         break;
505                 case 2: CYCLES(cpustate,CYCLES_MOV_REG_CR2); break;
506                 case 3:
507                         CYCLES(cpustate,CYCLES_MOV_REG_CR3);
508                         vtlb_flush_dynamic(cpustate->vtlb);
509                         break;
510                 case 4: CYCLES(cpustate,1); break; // TODO
511                 default:
512                         logerror("i386: mov_cr_r32 CR%d!\n", cr);
513                         return;
514         }
515         cpustate->cr[cr] = data;
516 }