OSDN Git Service

[General] Merge Upstream 2018-12-27.
[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, Philip 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,1);
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,2);
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,4);
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                 UINT8 sum = ADD8(cpustate, dst, src);
156                 STORE_REG8(modrm, dst);
157                 STORE_RM8(modrm, sum);
158                 CYCLES(cpustate,CYCLES_XADD_REG_REG);
159         } else {
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);
167         }
168 }
169
170 static void I486OP(xadd_rm16_r16)(i386_state *cpustate) // Opcode 0x0f c1
171 {
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);
180         } else {
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);
188         }
189 }
190
191 static void I486OP(xadd_rm32_r32)(i386_state *cpustate) // Opcode 0x0f c1
192 {
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);
201         } else {
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);
209         }
210 }
211
212 static void I486OP(group0F01_16)(i386_state *cpustate)      // Opcode 0x0f 01
213 {
214         UINT8 modrm = FETCH(cpustate);
215         UINT16 address;
216         UINT32 ea;
217
218         switch( (modrm >> 3) & 0x7 )
219         {
220                 case 0:         /* SGDT */
221                         {
222                                 if( modrm >= 0xc0 ) {
223                                         address = LOAD_RM16(modrm);
224                                         ea = i386_translate( cpustate, CS, address, 1, 6 );
225                                 } else {
226                                         ea = GetEA(cpustate,modrm,1,6);
227                                 }
228                                 WRITE16(cpustate,ea, cpustate->gdtr.limit);
229                                 WRITE32(cpustate,ea + 2, cpustate->gdtr.base);
230                                 CYCLES(cpustate,CYCLES_SGDT);
231                                 break;
232                         }
233                 case 1:         /* SIDT */
234                         {
235                                 if (modrm >= 0xc0)
236                                 {
237                                         address = LOAD_RM16(modrm);
238                                         ea = i386_translate( cpustate, CS, address, 1, 6 );
239                                 }
240                                 else
241                                 {
242                                         ea = GetEA(cpustate,modrm,1,6);
243                                 }
244                                 WRITE16(cpustate,ea, cpustate->idtr.limit);
245                                 WRITE32(cpustate,ea + 2, cpustate->idtr.base);
246                                 CYCLES(cpustate,CYCLES_SIDT);
247                                 break;
248                         }
249                 case 2:         /* LGDT */
250                         {
251                                 if(PROTECTED_MODE && cpustate->CPL)
252                                         FAULT(FAULT_GP,0)
253                                 if( modrm >= 0xc0 ) {
254                                         address = LOAD_RM16(modrm);
255                                         ea = i386_translate( cpustate, CS, address, 0, 6 );
256                                 } else {
257                                         ea = GetEA(cpustate,modrm,0,6);
258                                 }
259                                 cpustate->gdtr.limit = READ16(cpustate,ea);
260                                 cpustate->gdtr.base = READ32(cpustate,ea + 2) & 0xffffff;
261                                 CYCLES(cpustate,CYCLES_LGDT);
262                                 break;
263                         }
264                 case 3:         /* LIDT */
265                         {
266                                 if(PROTECTED_MODE && cpustate->CPL)
267                                         FAULT(FAULT_GP,0)
268                                 if( modrm >= 0xc0 ) {
269                                         address = LOAD_RM16(modrm);
270                                         ea = i386_translate( cpustate, CS, address, 0, 6 );
271                                 } else {
272                                         ea = GetEA(cpustate,modrm,0,6);
273                                 }
274                                 cpustate->idtr.limit = READ16(cpustate,ea);
275                                 cpustate->idtr.base = READ32(cpustate,ea + 2) & 0xffffff;
276                                 CYCLES(cpustate,CYCLES_LIDT);
277                                 break;
278                         }
279                 case 4:         /* SMSW */
280                         {
281                                 if( modrm >= 0xc0 ) {
282                                         STORE_RM16(modrm, cpustate->cr[0]);
283                                         CYCLES(cpustate,CYCLES_SMSW_REG);
284                                 } else {
285                                         ea = GetEA(cpustate,modrm,1,2);
286                                         WRITE16(cpustate,ea, cpustate->cr[0]);
287                                         CYCLES(cpustate,CYCLES_SMSW_MEM);
288                                 }
289                                 break;
290                         }
291                 case 6:         /* LMSW */
292                         {
293                                 if(PROTECTED_MODE && cpustate->CPL)
294                                         FAULT(FAULT_GP,0)
295                                 UINT16 b;
296                                 if( modrm >= 0xc0 ) {
297                                         b = LOAD_RM16(modrm);
298                                         CYCLES(cpustate,CYCLES_LMSW_REG);
299                                 } else {
300                                         ea = GetEA(cpustate,modrm,0,2);
301                                         CYCLES(cpustate,CYCLES_LMSW_MEM);
302                                         b = READ16(cpustate,ea);
303                                 }
304                                 if(PROTECTED_MODE)
305                                         b |= 0x0001;  // cannot return to real mode using this instruction.
306                                 cpustate->cr[0] &= ~0x0000000f;
307                                 cpustate->cr[0] |= b & 0x0000000f;
308                                 break;
309                         }
310                 case 7:         /* INVLPG */
311                         {
312                                 if(PROTECTED_MODE && cpustate->CPL)
313                                         FAULT(FAULT_GP,0)
314                                 if(modrm >= 0xc0)
315                                 {
316                                         logerror("i486: invlpg with modrm %02X\n", modrm);
317                                         FAULT(FAULT_UD,0)
318                                 }
319                                 ea = GetEA(cpustate,modrm,-1,1);
320                                 CYCLES(cpustate,25); // TODO: add to cycles.h
321                                 vtlb_flush_address(cpustate->vtlb, ea);
322                                 break;
323                         }
324                 default:
325                         report_invalid_modrm(cpustate, "group0F01_16", modrm);
326                         break;
327         }
328 }
329
330 static void I486OP(group0F01_32)(i386_state *cpustate)      // Opcode 0x0f 01
331 {
332         UINT8 modrm = FETCH(cpustate);
333         UINT32 address, ea;
334
335         switch( (modrm >> 3) & 0x7 )
336         {
337                 case 0:         /* SGDT */
338                         {
339                                 if( modrm >= 0xc0 ) {
340                                         address = LOAD_RM32(modrm);
341                                         ea = i386_translate( cpustate, CS, address, 1, 6 );
342                                 } else {
343                                         ea = GetEA(cpustate,modrm,1,6);
344                                 }
345                                 WRITE16(cpustate,ea, cpustate->gdtr.limit);
346                                 WRITE32(cpustate,ea + 2, cpustate->gdtr.base);
347                                 CYCLES(cpustate,CYCLES_SGDT);
348                                 break;
349                         }
350                 case 1:         /* SIDT */
351                         {
352                                 if (modrm >= 0xc0)
353                                 {
354                                         address = LOAD_RM32(modrm);
355                                         ea = i386_translate( cpustate, CS, address, 1, 6 );
356                                 }
357                                 else
358                                 {
359                                         ea = GetEA(cpustate,modrm,1,6);
360                                 }
361                                 WRITE16(cpustate,ea, cpustate->idtr.limit);
362                                 WRITE32(cpustate,ea + 2, cpustate->idtr.base);
363                                 CYCLES(cpustate,CYCLES_SIDT);
364                                 break;
365                         }
366                 case 2:         /* LGDT */
367                         {
368                                 if(PROTECTED_MODE && cpustate->CPL)
369                                         FAULT(FAULT_GP,0)
370                                 if( modrm >= 0xc0 ) {
371                                         address = LOAD_RM32(modrm);
372                                         ea = i386_translate( cpustate, CS, address, 0, 6 );
373                                 } else {
374                                         ea = GetEA(cpustate,modrm,0,6);
375                                 }
376                                 cpustate->gdtr.limit = READ16(cpustate,ea);
377                                 cpustate->gdtr.base = READ32(cpustate,ea + 2);
378                                 CYCLES(cpustate,CYCLES_LGDT);
379                                 break;
380                         }
381                 case 3:         /* LIDT */
382                         {
383                                 if(PROTECTED_MODE && cpustate->CPL)
384                                         FAULT(FAULT_GP,0)
385                                 if( modrm >= 0xc0 ) {
386                                         address = LOAD_RM32(modrm);
387                                         ea = i386_translate( cpustate, CS, address, 0, 6 );
388                                 } else {
389                                         ea = GetEA(cpustate,modrm,0,6);
390                                 }
391                                 cpustate->idtr.limit = READ16(cpustate,ea);
392                                 cpustate->idtr.base = READ32(cpustate,ea + 2);
393                                 CYCLES(cpustate,CYCLES_LIDT);
394                                 break;
395                         }
396                 case 4:         /* SMSW */
397                         {
398                                 if( modrm >= 0xc0 ) {
399                                         STORE_RM32(modrm, cpustate->cr[0] & 0xffff);
400                                         CYCLES(cpustate,CYCLES_SMSW_REG);
401                                 } else {
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);
406                                 }
407                                 break;
408                         }
409                 case 6:         /* LMSW */
410                         {
411                                 if(PROTECTED_MODE && cpustate->CPL)
412                                         FAULT(FAULT_GP,0)
413                                 UINT16 b;
414                                 if( modrm >= 0xc0 ) {
415                                         b = LOAD_RM16(modrm);
416                                         CYCLES(cpustate,CYCLES_LMSW_REG);
417                                 } else {
418                                         ea = GetEA(cpustate,modrm,0,2);
419                                         CYCLES(cpustate,CYCLES_LMSW_MEM);
420                                 b = READ16(cpustate,ea);
421                                 }
422                                 if(PROTECTED_MODE)
423                                         b |= 0x0001;  // cannot return to real mode using this instruction.
424                                 cpustate->cr[0] &= ~0x0000000f;
425                                 cpustate->cr[0] |= b & 0x0000000f;
426                                 break;
427                         }
428                 case 7:         /* INVLPG */
429                         {
430                                 if(PROTECTED_MODE && cpustate->CPL)
431                                         FAULT(FAULT_GP,0)
432                                 if(modrm >= 0xc0)
433                                 {
434                                         logerror("i486: invlpg with modrm %02X\n", modrm);
435                                         FAULT(FAULT_UD,0)
436                                 }
437                                 ea = GetEA(cpustate,modrm,-1,1);
438                                 CYCLES(cpustate,25); // TODO: add to cycles.h
439                                 vtlb_flush_address(cpustate->vtlb, ea);
440                                 break;
441                         }
442                 default:
443                         report_invalid_modrm(cpustate, "group0F01_32", modrm);
444                         break;
445         }
446 }
447
448 static void I486OP(bswap_eax)(i386_state *cpustate)     // Opcode 0x0f 38
449 {
450         REG32(EAX) = SWITCH_ENDIAN_32(REG32(EAX));
451         CYCLES(cpustate,1);     // TODO
452 }
453
454 static void I486OP(bswap_ecx)(i386_state *cpustate)     // Opcode 0x0f 39
455 {
456         REG32(ECX) = SWITCH_ENDIAN_32(REG32(ECX));
457         CYCLES(cpustate,1);     // TODO
458 }
459
460 static void I486OP(bswap_edx)(i386_state *cpustate)     // Opcode 0x0f 3A
461 {
462         REG32(EDX) = SWITCH_ENDIAN_32(REG32(EDX));
463         CYCLES(cpustate,1);     // TODO
464 }
465
466 static void I486OP(bswap_ebx)(i386_state *cpustate)     // Opcode 0x0f 3B
467 {
468         REG32(EBX) = SWITCH_ENDIAN_32(REG32(EBX));
469         CYCLES(cpustate,1);     // TODO
470 }
471
472 static void I486OP(bswap_esp)(i386_state *cpustate)     // Opcode 0x0f 3C
473 {
474         REG32(ESP) = SWITCH_ENDIAN_32(REG32(ESP));
475         CYCLES(cpustate,1);     // TODO
476 }
477
478 static void I486OP(bswap_ebp)(i386_state *cpustate)     // Opcode 0x0f 3D
479 {
480         REG32(EBP) = SWITCH_ENDIAN_32(REG32(EBP));
481         CYCLES(cpustate,1);     // TODO
482 }
483
484 static void I486OP(bswap_esi)(i386_state *cpustate)     // Opcode 0x0f 3E
485 {
486         REG32(ESI) = SWITCH_ENDIAN_32(REG32(ESI));
487         CYCLES(cpustate,1);     // TODO
488 }
489
490 static void I486OP(bswap_edi)(i386_state *cpustate)     // Opcode 0x0f 3F
491 {
492         REG32(EDI) = SWITCH_ENDIAN_32(REG32(EDI));
493         CYCLES(cpustate,1);     // TODO
494 }
495
496 static void I486OP(mov_cr_r32)(i386_state *cpustate)        // Opcode 0x0f 22
497 {
498         if(PROTECTED_MODE && cpustate->CPL)
499                 FAULT(FAULT_GP, 0);
500         UINT8 modrm = FETCH(cpustate);
501         UINT8 cr = (modrm >> 3) & 0x7;
502         UINT32 oldcr = cpustate->cr[cr];
503         UINT32 data = LOAD_RM32(modrm);
504         switch(cr)
505         {
506                 case 0:
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();
512                         break;
513                 case 2: CYCLES(cpustate,CYCLES_MOV_REG_CR2); break;
514                 case 3:
515                         CYCLES(cpustate,CYCLES_MOV_REG_CR3);
516                         vtlb_flush_dynamic(cpustate->vtlb);
517                         break;
518                 case 4: CYCLES(cpustate,1); break; // TODO
519                 default:
520                         logerror("i386: mov_cr_r32 CR%d!\n", cr);
521                         return;
522         }
523         cpustate->cr[cr] = data;
524 }