psxinterpreter: do interrupt test after doing target instruction
[pcsx_rearmed.git] / libpcsxcore / psxinterpreter.c
CommitLineData
ef79bbde
P
1/***************************************************************************
2 * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA. *
18 ***************************************************************************/
19
20/*
21 * PSX assembly interpreter.
22 */
23
24#include "psxcommon.h"
25#include "r3000a.h"
26#include "gte.h"
27#include "psxhle.h"
28
29static int branch = 0;
30static int branch2 = 0;
31static u32 branchPC;
32
33// These macros are used to assemble the repassembler functions
34
35#ifdef PSXCPU_LOG
36#define debugI() PSXCPU_LOG("%s\n", disR3000AF(psxRegs.code, psxRegs.pc));
37#else
38#define debugI()
39#endif
40
41inline void execI();
42
43// Subsets
44void (*psxBSC[64])();
45void (*psxSPC[64])();
46void (*psxREG[32])();
47void (*psxCP0[32])();
48void (*psxCP2[64])();
49void (*psxCP2BSC[32])();
50
51static void delayRead(int reg, u32 bpc) {
52 u32 rold, rnew;
53
54// SysPrintf("delayRead at %x!\n", psxRegs.pc);
55
56 rold = psxRegs.GPR.r[reg];
57 psxBSC[psxRegs.code >> 26](); // branch delay load
58 rnew = psxRegs.GPR.r[reg];
59
60 psxRegs.pc = bpc;
61
abbc1ca1 62 branch = 0;
ef79bbde
P
63
64 psxRegs.GPR.r[reg] = rold;
65 execI(); // first branch opcode
66 psxRegs.GPR.r[reg] = rnew;
67
abbc1ca1 68 psxBranchTest();
ef79bbde
P
69}
70
71static void delayWrite(int reg, u32 bpc) {
72
73/* SysPrintf("delayWrite at %x!\n", psxRegs.pc);
74
75 SysPrintf("%s\n", disR3000AF(psxRegs.code, psxRegs.pc-4));
76 SysPrintf("%s\n", disR3000AF(PSXMu32(bpc), bpc));*/
77
78 // no changes from normal behavior
79
80 psxBSC[psxRegs.code >> 26]();
81
82 branch = 0;
83 psxRegs.pc = bpc;
84
85 psxBranchTest();
86}
87
88static void delayReadWrite(int reg, u32 bpc) {
89
90// SysPrintf("delayReadWrite at %x!\n", psxRegs.pc);
91
92 // the branch delay load is skipped
93
94 branch = 0;
95 psxRegs.pc = bpc;
96
97 psxBranchTest();
98}
99
100// this defines shall be used with the tmp
101// of the next func (instead of _Funct_...)
102#define _tFunct_ ((tmp ) & 0x3F) // The funct part of the instruction register
103#define _tRd_ ((tmp >> 11) & 0x1F) // The rd part of the instruction register
104#define _tRt_ ((tmp >> 16) & 0x1F) // The rt part of the instruction register
105#define _tRs_ ((tmp >> 21) & 0x1F) // The rs part of the instruction register
106#define _tSa_ ((tmp >> 6) & 0x1F) // The sa part of the instruction register
107
108int psxTestLoadDelay(int reg, u32 tmp) {
109 if (tmp == 0) return 0; // NOP
110 switch (tmp >> 26) {
111 case 0x00: // SPECIAL
112 switch (_tFunct_) {
113 case 0x00: // SLL
114 case 0x02: case 0x03: // SRL/SRA
115 if (_tRd_ == reg && _tRt_ == reg) return 1; else
116 if (_tRt_ == reg) return 2; else
117 if (_tRd_ == reg) return 3;
118 break;
119
120 case 0x08: // JR
121 if (_tRs_ == reg) return 2;
122 break;
123 case 0x09: // JALR
124 if (_tRd_ == reg && _tRs_ == reg) return 1; else
125 if (_tRs_ == reg) return 2; else
126 if (_tRd_ == reg) return 3;
127 break;
128
129 // SYSCALL/BREAK just a break;
130
131 case 0x20: case 0x21: case 0x22: case 0x23:
132 case 0x24: case 0x25: case 0x26: case 0x27:
133 case 0x2a: case 0x2b: // ADD/ADDU...
134 case 0x04: case 0x06: case 0x07: // SLLV...
135 if (_tRd_ == reg && (_tRt_ == reg || _tRs_ == reg)) return 1; else
136 if (_tRt_ == reg || _tRs_ == reg) return 2; else
137 if (_tRd_ == reg) return 3;
138 break;
139
140 case 0x10: case 0x12: // MFHI/MFLO
141 if (_tRd_ == reg) return 3;
142 break;
143 case 0x11: case 0x13: // MTHI/MTLO
144 if (_tRs_ == reg) return 2;
145 break;
146
147 case 0x18: case 0x19:
148 case 0x1a: case 0x1b: // MULT/DIV...
149 if (_tRt_ == reg || _tRs_ == reg) return 2;
150 break;
151 }
152 break;
153
154 case 0x01: // REGIMM
155 switch (_tRt_) {
862bfc0d 156 case 0x00: case 0x01:
157 case 0x10: case 0x11: // BLTZ/BGEZ...
158 // Xenogears - lbu v0 / beq v0
159 // - no load delay (fixes battle loading)
160 break;
161
ef79bbde
P
162 if (_tRs_ == reg) return 2;
163 break;
164 }
165 break;
166
167 // J would be just a break;
168 case 0x03: // JAL
169 if (31 == reg) return 3;
170 break;
171
172 case 0x04: case 0x05: // BEQ/BNE
862bfc0d 173 // Xenogears - lbu v0 / beq v0
174 // - no load delay (fixes battle loading)
175 break;
176
ef79bbde
P
177 if (_tRs_ == reg || _tRt_ == reg) return 2;
178 break;
179
180 case 0x06: case 0x07: // BLEZ/BGTZ
862bfc0d 181 // Xenogears - lbu v0 / beq v0
182 // - no load delay (fixes battle loading)
183 break;
184
ef79bbde
P
185 if (_tRs_ == reg) return 2;
186 break;
187
188 case 0x08: case 0x09: case 0x0a: case 0x0b:
189 case 0x0c: case 0x0d: case 0x0e: // ADDI/ADDIU...
190 if (_tRt_ == reg && _tRs_ == reg) return 1; else
191 if (_tRs_ == reg) return 2; else
192 if (_tRt_ == reg) return 3;
193 break;
194
195 case 0x0f: // LUI
196 if (_tRt_ == reg) return 3;
197 break;
198
199 case 0x10: // COP0
200 switch (_tFunct_) {
201 case 0x00: // MFC0
202 if (_tRt_ == reg) return 3;
203 break;
204 case 0x02: // CFC0
205 if (_tRt_ == reg) return 3;
206 break;
207 case 0x04: // MTC0
208 if (_tRt_ == reg) return 2;
209 break;
210 case 0x06: // CTC0
211 if (_tRt_ == reg) return 2;
212 break;
213 // RFE just a break;
214 }
215 break;
216
217 case 0x12: // COP2
218 switch (_tFunct_) {
219 case 0x00:
220 switch (_tRs_) {
221 case 0x00: // MFC2
222 if (_tRt_ == reg) return 3;
223 break;
224 case 0x02: // CFC2
225 if (_tRt_ == reg) return 3;
226 break;
227 case 0x04: // MTC2
228 if (_tRt_ == reg) return 2;
229 break;
230 case 0x06: // CTC2
231 if (_tRt_ == reg) return 2;
232 break;
233 }
234 break;
235 // RTPS... break;
236 }
237 break;
238
239 case 0x22: case 0x26: // LWL/LWR
240 if (_tRt_ == reg) return 3; else
241 if (_tRs_ == reg) return 2;
242 break;
243
244 case 0x20: case 0x21: case 0x23:
245 case 0x24: case 0x25: // LB/LH/LW/LBU/LHU
246 if (_tRt_ == reg && _tRs_ == reg) return 1; else
247 if (_tRs_ == reg) return 2; else
248 if (_tRt_ == reg) return 3;
249 break;
250
251 case 0x28: case 0x29: case 0x2a:
252 case 0x2b: case 0x2e: // SB/SH/SWL/SW/SWR
253 if (_tRt_ == reg || _tRs_ == reg) return 2;
254 break;
255
256 case 0x32: case 0x3a: // LWC2/SWC2
257 if (_tRs_ == reg) return 2;
258 break;
259 }
260
261 return 0;
262}
263
264void psxDelayTest(int reg, u32 bpc) {
265 u32 *code;
266 u32 tmp;
267
268 code = (u32 *)PSXM(bpc);
269 tmp = ((code == NULL) ? 0 : SWAP32(*code));
270 branch = 1;
271
272 switch (psxTestLoadDelay(reg, tmp)) {
273 case 1:
274 delayReadWrite(reg, bpc); return;
275 case 2:
276 delayRead(reg, bpc); return;
277 case 3:
278 delayWrite(reg, bpc); return;
279 }
280 psxBSC[psxRegs.code >> 26]();
281
282 branch = 0;
283 psxRegs.pc = bpc;
284
285 psxBranchTest();
286}
287
990cb018 288static u32 psxBranchNoDelay(void) {
289 u32 *code;
290 u32 temp;
291
292 code = (u32 *)PSXM(psxRegs.pc);
293 psxRegs.code = ((code == NULL) ? 0 : SWAP32(*code));
294 switch (_Op_) {
295 case 0x00: // SPECIAL
296 switch (_Funct_) {
297 case 0x08: // JR
298 return _u32(_rRs_);
299 case 0x09: // JALR
300 temp = _u32(_rRs_);
301 if (_Rd_) { _SetLink(_Rd_); }
302 return temp;
303 }
304 break;
305 case 0x01: // REGIMM
306 switch (_Rt_) {
307 case 0x00: // BLTZ
308 if (_i32(_rRs_) < 0)
309 return _BranchTarget_;
310 break;
311 case 0x01: // BGEZ
312 if (_i32(_rRs_) >= 0)
313 return _BranchTarget_;
314 break;
315 case 0x08: // BLTZAL
316 if (_i32(_rRs_) < 0) {
317 _SetLink(31);
318 return _BranchTarget_;
319 }
320 break;
321 case 0x09: // BGEZAL
322 if (_i32(_rRs_) >= 0) {
323 _SetLink(31);
324 return _BranchTarget_;
325 }
326 break;
327 }
328 break;
329 case 0x02: // J
330 return _JumpTarget_;
331 case 0x03: // JAL
332 _SetLink(31);
333 return _JumpTarget_;
334 case 0x04: // BEQ
335 if (_i32(_rRs_) == _i32(_rRt_))
336 return _BranchTarget_;
337 break;
338 case 0x05: // BNE
339 if (_i32(_rRs_) != _i32(_rRt_))
340 return _BranchTarget_;
341 break;
342 case 0x06: // BLEZ
343 if (_i32(_rRs_) <= 0)
344 return _BranchTarget_;
345 break;
346 case 0x07: // BGTZ
347 if (_i32(_rRs_) > 0)
348 return _BranchTarget_;
349 break;
350 }
351
352 return (u32)-1;
353}
354
355static int psxDelayBranchExec(u32 tar) {
356 execI();
357
358 branch = 0;
359 psxRegs.pc = tar;
360 psxRegs.cycle += BIAS;
361 psxBranchTest();
362 return 1;
363}
364
365static int psxDelayBranchTest(u32 tar1) {
366 u32 tar2, tmp1, tmp2;
367
368 tar2 = psxBranchNoDelay();
369 if (tar2 == (u32)-1)
370 return 0;
371
372 debugI();
373
374 /*
375 * Branch in delay slot:
376 * - execute 1 instruction at tar1
377 * - jump to tar2 (target of branch in delay slot; this branch
378 * has no normal delay slot, instruction at tar1 was fetched instead)
379 */
380 psxRegs.pc = tar1;
381 tmp1 = psxBranchNoDelay();
382 if (tmp1 == (u32)-1) {
383 return psxDelayBranchExec(tar2);
384 }
385 debugI();
386 psxRegs.cycle += BIAS;
387
388 /*
389 * Got a branch at tar1:
390 * - execute 1 instruction at tar2
391 * - jump to target of that branch (tmp1)
392 */
393 psxRegs.pc = tar2;
394 tmp2 = psxBranchNoDelay();
395 if (tmp2 == (u32)-1) {
396 return psxDelayBranchExec(tmp1);
397 }
398 debugI();
399 psxRegs.cycle += BIAS;
400
401 /*
402 * Got a branch at tar2:
403 * - execute 1 instruction at tmp1
404 * - jump to target of that branch (tmp2)
405 */
406 psxRegs.pc = tmp1;
407 return psxDelayBranchExec(tmp2);
408}
409
ef79bbde
P
410__inline void doBranch(u32 tar) {
411 u32 *code;
412 u32 tmp;
413
414 branch2 = branch = 1;
415 branchPC = tar;
416
990cb018 417 // check for branch in delay slot
418 if (psxDelayBranchTest(tar))
419 return;
420
ef79bbde
P
421 code = (u32 *)PSXM(psxRegs.pc);
422 psxRegs.code = ((code == NULL) ? 0 : SWAP32(*code));
423
424 debugI();
425
426 psxRegs.pc += 4;
427 psxRegs.cycle += BIAS;
428
429 // check for load delay
430 tmp = psxRegs.code >> 26;
431 switch (tmp) {
432 case 0x10: // COP0
433 switch (_Rs_) {
434 case 0x00: // MFC0
435 case 0x02: // CFC0
436 psxDelayTest(_Rt_, branchPC);
437 return;
438 }
439 break;
440 case 0x12: // COP2
441 switch (_Funct_) {
442 case 0x00:
443 switch (_Rs_) {
444 case 0x00: // MFC2
445 case 0x02: // CFC2
446 psxDelayTest(_Rt_, branchPC);
447 return;
448 }
449 break;
450 }
451 break;
452 case 0x32: // LWC2
453 psxDelayTest(_Rt_, branchPC);
454 return;
455 default:
456 if (tmp >= 0x20 && tmp <= 0x26) { // LB/LH/LWL/LW/LBU/LHU/LWR
457 psxDelayTest(_Rt_, branchPC);
458 return;
459 }
460 break;
461 }
462
463 psxBSC[psxRegs.code >> 26]();
464
465 branch = 0;
466 psxRegs.pc = branchPC;
467
468 psxBranchTest();
469}
470
471/*********************************************************
472* Arithmetic with immediate operand *
473* Format: OP rt, rs, immediate *
474*********************************************************/
475void psxADDI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im (Exception on Integer Overflow)
476void psxADDIU() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im
477void psxANDI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) & _ImmU_; } // Rt = Rs And Im
478void psxORI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) | _ImmU_; } // Rt = Rs Or Im
479void psxXORI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) ^ _ImmU_; } // Rt = Rs Xor Im
480void psxSLTI() { if (!_Rt_) return; _rRt_ = _i32(_rRs_) < _Imm_ ; } // Rt = Rs < Im (Signed)
481void psxSLTIU() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) < ((u32)_Imm_); } // Rt = Rs < Im (Unsigned)
482
483/*********************************************************
484* Register arithmetic *
485* Format: OP rd, rs, rt *
486*********************************************************/
487void psxADD() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt (Exception on Integer Overflow)
488void psxADDU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt
489void psxSUB() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt (Exception on Integer Overflow)
490void psxSUBU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt
491void psxAND() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) & _u32(_rRt_); } // Rd = Rs And Rt
492void psxOR() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) | _u32(_rRt_); } // Rd = Rs Or Rt
493void psxXOR() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) ^ _u32(_rRt_); } // Rd = Rs Xor Rt
494void psxNOR() { if (!_Rd_) return; _rRd_ =~(_u32(_rRs_) | _u32(_rRt_)); }// Rd = Rs Nor Rt
495void psxSLT() { if (!_Rd_) return; _rRd_ = _i32(_rRs_) < _i32(_rRt_); } // Rd = Rs < Rt (Signed)
496void psxSLTU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) < _u32(_rRt_); } // Rd = Rs < Rt (Unsigned)
497
498/*********************************************************
499* Register mult/div & Register trap logic *
500* Format: OP rs, rt *
501*********************************************************/
502void psxDIV() {
503 if (_i32(_rRt_) != 0) {
504 _i32(_rLo_) = _i32(_rRs_) / _i32(_rRt_);
505 _i32(_rHi_) = _i32(_rRs_) % _i32(_rRt_);
506 }
507}
508
509void psxDIVU() {
510 if (_rRt_ != 0) {
511 _rLo_ = _rRs_ / _rRt_;
512 _rHi_ = _rRs_ % _rRt_;
513 }
514}
515
516void psxMULT() {
517 u64 res = (s64)((s64)_i32(_rRs_) * (s64)_i32(_rRt_));
518
519 psxRegs.GPR.n.lo = (u32)(res & 0xffffffff);
520 psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff);
521}
522
523void psxMULTU() {
524 u64 res = (u64)((u64)_u32(_rRs_) * (u64)_u32(_rRt_));
525
526 psxRegs.GPR.n.lo = (u32)(res & 0xffffffff);
527 psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff);
528}
529
530/*********************************************************
531* Register branch logic *
532* Format: OP rs, offset *
533*********************************************************/
534#define RepZBranchi32(op) if(_i32(_rRs_) op 0) doBranch(_BranchTarget_);
535#define RepZBranchLinki32(op) if(_i32(_rRs_) op 0) { _SetLink(31); doBranch(_BranchTarget_); }
536
537void psxBGEZ() { RepZBranchi32(>=) } // Branch if Rs >= 0
538void psxBGEZAL() { RepZBranchLinki32(>=) } // Branch if Rs >= 0 and link
539void psxBGTZ() { RepZBranchi32(>) } // Branch if Rs > 0
540void psxBLEZ() { RepZBranchi32(<=) } // Branch if Rs <= 0
541void psxBLTZ() { RepZBranchi32(<) } // Branch if Rs < 0
542void psxBLTZAL() { RepZBranchLinki32(<) } // Branch if Rs < 0 and link
543
544/*********************************************************
545* Shift arithmetic with constant shift *
546* Format: OP rd, rt, sa *
547*********************************************************/
548void psxSLL() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) << _Sa_; } // Rd = Rt << sa
549void psxSRA() { if (!_Rd_) return; _i32(_rRd_) = _i32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (arithmetic)
550void psxSRL() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (logical)
551
552/*********************************************************
553* Shift arithmetic with variant register shift *
554* Format: OP rd, rt, rs *
555*********************************************************/
556void psxSLLV() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) << _u32(_rRs_); } // Rd = Rt << rs
557void psxSRAV() { if (!_Rd_) return; _i32(_rRd_) = _i32(_rRt_) >> _u32(_rRs_); } // Rd = Rt >> rs (arithmetic)
558void psxSRLV() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) >> _u32(_rRs_); } // Rd = Rt >> rs (logical)
559
560/*********************************************************
561* Load higher 16 bits of the first word in GPR with imm *
562* Format: OP rt, immediate *
563*********************************************************/
564void psxLUI() { if (!_Rt_) return; _u32(_rRt_) = psxRegs.code << 16; } // Upper halfword of Rt = Im
565
566/*********************************************************
567* Move from HI/LO to GPR *
568* Format: OP rd *
569*********************************************************/
570void psxMFHI() { if (!_Rd_) return; _rRd_ = _rHi_; } // Rd = Hi
571void psxMFLO() { if (!_Rd_) return; _rRd_ = _rLo_; } // Rd = Lo
572
573/*********************************************************
574* Move to GPR to HI/LO & Register jump *
575* Format: OP rs *
576*********************************************************/
577void psxMTHI() { _rHi_ = _rRs_; } // Hi = Rs
578void psxMTLO() { _rLo_ = _rRs_; } // Lo = Rs
579
580/*********************************************************
581* Special purpose instructions *
582* Format: OP *
583*********************************************************/
584void psxBREAK() {
585 // Break exception - psx rom doens't handles this
586}
587
588void psxSYSCALL() {
589 psxRegs.pc -= 4;
590 psxException(0x20, branch);
591}
592
593void psxRFE() {
594// SysPrintf("psxRFE\n");
595 psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status & 0xfffffff0) |
596 ((psxRegs.CP0.n.Status & 0x3c) >> 2);
597}
598
599/*********************************************************
600* Register branch logic *
601* Format: OP rs, rt, offset *
602*********************************************************/
603#define RepBranchi32(op) if(_i32(_rRs_) op _i32(_rRt_)) doBranch(_BranchTarget_);
604
605void psxBEQ() { RepBranchi32(==) } // Branch if Rs == Rt
606void psxBNE() { RepBranchi32(!=) } // Branch if Rs != Rt
607
608/*********************************************************
609* Jump to target *
610* Format: OP target *
611*********************************************************/
612void psxJ() { doBranch(_JumpTarget_); }
613void psxJAL() { _SetLink(31); doBranch(_JumpTarget_); }
614
615/*********************************************************
616* Register jump *
617* Format: OP rs, rd *
618*********************************************************/
619void psxJR() {
620 doBranch(_u32(_rRs_));
621 psxJumpTest();
622}
623
624void psxJALR() {
625 u32 temp = _u32(_rRs_);
626 if (_Rd_) { _SetLink(_Rd_); }
627 doBranch(temp);
628}
629
630/*********************************************************
631* Load and store for GPR *
632* Format: OP rt, offset(base) *
633*********************************************************/
634
635#define _oB_ (_u32(_rRs_) + _Imm_)
636
637void psxLB() {
638 if (_Rt_) {
639 _i32(_rRt_) = (signed char)psxMemRead8(_oB_);
640 } else {
641 psxMemRead8(_oB_);
642 }
643}
644
645void psxLBU() {
646 if (_Rt_) {
647 _u32(_rRt_) = psxMemRead8(_oB_);
648 } else {
649 psxMemRead8(_oB_);
650 }
651}
652
653void psxLH() {
654 if (_Rt_) {
655 _i32(_rRt_) = (short)psxMemRead16(_oB_);
656 } else {
657 psxMemRead16(_oB_);
658 }
659}
660
661void psxLHU() {
662 if (_Rt_) {
663 _u32(_rRt_) = psxMemRead16(_oB_);
664 } else {
665 psxMemRead16(_oB_);
666 }
667}
668
669void psxLW() {
670 if (_Rt_) {
671 _u32(_rRt_) = psxMemRead32(_oB_);
672 } else {
673 psxMemRead32(_oB_);
674 }
675}
676
677u32 LWL_MASK[4] = { 0xffffff, 0xffff, 0xff, 0 };
678u32 LWL_SHIFT[4] = { 24, 16, 8, 0 };
679
680void psxLWL() {
681 u32 addr = _oB_;
682 u32 shift = addr & 3;
683 u32 mem = psxMemRead32(addr & ~3);
684
685 if (!_Rt_) return;
686 _u32(_rRt_) = ( _u32(_rRt_) & LWL_MASK[shift]) |
687 ( mem << LWL_SHIFT[shift]);
688
689 /*
690 Mem = 1234. Reg = abcd
691
692 0 4bcd (mem << 24) | (reg & 0x00ffffff)
693 1 34cd (mem << 16) | (reg & 0x0000ffff)
694 2 234d (mem << 8) | (reg & 0x000000ff)
695 3 1234 (mem ) | (reg & 0x00000000)
696 */
697}
698
699u32 LWR_MASK[4] = { 0, 0xff000000, 0xffff0000, 0xffffff00 };
700u32 LWR_SHIFT[4] = { 0, 8, 16, 24 };
701
702void psxLWR() {
703 u32 addr = _oB_;
704 u32 shift = addr & 3;
705 u32 mem = psxMemRead32(addr & ~3);
706
707 if (!_Rt_) return;
708 _u32(_rRt_) = ( _u32(_rRt_) & LWR_MASK[shift]) |
709 ( mem >> LWR_SHIFT[shift]);
710
711 /*
712 Mem = 1234. Reg = abcd
713
714 0 1234 (mem ) | (reg & 0x00000000)
715 1 a123 (mem >> 8) | (reg & 0xff000000)
716 2 ab12 (mem >> 16) | (reg & 0xffff0000)
717 3 abc1 (mem >> 24) | (reg & 0xffffff00)
718 */
719}
720
721void psxSB() { psxMemWrite8 (_oB_, _u8 (_rRt_)); }
722void psxSH() { psxMemWrite16(_oB_, _u16(_rRt_)); }
723void psxSW() { psxMemWrite32(_oB_, _u32(_rRt_)); }
724
725u32 SWL_MASK[4] = { 0xffffff00, 0xffff0000, 0xff000000, 0 };
726u32 SWL_SHIFT[4] = { 24, 16, 8, 0 };
727
728void psxSWL() {
729 u32 addr = _oB_;
730 u32 shift = addr & 3;
731 u32 mem = psxMemRead32(addr & ~3);
732
733 psxMemWrite32(addr & ~3, (_u32(_rRt_) >> SWL_SHIFT[shift]) |
734 ( mem & SWL_MASK[shift]) );
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
745u32 SWR_MASK[4] = { 0, 0xff, 0xffff, 0xffffff };
746u32 SWR_SHIFT[4] = { 0, 8, 16, 24 };
747
748void psxSWR() {
749 u32 addr = _oB_;
750 u32 shift = addr & 3;
751 u32 mem = psxMemRead32(addr & ~3);
752
753 psxMemWrite32(addr & ~3, (_u32(_rRt_) << SWR_SHIFT[shift]) |
754 ( mem & SWR_MASK[shift]) );
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/*********************************************************
767* Moves between GPR and COPx *
768* Format: OP rt, fs *
769*********************************************************/
770void psxMFC0() { if (!_Rt_) return; _i32(_rRt_) = (int)_rFs_; }
771void psxCFC0() { if (!_Rt_) return; _i32(_rRt_) = (int)_rFs_; }
772
773void psxTestSWInts() {
774 // the next code is untested, if u know please
775 // tell me if it works ok or not (linuzappz)
776 if (psxRegs.CP0.n.Cause & psxRegs.CP0.n.Status & 0x0300 &&
777 psxRegs.CP0.n.Status & 0x1) {
778 psxException(psxRegs.CP0.n.Cause, branch);
779 }
780}
781
782__inline void MTC0(int reg, u32 val) {
783// SysPrintf("MTC0 %d: %x\n", reg, val);
784 switch (reg) {
785 case 12: // Status
786 psxRegs.CP0.r[12] = val;
787 psxTestSWInts();
788 break;
789
790 case 13: // Cause
791 psxRegs.CP0.n.Cause = val & ~(0xfc00);
792 psxTestSWInts();
793 break;
794
795 default:
796 psxRegs.CP0.r[reg] = val;
797 break;
798 }
799}
800
801void psxMTC0() { MTC0(_Rd_, _u32(_rRt_)); }
802void psxCTC0() { MTC0(_Rd_, _u32(_rRt_)); }
803
804/*********************************************************
805* Unknow instruction (would generate an exception) *
806* Format: ? *
807*********************************************************/
808void psxNULL() {
809#ifdef PSXCPU_LOG
810 PSXCPU_LOG("psx: Unimplemented op %x\n", psxRegs.code);
811#endif
812}
813
814void psxSPECIAL() {
815 psxSPC[_Funct_]();
816}
817
818void psxREGIMM() {
819 psxREG[_Rt_]();
820}
821
822void psxCOP0() {
823 psxCP0[_Rs_]();
824}
825
826void psxCOP2() {
827 psxCP2[_Funct_]();
828}
829
830void psxBASIC() {
831 psxCP2BSC[_Rs_]();
832}
833
834void psxHLE() {
835// psxHLEt[psxRegs.code & 0xffff]();
836 psxHLEt[psxRegs.code & 0x07](); // HDHOSHY experimental patch
837}
838
839void (*psxBSC[64])() = {
840 psxSPECIAL, psxREGIMM, psxJ , psxJAL , psxBEQ , psxBNE , psxBLEZ, psxBGTZ,
841 psxADDI , psxADDIU , psxSLTI, psxSLTIU, psxANDI, psxORI , psxXORI, psxLUI ,
842 psxCOP0 , psxNULL , psxCOP2, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL,
843 psxNULL , psxNULL , psxNULL, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL,
844 psxLB , psxLH , psxLWL , psxLW , psxLBU , psxLHU , psxLWR , psxNULL,
845 psxSB , psxSH , psxSWL , psxSW , psxNULL, psxNULL, psxSWR , psxNULL,
846 psxNULL , psxNULL , gteLWC2, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL,
847 psxNULL , psxNULL , gteSWC2, psxHLE , psxNULL, psxNULL, psxNULL, psxNULL
848};
849
850
851void (*psxSPC[64])() = {
852 psxSLL , psxNULL , psxSRL , psxSRA , psxSLLV , psxNULL , psxSRLV, psxSRAV,
853 psxJR , psxJALR , psxNULL, psxNULL, psxSYSCALL, psxBREAK, psxNULL, psxNULL,
854 psxMFHI, psxMTHI , psxMFLO, psxMTLO, psxNULL , psxNULL , psxNULL, psxNULL,
855 psxMULT, psxMULTU, psxDIV , psxDIVU, psxNULL , psxNULL , psxNULL, psxNULL,
856 psxADD , psxADDU , psxSUB , psxSUBU, psxAND , psxOR , psxXOR , psxNOR ,
857 psxNULL, psxNULL , psxSLT , psxSLTU, psxNULL , psxNULL , psxNULL, psxNULL,
858 psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL,
859 psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL
860};
861
862void (*psxREG[32])() = {
863 psxBLTZ , psxBGEZ , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
864 psxNULL , psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
865 psxBLTZAL, psxBGEZAL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
866 psxNULL , psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL
867};
868
869void (*psxCP0[32])() = {
870 psxMFC0, psxNULL, psxCFC0, psxNULL, psxMTC0, psxNULL, psxCTC0, psxNULL,
871 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
872 psxRFE , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
873 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL
874};
875
876void (*psxCP2[64])() = {
877 psxBASIC, gteRTPS , psxNULL , psxNULL, psxNULL, psxNULL , gteNCLIP, psxNULL, // 00
878 psxNULL , psxNULL , psxNULL , psxNULL, gteOP , psxNULL , psxNULL , psxNULL, // 08
879 gteDPCS , gteINTPL, gteMVMVA, gteNCDS, gteCDP , psxNULL , gteNCDT , psxNULL, // 10
880 psxNULL , psxNULL , psxNULL , gteNCCS, gteCC , psxNULL , gteNCS , psxNULL, // 18
881 gteNCT , psxNULL , psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, // 20
882 gteSQR , gteDCPL , gteDPCT , psxNULL, psxNULL, gteAVSZ3, gteAVSZ4, psxNULL, // 28
883 gteRTPT , psxNULL , psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, // 30
884 psxNULL , psxNULL , psxNULL , psxNULL, psxNULL, gteGPF , gteGPL , gteNCCT // 38
885};
886
887void (*psxCP2BSC[32])() = {
888 gteMFC2, psxNULL, gteCFC2, psxNULL, gteMTC2, psxNULL, gteCTC2, psxNULL,
889 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
890 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
891 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL
892};
893
894
895///////////////////////////////////////////
896
897static int intInit() {
898 return 0;
899}
900
901static void intReset() {
902}
903
796a91ef 904void intExecute() {
905 extern int stop;
906 for (;!stop;)
ef79bbde
P
907 execI();
908}
909
796a91ef 910void intExecuteBlock() {
ef79bbde
P
911 branch2 = 0;
912 while (!branch2) execI();
913}
914
915static void intClear(u32 Addr, u32 Size) {
916}
917
918static void intShutdown() {
919}
920
921// interpreter execution
922inline void execI() {
923 u32 *code = (u32 *)PSXM(psxRegs.pc);
924 psxRegs.code = ((code == NULL) ? 0 : SWAP32(*code));
925
926 debugI();
927
928 if (Config.Debug) ProcessDebug();
929
930 psxRegs.pc += 4;
931 psxRegs.cycle += BIAS;
932
933 psxBSC[psxRegs.code >> 26]();
934}
935
936R3000Acpu psxInt = {
937 intInit,
938 intReset,
939 intExecute,
940 intExecuteBlock,
941 intClear,
942 intShutdown
943};