/[pcsx2_0.9.7]/trunk/pcsx2/R5900OpcodeImpl.cpp
ViewVC logotype

Annotation of /trunk/pcsx2/R5900OpcodeImpl.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 62 - (hide annotations) (download)
Tue Sep 7 11:08:22 2010 UTC (9 years, 5 months ago) by william
File size: 31845 byte(s)
Auto Commited Import of: pcsx2-0.9.7-r3738-debug in ./trunk
1 william 31 /* PCSX2 - PS2 Emulator for PCs
2     * Copyright (C) 2002-2010 PCSX2 Dev Team
3     *
4     * PCSX2 is free software: you can redistribute it and/or modify it under the terms
5     * of the GNU Lesser General Public License as published by the Free Software Found-
6     * ation, either version 3 of the License, or (at your option) any later version.
7     *
8     * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9     * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10     * PURPOSE. See the GNU General Public License for more details.
11     *
12     * You should have received a copy of the GNU General Public License along with PCSX2.
13     * If not, see <http://www.gnu.org/licenses/>.
14     */
15    
16    
17     #include "PrecompiledHeader.h"
18     #include "Common.h"
19    
20     #include <float.h>
21    
22     #include "R5900.h"
23     #include "R5900OpcodeTables.h"
24     #include "R5900Exceptions.h"
25    
26    
27 william 62 static __fi s64 _add64_Overflow( s64 x, s64 y )
28 william 31 {
29     const s64 result = x + y;
30    
31     // Let's all give gigaherz a big round of applause for finding this gem,
32     // which apparently works, and generates compact/fast x86 code too (the
33     // other method below is like 5-10 times slower).
34    
35     if( ((~(x^y))&(x^result)) < 0 )
36     cpuException(0x30, cpuRegs.branch); // fixme: is 0x30 right for overflow??
37    
38     // the not-as-fast style!
39     //if( ((x >= 0) && (y >= 0) && (result < 0)) ||
40     // ((x < 0) && (y < 0) && (result >= 0)) )
41     // cpuException(0x30, cpuRegs.branch);
42    
43     return result;
44     }
45    
46 william 62 static __fi s64 _add32_Overflow( s32 x, s32 y )
47 william 31 {
48     GPR_reg64 result; result.SD[0] = (s64)x + y;
49    
50     // This 32bit method can rely on the MIPS documented method of checking for
51     // overflow, whichs imply compares bit 32 (rightmost bit of the upper word),
52     // against bit 31 (leftmost of the lower word).
53    
54     // If bit32 != bit31 then we have an overflow.
55     if( (result.UL[0]>>31) != (result.UL[1] & 1) )
56     cpuException(0x30, cpuRegs.branch);
57    
58     return result.SD[0];
59     }
60    
61    
62     const R5900::OPCODE& R5900::GetCurrentInstruction()
63     {
64     const OPCODE* opcode = &R5900::OpcodeTables::tbl_Standard[_Opcode_];
65    
66     while( opcode->getsubclass != NULL )
67     opcode = &opcode->getsubclass();
68    
69     return *opcode;
70     }
71    
72     const char * const R5900::bios[256]=
73     {
74     //0x00
75     "RFU000_FullReset", "ResetEE", "SetGsCrt", "RFU003",
76     "Exit", "RFU005", "LoadExecPS2", "ExecPS2",
77     "RFU008", "RFU009", "AddSbusIntcHandler", "RemoveSbusIntcHandler",
78     "Interrupt2Iop", "SetVTLBRefillHandler", "SetVCommonHandler", "SetVInterruptHandler",
79     //0x10
80     "AddIntcHandler", "RemoveIntcHandler", "AddDmacHandler", "RemoveDmacHandler",
81     "_EnableIntc", "_DisableIntc", "_EnableDmac", "_DisableDmac",
82     "_SetAlarm", "_ReleaseAlarm", "_iEnableIntc", "_iDisableIntc",
83     "_iEnableDmac", "_iDisableDmac", "_iSetAlarm", "_iReleaseAlarm",
84     //0x20
85     "CreateThread", "DeleteThread", "StartThread", "ExitThread",
86     "ExitDeleteThread", "TerminateThread", "iTerminateThread", "DisableDispatchThread",
87     "EnableDispatchThread", "ChangeThreadPriority", "iChangeThreadPriority", "RotateThreadReadyQueue",
88     "iRotateThreadReadyQueue", "ReleaseWaitThread", "iReleaseWaitThread", "GetThreadId",
89     //0x30
90     "ReferThreadStatus","iReferThreadStatus", "SleepThread", "WakeupThread",
91     "_iWakeupThread", "CancelWakeupThread", "iCancelWakeupThread", "SuspendThread",
92     "iSuspendThread", "ResumeThread", "iResumeThread", "JoinThread",
93     "RFU060", "RFU061", "EndOfHeap", "RFU063",
94     //0x40
95     "CreateSema", "DeleteSema", "SignalSema", "iSignalSema",
96     "WaitSema", "PollSema", "iPollSema", "ReferSemaStatus",
97     "iReferSemaStatus", "RFU073", "SetOsdConfigParam", "GetOsdConfigParam",
98     "GetGsHParam", "GetGsVParam", "SetGsHParam", "SetGsVParam",
99     //0x50
100     "RFU080_CreateEventFlag", "RFU081_DeleteEventFlag",
101     "RFU082_SetEventFlag", "RFU083_iSetEventFlag",
102     "RFU084_ClearEventFlag", "RFU085_iClearEventFlag",
103     "RFU086_WaitEventFlag", "RFU087_PollEventFlag",
104     "RFU088_iPollEventFlag", "RFU089_ReferEventFlagStatus",
105     "RFU090_iReferEventFlagStatus", "RFU091_GetEntryAddress",
106     "EnableIntcHandler_iEnableIntcHandler",
107     "DisableIntcHandler_iDisableIntcHandler",
108     "EnableDmacHandler_iEnableDmacHandler",
109     "DisableDmacHandler_iDisableDmacHandler",
110     //0x60
111     "KSeg0", "EnableCache", "DisableCache", "GetCop0",
112     "FlushCache", "RFU101", "CpuConfig", "iGetCop0",
113     "iFlushCache", "RFU105", "iCpuConfig", "sceSifStopDma",
114     "SetCPUTimerHandler", "SetCPUTimer", "SetOsdConfigParam2", "SetOsdConfigParam2",
115     //0x70
116     "GsGetIMR_iGsGetIMR", "GsGetIMR_iGsPutIMR", "SetPgifHandler", "SetVSyncFlag",
117     "RFU116", "print", "sceSifDmaStat_isceSifDmaStat", "sceSifSetDma_isceSifSetDma",
118     "sceSifSetDChain_isceSifSetDChain", "sceSifSetReg", "sceSifGetReg", "ExecOSD",
119     "Deci2Call", "PSMode", "MachineType", "GetMemorySize",
120     };
121    
122     static u32 deci2addr = 0;
123     static u32 deci2handler = 0;
124     static char deci2buffer[256];
125    
126     void Deci2Reset()
127     {
128     deci2handler = 0;
129     deci2addr = 0;
130     memzero( deci2buffer );
131     }
132    
133     void SaveStateBase::deci2Freeze()
134     {
135     FreezeTag( "deci2" );
136    
137     Freeze( deci2addr );
138     Freeze( deci2handler );
139     Freeze( deci2buffer );
140     }
141    
142     /*
143     * int Deci2Call(int, u_int *);
144     *
145     * HLE implementation of the Deci2 interface.
146     */
147    
148     static int __Deci2Call(int call, u32 *addr)
149     {
150     if (call > 0x10)
151     return -1;
152    
153     switch (call)
154     {
155     case 1: // open
156     if( addr != NULL )
157     {
158     deci2addr = addr[1];
159     BIOS_LOG("deci2open: %x,%x,%x,%x",
160     addr[3], addr[2], addr[1], addr[0]);
161     deci2handler = addr[2];
162     }
163     else
164     {
165     deci2handler = 0;
166     DevCon.Warning( "Deci2Call.Open > NULL address ignored." );
167     }
168     return 1;
169    
170     case 2: // close
171     deci2addr = 0;
172     deci2handler = 0;
173     return 1;
174    
175     case 3: // reqsend
176     {
177     char reqaddr[128];
178     if( addr != NULL )
179     sprintf( reqaddr, "%x %x %x %x", addr[3], addr[2], addr[1], addr[0] );
180    
181     if (!deci2addr) return 1;
182    
183     const u32* d2ptr = (u32*)PSM(deci2addr);
184    
185     BIOS_LOG("deci2reqsend: %s: deci2addr: %x,%x,%x,buf=%x %x,%x,len=%x,%x",
186     (( addr == NULL ) ? "NULL" : reqaddr),
187     d2ptr[7], d2ptr[6], d2ptr[5], d2ptr[4],
188     d2ptr[3], d2ptr[2], d2ptr[1], d2ptr[0]);
189    
190     // cpuRegs.pc = deci2handler;
191     // Console.WriteLn("deci2msg: %s", (char*)PSM(d2ptr[4]+0xc));
192    
193     if (d2ptr[1]>0xc){
194     // this looks horribly wrong, justification please?
195     u8* pdeciaddr = (u8*)dmaGetAddr(d2ptr[4]+0xc, false);
196     if( pdeciaddr == NULL )
197     pdeciaddr = (u8*)PSM(d2ptr[4]+0xc);
198     else
199     pdeciaddr += (d2ptr[4]+0xc) % 16;
200    
201     const int copylen = std::min<uint>(255, d2ptr[1]-0xc);
202 william 62 memcpy_fast(deci2buffer, pdeciaddr, copylen );
203 william 31 deci2buffer[copylen] = '\0';
204    
205 william 62 eeConLog( ShiftJIS_ConvertString(deci2buffer) );
206 william 31 }
207     ((u32*)PSM(deci2addr))[3] = 0;
208     return 1;
209     }
210    
211     case 4: // poll
212     if( addr != NULL )
213     BIOS_LOG("deci2poll: %x,%x,%x,%x\n", addr[3], addr[2], addr[1], addr[0]);
214     return 1;
215    
216     case 5: // exrecv
217     return 1;
218    
219     case 6: // exsend
220     return 1;
221    
222     case 0x10://kputs
223 william 62 if( addr != NULL )
224     {
225     eeDeci2Log( ShiftJIS_ConvertString((char*)PSM(*addr)) );
226     }
227 william 31 return 1;
228     }
229    
230     return 0;
231     }
232    
233     namespace R5900 {
234     namespace Interpreter {
235     namespace OpcodeImpl {
236    
237     void COP2()
238     {
239     //std::string disOut;
240     //disR5900Fasm(disOut, cpuRegs.code, cpuRegs.pc);
241    
242     //VU0_LOG("%s", disOut.c_str());
243     Int_COP2PrintTable[_Rs_]();
244     }
245    
246     void Unknown() {
247     CPU_LOG("%8.8lx: Unknown opcode called", cpuRegs.pc);
248     }
249    
250     void MMI_Unknown() { Console.Warning("Unknown MMI opcode called"); }
251     void COP0_Unknown() { Console.Warning("Unknown COP0 opcode called"); }
252     void COP1_Unknown() { Console.Warning("Unknown FPU/COP1 opcode called"); }
253    
254    
255    
256     /*********************************************************
257     * Arithmetic with immediate operand *
258     * Format: OP rt, rs, immediate *
259     *********************************************************/
260    
261     // Implementation Notes:
262     // * It is important that instructions perform overflow checks prior to shortcutting on
263     // the zero register (when it is used as a destination). Overflow exceptions are still
264     // handled even though the result is discarded.
265    
266     // Rt = Rs + Im signed [exception on overflow]
267     void ADDI()
268     {
269     s64 result = _add32_Overflow( cpuRegs.GPR.r[_Rs_].SD[0], _Imm_ );
270     if (!_Rt_) return;
271     cpuRegs.GPR.r[_Rt_].SD[0] = result;
272     }
273    
274     // Rt = Rs + Im signed !!! [overflow ignored]
275     // This instruction is effectively identical to ADDI. It is not a true unsigned operation,
276     // but rather it is a signed operation that ignores overflows.
277     void ADDIU()
278     {
279     if (!_Rt_) return;
280     cpuRegs.GPR.r[_Rt_].SD[0] = cpuRegs.GPR.r[_Rs_].SL[0] + _Imm_;
281     }
282    
283     // Rt = Rs + Im [exception on overflow]
284     // This is the full 64 bit version of ADDI. Overflow occurs at 64 bits instead
285     // of at 32 bits.
286     void DADDI()
287     {
288     s64 result = _add64_Overflow( cpuRegs.GPR.r[_Rs_].SD[0], _Imm_ );
289     if (!_Rt_) return;
290     cpuRegs.GPR.r[_Rt_].SD[0] = result;
291     }
292    
293     // Rt = Rs + Im [overflow ignored]
294     // This instruction is effectively identical to DADDI. It is not a true unsigned operation,
295     // but rather it is a signed operation that ignores overflows.
296     void DADDIU()
297     {
298     if (!_Rt_) return;
299     cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] + _Imm_;
300     }
301     void ANDI() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] & (u64)_ImmU_; } // Rt = Rs And Im (zero-extended)
302     void ORI() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] | (u64)_ImmU_; } // Rt = Rs Or Im (zero-extended)
303     void XORI() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] ^ (u64)_ImmU_; } // Rt = Rs Xor Im (zero-extended)
304     void SLTI() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = (cpuRegs.GPR.r[_Rs_].SD[0] < (s64)(_Imm_)) ? 1 : 0; } // Rt = Rs < Im (signed)
305     void SLTIU() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = (cpuRegs.GPR.r[_Rs_].UD[0] < (u64)(_Imm_)) ? 1 : 0; } // Rt = Rs < Im (unsigned)
306    
307     /*********************************************************
308     * Register arithmetic *
309     * Format: OP rd, rs, rt *
310     *********************************************************/
311    
312     // Rd = Rs + Rt (Exception on Integer Overflow)
313     void ADD()
314     {
315     s64 result = _add32_Overflow( cpuRegs.GPR.r[_Rs_].SD[0], cpuRegs.GPR.r[_Rt_].SD[0] );
316     if (!_Rd_) return;
317     cpuRegs.GPR.r[_Rd_].SD[0] = result;
318     }
319    
320     void DADD()
321     {
322     s64 result = _add64_Overflow( cpuRegs.GPR.r[_Rs_].SD[0], cpuRegs.GPR.r[_Rt_].SD[0] );
323     if (!_Rd_) return;
324     cpuRegs.GPR.r[_Rd_].SD[0] = result;
325     }
326    
327     // Rd = Rs - Rt (Exception on Integer Overflow)
328     void SUB()
329     {
330     s64 result = _add32_Overflow( cpuRegs.GPR.r[_Rs_].SD[0], -cpuRegs.GPR.r[_Rt_].SD[0] );
331     if (!_Rd_) return;
332     cpuRegs.GPR.r[_Rd_].SD[0] = result;
333     }
334    
335     // Rd = Rs - Rt (Exception on Integer Overflow)
336     void DSUB()
337     {
338     s64 result = _add64_Overflow( cpuRegs.GPR.r[_Rs_].SD[0], -cpuRegs.GPR.r[_Rt_].SD[0] );
339     if (!_Rd_) return;
340     cpuRegs.GPR.r[_Rd_].SD[0] = result;
341     }
342    
343     void ADDU() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SL[0] + cpuRegs.GPR.r[_Rt_].SL[0];} // Rd = Rs + Rt
344     void DADDU() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] + cpuRegs.GPR.r[_Rt_].SD[0]; }
345     void SUBU() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SL[0] - cpuRegs.GPR.r[_Rt_].SL[0]; } // Rd = Rs - Rt
346     void DSUBU() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] - cpuRegs.GPR.r[_Rt_].SD[0]; }
347     void AND() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] & cpuRegs.GPR.r[_Rt_].UD[0]; } // Rd = Rs And Rt
348     void OR() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] | cpuRegs.GPR.r[_Rt_].UD[0]; } // Rd = Rs Or Rt
349     void XOR() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] ^ cpuRegs.GPR.r[_Rt_].UD[0]; } // Rd = Rs Xor Rt
350     void NOR() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] =~(cpuRegs.GPR.r[_Rs_].UD[0] | cpuRegs.GPR.r[_Rt_].UD[0]); }// Rd = Rs Nor Rt
351     void SLT() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (cpuRegs.GPR.r[_Rs_].SD[0] < cpuRegs.GPR.r[_Rt_].SD[0]) ? 1 : 0; } // Rd = Rs < Rt (signed)
352     void SLTU() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (cpuRegs.GPR.r[_Rs_].UD[0] < cpuRegs.GPR.r[_Rt_].UD[0]) ? 1 : 0; } // Rd = Rs < Rt (unsigned)
353    
354     /*********************************************************
355     * Register mult/div & Register trap logic *
356     * Format: OP rs, rt *
357     *********************************************************/
358    
359     // Signed division "overflows" on (0x80000000 / -1), here (LO = 0x80000000, HI = 0) is returned by MIPS
360     // in division by zero on MIPS, it appears that:
361     // LO gets 1 if rs is negative (and the division is signed) and -1 otherwise.
362     // HI gets the value of rs.
363    
364     // Result is stored in HI/LO [no arithmetic exceptions]
365     void DIV()
366     {
367     if (cpuRegs.GPR.r[_Rs_].UL[0] == 0x80000000 && cpuRegs.GPR.r[_Rt_].UL[0] == 0xffffffff)
368     {
369     cpuRegs.LO.SD[0] = (s32)0x80000000;
370     cpuRegs.HI.SD[0] = (s32)0x0;
371     }
372     else if (cpuRegs.GPR.r[_Rt_].SL[0] != 0)
373     {
374     cpuRegs.LO.SD[0] = cpuRegs.GPR.r[_Rs_].SL[0] / cpuRegs.GPR.r[_Rt_].SL[0];
375     cpuRegs.HI.SD[0] = cpuRegs.GPR.r[_Rs_].SL[0] % cpuRegs.GPR.r[_Rt_].SL[0];
376     }
377     else
378     {
379     cpuRegs.LO.SD[0] = (cpuRegs.GPR.r[_Rs_].SL[0] < 0) ? 1 : -1;
380     cpuRegs.HI.SD[0] = cpuRegs.GPR.r[_Rs_].SL[0];
381     }
382     }
383    
384     // Result is stored in HI/LO [no arithmetic exceptions]
385     void DIVU()
386     {
387     if (cpuRegs.GPR.r[_Rt_].UL[0] != 0)
388     {
389     // note: DIVU has no sign extension when assigning back to 64 bits
390     // note 2: reference material strongly disagrees. (air)
391     cpuRegs.LO.SD[0] = (s32)(cpuRegs.GPR.r[_Rs_].UL[0] / cpuRegs.GPR.r[_Rt_].UL[0]);
392     cpuRegs.HI.SD[0] = (s32)(cpuRegs.GPR.r[_Rs_].UL[0] % cpuRegs.GPR.r[_Rt_].UL[0]);
393     }
394     else
395     {
396     cpuRegs.LO.SD[0] = -1;
397     cpuRegs.HI.SD[0] = cpuRegs.GPR.r[_Rs_].SL[0];
398     }
399     }
400    
401     // Result is written to both HI/LO and to the _Rd_ (Lo only)
402     void MULT()
403     {
404     s64 res = (s64)cpuRegs.GPR.r[_Rs_].SL[0] * cpuRegs.GPR.r[_Rt_].SL[0];
405    
406     // Sign-extend into 64 bits:
407     cpuRegs.LO.SD[0] = (s32)(res & 0xffffffff);
408     cpuRegs.HI.SD[0] = (s32)(res >> 32);
409    
410     if( _Rd_ ) cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.LO.UD[0];
411     }
412    
413     // Result is written to both HI/LO and to the _Rd_ (Lo only)
414     void MULTU()
415     {
416     u64 res = (u64)cpuRegs.GPR.r[_Rs_].UL[0] * cpuRegs.GPR.r[_Rt_].UL[0];
417    
418     // Note: sign-extend into 64 bits even though it's an unsigned mult.
419     cpuRegs.LO.SD[0] = (s32)(res & 0xffffffff);
420     cpuRegs.HI.SD[0] = (s32)(res >> 32);
421    
422     if( _Rd_ ) cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.LO.UD[0];
423     }
424    
425     /*********************************************************
426     * Load higher 16 bits of the first word in GPR with imm *
427     * Format: OP rt, immediate *
428     *********************************************************/
429     void LUI() {
430     if (!_Rt_) return;
431     cpuRegs.GPR.r[_Rt_].UD[0] = (s32)(cpuRegs.code << 16);
432     }
433    
434     /*********************************************************
435     * Move from HI/LO to GPR *
436     * Format: OP rd *
437     *********************************************************/
438     void MFHI() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.HI.UD[0]; } // Rd = Hi
439     void MFLO() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.LO.UD[0]; } // Rd = Lo
440    
441     /*********************************************************
442     * Move to GPR to HI/LO & Register jump *
443     * Format: OP rs *
444     *********************************************************/
445     void MTHI() { cpuRegs.HI.UD[0] = cpuRegs.GPR.r[_Rs_].UD[0]; } // Hi = Rs
446     void MTLO() { cpuRegs.LO.UD[0] = cpuRegs.GPR.r[_Rs_].UD[0]; } // Lo = Rs
447    
448    
449     /*********************************************************
450     * Shift arithmetic with constant shift *
451     * Format: OP rd, rt, sa *
452     *********************************************************/
453     void SRA() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s32)(cpuRegs.GPR.r[_Rt_].SL[0] >> _Sa_); } // Rd = Rt >> sa (arithmetic)
454     void SRL() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s32)(cpuRegs.GPR.r[_Rt_].UL[0] >> _Sa_); } // Rd = Rt >> sa (logical) [sign extend!!]
455     void SLL() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s32)(cpuRegs.GPR.r[_Rt_].UL[0] << _Sa_); } // Rd = Rt << sa
456     void DSLL() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (u64)(cpuRegs.GPR.r[_Rt_].UD[0] << _Sa_); }
457     void DSLL32(){ if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (u64)(cpuRegs.GPR.r[_Rt_].UD[0] << (_Sa_+32));}
458     void DSRA() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = cpuRegs.GPR.r[_Rt_].SD[0] >> _Sa_; }
459     void DSRA32(){ if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = cpuRegs.GPR.r[_Rt_].SD[0] >> (_Sa_+32);}
460     void DSRL() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rt_].UD[0] >> _Sa_; }
461     void DSRL32(){ if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rt_].UD[0] >> (_Sa_+32);}
462    
463     /*********************************************************
464     * Shift arithmetic with variant register shift *
465     * Format: OP rd, rt, rs *
466     *********************************************************/
467     void SLLV() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s32)(cpuRegs.GPR.r[_Rt_].UL[0] << (cpuRegs.GPR.r[_Rs_].UL[0] &0x1f));} // Rd = Rt << rs
468     void SRAV() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s32)(cpuRegs.GPR.r[_Rt_].SL[0] >> (cpuRegs.GPR.r[_Rs_].UL[0] &0x1f));} // Rd = Rt >> rs (arithmetic)
469     void SRLV() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s32)(cpuRegs.GPR.r[_Rt_].UL[0] >> (cpuRegs.GPR.r[_Rs_].UL[0] &0x1f));} // Rd = Rt >> rs (logical)
470     void DSLLV(){ if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (u64)(cpuRegs.GPR.r[_Rt_].UD[0] << (cpuRegs.GPR.r[_Rs_].UL[0] &0x3f));}
471     void DSRAV(){ if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s64)(cpuRegs.GPR.r[_Rt_].SD[0] >> (cpuRegs.GPR.r[_Rs_].UL[0] &0x3f));}
472     void DSRLV(){ if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (u64)(cpuRegs.GPR.r[_Rt_].UD[0] >> (cpuRegs.GPR.r[_Rs_].UL[0] &0x3f));}
473    
474     /*********************************************************
475     * Load and store for GPR *
476     * Format: OP rt, offset(base) *
477     *********************************************************/
478    
479     // Implementation Notes Regarding Memory Operations:
480     // * It it 'correct' to do all loads into temp variables, even if the destination GPR
481     // is the zero reg (which nullifies the result). The memory needs to be accessed
482     // regardless so that hardware registers behave as expected (some clear on read) and
483     // so that TLB Misses are handled as expected as well.
484     //
485     // * Low/High varieties of instructions, such as LWL/LWH, do *not* raise Address Error
486     // exceptions, since the lower bits of the address are used to determine the portions
487     // of the address/register operations.
488    
489    
490     void LB()
491     {
492     u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
493     s8 temp = memRead8(addr);
494    
495     if (!_Rt_) return;
496     cpuRegs.GPR.r[_Rt_].SD[0] = temp;
497     }
498    
499     void LBU()
500     {
501     u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
502     u8 temp = memRead8(addr);
503    
504     if (!_Rt_) return;
505     cpuRegs.GPR.r[_Rt_].UD[0] = temp;
506     }
507    
508     void LH()
509     {
510     u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
511    
512     if( addr & 1 )
513     throw R5900Exception::AddressError( addr, false );
514    
515     s16 temp = memRead16(addr);
516    
517     if (!_Rt_) return;
518     cpuRegs.GPR.r[_Rt_].SD[0] = temp;
519     }
520    
521     void LHU()
522     {
523     u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
524    
525     if( addr & 1 )
526     throw R5900Exception::AddressError( addr, false );
527    
528     u16 temp = memRead16(addr);
529    
530     if (!_Rt_) return;
531     cpuRegs.GPR.r[_Rt_].UD[0] = temp;
532     }
533    
534     void LW()
535     {
536     u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
537    
538     if( addr & 3 )
539     throw R5900Exception::AddressError( addr, false );
540    
541     u32 temp = memRead32(addr);
542    
543     if (!_Rt_) return;
544     cpuRegs.GPR.r[_Rt_].SD[0] = (s32)temp;
545     }
546    
547     void LWU()
548     {
549     u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
550    
551     if( addr & 3 )
552     throw R5900Exception::AddressError( addr, false );
553    
554     u32 temp = memRead32(addr);
555    
556     if (!_Rt_) return;
557     cpuRegs.GPR.r[_Rt_].UD[0] = temp;
558     }
559    
560     static const s32 LWL_MASK[4] = { 0xffffff, 0x0000ffff, 0x000000ff, 0x00000000 };
561     static const s32 LWR_MASK[4] = { 0x000000, 0xff000000, 0xffff0000, 0xffffff00 };
562     static const u8 LWL_SHIFT[4] = { 24, 16, 8, 0 };
563     static const u8 LWR_SHIFT[4] = { 0, 8, 16, 24 };
564    
565     void LWL()
566     {
567     s32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
568     u32 shift = addr & 3;
569    
570     // ensure the compiler does correct sign extension into 64 bits by using s32
571     s32 mem = memRead32(addr & ~3);
572    
573     if (!_Rt_) return;
574    
575     cpuRegs.GPR.r[_Rt_].SD[0] = (cpuRegs.GPR.r[_Rt_].SL[0] & LWL_MASK[shift]) |
576     (mem << LWL_SHIFT[shift]);
577    
578     /*
579     Mem = 1234. Reg = abcd
580     (result is always sign extended into the upper 32 bits of the Rt)
581    
582     0 4bcd (mem << 24) | (reg & 0x00ffffff)
583     1 34cd (mem << 16) | (reg & 0x0000ffff)
584     2 234d (mem << 8) | (reg & 0x000000ff)
585     3 1234 (mem ) | (reg & 0x00000000)
586     */
587     }
588    
589     void LWR()
590     {
591     s32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
592     u32 shift = addr & 3;
593    
594     u32 mem = memRead32(addr & ~3);
595    
596     if (!_Rt_) return;
597    
598     // Use unsigned math here, and conditionally sign extend below, when needed.
599     mem = (cpuRegs.GPR.r[_Rt_].UL[0] & LWR_MASK[shift]) | (mem >> LWR_SHIFT[shift]);
600    
601     if( shift == 0 )
602     {
603     // This special case requires sign extension into the full 64 bit dest.
604     cpuRegs.GPR.r[_Rt_].SD[0] = (s32)mem;
605     }
606     else
607     {
608     // This case sets the lower 32 bits of the target register. Upper
609     // 32 bits are always preserved.
610     cpuRegs.GPR.r[_Rt_].UL[0] = mem;
611     }
612    
613     /*
614     Mem = 1234. Reg = abcd
615    
616     0 1234 (mem ) | (reg & 0x00000000) [sign extend into upper 32 bits!]
617     1 a123 (mem >> 8) | (reg & 0xff000000)
618     2 ab12 (mem >> 16) | (reg & 0xffff0000)
619     3 abc1 (mem >> 24) | (reg & 0xffffff00)
620     */
621     }
622    
623     // dummy variable used as a destination address for writes to the zero register, so
624     // that the zero register always stays zero.
625     static __aligned16 GPR_reg m_dummy_gpr_zero;
626    
627     // Returns the x86 address of the requested GPR, which is safe for writing. (includes
628     // special handling for returning a dummy var for GPR0(zero), so that it's value is
629     // always preserved)
630 william 62 static GPR_reg* gpr_GetWritePtr( uint gpr )
631 william 31 {
632 william 62 return (( gpr == 0 ) ? &m_dummy_gpr_zero : &cpuRegs.GPR.r[gpr]);
633 william 31 }
634    
635     void LD()
636     {
637     s32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
638    
639     if( addr & 7 )
640     throw R5900Exception::AddressError( addr, false );
641    
642 william 62 memRead64(addr, (u64*)gpr_GetWritePtr(_Rt_));
643 william 31 }
644    
645     static const u64 LDL_MASK[8] =
646     { 0x00ffffffffffffffLL, 0x0000ffffffffffffLL, 0x000000ffffffffffLL, 0x00000000ffffffffLL,
647     0x0000000000ffffffLL, 0x000000000000ffffLL, 0x00000000000000ffLL, 0x0000000000000000LL
648     };
649     static const u64 LDR_MASK[8] =
650     { 0x0000000000000000LL, 0xff00000000000000LL, 0xffff000000000000LL, 0xffffff0000000000LL,
651     0xffffffff00000000LL, 0xffffffffff000000LL, 0xffffffffffff0000LL, 0xffffffffffffff00LL
652     };
653    
654     static const u8 LDR_SHIFT[8] = { 0, 8, 16, 24, 32, 40, 48, 56 };
655     static const u8 LDL_SHIFT[8] = { 56, 48, 40, 32, 24, 16, 8, 0 };
656    
657    
658     void LDL()
659     {
660     u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
661     u32 shift = addr & 7;
662    
663     u64 mem;
664     memRead64(addr & ~7, &mem);
665    
666     if( !_Rt_ ) return;
667     cpuRegs.GPR.r[_Rt_].UD[0] = (cpuRegs.GPR.r[_Rt_].UD[0] & LDL_MASK[shift]) |
668     (mem << LDL_SHIFT[shift]);
669     }
670    
671     void LDR()
672     {
673     u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
674     u32 shift = addr & 7;
675    
676     u64 mem;
677     memRead64(addr & ~7, &mem);
678    
679     if (!_Rt_) return;
680     cpuRegs.GPR.r[_Rt_].UD[0] = (cpuRegs.GPR.r[_Rt_].UD[0] & LDR_MASK[shift]) |
681     (mem >> LDR_SHIFT[shift]);
682     }
683    
684     void LQ()
685     {
686     // MIPS Note: LQ and SQ are special and "silently" align memory addresses, thus
687     // an address error due to unaligned access isn't possible like it is on other loads/stores.
688    
689     u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
690 william 62 memRead128(addr & ~0xf, (u128*)gpr_GetWritePtr(_Rt_));
691 william 31 }
692    
693     void SB()
694     {
695     u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
696     memWrite8(addr, cpuRegs.GPR.r[_Rt_].UC[0]);
697     }
698    
699     void SH()
700     {
701     u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
702    
703     if( addr & 1 )
704     throw R5900Exception::AddressError( addr, true );
705    
706     memWrite16(addr, cpuRegs.GPR.r[_Rt_].US[0]);
707     }
708    
709     void SW()
710     {
711     u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
712    
713     if( addr & 3 )
714     throw R5900Exception::AddressError( addr, true );
715    
716     memWrite32(addr, cpuRegs.GPR.r[_Rt_].UL[0]);
717     }
718    
719     static const u32 SWL_MASK[4] = { 0xffffff00, 0xffff0000, 0xff000000, 0x00000000 };
720     static const u32 SWR_MASK[4] = { 0x00000000, 0x000000ff, 0x0000ffff, 0x00ffffff };
721    
722     static const u8 SWR_SHIFT[4] = { 0, 8, 16, 24 };
723     static const u8 SWL_SHIFT[4] = { 24, 16, 8, 0 };
724    
725     void SWL()
726     {
727     u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
728     u32 shift = addr & 3;
729     u32 mem = memRead32( addr & ~3 );
730    
731     memWrite32( addr & ~3,
732     (cpuRegs.GPR.r[_Rt_].UL[0] >> SWL_SHIFT[shift]) |
733     (mem & SWL_MASK[shift])
734     );
735    
736     /*
737     Mem = 1234. Reg = abcd
738    
739     0 123a (reg >> 24) | (mem & 0xffffff00)
740     1 12ab (reg >> 16) | (mem & 0xffff0000)
741     2 1abc (reg >> 8) | (mem & 0xff000000)
742     3 abcd (reg ) | (mem & 0x00000000)
743     */
744     }
745    
746     void SWR() {
747     u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
748     u32 shift = addr & 3;
749     u32 mem = memRead32(addr & ~3);
750    
751     memWrite32( addr & ~3,
752     (cpuRegs.GPR.r[_Rt_].UL[0] << SWR_SHIFT[shift]) |
753     (mem & SWR_MASK[shift])
754     );
755    
756     /*
757     Mem = 1234. Reg = abcd
758    
759     0 abcd (reg ) | (mem & 0x00000000)
760     1 bcd4 (reg << 8) | (mem & 0x000000ff)
761     2 cd34 (reg << 16) | (mem & 0x0000ffff)
762     3 d234 (reg << 24) | (mem & 0x00ffffff)
763     */
764     }
765    
766     void SD()
767     {
768     u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
769    
770     if( addr & 7 )
771     throw R5900Exception::AddressError( addr, true );
772    
773     memWrite64(addr,&cpuRegs.GPR.r[_Rt_].UD[0]);
774     }
775    
776     static const u64 SDL_MASK[8] =
777     { 0xffffffffffffff00LL, 0xffffffffffff0000LL, 0xffffffffff000000LL, 0xffffffff00000000LL,
778     0xffffff0000000000LL, 0xffff000000000000LL, 0xff00000000000000LL, 0x0000000000000000LL
779     };
780     static const u64 SDR_MASK[8] =
781     { 0x0000000000000000LL, 0x00000000000000ffLL, 0x000000000000ffffLL, 0x0000000000ffffffLL,
782     0x00000000ffffffffLL, 0x000000ffffffffffLL, 0x0000ffffffffffffLL, 0x00ffffffffffffffLL
783     };
784    
785     static const u8 SDL_SHIFT[8] = { 56, 48, 40, 32, 24, 16, 8, 0 };
786     static const u8 SDR_SHIFT[8] = { 0, 8, 16, 24, 32, 40, 48, 56 };
787    
788     void SDL()
789     {
790     u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
791     u32 shift = addr & 7;
792     u64 mem;
793    
794     memRead64(addr & ~7, &mem);
795     mem = (cpuRegs.GPR.r[_Rt_].UD[0] >> SDL_SHIFT[shift]) |
796     (mem & SDL_MASK[shift]);
797     memWrite64(addr & ~7, &mem);
798     }
799    
800    
801     void SDR()
802     {
803     u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
804     u32 shift = addr & 7;
805     u64 mem;
806    
807     memRead64(addr & ~7, &mem);
808     mem = (cpuRegs.GPR.r[_Rt_].UD[0] << SDR_SHIFT[shift]) |
809     (mem & SDR_MASK[shift]);
810     memWrite64(addr & ~7, &mem );
811     }
812    
813     void SQ()
814     {
815     // MIPS Note: LQ and SQ are special and "silently" align memory addresses, thus
816     // an address error due to unaligned access isn't possible like it is on other loads/stores.
817    
818     u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
819 william 62 memWrite128(addr & ~0xf, cpuRegs.GPR.r[_Rt_].UQ);
820 william 31 }
821    
822     /*********************************************************
823     * Conditional Move *
824     * Format: OP rd, rs, rt *
825     *********************************************************/
826    
827     void MOVZ() {
828     if (!_Rd_) return;
829     if (cpuRegs.GPR.r[_Rt_].UD[0] == 0) {
830     cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0];
831     }
832     }
833     void MOVN() {
834     if (!_Rd_) return;
835     if (cpuRegs.GPR.r[_Rt_].UD[0] != 0) {
836     cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0];
837     }
838     }
839    
840     /*********************************************************
841     * Special purpose instructions *
842     * Format: OP *
843     *********************************************************/
844    
845    
846     // This function is the only one that uses Sifcmd.h in Pcsx2.
847     #include "Sifcmd.h"
848    
849     void SYSCALL()
850     {
851     u8 call;
852    
853     if (cpuRegs.GPR.n.v1.SL[0] < 0)
854     call = (u8)(-cpuRegs.GPR.n.v1.SL[0]);
855     else
856     call = cpuRegs.GPR.n.v1.UC[0];
857    
858     BIOS_LOG("Bios call: %s (%x)", R5900::bios[call], call);
859    
860     if (call == 0x7c)
861     {
862     if(cpuRegs.GPR.n.a0.UL[0] == 0x10)
863 william 62 {
864     eeConLog( ShiftJIS_ConvertString((char*)PSM(memRead32(cpuRegs.GPR.n.a1.UL[0]))) );
865     }
866 william 31 else
867     __Deci2Call( cpuRegs.GPR.n.a0.UL[0], (u32*)PSM(cpuRegs.GPR.n.a1.UL[0]) );
868     }
869    
870     // The only thing this code is used for is the one log message, so don't execute it if we aren't logging bios messages.
871 william 62 if (SysTraceActive(EE.Bios) && (call == 0x77))
872 william 31 {
873     t_sif_dma_transfer *dmat;
874     //struct t_sif_cmd_header *hdr;
875     //struct t_sif_rpc_bind *bind;
876     //struct t_rpc_server_data *server;
877     int n_transfer;
878     u32 addr;
879     //int sid;
880    
881     n_transfer = cpuRegs.GPR.n.a1.UL[0] - 1;
882     if (n_transfer >= 0)
883     {
884     addr = cpuRegs.GPR.n.a0.UL[0] + n_transfer * sizeof(t_sif_dma_transfer);
885     dmat = (t_sif_dma_transfer*)PSM(addr);
886    
887     BIOS_LOG("bios_%s: n_transfer=%d, size=%x, attr=%x, dest=%x, src=%x",
888     R5900::bios[cpuRegs.GPR.n.v1.UC[0]], n_transfer,
889     dmat->size, dmat->attr,
890     dmat->dest, dmat->src);
891     }
892     }
893    
894     cpuRegs.pc -= 4;
895     cpuException(0x20, cpuRegs.branch);
896     }
897    
898     void BREAK(void) {
899     cpuRegs.pc -= 4;
900     cpuException(0x24, cpuRegs.branch);
901     }
902    
903     void MFSA( void ) {
904     if (!_Rd_) return;
905     cpuRegs.GPR.r[_Rd_].SD[0] = (s64)cpuRegs.sa;
906     }
907    
908     void MTSA( void ) {
909     cpuRegs.sa = (s32)cpuRegs.GPR.r[_Rs_].SD[0] & 0xf;
910     }
911    
912     // SNY supports three basic modes, two which synchronize memory accesses (related
913     // to the cache) and one which synchronizes the instruction pipeline (effectively
914     // a stall in either case). Our emulation model does not track EE-side pipeline
915     // status or stalls, nor does it implement the CACHE. Thus SYNC need do nothing.
916     void SYNC( void )
917     {
918     }
919    
920     // Used to prefetch data into the EE's cache, or schedule a dirty write-back.
921     // CACHE is not emulated at this time (nor is there any need to emulate it), so
922     // this function does nothing in the context of our emulator.
923     void PREF( void )
924     {
925     }
926    
927     static void trap(u16 code=0)
928     {
929     // unimplemented?
930     // throw R5900Exception::Trap(code);
931    
932     cpuRegs.pc -= 4;
933     Console.Warning("Trap exception at 0x%08x", cpuRegs.pc);
934     cpuException(0x34, cpuRegs.branch);
935     }
936    
937     /*********************************************************
938     * Register trap *
939     * Format: OP rs, rt *
940     *********************************************************/
941     void TGE() { if (cpuRegs.GPR.r[_Rs_].SD[0] >= cpuRegs.GPR.r[_Rt_].SD[0]) trap(_TrapCode_); }
942     void TGEU() { if (cpuRegs.GPR.r[_Rs_].UD[0] >= cpuRegs.GPR.r[_Rt_].UD[0]) trap(_TrapCode_); }
943     void TLT() { if (cpuRegs.GPR.r[_Rs_].SD[0] < cpuRegs.GPR.r[_Rt_].SD[0]) trap(_TrapCode_); }
944     void TLTU() { if (cpuRegs.GPR.r[_Rs_].UD[0] < cpuRegs.GPR.r[_Rt_].UD[0]) trap(_TrapCode_); }
945     void TEQ() { if (cpuRegs.GPR.r[_Rs_].SD[0] == cpuRegs.GPR.r[_Rt_].SD[0]) trap(_TrapCode_); }
946     void TNE() { if (cpuRegs.GPR.r[_Rs_].SD[0] != cpuRegs.GPR.r[_Rt_].SD[0]) trap(_TrapCode_); }
947    
948     /*********************************************************
949     * Trap with immediate operand *
950     * Format: OP rs, rt *
951     *********************************************************/
952     void TGEI() { if (cpuRegs.GPR.r[_Rs_].SD[0] >= _Imm_) trap(); }
953     void TLTI() { if (cpuRegs.GPR.r[_Rs_].SD[0] < _Imm_) trap(); }
954     void TEQI() { if (cpuRegs.GPR.r[_Rs_].SD[0] == _Imm_) trap(); }
955     void TNEI() { if (cpuRegs.GPR.r[_Rs_].SD[0] != _Imm_) trap(); }
956     void TGEIU() { if (cpuRegs.GPR.r[_Rs_].UD[0] >= (u64)_Imm_) trap(); }
957     void TLTIU() { if (cpuRegs.GPR.r[_Rs_].UD[0] < (u64)_Imm_) trap(); }
958    
959     /*********************************************************
960     * Sa intructions *
961     * Format: OP rs, rt *
962     *********************************************************/
963    
964     void MTSAB() {
965     cpuRegs.sa = ((cpuRegs.GPR.r[_Rs_].UL[0] & 0xF) ^ (_Imm_ & 0xF));
966     }
967    
968     void MTSAH() {
969     cpuRegs.sa = ((cpuRegs.GPR.r[_Rs_].UL[0] & 0x7) ^ (_Imm_ & 0x7)) << 1;
970     }
971    
972     } } } // end namespace R5900::Interpreter::OpcodeImpl

  ViewVC Help
Powered by ViewVC 1.1.22