RSP LLE plugin. Compile and run (slowly, eat 50% CPU) on the OpenPandora
[mupen64plus-pandora.git] / source / mupen64plus-rsp-z64 / src / rsp.h
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
36 extern 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
65 typedef union
66 {
67     UINT64 d[2];
68     UINT32 l[4];
69     INT16 s[8];
70     UINT8 b[16];
71 } VECTOR_REG;
72
73 typedef union
74 {
75     INT64 q;
76     INT32 l[2];
77     INT16 w[4];
78 } ACCUMULATOR_REG;
79
80 typedef 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
107 int rsp_execute(int cycles);
108 void rsp_reset(void);
109 void rsp_init(RSP_INFO info);
110 offs_t rsp_dasm_one(char *buffer, offs_t pc, UINT32 op);
111
112 extern UINT32 sp_read_reg(UINT32 reg);
113 extern 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) \
145 if ((GENTRACE("_JUMP %x\n", rsp.nextpc), 1) && rsp_jump(rsp.nextpc)) return 1; \
146 if (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
165 extern 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
171 INLINE UINT8 program_read_byte_32be(UINT32 address)
172 {
173     return ((UINT8*)z64_rspinfo.DMEM)[(address&0x1fff)^3];
174 }
175
176 INLINE UINT16 program_read_word_32be(UINT32 address)
177 {
178     return ((UINT16*)z64_rspinfo.DMEM)[((address&0x1fff)>>1)^1];
179 }
180
181 INLINE UINT32 program_read_dword_32be(UINT32 address)
182 {
183     return ((UINT32*)z64_rspinfo.DMEM)[(address&0x1fff)>>2];
184 }
185
186 INLINE void program_write_byte_32be(UINT32 address, UINT8 data)
187 {
188     ((UINT8*)z64_rspinfo.DMEM)[(address&0x1fff)^3] = data;
189 }
190
191 INLINE void program_write_word_32be(UINT32 address, UINT16 data)
192 {
193     ((UINT16*)z64_rspinfo.DMEM)[((address&0x1fff)>>1)^1] = data;
194 }
195
196 INLINE void program_write_dword_32be(UINT32 address, UINT32 data)
197 {
198     ((UINT32*)z64_rspinfo.DMEM)[(address&0x1fff)>>2] = data;
199 }
200
201 INLINE UINT8 READ8(UINT32 address)
202 {
203     address = 0x04000000 | (address & 0xfff);
204     return program_read_byte_32be(address);
205 }
206
207 INLINE 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
220 INLINE 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
237 INLINE void WRITE8(UINT32 address, UINT8 data)
238 {
239     address = 0x04000000 | (address & 0xfff);
240     program_write_byte_32be(address, data);
241 }
242
243 INLINE 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
258 INLINE 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
275 int rsp_jump(int pc);
276 void rsp_invalidate(int begin, int len);
277 void 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
306 void unimplemented_opcode(UINT32 op);
307 void handle_vector_ops(UINT32 op);
308 UINT32 get_cop0_reg(int reg);
309 void set_cop0_reg(int reg, UINT32 data);
310 void handle_lwc2(UINT32 op);
311 void handle_swc2(UINT32 op);
312
313 INLINE 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 }
339 INLINE 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
378 static __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
396 inline 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>
415 inline 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
445 extern uint64_t rsptimings[512];
446 extern int rspcounts[512];
447 #endif
448
449 #endif // ifndef _RSP_H_