Merge pull request #579 from gameblabla/pio_writes_sen_lib
[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"
fc8145b7 28#include "debug.h"
ef79bbde
P
29
30static int branch = 0;
31static int branch2 = 0;
32static u32 branchPC;
33
34// These macros are used to assemble the repassembler functions
35
36#ifdef PSXCPU_LOG
37#define debugI() PSXCPU_LOG("%s\n", disR3000AF(psxRegs.code, psxRegs.pc));
38#else
39#define debugI()
40#endif
41
9361a5aa
EC
42#ifndef NDEBUG
43#include "debug.h"
44#else
11a43034 45void StartDebugger() {}
46void ProcessDebug() {}
47void StopDebugger() {}
48#endif
49
4600ba03 50void execI();
ef79bbde
P
51
52// Subsets
53void (*psxBSC[64])();
54void (*psxSPC[64])();
55void (*psxREG[32])();
56void (*psxCP0[32])();
6c0eefaf 57void (*psxCP2[64])(struct psxCP2Regs *regs);
ef79bbde
P
58void (*psxCP2BSC[32])();
59
7a811716 60#ifdef ICACHE_EMULATION
61/*
62Formula One 2001 :
63Use old CPU cache code when the RAM location is updated with new code (affects in-game racing)
64*/
65static u8* ICache_Addr;
66static u8* ICache_Code;
67uint32_t *Read_ICache(uint32_t pc)
68{
69 uint32_t pc_bank, pc_offset, pc_cache;
70 uint8_t *IAddr, *ICode;
71
72 pc_bank = pc >> 24;
73 pc_offset = pc & 0xffffff;
74 pc_cache = pc & 0xfff;
75
76 IAddr = ICache_Addr;
77 ICode = ICache_Code;
78
79 // cached - RAM
80 if (pc_bank == 0x80 || pc_bank == 0x00)
81 {
82 if (SWAP32(*(uint32_t *)(IAddr + pc_cache)) == pc_offset)
83 {
84 // Cache hit - return last opcode used
85 return (uint32_t *)(ICode + pc_cache);
86 }
87 else
88 {
89 // Cache miss - addresses don't match
90 // - default: 0xffffffff (not init)
91
92 // cache line is 4 bytes wide
93 pc_offset &= ~0xf;
94 pc_cache &= ~0xf;
95
96 // address line
97 *(uint32_t *)(IAddr + pc_cache + 0x0) = SWAP32(pc_offset + 0x0);
98 *(uint32_t *)(IAddr + pc_cache + 0x4) = SWAP32(pc_offset + 0x4);
99 *(uint32_t *)(IAddr + pc_cache + 0x8) = SWAP32(pc_offset + 0x8);
100 *(uint32_t *)(IAddr + pc_cache + 0xc) = SWAP32(pc_offset + 0xc);
101
102 // opcode line
103 pc_offset = pc & ~0xf;
104 *(uint32_t *)(ICode + pc_cache + 0x0) = psxMu32ref(pc_offset + 0x0);
105 *(uint32_t *)(ICode + pc_cache + 0x4) = psxMu32ref(pc_offset + 0x4);
106 *(uint32_t *)(ICode + pc_cache + 0x8) = psxMu32ref(pc_offset + 0x8);
107 *(uint32_t *)(ICode + pc_cache + 0xc) = psxMu32ref(pc_offset + 0xc);
108 }
109 }
110
111 /*
112 TODO: Probably should add cached BIOS
113 */
114 // default
115 return (uint32_t *)PSXM(pc);
116}
117#endif
118
ef79bbde
P
119static void delayRead(int reg, u32 bpc) {
120 u32 rold, rnew;
121
122// SysPrintf("delayRead at %x!\n", psxRegs.pc);
123
124 rold = psxRegs.GPR.r[reg];
125 psxBSC[psxRegs.code >> 26](); // branch delay load
126 rnew = psxRegs.GPR.r[reg];
127
128 psxRegs.pc = bpc;
129
abbc1ca1 130 branch = 0;
ef79bbde
P
131
132 psxRegs.GPR.r[reg] = rold;
133 execI(); // first branch opcode
134 psxRegs.GPR.r[reg] = rnew;
135
abbc1ca1 136 psxBranchTest();
ef79bbde
P
137}
138
139static void delayWrite(int reg, u32 bpc) {
140
141/* SysPrintf("delayWrite at %x!\n", psxRegs.pc);
142
143 SysPrintf("%s\n", disR3000AF(psxRegs.code, psxRegs.pc-4));
144 SysPrintf("%s\n", disR3000AF(PSXMu32(bpc), bpc));*/
145
146 // no changes from normal behavior
147
148 psxBSC[psxRegs.code >> 26]();
149
150 branch = 0;
151 psxRegs.pc = bpc;
152
153 psxBranchTest();
154}
155
156static void delayReadWrite(int reg, u32 bpc) {
157
158// SysPrintf("delayReadWrite at %x!\n", psxRegs.pc);
159
160 // the branch delay load is skipped
161
162 branch = 0;
163 psxRegs.pc = bpc;
164
165 psxBranchTest();
166}
167
168// this defines shall be used with the tmp
169// of the next func (instead of _Funct_...)
170#define _tFunct_ ((tmp ) & 0x3F) // The funct part of the instruction register
171#define _tRd_ ((tmp >> 11) & 0x1F) // The rd part of the instruction register
172#define _tRt_ ((tmp >> 16) & 0x1F) // The rt part of the instruction register
173#define _tRs_ ((tmp >> 21) & 0x1F) // The rs part of the instruction register
174#define _tSa_ ((tmp >> 6) & 0x1F) // The sa part of the instruction register
175
176int psxTestLoadDelay(int reg, u32 tmp) {
177 if (tmp == 0) return 0; // NOP
178 switch (tmp >> 26) {
179 case 0x00: // SPECIAL
180 switch (_tFunct_) {
181 case 0x00: // SLL
182 case 0x02: case 0x03: // SRL/SRA
183 if (_tRd_ == reg && _tRt_ == reg) return 1; else
184 if (_tRt_ == reg) return 2; else
185 if (_tRd_ == reg) return 3;
186 break;
187
188 case 0x08: // JR
189 if (_tRs_ == reg) return 2;
190 break;
191 case 0x09: // JALR
192 if (_tRd_ == reg && _tRs_ == reg) return 1; else
193 if (_tRs_ == reg) return 2; else
194 if (_tRd_ == reg) return 3;
195 break;
196
197 // SYSCALL/BREAK just a break;
198
199 case 0x20: case 0x21: case 0x22: case 0x23:
200 case 0x24: case 0x25: case 0x26: case 0x27:
201 case 0x2a: case 0x2b: // ADD/ADDU...
202 case 0x04: case 0x06: case 0x07: // SLLV...
203 if (_tRd_ == reg && (_tRt_ == reg || _tRs_ == reg)) return 1; else
204 if (_tRt_ == reg || _tRs_ == reg) return 2; else
205 if (_tRd_ == reg) return 3;
206 break;
207
208 case 0x10: case 0x12: // MFHI/MFLO
209 if (_tRd_ == reg) return 3;
210 break;
211 case 0x11: case 0x13: // MTHI/MTLO
212 if (_tRs_ == reg) return 2;
213 break;
214
215 case 0x18: case 0x19:
216 case 0x1a: case 0x1b: // MULT/DIV...
217 if (_tRt_ == reg || _tRs_ == reg) return 2;
218 break;
219 }
220 break;
221
222 case 0x01: // REGIMM
223 switch (_tRt_) {
862bfc0d 224 case 0x00: case 0x01:
225 case 0x10: case 0x11: // BLTZ/BGEZ...
226 // Xenogears - lbu v0 / beq v0
227 // - no load delay (fixes battle loading)
228 break;
229
ef79bbde
P
230 if (_tRs_ == reg) return 2;
231 break;
232 }
233 break;
234
235 // J would be just a break;
236 case 0x03: // JAL
237 if (31 == reg) return 3;
238 break;
239
240 case 0x04: case 0x05: // BEQ/BNE
862bfc0d 241 // Xenogears - lbu v0 / beq v0
242 // - no load delay (fixes battle loading)
243 break;
244
ef79bbde
P
245 if (_tRs_ == reg || _tRt_ == reg) return 2;
246 break;
247
248 case 0x06: case 0x07: // BLEZ/BGTZ
862bfc0d 249 // Xenogears - lbu v0 / beq v0
250 // - no load delay (fixes battle loading)
251 break;
252
ef79bbde
P
253 if (_tRs_ == reg) return 2;
254 break;
255
256 case 0x08: case 0x09: case 0x0a: case 0x0b:
257 case 0x0c: case 0x0d: case 0x0e: // ADDI/ADDIU...
258 if (_tRt_ == reg && _tRs_ == reg) return 1; else
259 if (_tRs_ == reg) return 2; else
260 if (_tRt_ == reg) return 3;
261 break;
262
263 case 0x0f: // LUI
264 if (_tRt_ == reg) return 3;
265 break;
266
267 case 0x10: // COP0
268 switch (_tFunct_) {
269 case 0x00: // MFC0
270 if (_tRt_ == reg) return 3;
271 break;
272 case 0x02: // CFC0
273 if (_tRt_ == reg) return 3;
274 break;
275 case 0x04: // MTC0
276 if (_tRt_ == reg) return 2;
277 break;
278 case 0x06: // CTC0
279 if (_tRt_ == reg) return 2;
280 break;
281 // RFE just a break;
282 }
283 break;
284
285 case 0x12: // COP2
286 switch (_tFunct_) {
287 case 0x00:
288 switch (_tRs_) {
289 case 0x00: // MFC2
290 if (_tRt_ == reg) return 3;
291 break;
292 case 0x02: // CFC2
293 if (_tRt_ == reg) return 3;
294 break;
295 case 0x04: // MTC2
296 if (_tRt_ == reg) return 2;
297 break;
298 case 0x06: // CTC2
299 if (_tRt_ == reg) return 2;
300 break;
301 }
302 break;
303 // RTPS... break;
304 }
305 break;
306
307 case 0x22: case 0x26: // LWL/LWR
308 if (_tRt_ == reg) return 3; else
309 if (_tRs_ == reg) return 2;
310 break;
311
312 case 0x20: case 0x21: case 0x23:
313 case 0x24: case 0x25: // LB/LH/LW/LBU/LHU
314 if (_tRt_ == reg && _tRs_ == reg) return 1; else
315 if (_tRs_ == reg) return 2; else
316 if (_tRt_ == reg) return 3;
317 break;
318
319 case 0x28: case 0x29: case 0x2a:
320 case 0x2b: case 0x2e: // SB/SH/SWL/SW/SWR
321 if (_tRt_ == reg || _tRs_ == reg) return 2;
322 break;
323
324 case 0x32: case 0x3a: // LWC2/SWC2
325 if (_tRs_ == reg) return 2;
326 break;
327 }
328
329 return 0;
330}
331
332void psxDelayTest(int reg, u32 bpc) {
333 u32 *code;
334 u32 tmp;
335
7a811716 336 #ifdef ICACHE_EMULATION
337 if (Config.icache_emulation)
338 {
339 code = Read_ICache(psxRegs.pc);
340 }
341 else
342 #endif
343 {
344 code = (u32 *)PSXM(psxRegs.pc);
345 }
ef79bbde
P
346 tmp = ((code == NULL) ? 0 : SWAP32(*code));
347 branch = 1;
348
349 switch (psxTestLoadDelay(reg, tmp)) {
350 case 1:
351 delayReadWrite(reg, bpc); return;
352 case 2:
353 delayRead(reg, bpc); return;
354 case 3:
355 delayWrite(reg, bpc); return;
356 }
357 psxBSC[psxRegs.code >> 26]();
358
359 branch = 0;
360 psxRegs.pc = bpc;
361
362 psxBranchTest();
363}
364
990cb018 365static u32 psxBranchNoDelay(void) {
366 u32 *code;
367 u32 temp;
368
7a811716 369 #ifdef ICACHE_EMULATION
370 if (Config.icache_emulation)
371 {
372 code = Read_ICache(psxRegs.pc);
373 }
374 else
375 #endif
376 {
377 code = (u32 *)PSXM(psxRegs.pc);
378 }
990cb018 379 psxRegs.code = ((code == NULL) ? 0 : SWAP32(*code));
380 switch (_Op_) {
381 case 0x00: // SPECIAL
382 switch (_Funct_) {
383 case 0x08: // JR
384 return _u32(_rRs_);
385 case 0x09: // JALR
386 temp = _u32(_rRs_);
387 if (_Rd_) { _SetLink(_Rd_); }
388 return temp;
389 }
390 break;
391 case 0x01: // REGIMM
392 switch (_Rt_) {
393 case 0x00: // BLTZ
394 if (_i32(_rRs_) < 0)
395 return _BranchTarget_;
396 break;
397 case 0x01: // BGEZ
398 if (_i32(_rRs_) >= 0)
399 return _BranchTarget_;
400 break;
401 case 0x08: // BLTZAL
402 if (_i32(_rRs_) < 0) {
403 _SetLink(31);
404 return _BranchTarget_;
405 }
406 break;
407 case 0x09: // BGEZAL
408 if (_i32(_rRs_) >= 0) {
409 _SetLink(31);
410 return _BranchTarget_;
411 }
412 break;
413 }
414 break;
415 case 0x02: // J
416 return _JumpTarget_;
417 case 0x03: // JAL
418 _SetLink(31);
419 return _JumpTarget_;
420 case 0x04: // BEQ
421 if (_i32(_rRs_) == _i32(_rRt_))
422 return _BranchTarget_;
423 break;
424 case 0x05: // BNE
425 if (_i32(_rRs_) != _i32(_rRt_))
426 return _BranchTarget_;
427 break;
428 case 0x06: // BLEZ
429 if (_i32(_rRs_) <= 0)
430 return _BranchTarget_;
431 break;
432 case 0x07: // BGTZ
433 if (_i32(_rRs_) > 0)
434 return _BranchTarget_;
435 break;
436 }
437
438 return (u32)-1;
439}
440
441static int psxDelayBranchExec(u32 tar) {
442 execI();
443
444 branch = 0;
445 psxRegs.pc = tar;
446 psxRegs.cycle += BIAS;
447 psxBranchTest();
448 return 1;
449}
450
451static int psxDelayBranchTest(u32 tar1) {
452 u32 tar2, tmp1, tmp2;
453
454 tar2 = psxBranchNoDelay();
455 if (tar2 == (u32)-1)
456 return 0;
457
458 debugI();
459
460 /*
461 * Branch in delay slot:
462 * - execute 1 instruction at tar1
463 * - jump to tar2 (target of branch in delay slot; this branch
464 * has no normal delay slot, instruction at tar1 was fetched instead)
465 */
466 psxRegs.pc = tar1;
467 tmp1 = psxBranchNoDelay();
468 if (tmp1 == (u32)-1) {
469 return psxDelayBranchExec(tar2);
470 }
471 debugI();
472 psxRegs.cycle += BIAS;
473
474 /*
475 * Got a branch at tar1:
476 * - execute 1 instruction at tar2
477 * - jump to target of that branch (tmp1)
478 */
479 psxRegs.pc = tar2;
480 tmp2 = psxBranchNoDelay();
481 if (tmp2 == (u32)-1) {
482 return psxDelayBranchExec(tmp1);
483 }
484 debugI();
485 psxRegs.cycle += BIAS;
486
487 /*
488 * Got a branch at tar2:
489 * - execute 1 instruction at tmp1
490 * - jump to target of that branch (tmp2)
491 */
492 psxRegs.pc = tmp1;
493 return psxDelayBranchExec(tmp2);
494}
495
4600ba03 496static void doBranch(u32 tar) {
ef79bbde
P
497 u32 *code;
498 u32 tmp;
499
500 branch2 = branch = 1;
501 branchPC = tar;
502
990cb018 503 // check for branch in delay slot
504 if (psxDelayBranchTest(tar))
505 return;
506
7a811716 507 #ifdef ICACHE_EMULATION
508 if (Config.icache_emulation)
509 {
510 code = Read_ICache(psxRegs.pc);
511 }
512 else
513 #endif
514 {
515 code = (u32 *)PSXM(psxRegs.pc);
516 }
ef79bbde
P
517 psxRegs.code = ((code == NULL) ? 0 : SWAP32(*code));
518
519 debugI();
520
521 psxRegs.pc += 4;
522 psxRegs.cycle += BIAS;
523
524 // check for load delay
525 tmp = psxRegs.code >> 26;
526 switch (tmp) {
527 case 0x10: // COP0
528 switch (_Rs_) {
529 case 0x00: // MFC0
530 case 0x02: // CFC0
531 psxDelayTest(_Rt_, branchPC);
532 return;
533 }
534 break;
535 case 0x12: // COP2
536 switch (_Funct_) {
537 case 0x00:
538 switch (_Rs_) {
539 case 0x00: // MFC2
540 case 0x02: // CFC2
541 psxDelayTest(_Rt_, branchPC);
542 return;
543 }
544 break;
545 }
546 break;
547 case 0x32: // LWC2
548 psxDelayTest(_Rt_, branchPC);
549 return;
550 default:
551 if (tmp >= 0x20 && tmp <= 0x26) { // LB/LH/LWL/LW/LBU/LHU/LWR
552 psxDelayTest(_Rt_, branchPC);
553 return;
554 }
555 break;
556 }
557
558 psxBSC[psxRegs.code >> 26]();
559
560 branch = 0;
561 psxRegs.pc = branchPC;
562
563 psxBranchTest();
564}
565
566/*********************************************************
567* Arithmetic with immediate operand *
568* Format: OP rt, rs, immediate *
569*********************************************************/
570void psxADDI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im (Exception on Integer Overflow)
571void psxADDIU() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im
572void psxANDI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) & _ImmU_; } // Rt = Rs And Im
573void psxORI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) | _ImmU_; } // Rt = Rs Or Im
574void psxXORI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) ^ _ImmU_; } // Rt = Rs Xor Im
575void psxSLTI() { if (!_Rt_) return; _rRt_ = _i32(_rRs_) < _Imm_ ; } // Rt = Rs < Im (Signed)
576void psxSLTIU() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) < ((u32)_Imm_); } // Rt = Rs < Im (Unsigned)
577
578/*********************************************************
579* Register arithmetic *
580* Format: OP rd, rs, rt *
581*********************************************************/
582void psxADD() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt (Exception on Integer Overflow)
583void psxADDU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt
584void psxSUB() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt (Exception on Integer Overflow)
585void psxSUBU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt
586void psxAND() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) & _u32(_rRt_); } // Rd = Rs And Rt
587void psxOR() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) | _u32(_rRt_); } // Rd = Rs Or Rt
588void psxXOR() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) ^ _u32(_rRt_); } // Rd = Rs Xor Rt
589void psxNOR() { if (!_Rd_) return; _rRd_ =~(_u32(_rRs_) | _u32(_rRt_)); }// Rd = Rs Nor Rt
590void psxSLT() { if (!_Rd_) return; _rRd_ = _i32(_rRs_) < _i32(_rRt_); } // Rd = Rs < Rt (Signed)
591void psxSLTU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) < _u32(_rRt_); } // Rd = Rs < Rt (Unsigned)
592
593/*********************************************************
594* Register mult/div & Register trap logic *
595* Format: OP rs, rt *
596*********************************************************/
597void psxDIV() {
f533290e
EC
598 if (!_i32(_rRt_)) {
599 _i32(_rHi_) = _i32(_rRs_);
600 if (_i32(_rRs_) & 0x80000000) {
601 _i32(_rLo_) = 1;
602 } else {
603 _i32(_rLo_) = 0xFFFFFFFF;
604 }
605 } else if (_i32(_rRs_) == 0x80000000 && _i32(_rRt_) == 0xFFFFFFFF) {
606 _i32(_rLo_) = 0x80000000;
607 _i32(_rHi_) = 0;
608 } else {
609 _i32(_rLo_) = _i32(_rRs_) / _i32(_rRt_);
610 _i32(_rHi_) = _i32(_rRs_) % _i32(_rRt_);
611 }
ef79bbde
P
612}
613
614void psxDIVU() {
615 if (_rRt_ != 0) {
616 _rLo_ = _rRs_ / _rRt_;
617 _rHi_ = _rRs_ % _rRt_;
618 }
c7a56f4f 619 else {
620 _i32(_rLo_) = 0xffffffff;
621 _i32(_rHi_) = _i32(_rRs_);
622 }
ef79bbde
P
623}
624
625void psxMULT() {
626 u64 res = (s64)((s64)_i32(_rRs_) * (s64)_i32(_rRt_));
627
628 psxRegs.GPR.n.lo = (u32)(res & 0xffffffff);
629 psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff);
630}
631
632void psxMULTU() {
633 u64 res = (u64)((u64)_u32(_rRs_) * (u64)_u32(_rRt_));
634
635 psxRegs.GPR.n.lo = (u32)(res & 0xffffffff);
636 psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff);
637}
638
639/*********************************************************
640* Register branch logic *
641* Format: OP rs, offset *
642*********************************************************/
643#define RepZBranchi32(op) if(_i32(_rRs_) op 0) doBranch(_BranchTarget_);
db63e60d 644#define RepZBranchLinki32(op) { _SetLink(31); if(_i32(_rRs_) op 0) { doBranch(_BranchTarget_); } }
ef79bbde
P
645
646void psxBGEZ() { RepZBranchi32(>=) } // Branch if Rs >= 0
647void psxBGEZAL() { RepZBranchLinki32(>=) } // Branch if Rs >= 0 and link
648void psxBGTZ() { RepZBranchi32(>) } // Branch if Rs > 0
649void psxBLEZ() { RepZBranchi32(<=) } // Branch if Rs <= 0
650void psxBLTZ() { RepZBranchi32(<) } // Branch if Rs < 0
651void psxBLTZAL() { RepZBranchLinki32(<) } // Branch if Rs < 0 and link
652
653/*********************************************************
654* Shift arithmetic with constant shift *
655* Format: OP rd, rt, sa *
656*********************************************************/
657void psxSLL() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) << _Sa_; } // Rd = Rt << sa
658void psxSRA() { if (!_Rd_) return; _i32(_rRd_) = _i32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (arithmetic)
659void psxSRL() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (logical)
660
661/*********************************************************
662* Shift arithmetic with variant register shift *
663* Format: OP rd, rt, rs *
664*********************************************************/
cd15dd45 665void psxSLLV() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) << (_u32(_rRs_) & 0x1F); } // Rd = Rt << rs
666void psxSRAV() { if (!_Rd_) return; _i32(_rRd_) = _i32(_rRt_) >> (_u32(_rRs_) & 0x1F); } // Rd = Rt >> rs (arithmetic)
667void psxSRLV() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) >> (_u32(_rRs_) & 0x1F); } // Rd = Rt >> rs (logical)
ef79bbde
P
668
669/*********************************************************
670* Load higher 16 bits of the first word in GPR with imm *
671* Format: OP rt, immediate *
672*********************************************************/
673void psxLUI() { if (!_Rt_) return; _u32(_rRt_) = psxRegs.code << 16; } // Upper halfword of Rt = Im
674
675/*********************************************************
676* Move from HI/LO to GPR *
677* Format: OP rd *
678*********************************************************/
679void psxMFHI() { if (!_Rd_) return; _rRd_ = _rHi_; } // Rd = Hi
680void psxMFLO() { if (!_Rd_) return; _rRd_ = _rLo_; } // Rd = Lo
681
682/*********************************************************
683* Move to GPR to HI/LO & Register jump *
684* Format: OP rs *
685*********************************************************/
686void psxMTHI() { _rHi_ = _rRs_; } // Hi = Rs
687void psxMTLO() { _rLo_ = _rRs_; } // Lo = Rs
688
689/*********************************************************
690* Special purpose instructions *
691* Format: OP *
692*********************************************************/
693void psxBREAK() {
cd15dd45 694 psxRegs.pc -= 4;
695 psxException(0x24, branch);
ef79bbde
P
696}
697
698void psxSYSCALL() {
699 psxRegs.pc -= 4;
700 psxException(0x20, branch);
701}
702
703void psxRFE() {
704// SysPrintf("psxRFE\n");
705 psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status & 0xfffffff0) |
706 ((psxRegs.CP0.n.Status & 0x3c) >> 2);
707}
708
709/*********************************************************
710* Register branch logic *
711* Format: OP rs, rt, offset *
712*********************************************************/
713#define RepBranchi32(op) if(_i32(_rRs_) op _i32(_rRt_)) doBranch(_BranchTarget_);
714
715void psxBEQ() { RepBranchi32(==) } // Branch if Rs == Rt
716void psxBNE() { RepBranchi32(!=) } // Branch if Rs != Rt
717
718/*********************************************************
719* Jump to target *
720* Format: OP target *
721*********************************************************/
722void psxJ() { doBranch(_JumpTarget_); }
723void psxJAL() { _SetLink(31); doBranch(_JumpTarget_); }
724
725/*********************************************************
726* Register jump *
727* Format: OP rs, rd *
728*********************************************************/
729void psxJR() {
cd15dd45 730 doBranch(_u32(_rRs_) & ~3);
ef79bbde
P
731 psxJumpTest();
732}
733
734void psxJALR() {
735 u32 temp = _u32(_rRs_);
736 if (_Rd_) { _SetLink(_Rd_); }
cd15dd45 737 doBranch(temp & ~3);
ef79bbde
P
738}
739
740/*********************************************************
741* Load and store for GPR *
742* Format: OP rt, offset(base) *
743*********************************************************/
744
745#define _oB_ (_u32(_rRs_) + _Imm_)
746
747void psxLB() {
748 if (_Rt_) {
749 _i32(_rRt_) = (signed char)psxMemRead8(_oB_);
750 } else {
751 psxMemRead8(_oB_);
752 }
753}
754
755void psxLBU() {
756 if (_Rt_) {
757 _u32(_rRt_) = psxMemRead8(_oB_);
758 } else {
759 psxMemRead8(_oB_);
760 }
761}
762
763void psxLH() {
764 if (_Rt_) {
765 _i32(_rRt_) = (short)psxMemRead16(_oB_);
766 } else {
767 psxMemRead16(_oB_);
768 }
769}
770
771void psxLHU() {
772 if (_Rt_) {
773 _u32(_rRt_) = psxMemRead16(_oB_);
774 } else {
775 psxMemRead16(_oB_);
776 }
777}
778
779void psxLW() {
780 if (_Rt_) {
781 _u32(_rRt_) = psxMemRead32(_oB_);
782 } else {
783 psxMemRead32(_oB_);
784 }
785}
786
787u32 LWL_MASK[4] = { 0xffffff, 0xffff, 0xff, 0 };
788u32 LWL_SHIFT[4] = { 24, 16, 8, 0 };
789
790void psxLWL() {
791 u32 addr = _oB_;
792 u32 shift = addr & 3;
793 u32 mem = psxMemRead32(addr & ~3);
794
795 if (!_Rt_) return;
796 _u32(_rRt_) = ( _u32(_rRt_) & LWL_MASK[shift]) |
797 ( mem << LWL_SHIFT[shift]);
798
799 /*
800 Mem = 1234. Reg = abcd
801
802 0 4bcd (mem << 24) | (reg & 0x00ffffff)
803 1 34cd (mem << 16) | (reg & 0x0000ffff)
804 2 234d (mem << 8) | (reg & 0x000000ff)
805 3 1234 (mem ) | (reg & 0x00000000)
806 */
807}
808
809u32 LWR_MASK[4] = { 0, 0xff000000, 0xffff0000, 0xffffff00 };
810u32 LWR_SHIFT[4] = { 0, 8, 16, 24 };
811
812void psxLWR() {
813 u32 addr = _oB_;
814 u32 shift = addr & 3;
815 u32 mem = psxMemRead32(addr & ~3);
816
817 if (!_Rt_) return;
818 _u32(_rRt_) = ( _u32(_rRt_) & LWR_MASK[shift]) |
819 ( mem >> LWR_SHIFT[shift]);
820
821 /*
822 Mem = 1234. Reg = abcd
823
824 0 1234 (mem ) | (reg & 0x00000000)
825 1 a123 (mem >> 8) | (reg & 0xff000000)
826 2 ab12 (mem >> 16) | (reg & 0xffff0000)
827 3 abc1 (mem >> 24) | (reg & 0xffffff00)
828 */
829}
830
b1ba0851 831void psxSB() { psxMemWrite8 (_oB_, _rRt_ & 0xff); }
832void psxSH() { psxMemWrite16(_oB_, _rRt_ & 0xffff); }
833void psxSW() { psxMemWrite32(_oB_, _rRt_); }
ef79bbde
P
834
835u32 SWL_MASK[4] = { 0xffffff00, 0xffff0000, 0xff000000, 0 };
836u32 SWL_SHIFT[4] = { 24, 16, 8, 0 };
837
838void psxSWL() {
839 u32 addr = _oB_;
840 u32 shift = addr & 3;
841 u32 mem = psxMemRead32(addr & ~3);
842
843 psxMemWrite32(addr & ~3, (_u32(_rRt_) >> SWL_SHIFT[shift]) |
844 ( mem & SWL_MASK[shift]) );
845 /*
846 Mem = 1234. Reg = abcd
847
848 0 123a (reg >> 24) | (mem & 0xffffff00)
849 1 12ab (reg >> 16) | (mem & 0xffff0000)
850 2 1abc (reg >> 8) | (mem & 0xff000000)
851 3 abcd (reg ) | (mem & 0x00000000)
852 */
853}
854
855u32 SWR_MASK[4] = { 0, 0xff, 0xffff, 0xffffff };
856u32 SWR_SHIFT[4] = { 0, 8, 16, 24 };
857
858void psxSWR() {
859 u32 addr = _oB_;
860 u32 shift = addr & 3;
861 u32 mem = psxMemRead32(addr & ~3);
862
863 psxMemWrite32(addr & ~3, (_u32(_rRt_) << SWR_SHIFT[shift]) |
864 ( mem & SWR_MASK[shift]) );
865
866 /*
867 Mem = 1234. Reg = abcd
868
869 0 abcd (reg ) | (mem & 0x00000000)
870 1 bcd4 (reg << 8) | (mem & 0x000000ff)
871 2 cd34 (reg << 16) | (mem & 0x0000ffff)
872 3 d234 (reg << 24) | (mem & 0x00ffffff)
873 */
874}
875
876/*********************************************************
877* Moves between GPR and COPx *
878* Format: OP rt, fs *
879*********************************************************/
880void psxMFC0() { if (!_Rt_) return; _i32(_rRt_) = (int)_rFs_; }
881void psxCFC0() { if (!_Rt_) return; _i32(_rRt_) = (int)_rFs_; }
882
883void psxTestSWInts() {
ef79bbde 884 if (psxRegs.CP0.n.Cause & psxRegs.CP0.n.Status & 0x0300 &&
48e74ef5 885 psxRegs.CP0.n.Status & 0x1) {
886 psxRegs.CP0.n.Cause &= ~0x7c;
ef79bbde
P
887 psxException(psxRegs.CP0.n.Cause, branch);
888 }
889}
890
4600ba03 891void MTC0(int reg, u32 val) {
ef79bbde
P
892// SysPrintf("MTC0 %d: %x\n", reg, val);
893 switch (reg) {
894 case 12: // Status
895 psxRegs.CP0.r[12] = val;
896 psxTestSWInts();
897 break;
898
899 case 13: // Cause
48e74ef5 900 psxRegs.CP0.n.Cause &= ~0x0300;
901 psxRegs.CP0.n.Cause |= val & 0x0300;
ef79bbde
P
902 psxTestSWInts();
903 break;
904
905 default:
906 psxRegs.CP0.r[reg] = val;
907 break;
908 }
909}
910
911void psxMTC0() { MTC0(_Rd_, _u32(_rRt_)); }
912void psxCTC0() { MTC0(_Rd_, _u32(_rRt_)); }
913
914/*********************************************************
915* Unknow instruction (would generate an exception) *
916* Format: ? *
917*********************************************************/
918void psxNULL() {
919#ifdef PSXCPU_LOG
920 PSXCPU_LOG("psx: Unimplemented op %x\n", psxRegs.code);
921#endif
922}
923
924void psxSPECIAL() {
925 psxSPC[_Funct_]();
926}
927
928void psxREGIMM() {
929 psxREG[_Rt_]();
930}
931
932void psxCOP0() {
933 psxCP0[_Rs_]();
934}
935
db63e60d 936void psxCOP1() {
937#ifdef PSXCPU_LOG
938 PSXCPU_LOG("Attempted to use an invalid floating point instruction. Ignored.\n");
939#endif
940}
941
ef79bbde 942void psxCOP2() {
6c0eefaf 943 psxCP2[_Funct_]((struct psxCP2Regs *)&psxRegs.CP2D);
ef79bbde
P
944}
945
db63e60d 946void psxCOP3() {
947#ifdef PSXCPU_LOG
948 PSXCPU_LOG("Attempted to access COP3. Ignored\n");
949#endif
950}
951
6c0eefaf 952void psxBASIC(struct psxCP2Regs *regs) {
ef79bbde
P
953 psxCP2BSC[_Rs_]();
954}
955
956void psxHLE() {
957// psxHLEt[psxRegs.code & 0xffff]();
423b0da8 958// psxHLEt[psxRegs.code & 0x07](); // HDHOSHY experimental patch
959 uint32_t hleCode = psxRegs.code & 0x03ffffff;
960 if (hleCode >= (sizeof(psxHLEt) / sizeof(psxHLEt[0]))) {
961 psxNULL();
962 } else {
963 psxHLEt[hleCode]();
964 }
ef79bbde
P
965}
966
967void (*psxBSC[64])() = {
968 psxSPECIAL, psxREGIMM, psxJ , psxJAL , psxBEQ , psxBNE , psxBLEZ, psxBGTZ,
969 psxADDI , psxADDIU , psxSLTI, psxSLTIU, psxANDI, psxORI , psxXORI, psxLUI ,
db63e60d 970 psxCOP0 , psxCOP1 , psxCOP2, psxCOP3 , psxNULL, psxNULL, psxNULL, psxNULL,
ef79bbde
P
971 psxNULL , psxNULL , psxNULL, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL,
972 psxLB , psxLH , psxLWL , psxLW , psxLBU , psxLHU , psxLWR , psxNULL,
973 psxSB , psxSH , psxSWL , psxSW , psxNULL, psxNULL, psxSWR , psxNULL,
974 psxNULL , psxNULL , gteLWC2, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL,
975 psxNULL , psxNULL , gteSWC2, psxHLE , psxNULL, psxNULL, psxNULL, psxNULL
976};
977
978
979void (*psxSPC[64])() = {
980 psxSLL , psxNULL , psxSRL , psxSRA , psxSLLV , psxNULL , psxSRLV, psxSRAV,
981 psxJR , psxJALR , psxNULL, psxNULL, psxSYSCALL, psxBREAK, psxNULL, psxNULL,
982 psxMFHI, psxMTHI , psxMFLO, psxMTLO, psxNULL , psxNULL , psxNULL, psxNULL,
983 psxMULT, psxMULTU, psxDIV , psxDIVU, psxNULL , psxNULL , psxNULL, psxNULL,
984 psxADD , psxADDU , psxSUB , psxSUBU, psxAND , psxOR , psxXOR , psxNOR ,
985 psxNULL, psxNULL , psxSLT , psxSLTU, psxNULL , psxNULL , psxNULL, psxNULL,
986 psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL,
987 psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL
988};
989
990void (*psxREG[32])() = {
991 psxBLTZ , psxBGEZ , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
992 psxNULL , psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
993 psxBLTZAL, psxBGEZAL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
994 psxNULL , psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL
995};
996
997void (*psxCP0[32])() = {
998 psxMFC0, psxNULL, psxCFC0, psxNULL, psxMTC0, psxNULL, psxCTC0, psxNULL,
999 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
1000 psxRFE , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
1001 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL
1002};
1003
6c0eefaf 1004void (*psxCP2[64])(struct psxCP2Regs *regs) = {
ef79bbde
P
1005 psxBASIC, gteRTPS , psxNULL , psxNULL, psxNULL, psxNULL , gteNCLIP, psxNULL, // 00
1006 psxNULL , psxNULL , psxNULL , psxNULL, gteOP , psxNULL , psxNULL , psxNULL, // 08
1007 gteDPCS , gteINTPL, gteMVMVA, gteNCDS, gteCDP , psxNULL , gteNCDT , psxNULL, // 10
1008 psxNULL , psxNULL , psxNULL , gteNCCS, gteCC , psxNULL , gteNCS , psxNULL, // 18
1009 gteNCT , psxNULL , psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, // 20
1010 gteSQR , gteDCPL , gteDPCT , psxNULL, psxNULL, gteAVSZ3, gteAVSZ4, psxNULL, // 28
1011 gteRTPT , psxNULL , psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, // 30
1012 psxNULL , psxNULL , psxNULL , psxNULL, psxNULL, gteGPF , gteGPL , gteNCCT // 38
1013};
1014
1015void (*psxCP2BSC[32])() = {
1016 gteMFC2, psxNULL, gteCFC2, psxNULL, gteMTC2, psxNULL, gteCTC2, psxNULL,
1017 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
1018 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
1019 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL
1020};
1021
1022
1023///////////////////////////////////////////
1024
1025static int intInit() {
7a811716 1026#ifdef ICACHE_EMULATION
1027 if (!ICache_Addr)
1028 {
1029 ICache_Addr = malloc(0x1000);
1030 if (!ICache_Addr)
1031 {
1032 return -1;
1033 }
1034 }
1035
1036 if (!ICache_Code)
1037 {
1038 ICache_Code = malloc(0x1000);
1039 if (!ICache_Code)
1040 {
1041 return -1;
1042 }
1043 }
1044 memset(ICache_Addr, 0xff, 0x1000);
1045 memset(ICache_Code, 0xff, 0x1000);
1046#endif
ef79bbde
P
1047 return 0;
1048}
1049
1050static void intReset() {
7a811716 1051#ifdef ICACHE_EMULATION
1052 memset(ICache_Addr, 0xff, 0x1000);
1053 memset(ICache_Code, 0xff, 0x1000);
1054#endif
ef79bbde
P
1055}
1056
796a91ef 1057void intExecute() {
1058 extern int stop;
1059 for (;!stop;)
ef79bbde
P
1060 execI();
1061}
1062
796a91ef 1063void intExecuteBlock() {
ef79bbde
P
1064 branch2 = 0;
1065 while (!branch2) execI();
1066}
1067
1068static void intClear(u32 Addr, u32 Size) {
1069}
1070
7a811716 1071void intNotify (int note, void *data) {
1072#ifdef ICACHE_EMULATION
1073 /* Gameblabla - Only clear the icache if it's isolated */
1074 if (note == R3000ACPU_NOTIFY_CACHE_ISOLATED)
1075 {
1076 memset(ICache_Addr, 0xff, 0x1000);
1077 memset(ICache_Code, 0xff, 0x1000);
1078 }
1079#endif
1080}
1081
ef79bbde 1082static void intShutdown() {
7a811716 1083#ifdef ICACHE_EMULATION
1084 if (ICache_Addr)
1085 {
1086 free(ICache_Addr);
1087 ICache_Addr = NULL;
1088 }
1089
1090 if (ICache_Code)
1091 {
1092 free(ICache_Code);
1093 ICache_Code = NULL;
1094 }
1095#endif
ef79bbde
P
1096}
1097
1098// interpreter execution
4600ba03 1099void execI() {
7a811716 1100#ifndef ICACHE_EMULATION
ef79bbde 1101 u32 *code = (u32 *)PSXM(psxRegs.pc);
7a811716 1102#else
1103 u32 *code = Read_ICache(psxRegs.pc);
1104#endif
1105
ef79bbde
P
1106 psxRegs.code = ((code == NULL) ? 0 : SWAP32(*code));
1107
1108 debugI();
1109
1110 if (Config.Debug) ProcessDebug();
1111
1112 psxRegs.pc += 4;
1113 psxRegs.cycle += BIAS;
1114
1115 psxBSC[psxRegs.code >> 26]();
1116}
1117
1118R3000Acpu psxInt = {
1119 intInit,
1120 intReset,
1121 intExecute,
1122 intExecuteBlock,
1123 intClear,
7a811716 1124#ifdef ICACHE_EMULATION
1125 intNotify,
1126#endif
ef79bbde
P
1127 intShutdown
1128};