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 | |
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_ |