drc: something works on arm64
[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"
3968e69e 29#include "psxinterpreter.h"
ef79bbde
P
30
31static int branch = 0;
32static int branch2 = 0;
33static u32 branchPC;
34
35// These macros are used to assemble the repassembler functions
36
37#ifdef PSXCPU_LOG
38#define debugI() PSXCPU_LOG("%s\n", disR3000AF(psxRegs.code, psxRegs.pc));
39#else
40#define debugI()
41#endif
42
ef79bbde
P
43// Subsets
44void (*psxBSC[64])();
45void (*psxSPC[64])();
46void (*psxREG[32])();
47void (*psxCP0[32])();
6c0eefaf 48void (*psxCP2[64])(struct psxCP2Regs *regs);
ef79bbde
P
49void (*psxCP2BSC[32])();
50
943a507a 51#ifdef ICACHE_EMULATION
52/*
53Formula One 2001 :
54Use old CPU cache code when the RAM location is updated with new code (affects in-game racing)
55*/
56static u8* ICache_Addr;
57static u8* ICache_Code;
58uint32_t *Read_ICache(uint32_t pc)
59{
60 uint32_t pc_bank, pc_offset, pc_cache;
61 uint8_t *IAddr, *ICode;
62
63 pc_bank = pc >> 24;
64 pc_offset = pc & 0xffffff;
65 pc_cache = pc & 0xfff;
66
67 IAddr = ICache_Addr;
68 ICode = ICache_Code;
69
70 // cached - RAM
71 if (pc_bank == 0x80 || pc_bank == 0x00)
72 {
73 if (SWAP32(*(uint32_t *)(IAddr + pc_cache)) == pc_offset)
74 {
75 // Cache hit - return last opcode used
76 return (uint32_t *)(ICode + pc_cache);
77 }
78 else
79 {
80 // Cache miss - addresses don't match
81 // - default: 0xffffffff (not init)
82
83 // cache line is 4 bytes wide
84 pc_offset &= ~0xf;
85 pc_cache &= ~0xf;
86
87 // address line
88 *(uint32_t *)(IAddr + pc_cache + 0x0) = SWAP32(pc_offset + 0x0);
89 *(uint32_t *)(IAddr + pc_cache + 0x4) = SWAP32(pc_offset + 0x4);
90 *(uint32_t *)(IAddr + pc_cache + 0x8) = SWAP32(pc_offset + 0x8);
91 *(uint32_t *)(IAddr + pc_cache + 0xc) = SWAP32(pc_offset + 0xc);
92
93 // opcode line
94 pc_offset = pc & ~0xf;
95 *(uint32_t *)(ICode + pc_cache + 0x0) = psxMu32ref(pc_offset + 0x0);
96 *(uint32_t *)(ICode + pc_cache + 0x4) = psxMu32ref(pc_offset + 0x4);
97 *(uint32_t *)(ICode + pc_cache + 0x8) = psxMu32ref(pc_offset + 0x8);
98 *(uint32_t *)(ICode + pc_cache + 0xc) = psxMu32ref(pc_offset + 0xc);
99 }
100 }
101
102 /*
103 TODO: Probably should add cached BIOS
104 */
105 // default
106 return (uint32_t *)PSXM(pc);
107}
108#endif
109
ef79bbde
P
110static void delayRead(int reg, u32 bpc) {
111 u32 rold, rnew;
112
113// SysPrintf("delayRead at %x!\n", psxRegs.pc);
114
115 rold = psxRegs.GPR.r[reg];
116 psxBSC[psxRegs.code >> 26](); // branch delay load
117 rnew = psxRegs.GPR.r[reg];
118
119 psxRegs.pc = bpc;
120
abbc1ca1 121 branch = 0;
ef79bbde
P
122
123 psxRegs.GPR.r[reg] = rold;
124 execI(); // first branch opcode
125 psxRegs.GPR.r[reg] = rnew;
126
abbc1ca1 127 psxBranchTest();
ef79bbde
P
128}
129
130static void delayWrite(int reg, u32 bpc) {
131
132/* SysPrintf("delayWrite at %x!\n", psxRegs.pc);
133
134 SysPrintf("%s\n", disR3000AF(psxRegs.code, psxRegs.pc-4));
135 SysPrintf("%s\n", disR3000AF(PSXMu32(bpc), bpc));*/
136
137 // no changes from normal behavior
138
139 psxBSC[psxRegs.code >> 26]();
140
141 branch = 0;
142 psxRegs.pc = bpc;
143
144 psxBranchTest();
145}
146
147static void delayReadWrite(int reg, u32 bpc) {
148
149// SysPrintf("delayReadWrite at %x!\n", psxRegs.pc);
150
151 // the branch delay load is skipped
152
153 branch = 0;
154 psxRegs.pc = bpc;
155
156 psxBranchTest();
157}
158
159// this defines shall be used with the tmp
160// of the next func (instead of _Funct_...)
161#define _tFunct_ ((tmp ) & 0x3F) // The funct part of the instruction register
162#define _tRd_ ((tmp >> 11) & 0x1F) // The rd part of the instruction register
163#define _tRt_ ((tmp >> 16) & 0x1F) // The rt part of the instruction register
164#define _tRs_ ((tmp >> 21) & 0x1F) // The rs part of the instruction register
165#define _tSa_ ((tmp >> 6) & 0x1F) // The sa part of the instruction register
166
167int psxTestLoadDelay(int reg, u32 tmp) {
168 if (tmp == 0) return 0; // NOP
169 switch (tmp >> 26) {
170 case 0x00: // SPECIAL
171 switch (_tFunct_) {
172 case 0x00: // SLL
173 case 0x02: case 0x03: // SRL/SRA
174 if (_tRd_ == reg && _tRt_ == reg) return 1; else
175 if (_tRt_ == reg) return 2; else
176 if (_tRd_ == reg) return 3;
177 break;
178
179 case 0x08: // JR
180 if (_tRs_ == reg) return 2;
181 break;
182 case 0x09: // JALR
183 if (_tRd_ == reg && _tRs_ == reg) return 1; else
184 if (_tRs_ == reg) return 2; else
185 if (_tRd_ == reg) return 3;
186 break;
187
188 // SYSCALL/BREAK just a break;
189
190 case 0x20: case 0x21: case 0x22: case 0x23:
191 case 0x24: case 0x25: case 0x26: case 0x27:
192 case 0x2a: case 0x2b: // ADD/ADDU...
193 case 0x04: case 0x06: case 0x07: // SLLV...
194 if (_tRd_ == reg && (_tRt_ == reg || _tRs_ == reg)) return 1; else
195 if (_tRt_ == reg || _tRs_ == reg) return 2; else
196 if (_tRd_ == reg) return 3;
197 break;
198
199 case 0x10: case 0x12: // MFHI/MFLO
200 if (_tRd_ == reg) return 3;
201 break;
202 case 0x11: case 0x13: // MTHI/MTLO
203 if (_tRs_ == reg) return 2;
204 break;
205
206 case 0x18: case 0x19:
207 case 0x1a: case 0x1b: // MULT/DIV...
208 if (_tRt_ == reg || _tRs_ == reg) return 2;
209 break;
210 }
211 break;
212
213 case 0x01: // REGIMM
214 switch (_tRt_) {
862bfc0d 215 case 0x00: case 0x01:
216 case 0x10: case 0x11: // BLTZ/BGEZ...
217 // Xenogears - lbu v0 / beq v0
218 // - no load delay (fixes battle loading)
219 break;
220
ef79bbde
P
221 if (_tRs_ == reg) return 2;
222 break;
223 }
224 break;
225
226 // J would be just a break;
227 case 0x03: // JAL
228 if (31 == reg) return 3;
229 break;
230
231 case 0x04: case 0x05: // BEQ/BNE
862bfc0d 232 // Xenogears - lbu v0 / beq v0
233 // - no load delay (fixes battle loading)
234 break;
235
ef79bbde
P
236 if (_tRs_ == reg || _tRt_ == reg) return 2;
237 break;
238
239 case 0x06: case 0x07: // BLEZ/BGTZ
862bfc0d 240 // Xenogears - lbu v0 / beq v0
241 // - no load delay (fixes battle loading)
242 break;
243
ef79bbde
P
244 if (_tRs_ == reg) return 2;
245 break;
246
247 case 0x08: case 0x09: case 0x0a: case 0x0b:
248 case 0x0c: case 0x0d: case 0x0e: // ADDI/ADDIU...
249 if (_tRt_ == reg && _tRs_ == reg) return 1; else
250 if (_tRs_ == reg) return 2; else
251 if (_tRt_ == reg) return 3;
252 break;
253
254 case 0x0f: // LUI
255 if (_tRt_ == reg) return 3;
256 break;
257
258 case 0x10: // COP0
259 switch (_tFunct_) {
260 case 0x00: // MFC0
261 if (_tRt_ == reg) return 3;
262 break;
263 case 0x02: // CFC0
264 if (_tRt_ == reg) return 3;
265 break;
266 case 0x04: // MTC0
267 if (_tRt_ == reg) return 2;
268 break;
269 case 0x06: // CTC0
270 if (_tRt_ == reg) return 2;
271 break;
272 // RFE just a break;
273 }
274 break;
275
276 case 0x12: // COP2
277 switch (_tFunct_) {
278 case 0x00:
279 switch (_tRs_) {
280 case 0x00: // MFC2
281 if (_tRt_ == reg) return 3;
282 break;
283 case 0x02: // CFC2
284 if (_tRt_ == reg) return 3;
285 break;
286 case 0x04: // MTC2
287 if (_tRt_ == reg) return 2;
288 break;
289 case 0x06: // CTC2
290 if (_tRt_ == reg) return 2;
291 break;
292 }
293 break;
294 // RTPS... break;
295 }
296 break;
297
298 case 0x22: case 0x26: // LWL/LWR
299 if (_tRt_ == reg) return 3; else
300 if (_tRs_ == reg) return 2;
301 break;
302
303 case 0x20: case 0x21: case 0x23:
304 case 0x24: case 0x25: // LB/LH/LW/LBU/LHU
305 if (_tRt_ == reg && _tRs_ == reg) return 1; else
306 if (_tRs_ == reg) return 2; else
307 if (_tRt_ == reg) return 3;
308 break;
309
310 case 0x28: case 0x29: case 0x2a:
311 case 0x2b: case 0x2e: // SB/SH/SWL/SW/SWR
312 if (_tRt_ == reg || _tRs_ == reg) return 2;
313 break;
314
315 case 0x32: case 0x3a: // LWC2/SWC2
316 if (_tRs_ == reg) return 2;
317 break;
318 }
319
320 return 0;
321}
322
323void psxDelayTest(int reg, u32 bpc) {
324 u32 *code;
325 u32 tmp;
326
943a507a 327 #ifdef ICACHE_EMULATION
328 if (Config.icache_emulation)
329 {
330 code = Read_ICache(psxRegs.pc);
331 }
332 else
333 #endif
334 {
335 code = (u32 *)PSXM(psxRegs.pc);
336 }
337
ef79bbde
P
338 tmp = ((code == NULL) ? 0 : SWAP32(*code));
339 branch = 1;
340
341 switch (psxTestLoadDelay(reg, tmp)) {
342 case 1:
343 delayReadWrite(reg, bpc); return;
344 case 2:
345 delayRead(reg, bpc); return;
346 case 3:
347 delayWrite(reg, bpc); return;
348 }
349 psxBSC[psxRegs.code >> 26]();
350
351 branch = 0;
352 psxRegs.pc = bpc;
353
354 psxBranchTest();
355}
356
990cb018 357static u32 psxBranchNoDelay(void) {
358 u32 *code;
359 u32 temp;
360
943a507a 361 #ifdef ICACHE_EMULATION
362 if (Config.icache_emulation)
363 {
364 code = Read_ICache(psxRegs.pc);
365 }
366 else
367 #endif
368 {
369 code = (u32 *)PSXM(psxRegs.pc);
370 }
990cb018 371 psxRegs.code = ((code == NULL) ? 0 : SWAP32(*code));
372 switch (_Op_) {
373 case 0x00: // SPECIAL
374 switch (_Funct_) {
375 case 0x08: // JR
376 return _u32(_rRs_);
377 case 0x09: // JALR
378 temp = _u32(_rRs_);
379 if (_Rd_) { _SetLink(_Rd_); }
380 return temp;
381 }
382 break;
383 case 0x01: // REGIMM
384 switch (_Rt_) {
385 case 0x00: // BLTZ
386 if (_i32(_rRs_) < 0)
387 return _BranchTarget_;
388 break;
389 case 0x01: // BGEZ
390 if (_i32(_rRs_) >= 0)
391 return _BranchTarget_;
392 break;
393 case 0x08: // BLTZAL
394 if (_i32(_rRs_) < 0) {
395 _SetLink(31);
396 return _BranchTarget_;
397 }
398 break;
399 case 0x09: // BGEZAL
400 if (_i32(_rRs_) >= 0) {
401 _SetLink(31);
402 return _BranchTarget_;
403 }
404 break;
405 }
406 break;
407 case 0x02: // J
408 return _JumpTarget_;
409 case 0x03: // JAL
410 _SetLink(31);
411 return _JumpTarget_;
412 case 0x04: // BEQ
413 if (_i32(_rRs_) == _i32(_rRt_))
414 return _BranchTarget_;
415 break;
416 case 0x05: // BNE
417 if (_i32(_rRs_) != _i32(_rRt_))
418 return _BranchTarget_;
419 break;
420 case 0x06: // BLEZ
421 if (_i32(_rRs_) <= 0)
422 return _BranchTarget_;
423 break;
424 case 0x07: // BGTZ
425 if (_i32(_rRs_) > 0)
426 return _BranchTarget_;
427 break;
428 }
429
430 return (u32)-1;
431}
432
433static int psxDelayBranchExec(u32 tar) {
434 execI();
435
436 branch = 0;
437 psxRegs.pc = tar;
438 psxRegs.cycle += BIAS;
439 psxBranchTest();
440 return 1;
441}
442
443static int psxDelayBranchTest(u32 tar1) {
444 u32 tar2, tmp1, tmp2;
445
446 tar2 = psxBranchNoDelay();
447 if (tar2 == (u32)-1)
448 return 0;
449
450 debugI();
451
452 /*
453 * Branch in delay slot:
454 * - execute 1 instruction at tar1
455 * - jump to tar2 (target of branch in delay slot; this branch
456 * has no normal delay slot, instruction at tar1 was fetched instead)
457 */
458 psxRegs.pc = tar1;
459 tmp1 = psxBranchNoDelay();
460 if (tmp1 == (u32)-1) {
461 return psxDelayBranchExec(tar2);
462 }
463 debugI();
464 psxRegs.cycle += BIAS;
465
466 /*
467 * Got a branch at tar1:
468 * - execute 1 instruction at tar2
469 * - jump to target of that branch (tmp1)
470 */
471 psxRegs.pc = tar2;
472 tmp2 = psxBranchNoDelay();
473 if (tmp2 == (u32)-1) {
474 return psxDelayBranchExec(tmp1);
475 }
476 debugI();
477 psxRegs.cycle += BIAS;
478
479 /*
480 * Got a branch at tar2:
481 * - execute 1 instruction at tmp1
482 * - jump to target of that branch (tmp2)
483 */
484 psxRegs.pc = tmp1;
485 return psxDelayBranchExec(tmp2);
486}
487
4600ba03 488static void doBranch(u32 tar) {
ef79bbde
P
489 u32 *code;
490 u32 tmp;
491
492 branch2 = branch = 1;
493 branchPC = tar;
494
990cb018 495 // check for branch in delay slot
496 if (psxDelayBranchTest(tar))
497 return;
498
943a507a 499 #ifdef ICACHE_EMULATION
500 if (Config.icache_emulation)
501 {
502 code = Read_ICache(psxRegs.pc);
503 }
504 else
505 #endif
506 {
507 code = (u32 *)PSXM(psxRegs.pc);
508 }
ef79bbde
P
509 psxRegs.code = ((code == NULL) ? 0 : SWAP32(*code));
510
511 debugI();
512
513 psxRegs.pc += 4;
514 psxRegs.cycle += BIAS;
515
516 // check for load delay
517 tmp = psxRegs.code >> 26;
518 switch (tmp) {
519 case 0x10: // COP0
520 switch (_Rs_) {
521 case 0x00: // MFC0
522 case 0x02: // CFC0
523 psxDelayTest(_Rt_, branchPC);
524 return;
525 }
526 break;
527 case 0x12: // COP2
528 switch (_Funct_) {
529 case 0x00:
530 switch (_Rs_) {
531 case 0x00: // MFC2
532 case 0x02: // CFC2
533 psxDelayTest(_Rt_, branchPC);
534 return;
535 }
536 break;
537 }
538 break;
539 case 0x32: // LWC2
540 psxDelayTest(_Rt_, branchPC);
541 return;
542 default:
543 if (tmp >= 0x20 && tmp <= 0x26) { // LB/LH/LWL/LW/LBU/LHU/LWR
544 psxDelayTest(_Rt_, branchPC);
545 return;
546 }
547 break;
548 }
549
550 psxBSC[psxRegs.code >> 26]();
551
552 branch = 0;
553 psxRegs.pc = branchPC;
554
555 psxBranchTest();
556}
557
558/*********************************************************
559* Arithmetic with immediate operand *
560* Format: OP rt, rs, immediate *
561*********************************************************/
562void psxADDI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im (Exception on Integer Overflow)
563void psxADDIU() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im
564void psxANDI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) & _ImmU_; } // Rt = Rs And Im
565void psxORI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) | _ImmU_; } // Rt = Rs Or Im
566void psxXORI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) ^ _ImmU_; } // Rt = Rs Xor Im
567void psxSLTI() { if (!_Rt_) return; _rRt_ = _i32(_rRs_) < _Imm_ ; } // Rt = Rs < Im (Signed)
568void psxSLTIU() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) < ((u32)_Imm_); } // Rt = Rs < Im (Unsigned)
569
570/*********************************************************
571* Register arithmetic *
572* Format: OP rd, rs, rt *
573*********************************************************/
574void psxADD() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt (Exception on Integer Overflow)
575void psxADDU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt
576void psxSUB() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt (Exception on Integer Overflow)
577void psxSUBU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt
578void psxAND() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) & _u32(_rRt_); } // Rd = Rs And Rt
579void psxOR() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) | _u32(_rRt_); } // Rd = Rs Or Rt
580void psxXOR() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) ^ _u32(_rRt_); } // Rd = Rs Xor Rt
581void psxNOR() { if (!_Rd_) return; _rRd_ =~(_u32(_rRs_) | _u32(_rRt_)); }// Rd = Rs Nor Rt
582void psxSLT() { if (!_Rd_) return; _rRd_ = _i32(_rRs_) < _i32(_rRt_); } // Rd = Rs < Rt (Signed)
583void psxSLTU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) < _u32(_rRt_); } // Rd = Rs < Rt (Unsigned)
584
585/*********************************************************
586* Register mult/div & Register trap logic *
587* Format: OP rs, rt *
588*********************************************************/
589void psxDIV() {
a4ae3997 590 if (!_i32(_rRt_)) {
591 _i32(_rHi_) = _i32(_rRs_);
592 if (_i32(_rRs_) & 0x80000000) {
593 _i32(_rLo_) = 1;
594 } else {
595 _i32(_rLo_) = 0xFFFFFFFF;
596 }
597/*
598 * Notaz said that this was "not needed" for ARM platforms and could slow it down so let's disable for ARM.
599 * This fixes a crash issue that can happen when running Amidog's CPU test.
600 * (It still stays stuck to a black screen but at least it doesn't crash anymore)
601 */
602#if !defined(__arm__) && !defined(__aarch64__)
603 } else if (_i32(_rRs_) == 0x80000000 && _i32(_rRt_) == 0xFFFFFFFF) {
604 _i32(_rLo_) = 0x80000000;
605 _i32(_rHi_) = 0;
606#endif
607 } else {
608 _i32(_rLo_) = _i32(_rRs_) / _i32(_rRt_);
609 _i32(_rHi_) = _i32(_rRs_) % _i32(_rRt_);
610 }
ef79bbde
P
611}
612
613void psxDIVU() {
614 if (_rRt_ != 0) {
615 _rLo_ = _rRs_ / _rRt_;
616 _rHi_ = _rRs_ % _rRt_;
617 }
c7a56f4f 618 else {
619 _i32(_rLo_) = 0xffffffff;
620 _i32(_rHi_) = _i32(_rRs_);
621 }
ef79bbde
P
622}
623
624void psxMULT() {
625 u64 res = (s64)((s64)_i32(_rRs_) * (s64)_i32(_rRt_));
626
627 psxRegs.GPR.n.lo = (u32)(res & 0xffffffff);
628 psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff);
629}
630
631void psxMULTU() {
632 u64 res = (u64)((u64)_u32(_rRs_) * (u64)_u32(_rRt_));
633
634 psxRegs.GPR.n.lo = (u32)(res & 0xffffffff);
635 psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff);
636}
637
638/*********************************************************
639* Register branch logic *
640* Format: OP rs, offset *
641*********************************************************/
642#define RepZBranchi32(op) if(_i32(_rRs_) op 0) doBranch(_BranchTarget_);
943a507a 643#define RepZBranchLinki32(op) { _SetLink(31); if(_i32(_rRs_) op 0) { doBranch(_BranchTarget_); } }
ef79bbde
P
644
645void psxBGEZ() { RepZBranchi32(>=) } // Branch if Rs >= 0
646void psxBGEZAL() { RepZBranchLinki32(>=) } // Branch if Rs >= 0 and link
647void psxBGTZ() { RepZBranchi32(>) } // Branch if Rs > 0
648void psxBLEZ() { RepZBranchi32(<=) } // Branch if Rs <= 0
649void psxBLTZ() { RepZBranchi32(<) } // Branch if Rs < 0
650void psxBLTZAL() { RepZBranchLinki32(<) } // Branch if Rs < 0 and link
651
652/*********************************************************
653* Shift arithmetic with constant shift *
654* Format: OP rd, rt, sa *
655*********************************************************/
656void psxSLL() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) << _Sa_; } // Rd = Rt << sa
657void psxSRA() { if (!_Rd_) return; _i32(_rRd_) = _i32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (arithmetic)
658void psxSRL() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (logical)
659
660/*********************************************************
661* Shift arithmetic with variant register shift *
662* Format: OP rd, rt, rs *
663*********************************************************/
943a507a 664void psxSLLV() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) << (_u32(_rRs_) & 0x1F); } // Rd = Rt << rs
665void psxSRAV() { if (!_Rd_) return; _i32(_rRd_) = _i32(_rRt_) >> (_u32(_rRs_) & 0x1F); } // Rd = Rt >> rs (arithmetic)
666void psxSRLV() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) >> (_u32(_rRs_) & 0x1F); } // Rd = Rt >> rs (logical)
ef79bbde
P
667
668/*********************************************************
669* Load higher 16 bits of the first word in GPR with imm *
670* Format: OP rt, immediate *
671*********************************************************/
672void psxLUI() { if (!_Rt_) return; _u32(_rRt_) = psxRegs.code << 16; } // Upper halfword of Rt = Im
673
674/*********************************************************
675* Move from HI/LO to GPR *
676* Format: OP rd *
677*********************************************************/
678void psxMFHI() { if (!_Rd_) return; _rRd_ = _rHi_; } // Rd = Hi
679void psxMFLO() { if (!_Rd_) return; _rRd_ = _rLo_; } // Rd = Lo
680
681/*********************************************************
682* Move to GPR to HI/LO & Register jump *
683* Format: OP rs *
684*********************************************************/
685void psxMTHI() { _rHi_ = _rRs_; } // Hi = Rs
686void psxMTLO() { _rLo_ = _rRs_; } // Lo = Rs
687
688/*********************************************************
689* Special purpose instructions *
690* Format: OP *
691*********************************************************/
692void psxBREAK() {
943a507a 693 psxRegs.pc -= 4;
694 psxException(0x24, branch);
ef79bbde
P
695}
696
697void psxSYSCALL() {
698 psxRegs.pc -= 4;
699 psxException(0x20, branch);
700}
701
702void psxRFE() {
703// SysPrintf("psxRFE\n");
704 psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status & 0xfffffff0) |
705 ((psxRegs.CP0.n.Status & 0x3c) >> 2);
943a507a 706 psxTestSWInts();
ef79bbde
P
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() {
943a507a 730 doBranch(_rRs_ & ~3);
ef79bbde
P
731 psxJumpTest();
732}
733
734void psxJALR() {
735 u32 temp = _u32(_rRs_);
736 if (_Rd_) { _SetLink(_Rd_); }
943a507a 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
936void psxCOP2() {
6c0eefaf 937 psxCP2[_Funct_]((struct psxCP2Regs *)&psxRegs.CP2D);
ef79bbde
P
938}
939
6c0eefaf 940void psxBASIC(struct psxCP2Regs *regs) {
ef79bbde
P
941 psxCP2BSC[_Rs_]();
942}
943
944void psxHLE() {
945// psxHLEt[psxRegs.code & 0xffff]();
dd79da89 946// psxHLEt[psxRegs.code & 0x07](); // HDHOSHY experimental patch
947 uint32_t hleCode = psxRegs.code & 0x03ffffff;
948 if (hleCode >= (sizeof(psxHLEt) / sizeof(psxHLEt[0]))) {
949 psxNULL();
950 } else {
951 psxHLEt[hleCode]();
952 }
ef79bbde
P
953}
954
955void (*psxBSC[64])() = {
956 psxSPECIAL, psxREGIMM, psxJ , psxJAL , psxBEQ , psxBNE , psxBLEZ, psxBGTZ,
957 psxADDI , psxADDIU , psxSLTI, psxSLTIU, psxANDI, psxORI , psxXORI, psxLUI ,
958 psxCOP0 , psxNULL , psxCOP2, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL,
959 psxNULL , psxNULL , psxNULL, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL,
960 psxLB , psxLH , psxLWL , psxLW , psxLBU , psxLHU , psxLWR , psxNULL,
961 psxSB , psxSH , psxSWL , psxSW , psxNULL, psxNULL, psxSWR , psxNULL,
962 psxNULL , psxNULL , gteLWC2, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL,
963 psxNULL , psxNULL , gteSWC2, psxHLE , psxNULL, psxNULL, psxNULL, psxNULL
964};
965
966
967void (*psxSPC[64])() = {
968 psxSLL , psxNULL , psxSRL , psxSRA , psxSLLV , psxNULL , psxSRLV, psxSRAV,
969 psxJR , psxJALR , psxNULL, psxNULL, psxSYSCALL, psxBREAK, psxNULL, psxNULL,
970 psxMFHI, psxMTHI , psxMFLO, psxMTLO, psxNULL , psxNULL , psxNULL, psxNULL,
971 psxMULT, psxMULTU, psxDIV , psxDIVU, psxNULL , psxNULL , psxNULL, psxNULL,
972 psxADD , psxADDU , psxSUB , psxSUBU, psxAND , psxOR , psxXOR , psxNOR ,
973 psxNULL, psxNULL , psxSLT , psxSLTU, psxNULL , psxNULL , psxNULL, psxNULL,
974 psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL,
975 psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL
976};
977
978void (*psxREG[32])() = {
979 psxBLTZ , psxBGEZ , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
980 psxNULL , psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
981 psxBLTZAL, psxBGEZAL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
982 psxNULL , psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL
983};
984
985void (*psxCP0[32])() = {
986 psxMFC0, psxNULL, psxCFC0, psxNULL, psxMTC0, psxNULL, psxCTC0, psxNULL,
987 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
988 psxRFE , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
989 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL
990};
991
6c0eefaf 992void (*psxCP2[64])(struct psxCP2Regs *regs) = {
ef79bbde
P
993 psxBASIC, gteRTPS , psxNULL , psxNULL, psxNULL, psxNULL , gteNCLIP, psxNULL, // 00
994 psxNULL , psxNULL , psxNULL , psxNULL, gteOP , psxNULL , psxNULL , psxNULL, // 08
995 gteDPCS , gteINTPL, gteMVMVA, gteNCDS, gteCDP , psxNULL , gteNCDT , psxNULL, // 10
996 psxNULL , psxNULL , psxNULL , gteNCCS, gteCC , psxNULL , gteNCS , psxNULL, // 18
997 gteNCT , psxNULL , psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, // 20
998 gteSQR , gteDCPL , gteDPCT , psxNULL, psxNULL, gteAVSZ3, gteAVSZ4, psxNULL, // 28
999 gteRTPT , psxNULL , psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, // 30
1000 psxNULL , psxNULL , psxNULL , psxNULL, psxNULL, gteGPF , gteGPL , gteNCCT // 38
1001};
1002
1003void (*psxCP2BSC[32])() = {
1004 gteMFC2, psxNULL, gteCFC2, psxNULL, gteMTC2, psxNULL, gteCTC2, psxNULL,
1005 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
1006 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
1007 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL
1008};
1009
1010
1011///////////////////////////////////////////
1012
1013static int intInit() {
943a507a 1014 #ifdef ICACHE_EMULATION
1015 /* We have to allocate the icache memory even if
1016 * the user has not enabled it as otherwise it can cause issues.
1017 */
1018 if (!ICache_Addr)
1019 {
1020 ICache_Addr = malloc(0x1000);
1021 if (!ICache_Addr)
1022 {
1023 return -1;
1024 }
1025 }
1026
1027 if (!ICache_Code)
1028 {
1029 ICache_Code = malloc(0x1000);
1030 if (!ICache_Code)
1031 {
1032 return -1;
1033 }
1034 }
1035 memset(ICache_Addr, 0xff, 0x1000);
1036 memset(ICache_Code, 0xff, 0x1000);
1037 #endif
ef79bbde
P
1038 return 0;
1039}
1040
1041static void intReset() {
943a507a 1042 #ifdef ICACHE_EMULATION
1043 memset(ICache_Addr, 0xff, 0x1000);
1044 memset(ICache_Code, 0xff, 0x1000);
1045 #endif
ef79bbde
P
1046}
1047
796a91ef 1048void intExecute() {
1049 extern int stop;
1050 for (;!stop;)
ef79bbde
P
1051 execI();
1052}
1053
796a91ef 1054void intExecuteBlock() {
ef79bbde
P
1055 branch2 = 0;
1056 while (!branch2) execI();
1057}
1058
1059static void intClear(u32 Addr, u32 Size) {
1060}
1061
943a507a 1062void intNotify (int note, void *data) {
1063 #ifdef ICACHE_EMULATION
1064 /* Gameblabla - Only clear the icache if it's isolated */
1065 if (note == R3000ACPU_NOTIFY_CACHE_ISOLATED)
1066 {
1067 memset(ICache_Addr, 0xff, 0x1000);
1068 memset(ICache_Code, 0xff, 0x1000);
1069 }
1070 #endif
1071}
1072
ef79bbde 1073static void intShutdown() {
943a507a 1074 #ifdef ICACHE_EMULATION
1075 if (ICache_Addr)
1076 {
1077 free(ICache_Addr);
1078 ICache_Addr = NULL;
1079 }
1080
1081 if (ICache_Code)
1082 {
1083 free(ICache_Code);
1084 ICache_Code = NULL;
1085 }
1086 #endif
ef79bbde
P
1087}
1088
1089// interpreter execution
4600ba03 1090void execI() {
943a507a 1091 u32 *code;
1092 #ifdef ICACHE_EMULATION
1093 if (Config.icache_emulation)
1094 {
1095 code = Read_ICache(psxRegs.pc);
1096 }
1097 else
1098 #endif
1099 {
1100 code = (u32 *)PSXM(psxRegs.pc);
1101 }
ef79bbde
P
1102 psxRegs.code = ((code == NULL) ? 0 : SWAP32(*code));
1103
1104 debugI();
1105
1106 if (Config.Debug) ProcessDebug();
1107
1108 psxRegs.pc += 4;
1109 psxRegs.cycle += BIAS;
1110
1111 psxBSC[psxRegs.code >> 26]();
1112}
1113
1114R3000Acpu psxInt = {
1115 intInit,
1116 intReset,
1117 intExecute,
1118 intExecuteBlock,
1119 intClear,
943a507a 1120#ifdef ICACHE_EMULATION
1121 intNotify,
1122#endif
ef79bbde
P
1123 intShutdown
1124};