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