fbf0c6d374d8b0da7a83231b87fc00ad55ae8bc4
[picodrive.git] / cpu / sh2 / sh2.c
1 /*
2  * PicoDrive
3  * (C) notaz, 2009,2010
4  *
5  * This work is licensed under the terms of MAME license.
6  * See COPYING file in the top-level directory.
7  */
8 #include <string.h>
9 #include <stddef.h>
10
11 #include "sh2.h"
12 #include "../debug.h"
13 #include "compiler.h"
14
15 #define I 0xf0
16
17 int sh2_init(SH2 *sh2, int is_slave)
18 {
19         int ret = 0;
20
21         memset(sh2, 0, offsetof(SH2, mult_m68k_to_sh2));
22         sh2->is_slave = is_slave;
23         pdb_register_cpu(sh2, PDBCT_SH2, is_slave ? "ssh2" : "msh2");
24 #ifdef DRC_SH2
25         ret = sh2_drc_init(sh2);
26 #endif
27         return ret;
28 }
29
30 void sh2_finish(SH2 *sh2)
31 {
32 #ifdef DRC_SH2
33         sh2_drc_finish(sh2);
34 #endif
35 }
36
37 void sh2_reset(SH2 *sh2)
38 {
39         sh2->pc = p32x_sh2_read32(0, sh2);
40         sh2->r[15] = p32x_sh2_read32(4, sh2);
41         sh2->sr = I;
42         sh2->vbr = 0;
43         sh2->pending_int_irq = 0;
44 }
45
46 void sh2_do_irq(SH2 *sh2, int level, int vector)
47 {
48         sh2->sr &= 0x3f3;
49
50         sh2->r[15] -= 4;
51         p32x_sh2_write32(sh2->r[15], sh2->sr, sh2);     /* push SR onto stack */
52         sh2->r[15] -= 4;
53         p32x_sh2_write32(sh2->r[15], sh2->pc, sh2);     /* push PC onto stack */
54
55         /* set I flags in SR */
56         sh2->sr = (sh2->sr & ~I) | (level << 4);
57
58         /* fetch PC */
59         sh2->pc = p32x_sh2_read32(sh2->vbr + vector * 4, sh2);
60
61         /* 13 cycles at best */
62         sh2->icount -= 13;
63 }
64
65 int sh2_irl_irq(SH2 *sh2, int level, int nested_call)
66 {
67         int taken;
68
69         sh2->pending_irl = level;
70         if (level < sh2->pending_int_irq)
71                 level = sh2->pending_int_irq;
72         sh2->pending_level = level;
73
74         taken = (level > ((sh2->sr >> 4) & 0x0f));
75         if (taken) {
76                 if (!nested_call) {
77                         // not in memhandler, so handle this now (recompiler friendly)
78                         // do this to avoid missing irqs that other SH2 might clear
79                         int vector = sh2->irq_callback(sh2, level);
80                         sh2_do_irq(sh2, level, vector);
81                         sh2->m68krcycles_done += C_SH2_TO_M68K(*sh2, 13);
82                 }
83                 else
84                         sh2->test_irq = 1;
85         }
86         return taken;
87 }
88
89 void sh2_internal_irq(SH2 *sh2, int level, int vector)
90 {
91         // FIXME: multiple internal irqs not handled..
92         // assuming internal irqs never clear until accepted
93         sh2->pending_int_irq = level;
94         sh2->pending_int_vector = vector;
95         if (level > sh2->pending_level)
96                 sh2->pending_level = level;
97
98         sh2->test_irq = 1;
99 }
100
101 #define SH2_REG_SIZE (offsetof(SH2, macl) + sizeof(sh2->macl))
102
103 void sh2_pack(const SH2 *sh2, unsigned char *buff)
104 {
105         unsigned int *p;
106
107         memcpy(buff, sh2, SH2_REG_SIZE);
108         p = (void *)(buff + SH2_REG_SIZE);
109
110         p[0] = sh2->pending_int_irq;
111         p[1] = sh2->pending_int_vector;
112 }
113
114 void sh2_unpack(SH2 *sh2, const unsigned char *buff)
115 {
116         unsigned int *p;
117
118         memcpy(sh2, buff, SH2_REG_SIZE);
119         p = (void *)(buff + SH2_REG_SIZE);
120
121         sh2->pending_int_irq = p[0];
122         sh2->pending_int_vector = p[1];
123         sh2->test_irq = 1;
124 }
125
126 #ifdef DRC_CMP
127
128 /* trace/compare */
129 #include <stdio.h>
130 #include <stdlib.h>
131 #include <pico/memory.h>
132 #undef _USE_CZ80 // HACK
133 #include <pico/pico_int.h>
134 #include <pico/debug.h>
135
136 static SH2 sh2ref[2];
137 static unsigned int mem_val;
138 static FILE *f;
139
140 enum ctl_byte {
141         CTL_MASTERSLAVE = 0x80,
142         CTL_EA = 0x82,
143         CTL_EAVAL = 0x83,
144         CTL_M68KPC = 0x84,
145         CTL_CYCLES = 0x85,
146 };
147
148 #define SH2MAP_ADDR2OFFS_R(a) \
149   ((((a) >> 25) & 3) | (((a) >> 27) & 0x1c))
150
151 static unsigned int local_read32(SH2 *sh2, u32 a)
152 {
153         const sh2_memmap *sh2_map = sh2->read16_map;
154         u16 *pd;
155         uptr p;
156
157         sh2_map += SH2MAP_ADDR2OFFS_R(a);
158         p = sh2_map->addr;
159         if (!map_flag_set(p)) {
160                 pd = (u16 *)((p << 1) + ((a & sh2_map->mask) & ~1));
161                 return (pd[0] << 16) | pd[1];
162         }
163
164         if ((a & 0xfffff000) == 0xc0000000) {
165                 // data array
166                 pd = (u16 *)Pico32xMem->data_array[sh2->is_slave]
167                         + (a & 0xfff) / 2;
168                 return (pd[0] << 16) | pd[1];
169         }
170         if ((a & 0xdfffffc0) == 0x4000) {
171                 pd = &Pico32x.regs[(a & 0x3f) / 2];
172                 return (pd[0] << 16) | pd[1];
173         }
174         if ((a & 0xdffffe00) == 0x4200) {
175                 pd = &Pico32xMem->pal[(a & 0x1ff) / 2];
176                 return (pd[0] << 16) | pd[1];
177         }
178
179         return 0;
180 }
181
182 static void write_uint(unsigned char ctl, unsigned int v)
183 {
184         fwrite(&ctl, 1, 1, f);
185         fwrite(&v, sizeof(v), 1, f);
186 }
187
188 void do_sh2_trace(SH2 *current, int cycles)
189 {
190         static int current_slave = -1;
191         static u32 current_m68k_pc;
192         SH2 *sh2o = &sh2ref[current->is_slave];
193         u32 *regs_a = (void *)current;
194         u32 *regs_o = (void *)sh2o;
195         unsigned char v;
196         u32 val;
197         int i;
198
199         if (f == NULL)
200                 f = fopen("tracelog", "wb");
201
202         if (SekPc != current_m68k_pc) {
203                 current_m68k_pc = SekPc;
204                 write_uint(CTL_M68KPC, current_m68k_pc);
205         }
206
207         if (current->is_slave != current_slave) {
208                 current_slave = current->is_slave;
209                 v = CTL_MASTERSLAVE | current->is_slave;
210                 fwrite(&v, 1, 1, f);
211         }
212
213         for (i = 0; i < offsetof(SH2, read8_map) / 4; i++) {
214                 if (i == 17) // ppc
215                         continue;
216                 if (regs_a[i] != regs_o[i]) {
217                         write_uint(i, regs_a[i]);
218                         regs_o[i] = regs_a[i];
219                 }
220         }
221
222         if (current->ea != sh2o->ea) {
223                 write_uint(CTL_EA, current->ea);
224                 sh2o->ea = current->ea;
225         }
226         val = local_read32(current, current->ea);
227         if (mem_val != val) {
228                 write_uint(CTL_EAVAL, val);
229                 mem_val = val;
230         }
231         write_uint(CTL_CYCLES, cycles);
232 }
233
234 static const char *regnames[] = {
235         "r0",  "r1",  "r2",  "r3",
236         "r4",  "r5",  "r6",  "r7",
237         "r8",  "r9",  "r10", "r11",
238         "r12", "r13", "r14", "r15",
239         "pc",  "ppc", "pr",  "sr",
240         "gbr", "vbr", "mach","macl",
241 };
242
243 static void dump_regs(SH2 *sh2)
244 {
245         char csh2;
246         int i;
247
248         csh2 = sh2->is_slave ? 's' : 'm';
249         for (i = 0; i < 16/2; i++)
250                 printf("%csh2 r%d: %08x r%02d: %08x\n", csh2,
251                         i, sh2->r[i], i+8, sh2->r[i+8]);
252         printf("%csh2 PC: %08x  ,   %08x\n", csh2, sh2->pc, sh2->ppc);
253         printf("%csh2 SR:      %03x  PR: %08x\n", csh2, sh2->sr, sh2->pr);
254 }
255
256 void do_sh2_cmp(SH2 *current)
257 {
258         static int current_slave;
259         static u32 current_val;
260         SH2 *sh2o = &sh2ref[current->is_slave];
261         u32 *regs_a = (void *)current;
262         u32 *regs_o = (void *)sh2o;
263         unsigned char code;
264         int cycles_o = 666;
265         u32 sr, val;
266         int bad = 0;
267         int cycles;
268         int i, ret;
269
270         if (f == NULL) {
271                 f = fopen("tracelog", "rb");
272                 sh2ref[1].is_slave = 1;
273         }
274
275         while (1) {
276                 ret = fread(&code, 1, 1, f);
277                 if (ret <= 0)
278                         break;
279                 if (code == CTL_CYCLES) {
280                         fread(&cycles_o, 1, 4, f);
281                         break;
282                 }
283
284                 switch (code) {
285                 case CTL_MASTERSLAVE:
286                 case CTL_MASTERSLAVE + 1:
287                         current_slave = code & 1;
288                         break;
289                 case CTL_EA:
290                         fread(&sh2o->ea, 4, 1, f);
291                         break;
292                 case CTL_EAVAL:
293                         fread(&current_val, 4, 1, f);
294                         break;
295                 case CTL_M68KPC:
296                         fread(&val, 4, 1, f);
297                         if (SekPc != val) {
298                                 printf("m68k: %08x %08x\n", SekPc, val);
299                                 bad = 1;
300                         }
301                         break;
302                 default:
303                         if (code < offsetof(SH2, read8_map) / 4)
304                                 fread(regs_o + code, 4, 1, f);
305                         else {
306                                 printf("invalid code: %02x\n", code);
307                                 goto end;
308                         }
309                         break;
310                 }
311         }
312
313         if (ret <= 0) {
314                 printf("EOF?\n");
315                 goto end;
316         }
317
318         if (current->is_slave != current_slave) {
319                 printf("bad slave: %d %d\n", current->is_slave,
320                         current_slave);
321                 bad = 1;
322         }
323
324         for (i = 0; i < offsetof(SH2, read8_map) / 4; i++) {
325                 if (i == 17 || i == 19) // ppc, sr
326                         continue;
327                 if (regs_a[i] != regs_o[i]) {
328                         printf("bad %4s: %08x %08x\n",
329                                 regnames[i], regs_a[i], regs_o[i]);
330                         bad = 1;
331                 }
332         }
333
334         sr = current->sr & 0x3f3;
335         cycles = (signed int)current->sr >> 12;
336
337         if (sr != sh2o->sr) {
338                 printf("bad SR:  %03x %03x\n", sr, sh2o->sr);
339                 bad = 1;
340         }
341
342         if (cycles != cycles_o) {
343                 printf("bad cycles: %d %d\n", cycles, cycles_o);
344                 bad = 1;
345         }
346
347         val = local_read32(current, sh2o->ea);
348         if (val != current_val) {
349                 printf("bad val @%08x: %08x %08x\n", sh2o->ea, val, current_val);
350                 bad = 1;
351         }
352
353         if (!bad) {
354                 sh2o->ppc = current->pc;
355                 return;
356         }
357
358 end:
359         printf("--\n");
360         dump_regs(sh2o);
361         if (current->is_slave != current_slave)
362                 dump_regs(&sh2ref[current->is_slave ^ 1]);
363         PDebugDumpMem();
364         exit(1);
365 }
366
367 #endif // DRC_CMP