RSP LLE plugin. Compile and run (slowly, eat 50% CPU) on the OpenPandora
[mupen64plus-pandora.git] / source / mupen64plus-rsp-z64 / src / rsp.h
CommitLineData
fc5d46b4 1/*
2 * z64
3 *
4 * Copyright (C) 2007 ziggy
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20**/
21
22#ifndef _RSP_H_
23#define _RSP_H_
24
25#define M64P_PLUGIN_PROTOTYPES 1
26#include "m64p_types.h"
27#include "m64p_plugin.h"
28#include "z64.h"
29#include <math.h> // sqrt
30#include <stdlib.h>
31#include <stdio.h>
32#include <string.h> // memset
33
34#define INLINE inline
35
36extern void log(m64p_msg_level level, const char *msg, ...);
37
38/* defined in systems/n64.c */
39#define rdram ((UINT32*)z64_rspinfo.RDRAM)
40//extern UINT32 *rdram;
41#define rsp_imem ((UINT32*)z64_rspinfo.IMEM)
42//extern UINT32 *rsp_imem;
43#define rsp_dmem ((UINT32*)z64_rspinfo.DMEM)
44//extern UINT32 *rsp_dmem;
45//extern void dp_full_sync(void);
46
47#define vi_origin (*(UINT32*)z64_rspinfo.VI_ORIGIN_REG)
48//extern UINT32 vi_origin;
49#define vi_width (*(UINT32*)z64_rspinfo.VI_WIDTH_REG)
50//extern UINT32 vi_width;
51#define vi_control (*(UINT32*)z64_rspinfo.VI_STATUS_REG)
52//extern UINT32 vi_control;
53
54#define dp_start (*(UINT32*)z64_rspinfo.DPC_START_REG)
55//extern UINT32 dp_start;
56#define dp_end (*(UINT32*)z64_rspinfo.DPC_END_REG)
57//extern UINT32 dp_end;
58#define dp_current (*(UINT32*)z64_rspinfo.DPC_CURRENT_REG)
59//extern UINT32 dp_current;
60#define dp_status (*(UINT32*)z64_rspinfo.DPC_STATUS_REG)
61//extern UINT32 dp_status;
62
63#define sp_pc (*(UINT32*)z64_rspinfo.SP_PC_REG)
64
65typedef union
66{
67 UINT64 d[2];
68 UINT32 l[4];
69 INT16 s[8];
70 UINT8 b[16];
71} VECTOR_REG;
72
73typedef union
74{
75 INT64 q;
76 INT32 l[2];
77 INT16 w[4];
78} ACCUMULATOR_REG;
79
80typedef struct
81{
82 // vectors first , need to be memory aligned for sse
83 VECTOR_REG v[32];
84 ACCUMULATOR_REG accum[8];
85
86 //UINT32 pc;
87 UINT32 r[32];
88 UINT16 flag[4];
89
90 INT32 square_root_res;
91 INT32 square_root_high;
92 INT32 reciprocal_res;
93 INT32 reciprocal_high;
94
95 UINT32 ppc;
96 UINT32 nextpc;
97
98 UINT32 step_count;
99
100 int inval_gen;
101
102 RSP_INFO ext;
103} RSP_REGS;
104
105#define z64_rspinfo (rsp.ext)
106
107int rsp_execute(int cycles);
108void rsp_reset(void);
109void rsp_init(RSP_INFO info);
110offs_t rsp_dasm_one(char *buffer, offs_t pc, UINT32 op);
111
112extern UINT32 sp_read_reg(UINT32 reg);
113extern void sp_write_reg(UINT32 reg, UINT32 data);
114// extern READ32_HANDLER( n64_dp_reg_r );
115// extern WRITE32_HANDLER( n64_dp_reg_w );
116
117#define RSREG ((op >> 21) & 0x1f)
118#define RTREG ((op >> 16) & 0x1f)
119#define RDREG ((op >> 11) & 0x1f)
120#define SHIFT ((op >> 6) & 0x1f)
121
122#define RSVAL (rsp.r[RSREG])
123#define RTVAL (rsp.r[RTREG])
124#define RDVAL (rsp.r[RDREG])
125
126#define _RSREG(op) ((op >> 21) & 0x1f)
127#define _RTREG(op) ((op >> 16) & 0x1f)
128#define _RDREG(op) ((op >> 11) & 0x1f)
129#define _SHIFT(op) ((op >> 6) & 0x1f)
130
131#define _RSVAL(op) (rsp.r[_RSREG(op)])
132#define _RTVAL(op) (rsp.r[_RTREG(op)])
133#define _RDVAL(op) (rsp.r[_RDREG(op)])
134
135#define SIMM16 ((INT32)(INT16)(op))
136#define UIMM16 ((UINT16)(op))
137#define UIMM26 (op & 0x03ffffff)
138
139#define _SIMM16(op) ((INT32)(INT16)(op))
140#define _UIMM16(op) ((UINT16)(op))
141#define _UIMM26(op) (op & 0x03ffffff)
142
143
144/*#define _JUMP(pc) \
145if ((GENTRACE("_JUMP %x\n", rsp.nextpc), 1) && rsp_jump(rsp.nextpc)) return 1; \
146if (rsp.inval_gen || sp_pc != pc+8) return 0;
147*/
148
149#define CARRY_FLAG(x) ((rsp.flag[0] & (1 << ((x)))) ? 1 : 0)
150#define CLEAR_CARRY_FLAGS() { rsp.flag[0] &= ~0xff; }
151#define SET_CARRY_FLAG(x) { rsp.flag[0] |= (1 << ((x))); }
152#define CLEAR_CARRY_FLAG(x) { rsp.flag[0] &= ~(1 << ((x))); }
153
154#define COMPARE_FLAG(x) ((rsp.flag[1] & (1 << ((x)))) ? 1 : 0)
155#define CLEAR_COMPARE_FLAGS() { rsp.flag[1] &= ~0xff; }
156#define SET_COMPARE_FLAG(x) { rsp.flag[1] |= (1 << ((x))); }
157#define CLEAR_COMPARE_FLAG(x) { rsp.flag[1] &= ~(1 << ((x))); }
158
159#define ZERO_FLAG(x) ((rsp.flag[0] & (1 << (8+(x)))) ? 1 : 0)
160#define CLEAR_ZERO_FLAGS() { rsp.flag[0] &= ~0xff00; }
161#define SET_ZERO_FLAG(x) { rsp.flag[0] |= (1 << (8+(x))); }
162#define CLEAR_ZERO_FLAG(x) { rsp.flag[0] &= ~(1 << (8+(x))); }
163
164//#define rsp z64_rsp // to avoid namespace collision with other libs
165extern RSP_REGS rsp __attribute__((aligned(16)));
166
167
168//#define ROPCODE(pc) cpu_readop32(pc)
169#define ROPCODE(pc) program_read_dword_32be(pc | 0x1000)
170
171INLINE UINT8 program_read_byte_32be(UINT32 address)
172{
173 return ((UINT8*)z64_rspinfo.DMEM)[(address&0x1fff)^3];
174}
175
176INLINE UINT16 program_read_word_32be(UINT32 address)
177{
178 return ((UINT16*)z64_rspinfo.DMEM)[((address&0x1fff)>>1)^1];
179}
180
181INLINE UINT32 program_read_dword_32be(UINT32 address)
182{
183 return ((UINT32*)z64_rspinfo.DMEM)[(address&0x1fff)>>2];
184}
185
186INLINE void program_write_byte_32be(UINT32 address, UINT8 data)
187{
188 ((UINT8*)z64_rspinfo.DMEM)[(address&0x1fff)^3] = data;
189}
190
191INLINE void program_write_word_32be(UINT32 address, UINT16 data)
192{
193 ((UINT16*)z64_rspinfo.DMEM)[((address&0x1fff)>>1)^1] = data;
194}
195
196INLINE void program_write_dword_32be(UINT32 address, UINT32 data)
197{
198 ((UINT32*)z64_rspinfo.DMEM)[(address&0x1fff)>>2] = data;
199}
200
201INLINE UINT8 READ8(UINT32 address)
202{
203 address = 0x04000000 | (address & 0xfff);
204 return program_read_byte_32be(address);
205}
206
207INLINE UINT16 READ16(UINT32 address)
208{
209 address = 0x04000000 | (address & 0xfff);
210
211 if (address & 1)
212 {
213 //osd_die("RSP: READ16: unaligned %08X at %08X\n", address, rsp.ppc);
214 return ((program_read_byte_32be(address+0) & 0xff) << 8) | (program_read_byte_32be(address+1) & 0xff);
215 }
216
217 return program_read_word_32be(address);
218}
219
220INLINE UINT32 READ32(UINT32 address)
221{
222 address = 0x04000000 | (address & 0xfff);
223
224 if (address & 3)
225 {
226 //fatalerror("RSP: READ32: unaligned %08X at %08X\n", address, rsp.ppc);
227 return ((program_read_byte_32be(address + 0) & 0xff) << 24) |
228 ((program_read_byte_32be(address + 1) & 0xff) << 16) |
229 ((program_read_byte_32be(address + 2) & 0xff) << 8) |
230 ((program_read_byte_32be(address + 3) & 0xff) << 0);
231 }
232
233 return program_read_dword_32be(address);
234}
235
236
237INLINE void WRITE8(UINT32 address, UINT8 data)
238{
239 address = 0x04000000 | (address & 0xfff);
240 program_write_byte_32be(address, data);
241}
242
243INLINE void WRITE16(UINT32 address, UINT16 data)
244{
245 address = 0x04000000 | (address & 0xfff);
246
247 if (address & 1)
248 {
249 //fatalerror("RSP: WRITE16: unaligned %08X, %04X at %08X\n", address, data, rsp.ppc);
250 program_write_byte_32be(address + 0, (data >> 8) & 0xff);
251 program_write_byte_32be(address + 1, (data >> 0) & 0xff);
252 return;
253 }
254
255 program_write_word_32be(address, data);
256}
257
258INLINE void WRITE32(UINT32 address, UINT32 data)
259{
260 address = 0x04000000 | (address & 0xfff);
261
262 if (address & 3)
263 {
264 //fatalerror("RSP: WRITE32: unaligned %08X, %08X at %08X\n", address, data, rsp.ppc);
265 program_write_byte_32be(address + 0, (data >> 24) & 0xff);
266 program_write_byte_32be(address + 1, (data >> 16) & 0xff);
267 program_write_byte_32be(address + 2, (data >> 8) & 0xff);
268 program_write_byte_32be(address + 3, (data >> 0) & 0xff);
269 return;
270 }
271
272 program_write_dword_32be(address, data);
273}
274
275int rsp_jump(int pc);
276void rsp_invalidate(int begin, int len);
277void rsp_execute_one(UINT32 op);
278
279
280
281#define JUMP_ABS(addr) { rsp.nextpc = 0x04001000 | (((addr) << 2) & 0xfff); }
282#define JUMP_ABS_L(addr,l) { rsp.nextpc = 0x04001000 | (((addr) << 2) & 0xfff); rsp.r[l] = sp_pc + 4; }
283#define JUMP_REL(offset) { rsp.nextpc = 0x04001000 | ((sp_pc + ((offset) << 2)) & 0xfff); }
284#define JUMP_REL_L(offset,l) { rsp.nextpc = 0x04001000 | ((sp_pc + ((offset) << 2)) & 0xfff); rsp.r[l] = sp_pc + 4; }
285#define JUMP_PC(addr) { rsp.nextpc = 0x04001000 | ((addr) & 0xfff); }
286#define JUMP_PC_L(addr,l) { rsp.nextpc = 0x04001000 | ((addr) & 0xfff); rsp.r[l] = sp_pc + 4; }
287#define LINK(l) rsp.r[l] = sp_pc + 4
288
289#define VDREG ((op >> 6) & 0x1f)
290#define VS1REG ((op >> 11) & 0x1f)
291#define VS2REG ((op >> 16) & 0x1f)
292#define EL ((op >> 21) & 0xf)
293
294#define VREG_B(reg, offset) rsp.v[(reg)].b[((offset)^1)]
295#define VREG_S(reg, offset) rsp.v[(reg)].s[((offset))]
296#define VREG_L(reg, offset) rsp.v[(reg)].l[((offset))]
297
298#define VEC_EL_1(x,z) (z) //(vector_elements_1[(x)][(z)])
299#define VEC_EL_2(x,z) (vector_elements_2[(x)][(z)])
300
301#define ACCUM(x) rsp.accum[((x))].q
302#define ACCUM_H(x) rsp.accum[((x))].w[3]
303#define ACCUM_M(x) rsp.accum[((x))].w[2]
304#define ACCUM_L(x) rsp.accum[((x))].w[1]
305
306void unimplemented_opcode(UINT32 op);
307void handle_vector_ops(UINT32 op);
308UINT32 get_cop0_reg(int reg);
309void set_cop0_reg(int reg, UINT32 data);
310void handle_lwc2(UINT32 op);
311void handle_swc2(UINT32 op);
312
313INLINE UINT32 n64_dp_reg_r(UINT32 offset, UINT32 dummy)
314{
315 switch (offset)
316 {
317 case 0x00/4: // DP_START_REG
318 return dp_start;
319
320 case 0x04/4: // DP_END_REG
321 return dp_end;
322
323 case 0x08/4: // DP_CURRENT_REG
324 return dp_current;
325
326 case 0x0c/4: // DP_STATUS_REG
327 return dp_status;
328
329 case 0x10/4: // DP_CLOCK_REG
330 return *z64_rspinfo.DPC_CLOCK_REG;
331
332 default:
333 log(M64MSG_WARNING, "dp_reg_r: %08X\n", offset);
334 break;
335 }
336
337 return 0;
338}
339INLINE void n64_dp_reg_w(UINT32 offset, UINT32 data, UINT32 dummy)
340{
341 switch (offset)
342 {
343 case 0x00/4: // DP_START_REG
344 dp_start = data;
345 dp_current = dp_start;
346 break;
347
348 case 0x04/4: // DP_END_REG
349 dp_end = data;
350 //rdp_process_list();
351 if (dp_end<dp_start)//three lines for debugging
352 {
353 log(M64MSG_INFO, "RDP End < RDP Start!");//happens in Stunt Racer with Ville Linde's sp_dma
354 break;
355 }
356 if (dp_end==dp_start)
357 break;
358 if (z64_rspinfo.ProcessRdpList != NULL) { z64_rspinfo.ProcessRdpList(); }
359 break;
360
361 case 0x0c/4: // DP_STATUS_REG
362 if (data & 0x00000001) dp_status &= ~DP_STATUS_XBUS_DMA;
363 if (data & 0x00000002) dp_status |= DP_STATUS_XBUS_DMA;
364 if (data & 0x00000004) dp_status &= ~DP_STATUS_FREEZE;
365 if (data & 0x00000008) dp_status |= DP_STATUS_FREEZE;
366 if (data & 0x00000010) dp_status &= ~DP_STATUS_FLUSH;
367 if (data & 0x00000020) dp_status |= DP_STATUS_FLUSH;
368 break;
369
370 default:
371 log(M64MSG_WARNING, "dp_reg_w: %08X, %08X\n", data, offset);
372 break;
373 }
374}
375
376#define INTEL86
377#if defined(INTEL86) && defined __GNUC__ && __GNUC__ >= 2
378static __inline__ unsigned long long RDTSC(void)
379{
380 unsigned long long int x;
381 __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
382 return x;
383}
384// inline volatile uint64_t RDTSC() {
385// register uint64_t TSC asm("eax");
386// asm volatile (".byte 15, 49" : : : "eax", "edx");
387// return TSC;
388// }
389// #define RDTSC1(n) __asm__ __volatile__("rdtsc" : "=a" (n): )
390// #define RDTSC2(n) __asm__ __volatile__ ("rdtsc\nmov %%edx,%%eax" : "=a" (n): )
391// inline void RDTSC(uint64_t& a) { uint32_t b, c; RDTSC1(b); RDTSC2(c);
392// a = (((uint64_t)c)<<32) | b; }
393#elif defined(INTEL86) && defined WIN32
394#define rdtsc __asm __emit 0fh __asm __emit 031h
395#define cpuid __asm __emit 0fh __asm __emit 0a2h
396inline uint64_t RDTSC() {
397 static uint32_t temp;
398 __asm {
399 push edx
400 push eax
401 rdtsc
402 mov temp, eax
403 pop eax
404 pop edx
405 }
406 return temp;
407}
408#else
409#define RDTSC(n) n=0
410#endif
411
412#ifdef GENTRACE
413#undef GENTRACE
414#include <stdarg.h>
415inline void GENTRACE(const char * s, ...) {
416 va_list ap;
417 va_start(ap, s);
418 vfprintf(stderr, s, ap);
419 va_end(ap);
420 int i;
421 for (i=0; i<32; i++)
422 fprintf(stderr, "r%d=%x ", i, rsp.r[i]);
423 fprintf(stderr, "\n");
424 for (i=0; i<32; i++)
425 fprintf(stderr, "v%d=%x %x %x %x %x %x %x %x ", i,
426 (UINT16)rsp.v[i].s[0],
427 (UINT16)rsp.v[i].s[1],
428 (UINT16)rsp.v[i].s[2],
429 (UINT16)rsp.v[i].s[3],
430 (UINT16)rsp.v[i].s[4],
431 (UINT16)rsp.v[i].s[5],
432 (UINT16)rsp.v[i].s[6],
433 (UINT16)rsp.v[i].s[7]
434 );
435 fprintf(stderr, "\n");
436
437 fprintf(stderr, "f0=%x f1=%x f2=%x f3=%x\n", rsp.flag[0],
438 rsp.flag[1],rsp.flag[2],rsp.flag[3]);
439}
440#endif
441//#define GENTRACE printf
442//#define GENTRACE
443
444#ifdef RSPTIMING
445extern uint64_t rsptimings[512];
446extern int rspcounts[512];
447#endif
448
449#endif // ifndef _RSP_H_