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

Contents of /trunk/pcsx2/R5900OpcodeImpl.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (show annotations) (download)
Tue Sep 7 03:24:11 2010 UTC (9 years, 9 months ago) by william
File size: 32008 byte(s)
committing r3113 initial commit again...
1 /* 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 static __forceinline s64 _add64_Overflow( s64 x, s64 y )
28 {
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 static __forceinline s64 _add32_Overflow( s32 x, s32 y )
47 {
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 memcpy(deci2buffer, pdeciaddr, copylen );
203 deci2buffer[copylen] = '\0';
204
205 if( EmuConfig.Log.Deci2 )
206 Console.Write( ConColor_EE, L"%s", ShiftJIS_ConvertString(deci2buffer).c_str() );
207 }
208 ((u32*)PSM(deci2addr))[3] = 0;
209 return 1;
210 }
211
212 case 4: // poll
213 if( addr != NULL )
214 BIOS_LOG("deci2poll: %x,%x,%x,%x\n", addr[3], addr[2], addr[1], addr[0]);
215 return 1;
216
217 case 5: // exrecv
218 return 1;
219
220 case 6: // exsend
221 return 1;
222
223 case 0x10://kputs
224 if( addr != NULL && EmuConfig.Log.Deci2 )
225 Console.Write( ConColor_EE, L"%s", ShiftJIS_ConvertString((char*)PSM(*addr)).c_str() );
226 return 1;
227 }
228
229 return 0;
230 }
231
232 namespace R5900 {
233 namespace Interpreter {
234 namespace OpcodeImpl {
235
236 void COP2()
237 {
238 //std::string disOut;
239 //disR5900Fasm(disOut, cpuRegs.code, cpuRegs.pc);
240
241 //VU0_LOG("%s", disOut.c_str());
242 Int_COP2PrintTable[_Rs_]();
243 }
244
245 void Unknown() {
246 CPU_LOG("%8.8lx: Unknown opcode called", cpuRegs.pc);
247 }
248
249 void MMI_Unknown() { Console.Warning("Unknown MMI opcode called"); }
250 void COP0_Unknown() { Console.Warning("Unknown COP0 opcode called"); }
251 void COP1_Unknown() { Console.Warning("Unknown FPU/COP1 opcode called"); }
252
253
254
255 /*********************************************************
256 * Arithmetic with immediate operand *
257 * Format: OP rt, rs, immediate *
258 *********************************************************/
259
260 // Implementation Notes:
261 // * It is important that instructions perform overflow checks prior to shortcutting on
262 // the zero register (when it is used as a destination). Overflow exceptions are still
263 // handled even though the result is discarded.
264
265 // Rt = Rs + Im signed [exception on overflow]
266 void ADDI()
267 {
268 s64 result = _add32_Overflow( cpuRegs.GPR.r[_Rs_].SD[0], _Imm_ );
269 if (!_Rt_) return;
270 cpuRegs.GPR.r[_Rt_].SD[0] = result;
271 }
272
273 // Rt = Rs + Im signed !!! [overflow ignored]
274 // This instruction is effectively identical to ADDI. It is not a true unsigned operation,
275 // but rather it is a signed operation that ignores overflows.
276 void ADDIU()
277 {
278 if (!_Rt_) return;
279 cpuRegs.GPR.r[_Rt_].SD[0] = cpuRegs.GPR.r[_Rs_].SL[0] + _Imm_;
280 }
281
282 // Rt = Rs + Im [exception on overflow]
283 // This is the full 64 bit version of ADDI. Overflow occurs at 64 bits instead
284 // of at 32 bits.
285 void DADDI()
286 {
287 s64 result = _add64_Overflow( cpuRegs.GPR.r[_Rs_].SD[0], _Imm_ );
288 if (!_Rt_) return;
289 cpuRegs.GPR.r[_Rt_].SD[0] = result;
290 }
291
292 // Rt = Rs + Im [overflow ignored]
293 // This instruction is effectively identical to DADDI. It is not a true unsigned operation,
294 // but rather it is a signed operation that ignores overflows.
295 void DADDIU()
296 {
297 if (!_Rt_) return;
298 cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] + _Imm_;
299 }
300 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)
301 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)
302 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)
303 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)
304 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)
305
306 /*********************************************************
307 * Register arithmetic *
308 * Format: OP rd, rs, rt *
309 *********************************************************/
310
311 // Rd = Rs + Rt (Exception on Integer Overflow)
312 void ADD()
313 {
314 s64 result = _add32_Overflow( cpuRegs.GPR.r[_Rs_].SD[0], cpuRegs.GPR.r[_Rt_].SD[0] );
315 if (!_Rd_) return;
316 cpuRegs.GPR.r[_Rd_].SD[0] = result;
317 }
318
319 void DADD()
320 {
321 s64 result = _add64_Overflow( cpuRegs.GPR.r[_Rs_].SD[0], cpuRegs.GPR.r[_Rt_].SD[0] );
322 if (!_Rd_) return;
323 cpuRegs.GPR.r[_Rd_].SD[0] = result;
324 }
325
326 // Rd = Rs - Rt (Exception on Integer Overflow)
327 void SUB()
328 {
329 s64 result = _add32_Overflow( cpuRegs.GPR.r[_Rs_].SD[0], -cpuRegs.GPR.r[_Rt_].SD[0] );
330 if (!_Rd_) return;
331 cpuRegs.GPR.r[_Rd_].SD[0] = result;
332 }
333
334 // Rd = Rs - Rt (Exception on Integer Overflow)
335 void DSUB()
336 {
337 s64 result = _add64_Overflow( cpuRegs.GPR.r[_Rs_].SD[0], -cpuRegs.GPR.r[_Rt_].SD[0] );
338 if (!_Rd_) return;
339 cpuRegs.GPR.r[_Rd_].SD[0] = result;
340 }
341
342 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
343 void DADDU() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] + cpuRegs.GPR.r[_Rt_].SD[0]; }
344 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
345 void DSUBU() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] - cpuRegs.GPR.r[_Rt_].SD[0]; }
346 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
347 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
348 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
349 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
350 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)
351 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)
352
353 /*********************************************************
354 * Register mult/div & Register trap logic *
355 * Format: OP rs, rt *
356 *********************************************************/
357
358 // Signed division "overflows" on (0x80000000 / -1), here (LO = 0x80000000, HI = 0) is returned by MIPS
359 // in division by zero on MIPS, it appears that:
360 // LO gets 1 if rs is negative (and the division is signed) and -1 otherwise.
361 // HI gets the value of rs.
362
363 // Result is stored in HI/LO [no arithmetic exceptions]
364 void DIV()
365 {
366 if (cpuRegs.GPR.r[_Rs_].UL[0] == 0x80000000 && cpuRegs.GPR.r[_Rt_].UL[0] == 0xffffffff)
367 {
368 cpuRegs.LO.SD[0] = (s32)0x80000000;
369 cpuRegs.HI.SD[0] = (s32)0x0;
370 }
371 else if (cpuRegs.GPR.r[_Rt_].SL[0] != 0)
372 {
373 cpuRegs.LO.SD[0] = cpuRegs.GPR.r[_Rs_].SL[0] / cpuRegs.GPR.r[_Rt_].SL[0];
374 cpuRegs.HI.SD[0] = cpuRegs.GPR.r[_Rs_].SL[0] % cpuRegs.GPR.r[_Rt_].SL[0];
375 }
376 else
377 {
378 cpuRegs.LO.SD[0] = (cpuRegs.GPR.r[_Rs_].SL[0] < 0) ? 1 : -1;
379 cpuRegs.HI.SD[0] = cpuRegs.GPR.r[_Rs_].SL[0];
380 }
381 }
382
383 // Result is stored in HI/LO [no arithmetic exceptions]
384 void DIVU()
385 {
386 if (cpuRegs.GPR.r[_Rt_].UL[0] != 0)
387 {
388 // note: DIVU has no sign extension when assigning back to 64 bits
389 // note 2: reference material strongly disagrees. (air)
390 cpuRegs.LO.SD[0] = (s32)(cpuRegs.GPR.r[_Rs_].UL[0] / cpuRegs.GPR.r[_Rt_].UL[0]);
391 cpuRegs.HI.SD[0] = (s32)(cpuRegs.GPR.r[_Rs_].UL[0] % cpuRegs.GPR.r[_Rt_].UL[0]);
392 }
393 else
394 {
395 cpuRegs.LO.SD[0] = -1;
396 cpuRegs.HI.SD[0] = cpuRegs.GPR.r[_Rs_].SL[0];
397 }
398 }
399
400 // Result is written to both HI/LO and to the _Rd_ (Lo only)
401 void MULT()
402 {
403 s64 res = (s64)cpuRegs.GPR.r[_Rs_].SL[0] * cpuRegs.GPR.r[_Rt_].SL[0];
404
405 // Sign-extend into 64 bits:
406 cpuRegs.LO.SD[0] = (s32)(res & 0xffffffff);
407 cpuRegs.HI.SD[0] = (s32)(res >> 32);
408
409 if( _Rd_ ) cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.LO.UD[0];
410 }
411
412 // Result is written to both HI/LO and to the _Rd_ (Lo only)
413 void MULTU()
414 {
415 u64 res = (u64)cpuRegs.GPR.r[_Rs_].UL[0] * cpuRegs.GPR.r[_Rt_].UL[0];
416
417 // Note: sign-extend into 64 bits even though it's an unsigned mult.
418 cpuRegs.LO.SD[0] = (s32)(res & 0xffffffff);
419 cpuRegs.HI.SD[0] = (s32)(res >> 32);
420
421 if( _Rd_ ) cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.LO.UD[0];
422 }
423
424 /*********************************************************
425 * Load higher 16 bits of the first word in GPR with imm *
426 * Format: OP rt, immediate *
427 *********************************************************/
428 void LUI() {
429 if (!_Rt_) return;
430 cpuRegs.GPR.r[_Rt_].UD[0] = (s32)(cpuRegs.code << 16);
431 }
432
433 /*********************************************************
434 * Move from HI/LO to GPR *
435 * Format: OP rd *
436 *********************************************************/
437 void MFHI() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.HI.UD[0]; } // Rd = Hi
438 void MFLO() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.LO.UD[0]; } // Rd = Lo
439
440 /*********************************************************
441 * Move to GPR to HI/LO & Register jump *
442 * Format: OP rs *
443 *********************************************************/
444 void MTHI() { cpuRegs.HI.UD[0] = cpuRegs.GPR.r[_Rs_].UD[0]; } // Hi = Rs
445 void MTLO() { cpuRegs.LO.UD[0] = cpuRegs.GPR.r[_Rs_].UD[0]; } // Lo = Rs
446
447
448 /*********************************************************
449 * Shift arithmetic with constant shift *
450 * Format: OP rd, rt, sa *
451 *********************************************************/
452 void SRA() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s32)(cpuRegs.GPR.r[_Rt_].SL[0] >> _Sa_); } // Rd = Rt >> sa (arithmetic)
453 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!!]
454 void SLL() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s32)(cpuRegs.GPR.r[_Rt_].UL[0] << _Sa_); } // Rd = Rt << sa
455 void DSLL() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (u64)(cpuRegs.GPR.r[_Rt_].UD[0] << _Sa_); }
456 void DSLL32(){ if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (u64)(cpuRegs.GPR.r[_Rt_].UD[0] << (_Sa_+32));}
457 void DSRA() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = cpuRegs.GPR.r[_Rt_].SD[0] >> _Sa_; }
458 void DSRA32(){ if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = cpuRegs.GPR.r[_Rt_].SD[0] >> (_Sa_+32);}
459 void DSRL() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rt_].UD[0] >> _Sa_; }
460 void DSRL32(){ if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rt_].UD[0] >> (_Sa_+32);}
461
462 /*********************************************************
463 * Shift arithmetic with variant register shift *
464 * Format: OP rd, rt, rs *
465 *********************************************************/
466 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
467 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)
468 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)
469 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));}
470 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));}
471 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));}
472
473 /*********************************************************
474 * Load and store for GPR *
475 * Format: OP rt, offset(base) *
476 *********************************************************/
477
478 // Implementation Notes Regarding Memory Operations:
479 // * It it 'correct' to do all loads into temp variables, even if the destination GPR
480 // is the zero reg (which nullifies the result). The memory needs to be accessed
481 // regardless so that hardware registers behave as expected (some clear on read) and
482 // so that TLB Misses are handled as expected as well.
483 //
484 // * Low/High varieties of instructions, such as LWL/LWH, do *not* raise Address Error
485 // exceptions, since the lower bits of the address are used to determine the portions
486 // of the address/register operations.
487
488
489 void LB()
490 {
491 u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
492 s8 temp = memRead8(addr);
493
494 if (!_Rt_) return;
495 cpuRegs.GPR.r[_Rt_].SD[0] = temp;
496 }
497
498 void LBU()
499 {
500 u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
501 u8 temp = memRead8(addr);
502
503 if (!_Rt_) return;
504 cpuRegs.GPR.r[_Rt_].UD[0] = temp;
505 }
506
507 void LH()
508 {
509 u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
510
511 if( addr & 1 )
512 throw R5900Exception::AddressError( addr, false );
513
514 s16 temp = memRead16(addr);
515
516 if (!_Rt_) return;
517 cpuRegs.GPR.r[_Rt_].SD[0] = temp;
518 }
519
520 void LHU()
521 {
522 u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
523
524 if( addr & 1 )
525 throw R5900Exception::AddressError( addr, false );
526
527 u16 temp = memRead16(addr);
528
529 if (!_Rt_) return;
530 cpuRegs.GPR.r[_Rt_].UD[0] = temp;
531 }
532
533 void LW()
534 {
535 u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
536
537 if( addr & 3 )
538 throw R5900Exception::AddressError( addr, false );
539
540 u32 temp = memRead32(addr);
541
542 if (!_Rt_) return;
543 cpuRegs.GPR.r[_Rt_].SD[0] = (s32)temp;
544 }
545
546 void LWU()
547 {
548 u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
549
550 if( addr & 3 )
551 throw R5900Exception::AddressError( addr, false );
552
553 u32 temp = memRead32(addr);
554
555 if (!_Rt_) return;
556 cpuRegs.GPR.r[_Rt_].UD[0] = temp;
557 }
558
559 static const s32 LWL_MASK[4] = { 0xffffff, 0x0000ffff, 0x000000ff, 0x00000000 };
560 static const s32 LWR_MASK[4] = { 0x000000, 0xff000000, 0xffff0000, 0xffffff00 };
561 static const u8 LWL_SHIFT[4] = { 24, 16, 8, 0 };
562 static const u8 LWR_SHIFT[4] = { 0, 8, 16, 24 };
563
564 void LWL()
565 {
566 s32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
567 u32 shift = addr & 3;
568
569 // ensure the compiler does correct sign extension into 64 bits by using s32
570 s32 mem = memRead32(addr & ~3);
571
572 if (!_Rt_) return;
573
574 cpuRegs.GPR.r[_Rt_].SD[0] = (cpuRegs.GPR.r[_Rt_].SL[0] & LWL_MASK[shift]) |
575 (mem << LWL_SHIFT[shift]);
576
577 /*
578 Mem = 1234. Reg = abcd
579 (result is always sign extended into the upper 32 bits of the Rt)
580
581 0 4bcd (mem << 24) | (reg & 0x00ffffff)
582 1 34cd (mem << 16) | (reg & 0x0000ffff)
583 2 234d (mem << 8) | (reg & 0x000000ff)
584 3 1234 (mem ) | (reg & 0x00000000)
585 */
586 }
587
588 void LWR()
589 {
590 s32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
591 u32 shift = addr & 3;
592
593 u32 mem = memRead32(addr & ~3);
594
595 if (!_Rt_) return;
596
597 // Use unsigned math here, and conditionally sign extend below, when needed.
598 mem = (cpuRegs.GPR.r[_Rt_].UL[0] & LWR_MASK[shift]) | (mem >> LWR_SHIFT[shift]);
599
600 if( shift == 0 )
601 {
602 // This special case requires sign extension into the full 64 bit dest.
603 cpuRegs.GPR.r[_Rt_].SD[0] = (s32)mem;
604 }
605 else
606 {
607 // This case sets the lower 32 bits of the target register. Upper
608 // 32 bits are always preserved.
609 cpuRegs.GPR.r[_Rt_].UL[0] = mem;
610 }
611
612 /*
613 Mem = 1234. Reg = abcd
614
615 0 1234 (mem ) | (reg & 0x00000000) [sign extend into upper 32 bits!]
616 1 a123 (mem >> 8) | (reg & 0xff000000)
617 2 ab12 (mem >> 16) | (reg & 0xffff0000)
618 3 abc1 (mem >> 24) | (reg & 0xffffff00)
619 */
620 }
621
622 // dummy variable used as a destination address for writes to the zero register, so
623 // that the zero register always stays zero.
624 static __aligned16 GPR_reg m_dummy_gpr_zero;
625
626 // Returns the x86 address of the requested GPR, which is safe for writing. (includes
627 // special handling for returning a dummy var for GPR0(zero), so that it's value is
628 // always preserved)
629 static u64* gpr_GetWritePtr( uint gpr )
630 {
631 return (u64*)(( gpr == 0 ) ? &m_dummy_gpr_zero : &cpuRegs.GPR.r[gpr]);
632 }
633
634 void LD()
635 {
636 s32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
637
638 if( addr & 7 )
639 throw R5900Exception::AddressError( addr, false );
640
641 memRead64(addr, gpr_GetWritePtr(_Rt_));
642 }
643
644 static const u64 LDL_MASK[8] =
645 { 0x00ffffffffffffffLL, 0x0000ffffffffffffLL, 0x000000ffffffffffLL, 0x00000000ffffffffLL,
646 0x0000000000ffffffLL, 0x000000000000ffffLL, 0x00000000000000ffLL, 0x0000000000000000LL
647 };
648 static const u64 LDR_MASK[8] =
649 { 0x0000000000000000LL, 0xff00000000000000LL, 0xffff000000000000LL, 0xffffff0000000000LL,
650 0xffffffff00000000LL, 0xffffffffff000000LL, 0xffffffffffff0000LL, 0xffffffffffffff00LL
651 };
652
653 static const u8 LDR_SHIFT[8] = { 0, 8, 16, 24, 32, 40, 48, 56 };
654 static const u8 LDL_SHIFT[8] = { 56, 48, 40, 32, 24, 16, 8, 0 };
655
656
657 void LDL()
658 {
659 u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
660 u32 shift = addr & 7;
661
662 u64 mem;
663 memRead64(addr & ~7, &mem);
664
665 if( !_Rt_ ) return;
666 cpuRegs.GPR.r[_Rt_].UD[0] = (cpuRegs.GPR.r[_Rt_].UD[0] & LDL_MASK[shift]) |
667 (mem << LDL_SHIFT[shift]);
668 }
669
670 void LDR()
671 {
672 u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
673 u32 shift = addr & 7;
674
675 u64 mem;
676 memRead64(addr & ~7, &mem);
677
678 if (!_Rt_) return;
679 cpuRegs.GPR.r[_Rt_].UD[0] = (cpuRegs.GPR.r[_Rt_].UD[0] & LDR_MASK[shift]) |
680 (mem >> LDR_SHIFT[shift]);
681 }
682
683 void LQ()
684 {
685 // MIPS Note: LQ and SQ are special and "silently" align memory addresses, thus
686 // an address error due to unaligned access isn't possible like it is on other loads/stores.
687
688 u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
689 memRead128(addr & ~0xf, gpr_GetWritePtr(_Rt_));
690 }
691
692 void SB()
693 {
694 u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
695 memWrite8(addr, cpuRegs.GPR.r[_Rt_].UC[0]);
696 }
697
698 void SH()
699 {
700 u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
701
702 if( addr & 1 )
703 throw R5900Exception::AddressError( addr, true );
704
705 memWrite16(addr, cpuRegs.GPR.r[_Rt_].US[0]);
706 }
707
708 void SW()
709 {
710 u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
711
712 if( addr & 3 )
713 throw R5900Exception::AddressError( addr, true );
714
715 memWrite32(addr, cpuRegs.GPR.r[_Rt_].UL[0]);
716 }
717
718 static const u32 SWL_MASK[4] = { 0xffffff00, 0xffff0000, 0xff000000, 0x00000000 };
719 static const u32 SWR_MASK[4] = { 0x00000000, 0x000000ff, 0x0000ffff, 0x00ffffff };
720
721 static const u8 SWR_SHIFT[4] = { 0, 8, 16, 24 };
722 static const u8 SWL_SHIFT[4] = { 24, 16, 8, 0 };
723
724 void SWL()
725 {
726 u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
727 u32 shift = addr & 3;
728 u32 mem = memRead32( addr & ~3 );
729
730 memWrite32( addr & ~3,
731 (cpuRegs.GPR.r[_Rt_].UL[0] >> SWL_SHIFT[shift]) |
732 (mem & SWL_MASK[shift])
733 );
734
735 /*
736 Mem = 1234. Reg = abcd
737
738 0 123a (reg >> 24) | (mem & 0xffffff00)
739 1 12ab (reg >> 16) | (mem & 0xffff0000)
740 2 1abc (reg >> 8) | (mem & 0xff000000)
741 3 abcd (reg ) | (mem & 0x00000000)
742 */
743 }
744
745 void SWR() {
746 u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
747 u32 shift = addr & 3;
748 u32 mem = memRead32(addr & ~3);
749
750 memWrite32( addr & ~3,
751 (cpuRegs.GPR.r[_Rt_].UL[0] << SWR_SHIFT[shift]) |
752 (mem & SWR_MASK[shift])
753 );
754
755 /*
756 Mem = 1234. Reg = abcd
757
758 0 abcd (reg ) | (mem & 0x00000000)
759 1 bcd4 (reg << 8) | (mem & 0x000000ff)
760 2 cd34 (reg << 16) | (mem & 0x0000ffff)
761 3 d234 (reg << 24) | (mem & 0x00ffffff)
762 */
763 }
764
765 void SD()
766 {
767 u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
768
769 if( addr & 7 )
770 throw R5900Exception::AddressError( addr, true );
771
772 memWrite64(addr,&cpuRegs.GPR.r[_Rt_].UD[0]);
773 }
774
775 static const u64 SDL_MASK[8] =
776 { 0xffffffffffffff00LL, 0xffffffffffff0000LL, 0xffffffffff000000LL, 0xffffffff00000000LL,
777 0xffffff0000000000LL, 0xffff000000000000LL, 0xff00000000000000LL, 0x0000000000000000LL
778 };
779 static const u64 SDR_MASK[8] =
780 { 0x0000000000000000LL, 0x00000000000000ffLL, 0x000000000000ffffLL, 0x0000000000ffffffLL,
781 0x00000000ffffffffLL, 0x000000ffffffffffLL, 0x0000ffffffffffffLL, 0x00ffffffffffffffLL
782 };
783
784 static const u8 SDL_SHIFT[8] = { 56, 48, 40, 32, 24, 16, 8, 0 };
785 static const u8 SDR_SHIFT[8] = { 0, 8, 16, 24, 32, 40, 48, 56 };
786
787 void SDL()
788 {
789 u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
790 u32 shift = addr & 7;
791 u64 mem;
792
793 memRead64(addr & ~7, &mem);
794 mem = (cpuRegs.GPR.r[_Rt_].UD[0] >> SDL_SHIFT[shift]) |
795 (mem & SDL_MASK[shift]);
796 memWrite64(addr & ~7, &mem);
797 }
798
799
800 void SDR()
801 {
802 u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
803 u32 shift = addr & 7;
804 u64 mem;
805
806 memRead64(addr & ~7, &mem);
807 mem = (cpuRegs.GPR.r[_Rt_].UD[0] << SDR_SHIFT[shift]) |
808 (mem & SDR_MASK[shift]);
809 memWrite64(addr & ~7, &mem );
810 }
811
812 void SQ()
813 {
814 // MIPS Note: LQ and SQ are special and "silently" align memory addresses, thus
815 // an address error due to unaligned access isn't possible like it is on other loads/stores.
816
817 u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
818 memWrite128(addr & ~0xf, &cpuRegs.GPR.r[_Rt_].UD[0]);
819 }
820
821 /*********************************************************
822 * Conditional Move *
823 * Format: OP rd, rs, rt *
824 *********************************************************/
825
826 void MOVZ() {
827 if (!_Rd_) return;
828 if (cpuRegs.GPR.r[_Rt_].UD[0] == 0) {
829 cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0];
830 }
831 }
832 void MOVN() {
833 if (!_Rd_) return;
834 if (cpuRegs.GPR.r[_Rt_].UD[0] != 0) {
835 cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0];
836 }
837 }
838
839 /*********************************************************
840 * Special purpose instructions *
841 * Format: OP *
842 *********************************************************/
843
844
845 // This function is the only one that uses Sifcmd.h in Pcsx2.
846 #include "Sifcmd.h"
847
848 void SYSCALL()
849 {
850 u8 call;
851
852 if (cpuRegs.GPR.n.v1.SL[0] < 0)
853 call = (u8)(-cpuRegs.GPR.n.v1.SL[0]);
854 else
855 call = cpuRegs.GPR.n.v1.UC[0];
856
857 BIOS_LOG("Bios call: %s (%x)", R5900::bios[call], call);
858
859 if (call == 0x7c)
860 {
861 if(cpuRegs.GPR.n.a0.UL[0] == 0x10)
862 Console.Write( ConColor_EE, L"%s", ShiftJIS_ConvertString((char*)PSM(memRead32(cpuRegs.GPR.n.a1.UL[0]))).c_str() );
863 else
864 __Deci2Call( cpuRegs.GPR.n.a0.UL[0], (u32*)PSM(cpuRegs.GPR.n.a1.UL[0]) );
865 }
866
867 // 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.
868 #ifdef PCSX2_DEVBUILD
869 if (macTrace.EE.Bios() && (call == 0x77))
870 {
871 t_sif_dma_transfer *dmat;
872 //struct t_sif_cmd_header *hdr;
873 //struct t_sif_rpc_bind *bind;
874 //struct t_rpc_server_data *server;
875 int n_transfer;
876 u32 addr;
877 //int sid;
878
879 n_transfer = cpuRegs.GPR.n.a1.UL[0] - 1;
880 if (n_transfer >= 0)
881 {
882 addr = cpuRegs.GPR.n.a0.UL[0] + n_transfer * sizeof(t_sif_dma_transfer);
883 dmat = (t_sif_dma_transfer*)PSM(addr);
884
885 BIOS_LOG("bios_%s: n_transfer=%d, size=%x, attr=%x, dest=%x, src=%x",
886 R5900::bios[cpuRegs.GPR.n.v1.UC[0]], n_transfer,
887 dmat->size, dmat->attr,
888 dmat->dest, dmat->src);
889 }
890 }
891 #endif
892
893 cpuRegs.pc -= 4;
894 cpuException(0x20, cpuRegs.branch);
895 }
896
897 void BREAK(void) {
898 cpuRegs.pc -= 4;
899 cpuException(0x24, cpuRegs.branch);
900 }
901
902 void MFSA( void ) {
903 if (!_Rd_) return;
904 cpuRegs.GPR.r[_Rd_].SD[0] = (s64)cpuRegs.sa;
905 }
906
907 void MTSA( void ) {
908 cpuRegs.sa = (s32)cpuRegs.GPR.r[_Rs_].SD[0] & 0xf;
909 }
910
911 // SNY supports three basic modes, two which synchronize memory accesses (related
912 // to the cache) and one which synchronizes the instruction pipeline (effectively
913 // a stall in either case). Our emulation model does not track EE-side pipeline
914 // status or stalls, nor does it implement the CACHE. Thus SYNC need do nothing.
915 void SYNC( void )
916 {
917 }
918
919 // Used to prefetch data into the EE's cache, or schedule a dirty write-back.
920 // CACHE is not emulated at this time (nor is there any need to emulate it), so
921 // this function does nothing in the context of our emulator.
922 void PREF( void )
923 {
924 }
925
926 static void trap(u16 code=0)
927 {
928 // unimplemented?
929 // throw R5900Exception::Trap(code);
930
931 cpuRegs.pc -= 4;
932 Console.Warning("Trap exception at 0x%08x", cpuRegs.pc);
933 cpuException(0x34, cpuRegs.branch);
934 }
935
936 /*********************************************************
937 * Register trap *
938 * Format: OP rs, rt *
939 *********************************************************/
940 void TGE() { if (cpuRegs.GPR.r[_Rs_].SD[0] >= cpuRegs.GPR.r[_Rt_].SD[0]) trap(_TrapCode_); }
941 void TGEU() { if (cpuRegs.GPR.r[_Rs_].UD[0] >= cpuRegs.GPR.r[_Rt_].UD[0]) trap(_TrapCode_); }
942 void TLT() { if (cpuRegs.GPR.r[_Rs_].SD[0] < cpuRegs.GPR.r[_Rt_].SD[0]) trap(_TrapCode_); }
943 void TLTU() { if (cpuRegs.GPR.r[_Rs_].UD[0] < cpuRegs.GPR.r[_Rt_].UD[0]) trap(_TrapCode_); }
944 void TEQ() { if (cpuRegs.GPR.r[_Rs_].SD[0] == cpuRegs.GPR.r[_Rt_].SD[0]) trap(_TrapCode_); }
945 void TNE() { if (cpuRegs.GPR.r[_Rs_].SD[0] != cpuRegs.GPR.r[_Rt_].SD[0]) trap(_TrapCode_); }
946
947 /*********************************************************
948 * Trap with immediate operand *
949 * Format: OP rs, rt *
950 *********************************************************/
951 void TGEI() { if (cpuRegs.GPR.r[_Rs_].SD[0] >= _Imm_) trap(); }
952 void TLTI() { if (cpuRegs.GPR.r[_Rs_].SD[0] < _Imm_) trap(); }
953 void TEQI() { if (cpuRegs.GPR.r[_Rs_].SD[0] == _Imm_) trap(); }
954 void TNEI() { if (cpuRegs.GPR.r[_Rs_].SD[0] != _Imm_) trap(); }
955 void TGEIU() { if (cpuRegs.GPR.r[_Rs_].UD[0] >= (u64)_Imm_) trap(); }
956 void TLTIU() { if (cpuRegs.GPR.r[_Rs_].UD[0] < (u64)_Imm_) trap(); }
957
958 /*********************************************************
959 * Sa intructions *
960 * Format: OP rs, rt *
961 *********************************************************/
962
963 void MTSAB() {
964 cpuRegs.sa = ((cpuRegs.GPR.r[_Rs_].UL[0] & 0xF) ^ (_Imm_ & 0xF));
965 }
966
967 void MTSAH() {
968 cpuRegs.sa = ((cpuRegs.GPR.r[_Rs_].UL[0] & 0x7) ^ (_Imm_ & 0x7)) << 1;
969 }
970
971 } } } // end namespace R5900::Interpreter::OpcodeImpl

  ViewVC Help
Powered by ViewVC 1.1.22