32x: drc: bugfix
[picodrive.git] / pico / 32x / memory.c
CommitLineData
83ff19ec 1/*
bcf65fd6 2 * SH2 addr lines:
3 * iii. .cc. ..xx * // Internal, Cs, x
4 *
83ff19ec 5 * Register map:
6 * a15100 F....... R.....EA F.....AC N...VHMP 4000 // Fm Ren nrEs Aden Cart heN V H cMd Pwm
7 * a15102 ........ ......SM ? 4002 // intS intM
8 * a15104 ........ ......10 ........ hhhhhhhh 4004 // bk1 bk0 Hint
9 * a15106 F....... .....SDR UE...... .....SDR 4006 // Full 68S Dma Rv fUll[fb] Empt[fb]
10 * a15108 (32bit DREQ src) 4008
11 * a1510c (32bit DREQ dst) 400c
12 * a15110 llllllll llllll00 4010 // DREQ Len
13 * a15112 (16bit FIFO reg) 4012
14 * a15114 ? (16bit VRES clr) 4014
15 * a15116 ? (16bit Vint clr) 4016
16 * a15118 ? (16bit Hint clr) 4018
17 * a1511a ........ .......C (16bit CMD clr) 401a // Cm
18 * a1511c ? (16bit PWM clr) 401c
19 * a1511e ? ? 401e
20 * a15120 (16 bytes comm) 2020
21 * a15130 (PWM) 2030
22 */
be2c4208 23#include "../pico_int.h"
24#include "../memory.h"
25
236990cf 26#if 0
c987bb5c 27#undef ash2_end_run
28#undef SekEndRun
29#define ash2_end_run(x)
30#define SekEndRun(x)
31#endif
32
be2c4208 33static const char str_mars[] = "MARS";
34
83ff19ec 35void *p32x_bios_g, *p32x_bios_m, *p32x_bios_s;
974fdb5b 36struct Pico32xMem *Pico32xMem;
37
5e49c3a8 38static void bank_switch(int b);
39
266c6afa 40// poll detection
4ea707e1 41#define POLL_THRESHOLD 6
42
266c6afa 43struct poll_det {
be20816c 44 u32 addr, cycles, cyc_max;
45 int cnt, flag;
266c6afa 46};
b78efee2 47static struct poll_det m68k_poll, sh2_poll[2];
266c6afa 48
be20816c 49static int p32x_poll_detect(struct poll_det *pd, u32 a, u32 cycles, int is_vdp)
266c6afa 50{
b78efee2 51 int ret = 0, flag = pd->flag;
52
53 if (is_vdp)
54 flag <<= 3;
266c6afa 55
1d7a28a7 56 if (a - 2 <= pd->addr && pd->addr <= a + 2 && cycles - pd->cycles <= pd->cyc_max) {
266c6afa 57 pd->cnt++;
58 if (pd->cnt > POLL_THRESHOLD) {
59 if (!(Pico32x.emu_flags & flag)) {
be20816c 60 elprintf(EL_32X, "%s poll addr %08x, cyc %u",
61 flag & (P32XF_68KPOLL|P32XF_68KVPOLL) ? "m68k" :
62 (flag & (P32XF_MSH2POLL|P32XF_MSH2VPOLL) ? "msh2" : "ssh2"), a, cycles - pd->cycles);
266c6afa 63 ret = 1;
64 }
65 Pico32x.emu_flags |= flag;
66 }
67 }
c987bb5c 68 else {
266c6afa 69 pd->cnt = 0;
c987bb5c 70 pd->addr = a;
71 }
be20816c 72 pd->cycles = cycles;
266c6afa 73
74 return ret;
75}
76
b78efee2 77static int p32x_poll_undetect(struct poll_det *pd, int is_vdp)
266c6afa 78{
b78efee2 79 int ret = 0, flag = pd->flag;
80 if (is_vdp)
be20816c 81 flag <<= 3; // VDP only
82 else
83 flag |= flag << 3; // both
84 if (Pico32x.emu_flags & flag) {
85 elprintf(EL_32X, "poll %02x -> %02x", Pico32x.emu_flags, Pico32x.emu_flags & ~flag);
266c6afa 86 ret = 1;
be20816c 87 }
266c6afa 88 Pico32x.emu_flags &= ~flag;
be20816c 89 pd->addr = pd->cnt = 0;
266c6afa 90 return ret;
91}
92
87accdf7 93void p32x_poll_event(int cpu_mask, int is_vdp)
4ea707e1 94{
87accdf7 95 if (cpu_mask & 1)
96 p32x_poll_undetect(&sh2_poll[0], is_vdp);
97 if (cpu_mask & 2)
98 p32x_poll_undetect(&sh2_poll[1], is_vdp);
4ea707e1 99}
100
974fdb5b 101// SH2 faking
b78efee2 102//#define FAKE_SH2
acd35d4c 103int p32x_csum_faked;
104#ifdef FAKE_SH2
974fdb5b 105static const u16 comm_fakevals[] = {
106 0x4d5f, 0x4f4b, // M_OK
107 0x535f, 0x4f4b, // S_OK
5e49c3a8 108 0x4D41, 0x5346, // MASF - Brutal Unleashed
109 0x5331, 0x4d31, // Darxide
110 0x5332, 0x4d32,
111 0x5333, 0x4d33,
112 0x0000, 0x0000, // eq for doom
974fdb5b 113 0x0002, // Mortal Kombat
acd35d4c 114// 0, // pad
be2c4208 115};
acd35d4c 116
117static u32 sh2_comm_faker(u32 a)
118{
119 static int f = 0;
120 if (a == 0x28 && !p32x_csum_faked) {
121 p32x_csum_faked = 1;
122 return *(unsigned short *)(Pico.rom + 0x18e);
123 }
124 if (f >= sizeof(comm_fakevals) / sizeof(comm_fakevals[0]))
125 f = 0;
126 return comm_fakevals[f++];
127}
128#endif
be2c4208 129
4ea707e1 130// DMAC handling
131static struct {
132 unsigned int sar0, dar0, tcr0; // src addr, dst addr, transfer count
133 unsigned int chcr0; // chan ctl
134 unsigned int sar1, dar1, tcr1; // same for chan 1
135 unsigned int chcr1;
136 int pad[4];
137 unsigned int dmaor;
138} * dmac0;
139
140static void dma_68k2sh2_do(void)
141{
142 unsigned short *dreqlen = &Pico32x.regs[0x10 / 2];
143 int i;
144
145 if (dmac0->tcr0 != *dreqlen)
146 elprintf(EL_32X|EL_ANOMALY, "tcr0 and dreq len differ: %d != %d", dmac0->tcr0, *dreqlen);
147
1b3f5844 148 // HACK: assume bus is busy and SH2 is halted
149 // XXX: use different mechanism for this, not poll det
150 Pico32x.emu_flags |= P32XF_MSH2POLL; // id ? P32XF_SSH2POLL : P32XF_MSH2POLL;
151
4ea707e1 152 for (i = 0; i < Pico32x.dmac_ptr && dmac0->tcr0 > 0; i++) {
bcf65fd6 153 elprintf(EL_32X, "dmaw [%08x] %04x, left %d", dmac0->dar0, Pico32x.dmac_fifo[i], *dreqlen);
154 p32x_sh2_write16(dmac0->dar0, Pico32x.dmac_fifo[i], &msh2);
4ea707e1 155 dmac0->dar0 += 2;
156 dmac0->tcr0--;
157 (*dreqlen)--;
158 }
159
160 Pico32x.dmac_ptr = 0; // HACK
161 Pico32x.regs[6 / 2] &= ~P32XS_FULL;
162 if (*dreqlen == 0)
163 Pico32x.regs[6 / 2] &= ~P32XS_68S; // transfer complete
be20816c 164 if (dmac0->tcr0 == 0) {
4ea707e1 165 dmac0->chcr0 |= 2; // DMA has ended normally
be20816c 166 p32x_poll_undetect(&sh2_poll[0], 0);
167 }
4ea707e1 168}
169
170// ------------------------------------------------------------------
b78efee2 171// 68k regs
4ea707e1 172
be2c4208 173static u32 p32x_reg_read16(u32 a)
174{
175 a &= 0x3e;
176
87accdf7 177 if (a == 2) // INTM, INTS
178 return ((Pico32x.sh2irqi[0] & P32XI_CMD) >> 4) | ((Pico32x.sh2irqi[1] & P32XI_CMD) >> 3);
3cf9570b 179#if 0
974fdb5b 180 if ((a & 0x30) == 0x20)
acd35d4c 181 return sh2_comm_faker(a);
266c6afa 182#else
5fadfb1c 183 if ((a & 0x30) == 0x20) {
184 // evil X-Men proto polls in a dbra loop and expects it to expire..
185 static u32 dr2 = 0;
186 if (SekDar(2) != dr2)
187 m68k_poll.cnt = 0;
188 dr2 = SekDar(2);
189
190 if (p32x_poll_detect(&m68k_poll, a, SekCyclesDoneT(), 0)) {
191 SekSetStop(1);
192 SekEndTimeslice(16);
193 }
194 dr2 = SekDar(2);
266c6afa 195 }
acd35d4c 196#endif
87accdf7 197
db1d3564 198 if ((a & 0x30) == 0x30)
199 return p32x_pwm_read16(a);
974fdb5b 200
be2c4208 201 return Pico32x.regs[a / 2];
202}
203
be2c4208 204static void p32x_reg_write8(u32 a, u32 d)
205{
acd35d4c 206 u16 *r = Pico32x.regs;
be2c4208 207 a &= 0x3f;
208
97d3f47f 209 // for things like bset on comm port
210 m68k_poll.cnt = 0;
211
acd35d4c 212 switch (a) {
4ea707e1 213 case 0: // adapter ctl
83ff19ec 214 r[0] = (r[0] & ~P32XS_FM) | ((d << 8) & P32XS_FM);
215 return;
216 case 1: // adapter ctl, RES bit writeable
217 if ((d ^ r[0]) & d & P32XS_nRES)
218 p32x_reset_sh2s();
219 r[0] = (r[0] & ~P32XS_nRES) | (d & P32XS_nRES);
1b3f5844 220 return;
4ea707e1 221 case 3: // irq ctl
222 if ((d & 1) && !(Pico32x.sh2irqi[0] & P32XI_CMD)) {
223 Pico32x.sh2irqi[0] |= P32XI_CMD;
224 p32x_update_irls();
87accdf7 225 SekEndRun(16);
4ea707e1 226 }
b78efee2 227 if ((d & 2) && !(Pico32x.sh2irqi[1] & P32XI_CMD)) {
228 Pico32x.sh2irqi[1] |= P32XI_CMD;
229 p32x_update_irls();
87accdf7 230 SekEndRun(16);
b78efee2 231 }
1b3f5844 232 return;
4ea707e1 233 case 5: // bank
acd35d4c 234 d &= 7;
4ea707e1 235 if (r[4 / 2] != d) {
236 r[4 / 2] = d;
acd35d4c 237 bank_switch(d);
238 }
1b3f5844 239 return;
4ea707e1 240 case 7: // DREQ ctl
97d3f47f 241 r[6 / 2] = (r[6 / 2] & P32XS_FULL) | (d & (P32XS_68S|P32XS_DMA|P32XS_RV));
1b3f5844 242 return;
87accdf7 243 case 0x1b: // TV
244 r[0x1a / 2] = d;
1b3f5844 245 return;
246 }
247
248 if ((a & 0x30) == 0x20) {
249 u8 *r8 = (u8 *)r;
250 r8[a ^ 1] = d;
236990cf 251 p32x_poll_undetect(&sh2_poll[0], 0);
252 p32x_poll_undetect(&sh2_poll[1], 0);
253 // if some SH2 is busy waiting, it needs to see the result ASAP
254 if (SekCyclesLeftNoMCD > 32)
255 SekEndRun(32);
1b3f5844 256 return;
5e49c3a8 257 }
258}
259
260static void p32x_reg_write16(u32 a, u32 d)
261{
acd35d4c 262 u16 *r = Pico32x.regs;
263 a &= 0x3e;
264
97d3f47f 265 // for things like bset on comm port
266 m68k_poll.cnt = 0;
267
acd35d4c 268 switch (a) {
4ea707e1 269 case 0x00: // adapter ctl
83ff19ec 270 if ((d ^ r[0]) & d & P32XS_nRES)
271 p32x_reset_sh2s();
272 r[0] = (r[0] & ~(P32XS_FM|P32XS_nRES)) | (d & (P32XS_FM|P32XS_nRES));
acd35d4c 273 return;
4ea707e1 274 case 0x10: // DREQ len
275 r[a / 2] = d & ~3;
276 return;
277 case 0x12: // FIFO reg
278 if (!(r[6 / 2] & P32XS_68S)) {
279 elprintf(EL_32X|EL_ANOMALY, "DREQ FIFO w16 without 68S?");
280 return;
281 }
282 if (Pico32x.dmac_ptr < DMAC_FIFO_LEN) {
283 Pico32x.dmac_fifo[Pico32x.dmac_ptr++] = d;
284 if ((Pico32x.dmac_ptr & 3) == 0 && (dmac0->chcr0 & 3) == 1 && (dmac0->dmaor & 1))
285 dma_68k2sh2_do();
286 if (Pico32x.dmac_ptr == DMAC_FIFO_LEN)
287 r[6 / 2] |= P32XS_FULL;
288 }
289 break;
acd35d4c 290 }
291
4ea707e1 292 // DREQ src, dst
293 if ((a & 0x38) == 0x08) {
294 r[a / 2] = d;
295 return;
296 }
297 // comm port
298 else if ((a & 0x30) == 0x20 && r[a / 2] != d) {
acd35d4c 299 r[a / 2] = d;
236990cf 300 p32x_poll_undetect(&sh2_poll[0], 0);
301 p32x_poll_undetect(&sh2_poll[1], 0);
302 // same as for w8
303 if (SekCyclesLeftNoMCD > 32)
304 SekEndRun(32);
acd35d4c 305 return;
306 }
db1d3564 307 // PWM
308 else if ((a & 0x30) == 0x30) {
309 p32x_pwm_write16(a, d);
310 return;
311 }
acd35d4c 312
5e49c3a8 313 p32x_reg_write8(a + 1, d);
be2c4208 314}
315
4ea707e1 316// ------------------------------------------------------------------
be2c4208 317// VDP regs
318static u32 p32x_vdp_read16(u32 a)
319{
320 a &= 0x0e;
321
322 return Pico32x.vdp_regs[a / 2];
323}
324
be2c4208 325static void p32x_vdp_write8(u32 a, u32 d)
326{
974fdb5b 327 u16 *r = Pico32x.vdp_regs;
be2c4208 328 a &= 0x0f;
329
4ea707e1 330 // for FEN checks between writes
b78efee2 331 sh2_poll[0].cnt = 0;
4ea707e1 332
974fdb5b 333 // TODO: verify what's writeable
be2c4208 334 switch (a) {
974fdb5b 335 case 0x01:
5e49c3a8 336 // priority inversion is handled in palette
337 if ((r[0] ^ d) & P32XV_PRI)
338 Pico32x.dirty_pal = 1;
974fdb5b 339 r[0] = (r[0] & P32XV_nPAL) | (d & 0xff);
be20816c 340 break;
341 case 0x05: // fill len
342 r[4 / 2] = d & 0xff;
974fdb5b 343 break;
be2c4208 344 case 0x0b:
974fdb5b 345 d &= 1;
346 Pico32x.pending_fb = d;
347 // if we are blanking and FS bit is changing
4ea707e1 348 if (((r[0x0a/2] & P32XV_VBLK) || (r[0] & P32XV_Mx) == 0) && ((r[0x0a/2] ^ d) & P32XV_FS)) {
974fdb5b 349 r[0x0a/2] ^= 1;
350 Pico32xSwapDRAM(d ^ 1);
266c6afa 351 elprintf(EL_32X, "VDP FS: %d", r[0x0a/2] & P32XV_FS);
be2c4208 352 }
353 break;
354 }
355}
356
974fdb5b 357static void p32x_vdp_write16(u32 a, u32 d)
358{
be20816c 359 a &= 0x0e;
360 if (a == 6) { // fill start
361 Pico32x.vdp_regs[6 / 2] = d;
362 return;
363 }
364 if (a == 8) { // fill data
365 u16 *dram = Pico32xMem->dram[(Pico32x.vdp_regs[0x0a/2] & P32XV_FS) ^ 1];
1b3f5844 366 int len = Pico32x.vdp_regs[4 / 2] + 1;
be20816c 367 a = Pico32x.vdp_regs[6 / 2];
368 while (len--) {
369 dram[a] = d;
370 a = (a & 0xff00) | ((a + 1) & 0xff);
371 }
372 Pico32x.vdp_regs[6 / 2] = a;
373 Pico32x.vdp_regs[8 / 2] = d;
374 return;
375 }
376
974fdb5b 377 p32x_vdp_write8(a | 1, d);
378}
379
4ea707e1 380// ------------------------------------------------------------------
acd35d4c 381// SH2 regs
b78efee2 382
383static u32 p32x_sh2reg_read16(u32 a, int cpuid)
acd35d4c 384{
4ea707e1 385 u16 *r = Pico32x.regs;
386 a &= 0xfe; // ?
266c6afa 387
4ea707e1 388 switch (a) {
389 case 0x00: // adapter/irq ctl
87accdf7 390 return (r[0] & P32XS_FM) | Pico32x.sh2_regs[0] | Pico32x.sh2irq_mask[cpuid];
c987bb5c 391 case 0x04: // H count (often as comm too)
392 if (p32x_poll_detect(&sh2_poll[cpuid], a, ash2_cycles_done(), 0))
393 ash2_end_run(8);
87accdf7 394 return Pico32x.sh2_regs[4 / 2];
4ea707e1 395 case 0x10: // DREQ len
396 return r[a / 2];
acd35d4c 397 }
4ea707e1 398
db1d3564 399 // DREQ src, dst
400 if ((a & 0x38) == 0x08)
4ea707e1 401 return r[a / 2];
db1d3564 402 // comm port
403 if ((a & 0x30) == 0x20) {
be20816c 404 if (p32x_poll_detect(&sh2_poll[cpuid], a, ash2_cycles_done(), 0))
db1d3564 405 ash2_end_run(8);
406 return r[a / 2];
407 }
408 if ((a & 0x30) == 0x30) {
409 sh2_poll[cpuid].cnt = 0;
410 return p32x_pwm_read16(a);
411 }
acd35d4c 412
413 return 0;
414}
415
b78efee2 416static void p32x_sh2reg_write8(u32 a, u32 d, int cpuid)
acd35d4c 417{
4ea707e1 418 a &= 0xff;
87accdf7 419 switch (a) {
420 case 0: // FM
421 Pico32x.regs[0] &= ~P32XS_FM;
422 Pico32x.regs[0] |= (d << 8) & P32XS_FM;
1b3f5844 423 return;
87accdf7 424 case 1: //
425 Pico32x.sh2irq_mask[cpuid] = d & 0x8f;
426 Pico32x.sh2_regs[0] &= ~0x80;
427 Pico32x.sh2_regs[0] |= d & 0x80;
428 p32x_update_irls();
1b3f5844 429 return;
87accdf7 430 case 5: // H count
431 Pico32x.sh2_regs[4 / 2] = d & 0xff;
c987bb5c 432 p32x_poll_undetect(&sh2_poll[cpuid ^ 1], 0);
1b3f5844 433 return;
434 }
435
436 if ((a & 0x30) == 0x20) {
437 u8 *r8 = (u8 *)Pico32x.regs;
438 r8[a ^ 1] = d;
5fadfb1c 439 if (p32x_poll_undetect(&m68k_poll, 0))
440 SekSetStop(0);
1b3f5844 441 p32x_poll_undetect(&sh2_poll[cpuid ^ 1], 0);
442 return;
4ea707e1 443 }
acd35d4c 444}
445
b78efee2 446static void p32x_sh2reg_write16(u32 a, u32 d, int cpuid)
acd35d4c 447{
4ea707e1 448 a &= 0xfe;
acd35d4c 449
db1d3564 450 // comm
4ea707e1 451 if ((a & 0x30) == 0x20 && Pico32x.regs[a/2] != d) {
b78efee2 452 Pico32x.regs[a / 2] = d;
5fadfb1c 453 if (p32x_poll_undetect(&m68k_poll, 0))
454 SekSetStop(0);
b78efee2 455 p32x_poll_undetect(&sh2_poll[cpuid ^ 1], 0);
acd35d4c 456 return;
457 }
db1d3564 458 // PWM
459 else if ((a & 0x30) == 0x30) {
460 p32x_pwm_write16(a, d);
461 return;
462 }
acd35d4c 463
4ea707e1 464 switch (a) {
87accdf7 465 case 0: // FM
466 Pico32x.regs[0] &= ~P32XS_FM;
467 Pico32x.regs[0] |= d & P32XS_FM;
468 break;
4ea707e1 469 case 0x14: Pico32x.sh2irqs &= ~P32XI_VRES; goto irls;
470 case 0x16: Pico32x.sh2irqs &= ~P32XI_VINT; goto irls;
471 case 0x18: Pico32x.sh2irqs &= ~P32XI_HINT; goto irls;
b78efee2 472 case 0x1a: Pico32x.sh2irqi[cpuid] &= ~P32XI_CMD; goto irls;
be20816c 473 case 0x1c:
474 Pico32x.sh2irqs &= ~P32XI_PWM;
1d7a28a7 475 p32x_timers_do(0);
be20816c 476 goto irls;
4ea707e1 477 }
478
b78efee2 479 p32x_sh2reg_write8(a | 1, d, cpuid);
4ea707e1 480 return;
481
482irls:
483 p32x_update_irls();
484}
485
87accdf7 486// ------------------------------------------------------------------
487// SH2 internal peripherals
1d7a28a7 488// we keep them in little endian format
87accdf7 489static u32 sh2_peripheral_read8(u32 a, int id)
490{
491 u8 *r = (void *)Pico32xMem->sh2_peri_regs[id];
492 u32 d;
493
494 a &= 0x1ff;
1d7a28a7 495 d = PREG8(r, a);
87accdf7 496
497 elprintf(EL_32X, "%csh2 peri r8 [%08x] %02x @%06x", id ? 's' : 'm', a | ~0x1ff, d, sh2_pc(id));
498 return d;
499}
500
1d7a28a7 501static u32 sh2_peripheral_read16(u32 a, int id)
502{
503 u16 *r = (void *)Pico32xMem->sh2_peri_regs[id];
504 u32 d;
505
506 a &= 0x1ff;
507 d = r[(a / 2) ^ 1];
508
509 elprintf(EL_32X, "%csh2 peri r16 [%08x] %04x @%06x", id ? 's' : 'm', a | ~0x1ff, d, sh2_pc(id));
510 return d;
511}
512
87accdf7 513static u32 sh2_peripheral_read32(u32 a, int id)
4ea707e1 514{
515 u32 d;
516 a &= 0x1fc;
97d3f47f 517 d = Pico32xMem->sh2_peri_regs[id][a / 4];
4ea707e1 518
97d3f47f 519 elprintf(EL_32X, "%csh2 peri r32 [%08x] %08x @%06x", id ? 's' : 'm', a | ~0x1ff, d, sh2_pc(id));
4ea707e1 520 return d;
acd35d4c 521}
522
87accdf7 523static void sh2_peripheral_write8(u32 a, u32 d, int id)
524{
525 u8 *r = (void *)Pico32xMem->sh2_peri_regs[id];
526 elprintf(EL_32X, "%csh2 peri w8 [%08x] %02x @%06x", id ? 's' : 'm', a, d, sh2_pc(id));
527
528 a &= 0x1ff;
1d7a28a7 529 PREG8(r, a) = d;
530
531 // X-men SCI hack
532 if ((a == 2 && (d & 0x20)) || // transmiter enabled
533 (a == 4 && !(d & 0x80))) { // valid data in TDR
534 void *oregs = Pico32xMem->sh2_peri_regs[id ^ 1];
535 if ((PREG8(oregs, 2) & 0x50) == 0x50) { // receiver + irq enabled
536 int level = PREG8(oregs, 0x60) >> 4;
537 int vector = PREG8(oregs, 0x63) & 0x7f;
538 elprintf(EL_32X, "%csh2 SCI recv irq (%d, %d)", (id ^ 1) ? 's' : 'm', level, vector);
539 sh2_internal_irq(&sh2s[id ^ 1], level, vector);
540 }
541 }
542}
543
544static void sh2_peripheral_write16(u32 a, u32 d, int id)
545{
546 u16 *r = (void *)Pico32xMem->sh2_peri_regs[id];
547 elprintf(EL_32X, "%csh2 peri w16 [%08x] %04x @%06x", id ? 's' : 'm', a, d, sh2_pc(id));
548
549 a &= 0x1ff;
550
551 // evil WDT
552 if (a == 0x80) {
553 if ((d & 0xff00) == 0xa500) { // WTCSR
554 PREG8(r, 0x80) = d;
555 p32x_timers_recalc();
556 }
557 if ((d & 0xff00) == 0x5a00) // WTCNT
558 PREG8(r, 0x81) = d;
559 return;
560 }
561
562 r[(a / 2) ^ 1] = d;
87accdf7 563}
564
565static void sh2_peripheral_write32(u32 a, u32 d, int id)
4ea707e1 566{
be20816c 567 u32 *r = Pico32xMem->sh2_peri_regs[id];
b78efee2 568 elprintf(EL_32X, "%csh2 peri w32 [%08x] %08x @%06x", id ? 's' : 'm', a, d, sh2_pc(id));
4ea707e1 569
570 a &= 0x1fc;
571 r[a / 4] = d;
572
97d3f47f 573 switch (a) {
be20816c 574 // division unit (TODO: verify):
97d3f47f 575 case 0x104: // DVDNT: divident L, starts divide
576 elprintf(EL_32X, "%csh2 divide %08x / %08x", id ? 's' : 'm', d, r[0x100 / 4]);
577 if (r[0x100 / 4]) {
be20816c 578 signed int divisor = r[0x100 / 4];
579 r[0x118 / 4] = r[0x110 / 4] = (signed int)d % divisor;
580 r[0x104 / 4] = r[0x11c / 4] = r[0x114 / 4] = (signed int)d / divisor;
97d3f47f 581 }
1625ed01 582 else
583 r[0x110 / 4] = r[0x114 / 4] = r[0x118 / 4] = r[0x11c / 4] = 0; // ?
97d3f47f 584 break;
585 case 0x114:
586 elprintf(EL_32X, "%csh2 divide %08x%08x / %08x @%08x",
587 id ? 's' : 'm', r[0x110 / 4], d, r[0x100 / 4], sh2_pc(id));
588 if (r[0x100 / 4]) {
be20816c 589 signed long long divident = (signed long long)r[0x110 / 4] << 32 | d;
590 signed int divisor = r[0x100 / 4];
97d3f47f 591 // XXX: undocumented mirroring to 0x118,0x11c?
be20816c 592 r[0x118 / 4] = r[0x110 / 4] = divident % divisor;
1625ed01 593 divident /= divisor;
594 r[0x11c / 4] = r[0x114 / 4] = divident;
595 divident >>= 31;
596 if ((unsigned long long)divident + 1 > 1) {
597 //elprintf(EL_32X, "%csh2 divide overflow! @%08x", id ? 's' : 'm', sh2_pc(id));
598 r[0x11c / 4] = r[0x114 / 4] = divident > 0 ? 0x7fffffff : 0x80000000; // overflow
599 }
97d3f47f 600 }
1625ed01 601 else
602 r[0x110 / 4] = r[0x114 / 4] = r[0x118 / 4] = r[0x11c / 4] = 0; // ?
97d3f47f 603 break;
604 }
605
4ea707e1 606 if ((a == 0x1b0 || a == 0x18c) && (dmac0->chcr0 & 3) == 1 && (dmac0->dmaor & 1)) {
607 elprintf(EL_32X, "sh2 DMA %08x -> %08x, cnt %d, chcr %04x @%06x",
b78efee2 608 dmac0->sar0, dmac0->dar0, dmac0->tcr0, dmac0->chcr0, sh2_pc(id));
4ea707e1 609 dmac0->tcr0 &= 0xffffff;
be20816c 610
1b3f5844 611 // HACK: assume 68k starts writing soon and end the timeslice
612 ash2_end_run(16);
be20816c 613
4ea707e1 614 // DREQ is only sent after first 4 words are written.
615 // we do multiple of 4 words to avoid messing up alignment
616 if (dmac0->sar0 == 0x20004012 && Pico32x.dmac_ptr && (Pico32x.dmac_ptr & 3) == 0) {
617 elprintf(EL_32X, "68k -> sh2 DMA");
618 dma_68k2sh2_do();
619 }
620 }
621}
622
623// ------------------------------------------------------------------
83ff19ec 624// 32x handlers
625
626// after ADEN
627static u32 PicoRead8_32x_on(u32 a)
be2c4208 628{
629 u32 d = 0;
630 if ((a & 0xffc0) == 0x5100) { // a15100
631 d = p32x_reg_read16(a);
632 goto out_16to8;
633 }
634
83ff19ec 635 if ((a & 0xfc00) != 0x5000)
636 return PicoRead8_io(a);
974fdb5b 637
638 if ((a & 0xfff0) == 0x5180) { // a15180
be2c4208 639 d = p32x_vdp_read16(a);
640 goto out_16to8;
641 }
642
974fdb5b 643 if ((a & 0xfe00) == 0x5200) { // a15200
644 d = Pico32xMem->pal[(a & 0x1ff) / 2];
645 goto out_16to8;
646 }
647
be2c4208 648 if ((a & 0xfffc) == 0x30ec) { // a130ec
649 d = str_mars[a & 3];
650 goto out;
651 }
652
653 elprintf(EL_UIO, "m68k unmapped r8 [%06x] @%06x", a, SekPc);
654 return d;
655
656out_16to8:
657 if (a & 1)
658 d &= 0xff;
659 else
660 d >>= 8;
661
662out:
663 elprintf(EL_32X, "m68k 32x r8 [%06x] %02x @%06x", a, d, SekPc);
664 return d;
665}
666
83ff19ec 667static u32 PicoRead16_32x_on(u32 a)
be2c4208 668{
669 u32 d = 0;
670 if ((a & 0xffc0) == 0x5100) { // a15100
671 d = p32x_reg_read16(a);
672 goto out;
673 }
674
83ff19ec 675 if ((a & 0xfc00) != 0x5000)
676 return PicoRead16_io(a);
974fdb5b 677
678 if ((a & 0xfff0) == 0x5180) { // a15180
be2c4208 679 d = p32x_vdp_read16(a);
680 goto out;
681 }
682
974fdb5b 683 if ((a & 0xfe00) == 0x5200) { // a15200
684 d = Pico32xMem->pal[(a & 0x1ff) / 2];
685 goto out;
686 }
687
be2c4208 688 if ((a & 0xfffc) == 0x30ec) { // a130ec
689 d = !(a & 2) ? ('M'<<8)|'A' : ('R'<<8)|'S';
690 goto out;
691 }
692
693 elprintf(EL_UIO, "m68k unmapped r16 [%06x] @%06x", a, SekPc);
694 return d;
695
696out:
697 elprintf(EL_32X, "m68k 32x r16 [%06x] %04x @%06x", a, d, SekPc);
698 return d;
699}
700
83ff19ec 701static void PicoWrite8_32x_on(u32 a, u32 d)
be2c4208 702{
703 if ((a & 0xfc00) == 0x5000)
704 elprintf(EL_32X, "m68k 32x w8 [%06x] %02x @%06x", a, d & 0xff, SekPc);
705
706 if ((a & 0xffc0) == 0x5100) { // a15100
707 p32x_reg_write8(a, d);
708 return;
709 }
710
83ff19ec 711 if ((a & 0xfc00) != 0x5000) {
712 PicoWrite8_io(a, d);
713 return;
714 }
974fdb5b 715
716 if ((a & 0xfff0) == 0x5180) { // a15180
be2c4208 717 p32x_vdp_write8(a, d);
718 return;
719 }
720
974fdb5b 721 // TODO: verify
722 if ((a & 0xfe00) == 0x5200) { // a15200
723 elprintf(EL_32X|EL_ANOMALY, "m68k 32x PAL w8 [%06x] %02x @%06x", a, d & 0xff, SekPc);
724 ((u8 *)Pico32xMem->pal)[(a & 0x1ff) ^ 1] = d;
725 Pico32x.dirty_pal = 1;
726 return;
727 }
728
be2c4208 729 elprintf(EL_UIO, "m68k unmapped w8 [%06x] %02x @%06x", a, d & 0xff, SekPc);
730}
731
83ff19ec 732static void PicoWrite16_32x_on(u32 a, u32 d)
be2c4208 733{
734 if ((a & 0xfc00) == 0x5000)
735 elprintf(EL_UIO, "m68k 32x w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc);
736
737 if ((a & 0xffc0) == 0x5100) { // a15100
738 p32x_reg_write16(a, d);
739 return;
740 }
741
83ff19ec 742 if ((a & 0xfc00) != 0x5000) {
743 PicoWrite16_io(a, d);
744 return;
745 }
974fdb5b 746
747 if ((a & 0xfff0) == 0x5180) { // a15180
be2c4208 748 p32x_vdp_write16(a, d);
749 return;
750 }
751
974fdb5b 752 if ((a & 0xfe00) == 0x5200) { // a15200
753 Pico32xMem->pal[(a & 0x1ff) / 2] = d;
754 Pico32x.dirty_pal = 1;
755 return;
756 }
757
be2c4208 758 elprintf(EL_UIO, "m68k unmapped w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc);
759}
760
83ff19ec 761// before ADEN
762u32 PicoRead8_32x(u32 a)
763{
764 u32 d = 0;
765 if ((a & 0xffc0) == 0x5100) { // a15100
766 // regs are always readable
767 d = ((u8 *)Pico32x.regs)[(a & 0x3f) ^ 1];
768 goto out;
769 }
770
771 if ((a & 0xfffc) == 0x30ec) { // a130ec
772 d = str_mars[a & 3];
773 goto out;
774 }
775
776 elprintf(EL_UIO, "m68k unmapped r8 [%06x] @%06x", a, SekPc);
777 return d;
778
779out:
780 elprintf(EL_32X, "m68k 32x r8 [%06x] %02x @%06x", a, d, SekPc);
781 return d;
782}
783
784u32 PicoRead16_32x(u32 a)
785{
786 u32 d = 0;
787 if ((a & 0xffc0) == 0x5100) { // a15100
788 d = Pico32x.regs[(a & 0x3f) / 2];
789 goto out;
790 }
791
792 if ((a & 0xfffc) == 0x30ec) { // a130ec
793 d = !(a & 2) ? ('M'<<8)|'A' : ('R'<<8)|'S';
794 goto out;
795 }
796
797 elprintf(EL_UIO, "m68k unmapped r16 [%06x] @%06x", a, SekPc);
798 return d;
799
800out:
801 elprintf(EL_32X, "m68k 32x r16 [%06x] %04x @%06x", a, d, SekPc);
802 return d;
803}
804
805void PicoWrite8_32x(u32 a, u32 d)
806{
807 if ((a & 0xffc0) == 0x5100) { // a15100
808 u16 *r = Pico32x.regs;
809
810 elprintf(EL_32X, "m68k 32x w8 [%06x] %02x @%06x", a, d & 0xff, SekPc);
811 a &= 0x3f;
812 if (a == 1) {
813 if ((d ^ r[0]) & d & P32XS_ADEN) {
814 Pico32xStartup();
815 r[0] &= ~P32XS_nRES; // causes reset if specified by this write
816 r[0] |= P32XS_ADEN;
817 p32x_reg_write8(a, d); // forward for reset processing
818 }
819 return;
820 }
821
822 // allow only COMM for now
823 if ((a & 0x30) == 0x20) {
824 u8 *r8 = (u8 *)r;
825 r8[a ^ 1] = d;
826 }
827 return;
828 }
829
830 elprintf(EL_UIO, "m68k unmapped w8 [%06x] %02x @%06x", a, d & 0xff, SekPc);
831}
832
833void PicoWrite16_32x(u32 a, u32 d)
834{
835 if ((a & 0xffc0) == 0x5100) { // a15100
836 u16 *r = Pico32x.regs;
837
838 elprintf(EL_UIO, "m68k 32x w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc);
839 a &= 0x3e;
840 if (a == 0) {
841 if ((d ^ r[0]) & d & P32XS_ADEN) {
842 Pico32xStartup();
843 r[0] &= ~P32XS_nRES; // causes reset if specified by this write
844 r[0] |= P32XS_ADEN;
845 p32x_reg_write16(a, d); // forward for reset processing
846 }
847 return;
848 }
849
850 // allow only COMM for now
851 if ((a & 0x30) == 0x20)
852 r[a / 2] = d;
853 return;
854 }
855
856 elprintf(EL_UIO, "m68k unmapped w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc);
857}
858
859// -----------------------------------------------------------------
860
be2c4208 861// hint vector is writeable
862static void PicoWrite8_hint(u32 a, u32 d)
863{
864 if ((a & 0xfffc) == 0x0070) {
865 Pico32xMem->m68k_rom[a ^ 1] = d;
866 return;
867 }
868
869 elprintf(EL_UIO, "m68k unmapped w8 [%06x] %02x @%06x", a, d & 0xff, SekPc);
870}
871
872static void PicoWrite16_hint(u32 a, u32 d)
873{
874 if ((a & 0xfffc) == 0x0070) {
875 ((u16 *)Pico32xMem->m68k_rom)[a/2] = d;
876 return;
877 }
878
879 elprintf(EL_UIO, "m68k unmapped w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc);
880}
881
5e49c3a8 882static void bank_switch(int b)
883{
884 unsigned int rs, bank;
885
886 bank = b << 20;
887 if (bank >= Pico.romsize) {
888 elprintf(EL_32X|EL_ANOMALY, "missing bank @ %06x", bank);
889 return;
890 }
891
892 // 32X ROM (unbanked, XXX: consider mirroring?)
893 rs = (Pico.romsize + M68K_BANK_MASK) & ~M68K_BANK_MASK;
894 rs -= bank;
895 if (rs > 0x100000)
896 rs = 0x100000;
897 cpu68k_map_set(m68k_read8_map, 0x900000, 0x900000 + rs - 1, Pico.rom + bank, 0);
898 cpu68k_map_set(m68k_read16_map, 0x900000, 0x900000 + rs - 1, Pico.rom + bank, 0);
899
900 elprintf(EL_32X, "bank %06x-%06x -> %06x", 0x900000, 0x900000 + rs - 1, bank);
602c28ca 901
902#ifdef EMU_F68K
903 // setup FAME fetchmap
904 for (rs = 0x90; rs < 0xa0; rs++)
905 PicoCpuFM68k.Fetch[rs] = (u32)Pico.rom + bank - 0x900000;
906#endif
5e49c3a8 907}
908
acd35d4c 909// -----------------------------------------------------------------
910// SH2
911// -----------------------------------------------------------------
912
bcf65fd6 913// read8
914static u32 sh2_read8_unmapped(u32 a, int id)
acd35d4c 915{
bcf65fd6 916 elprintf(EL_UIO, "%csh2 unmapped r8 [%08x] %02x @%06x",
917 id ? 's' : 'm', a, 0, sh2_pc(id));
918 return 0;
919}
b78efee2 920
bcf65fd6 921static u32 sh2_read8_cs0(u32 a, int id)
922{
923 u32 d = 0;
97d3f47f 924
bcf65fd6 925 // 0x3ff00 is veridied
926 if ((a & 0x3ff00) == 0x4000) {
b78efee2 927 d = p32x_sh2reg_read16(a, id);
db1d3564 928 goto out_16to8;
acd35d4c 929 }
930
bcf65fd6 931 if ((a & 0x3ff00) == 0x4100) {
acd35d4c 932 d = p32x_vdp_read16(a);
be20816c 933 if (p32x_poll_detect(&sh2_poll[id], a, ash2_cycles_done(), 1))
db1d3564 934 ash2_end_run(8);
935 goto out_16to8;
acd35d4c 936 }
937
bcf65fd6 938 // TODO: mirroring?
939 if (id == 0 && a < sizeof(Pico32xMem->sh2_rom_m))
940 return Pico32xMem->sh2_rom_m[a ^ 1];
941 if (id == 1 && a < sizeof(Pico32xMem->sh2_rom_s))
942 return Pico32xMem->sh2_rom_s[a ^ 1];
943
944 if ((a & 0x3ff00) == 0x4200) {
acd35d4c 945 d = Pico32xMem->pal[(a & 0x1ff) / 2];
946 goto out_16to8;
947 }
948
bcf65fd6 949 return sh2_read8_unmapped(a, id);
acd35d4c 950
951out_16to8:
952 if (a & 1)
953 d &= 0xff;
954 else
955 d >>= 8;
956
b78efee2 957 elprintf(EL_32X, "%csh2 r8 [%08x] %02x @%06x",
958 id ? 's' : 'm', a, d, sh2_pc(id));
acd35d4c 959 return d;
960}
961
bcf65fd6 962static u32 sh2_read8_da(u32 a, int id)
acd35d4c 963{
bcf65fd6 964 return Pico32xMem->data_array[id][(a & 0xfff) ^ 1];
965}
acd35d4c 966
bcf65fd6 967// read16
968static u32 sh2_read16_unmapped(u32 a, int id)
969{
970 elprintf(EL_UIO, "%csh2 unmapped r16 [%08x] %04x @%06x",
971 id ? 's' : 'm', a, 0, sh2_pc(id));
972 return 0;
973}
b78efee2 974
bcf65fd6 975static u32 sh2_read16_cs0(u32 a, int id)
976{
977 u32 d = 0;
97d3f47f 978
bcf65fd6 979 if ((a & 0x3ff00) == 0x4000) {
b78efee2 980 d = p32x_sh2reg_read16(a, id);
1b3f5844 981 if (!(EL_LOGMASK & EL_PWM) && (a & 0x30) == 0x30) // hide PWM
982 return d;
db1d3564 983 goto out;
acd35d4c 984 }
985
bcf65fd6 986 if ((a & 0x3ff00) == 0x4100) {
acd35d4c 987 d = p32x_vdp_read16(a);
be20816c 988 if (p32x_poll_detect(&sh2_poll[id], a, ash2_cycles_done(), 1))
db1d3564 989 ash2_end_run(8);
990 goto out;
acd35d4c 991 }
992
bcf65fd6 993 if (id == 0 && a < sizeof(Pico32xMem->sh2_rom_m))
994 return *(u16 *)(Pico32xMem->sh2_rom_m + a);
995 if (id == 1 && a < sizeof(Pico32xMem->sh2_rom_s))
996 return *(u16 *)(Pico32xMem->sh2_rom_s + a);
997
998 if ((a & 0x3ff00) == 0x4200) {
acd35d4c 999 d = Pico32xMem->pal[(a & 0x1ff) / 2];
1000 goto out;
1001 }
1002
bcf65fd6 1003 return sh2_read16_unmapped(a, id);
acd35d4c 1004
1005out:
b78efee2 1006 elprintf(EL_32X, "%csh2 r16 [%08x] %04x @%06x",
1007 id ? 's' : 'm', a, d, sh2_pc(id));
acd35d4c 1008 return d;
1009}
1010
bcf65fd6 1011static u32 sh2_read16_da(u32 a, int id)
acd35d4c 1012{
bcf65fd6 1013 return ((u16 *)Pico32xMem->data_array[id])[(a & 0xfff) / 2];
acd35d4c 1014}
1015
bcf65fd6 1016// write8
1017static void sh2_write8_unmapped(u32 a, u32 d, int id)
acd35d4c 1018{
bcf65fd6 1019 elprintf(EL_UIO, "%csh2 unmapped w8 [%08x] %02x @%06x",
1020 id ? 's' : 'm', a, d & 0xff, sh2_pc(id));
1021}
266c6afa 1022
bcf65fd6 1023static void sh2_write8_cs0(u32 a, u32 d, int id)
1024{
1025 elprintf(EL_32X, "%csh2 w8 [%08x] %02x @%06x",
1026 id ? 's' : 'm', a, d & 0xff, sh2_pc(id));
b78efee2 1027
bcf65fd6 1028 if ((a & 0x3ff00) == 0x4100) {
acd35d4c 1029 p32x_vdp_write8(a, d);
1030 return;
1031 }
1032
bcf65fd6 1033 if ((a & 0x3ff00) == 0x4000) {
b78efee2 1034 p32x_sh2reg_write8(a, d, id);
acd35d4c 1035 return;
1036 }
1037
bcf65fd6 1038 sh2_write8_unmapped(a, d, id);
1039}
1040
1041#define sh2_write8_dramN(n) \
1042 if (!(a & 0x20000) || d) { \
1043 u8 *dram = (u8 *)Pico32xMem->dram[n]; \
1044 dram[(a & 0x1ffff) ^ 1] = d; \
87accdf7 1045 }
1046
bcf65fd6 1047static void sh2_write8_dram0(u32 a, u32 d, int id)
1048{
1049 sh2_write8_dramN(0);
acd35d4c 1050}
1051
bcf65fd6 1052static void sh2_write8_dram1(u32 a, u32 d, int id)
acd35d4c 1053{
bcf65fd6 1054 sh2_write8_dramN(1);
1055}
87accdf7 1056
bcf65fd6 1057static void sh2_write8_da(u32 a, u32 d, int id)
1058{
1059 Pico32xMem->data_array[id][(a & 0xfff) ^ 1] = d;
1060}
acd35d4c 1061
bcf65fd6 1062// write16
1063static void sh2_write16_unmapped(u32 a, u32 d, int id)
1064{
1065 elprintf(EL_UIO, "%csh2 unmapped w16 [%08x] %04x @%06x",
1066 id ? 's' : 'm', a, d & 0xffff, sh2_pc(id));
1067}
b78efee2 1068
bcf65fd6 1069static void sh2_write16_cs0(u32 a, u32 d, int id)
1070{
1071 if (((EL_LOGMASK & EL_PWM) || (a & 0x30) != 0x30)) // hide PWM
1072 elprintf(EL_32X, "%csh2 w16 [%08x] %04x @%06x",
1073 id ? 's' : 'm', a, d & 0xffff, sh2_pc(id));
266c6afa 1074
bcf65fd6 1075 if ((a & 0x3ff00) == 0x4100) {
be20816c 1076 sh2_poll[id].cnt = 0; // for poll before VDP accesses
acd35d4c 1077 p32x_vdp_write16(a, d);
1078 return;
1079 }
1080
bcf65fd6 1081 if ((a & 0x3fe00) == 0x4200) {
acd35d4c 1082 Pico32xMem->pal[(a & 0x1ff) / 2] = d;
1083 Pico32x.dirty_pal = 1;
1084 return;
1085 }
1086
bcf65fd6 1087 if ((a & 0x3ff00) == 0x4000) {
b78efee2 1088 p32x_sh2reg_write16(a, d, id);
acd35d4c 1089 return;
1090 }
1091
bcf65fd6 1092 sh2_write16_unmapped(a, d, id);
1093}
1094
1095#define sh2_write16_dramN(n) \
1096 u16 *pd = &Pico32xMem->dram[n][(a & 0x1ffff) / 2]; \
1097 if (!(a & 0x20000)) { \
1098 *pd = d; \
1099 return; \
1100 } \
1101 /* overwrite */ \
1102 if (!(d & 0xff00)) d |= *pd & 0xff00; \
1103 if (!(d & 0x00ff)) d |= *pd & 0x00ff; \
1104 *pd = d
1105
1106static void sh2_write16_dram0(u32 a, u32 d, int id)
1107{
1108 sh2_write16_dramN(0);
1109}
1110
1111static void sh2_write16_dram1(u32 a, u32 d, int id)
1112{
1113 sh2_write16_dramN(1);
1114}
1115
1116static void sh2_write16_da(u32 a, u32 d, int id)
1117{
1118 ((u16 *)Pico32xMem->data_array[id])[(a & 0xfff) / 2] = d;
1119}
1120
1121
1122typedef struct {
1123 uptr addr; // stores (membase >> 1) or ((handler >> 1) | (1<<31))
1124 u32 mask;
1125} sh2_memmap;
1126
1127typedef u32 (sh2_read_handler)(u32 a, int id);
1128typedef void (sh2_write_handler)(u32 a, u32 d, int id);
1129
1130#define SH2MAP_ADDR2OFFS(a) \
1131 (((a >> 25) & 3) | ((a >> 27) & 0x1c))
1132
1133u32 p32x_sh2_read8(u32 a, SH2 *sh2)
1134{
1135 const sh2_memmap *sh2_map = sh2->read8_map;
1136 uptr p;
1137
1138 sh2_map += SH2MAP_ADDR2OFFS(a);
1139 p = sh2_map->addr;
1140 if (p & (1 << 31))
1141 return ((sh2_read_handler *)(p << 1))(a, sh2->is_slave);
1142 else
1143 return *(u8 *)((p << 1) + ((a & sh2_map->mask) ^ 1));
1144}
1145
1146u32 p32x_sh2_read16(u32 a, SH2 *sh2)
1147{
1148 const sh2_memmap *sh2_map = sh2->read16_map;
1149 uptr p;
1150
1151 sh2_map += SH2MAP_ADDR2OFFS(a);
1152 p = sh2_map->addr;
1153 if (p & (1 << 31))
1154 return ((sh2_read_handler *)(p << 1))(a, sh2->is_slave);
1155 else
1156 return *(u16 *)((p << 1) + ((a & sh2_map->mask) & ~1));
1157}
1158
1159u32 p32x_sh2_read32(u32 a, SH2 *sh2)
1160{
1161 const sh2_memmap *sh2_map = sh2->read16_map;
1162 sh2_read_handler *handler;
1163 u32 offs;
1164 uptr p;
1165
1166 offs = SH2MAP_ADDR2OFFS(a);
1167 sh2_map += offs;
1168 p = sh2_map->addr;
1169 if (!(p & (1 << 31))) {
1170 // XXX: maybe 32bit access instead with ror?
1171 u16 *pd = (u16 *)((p << 1) + ((a & sh2_map->mask) & ~1));
1172 return (pd[0] << 16) | pd[1];
1d7a28a7 1173 }
1174
bcf65fd6 1175 if (offs == 0x1f)
1176 return sh2_peripheral_read32(a, sh2->is_slave);
1177
1178 handler = (sh2_read_handler *)(p << 1);
1179 return (handler(a, sh2->is_slave) << 16) | handler(a + 2, sh2->is_slave);
1180}
1181
1182void p32x_sh2_write8(u32 a, u32 d, SH2 *sh2)
1183{
1184 const sh2_memmap *sh2_map = sh2->write8_map;
1185 uptr p;
1186
1187 sh2_map += SH2MAP_ADDR2OFFS(a);
1188 p = sh2_map->addr;
1189 if (p & (1 << 31))
1190 ((sh2_write_handler *)(p << 1))(a, d, sh2->is_slave);
1191 else
1192 *(u8 *)((p << 1) + ((a & sh2_map->mask) ^ 1)) = d;
1193}
1194
1195void p32x_sh2_write16(u32 a, u32 d, SH2 *sh2)
1196{
1197 const sh2_memmap *sh2_map = sh2->write16_map;
1198 uptr p;
1199
1200 sh2_map += SH2MAP_ADDR2OFFS(a);
1201 p = sh2_map->addr;
1202 if (p & (1 << 31))
1203 ((sh2_write_handler *)(p << 1))(a, d, sh2->is_slave);
1204 else
1205 *(u16 *)((p << 1) + ((a & sh2_map->mask) & ~1)) = d;
acd35d4c 1206}
1207
bcf65fd6 1208void p32x_sh2_write32(u32 a, u32 d, SH2 *sh2)
acd35d4c 1209{
bcf65fd6 1210 const sh2_memmap *sh2_map = sh2->write16_map;
1211 sh2_write_handler *handler;
1212 u32 offs;
1213 uptr p;
1214
1215 offs = SH2MAP_ADDR2OFFS(a);
1216 sh2_map += offs;
1217 p = sh2_map->addr;
1218 if (!(p & (1 << 31))) {
1219 u16 *pd = (u16 *)((p << 1) + ((a & sh2_map->mask) & ~1));
1220 pd[0] = d >> 16;
1221 pd[1] = d;
1222 return;
1223 }
1224
1225 if (offs == 0x1f) {
1226 sh2_peripheral_write32(a, d, sh2->is_slave);
4ea707e1 1227 return;
1228 }
1229
bcf65fd6 1230 handler = (sh2_write_handler *)(p << 1);
1231 handler(a, d >> 16, sh2->is_slave);
1232 handler(a + 2, d, sh2->is_slave);
acd35d4c 1233}
1234
bcf65fd6 1235// -----------------------------------------------------------------
1236
83ff19ec 1237static const u16 msh2_code[] = {
1238 // trap instructions
1239 0xaffe, // bra <self>
1240 0x0009, // nop
1241 // have to wait a bit until m68k initial program finishes clearing stuff
1242 // to avoid races with game SH2 code, like in Tempo
1243 0xd004, // mov.l @(_m_ok,pc), r0
1244 0xd105, // mov.l @(_cnt,pc), r1
1245 0xd205, // mov.l @(_start,pc), r2
1246 0x71ff, // add #-1, r1
1247 0x4115, // cmp/pl r1
1248 0x89fc, // bt -2
1249 0xc208, // mov.l r0, @(h'20,gbr)
1250 0x6822, // mov.l @r2, r8
1251 0x482b, // jmp @r8
1252 0x0009, // nop
1253 ('M'<<8)|'_', ('O'<<8)|'K',
1254 0x0001, 0x0000,
1255 0x2200, 0x03e0 // master start pointer in ROM
1256};
1257
1258static const u16 ssh2_code[] = {
1259 0xaffe, // bra <self>
1260 0x0009, // nop
1261 // code to wait for master, in case authentic master BIOS is used
1262 0xd104, // mov.l @(_m_ok,pc), r1
1263 0xd206, // mov.l @(_start,pc), r2
1264 0xc608, // mov.l @(h'20,gbr), r0
1265 0x3100, // cmp/eq r0, r1
1266 0x8bfc, // bf #-2
1267 0xd003, // mov.l @(_s_ok,pc), r0
1268 0xc209, // mov.l r0, @(h'24,gbr)
1269 0x6822, // mov.l @r2, r8
1270 0x482b, // jmp @r8
1271 0x0009, // nop
1272 ('M'<<8)|'_', ('O'<<8)|'K',
1273 ('S'<<8)|'_', ('O'<<8)|'K',
1274 0x2200, 0x03e4 // slave start pointer in ROM
1275};
1276
be2c4208 1277#define HWSWAP(x) (((x) << 16) | ((x) >> 16))
83ff19ec 1278static void get_bios(void)
be2c4208 1279{
83ff19ec 1280 u16 *ps;
1281 u32 *pl;
be2c4208 1282 int i;
1283
83ff19ec 1284 // M68K ROM
1285 if (p32x_bios_g != NULL) {
1286 elprintf(EL_STATUS|EL_32X, "32x: using supplied 68k BIOS");
1287 Byteswap(Pico32xMem->m68k_rom, p32x_bios_g, 0x100);
be2c4208 1288 }
83ff19ec 1289 else {
1290 // generate 68k ROM
1291 ps = (u16 *)Pico32xMem->m68k_rom;
1292 pl = (u32 *)ps;
1293 for (i = 1; i < 0xc0/4; i++)
1294 pl[i] = HWSWAP(0x880200 + (i - 1) * 6);
be2c4208 1295
83ff19ec 1296 // fill with nops
1297 for (i = 0xc0/2; i < 0x100/2; i++)
1298 ps[i] = 0x4e71;
be2c4208 1299
5e49c3a8 1300#if 0
83ff19ec 1301 ps[0xc0/2] = 0x46fc;
1302 ps[0xc2/2] = 0x2700; // move #0x2700,sr
1303 ps[0xfe/2] = 0x60fe; // jump to self
5e49c3a8 1304#else
83ff19ec 1305 ps[0xfe/2] = 0x4e75; // rts
5e49c3a8 1306#endif
83ff19ec 1307 }
1308 // fill remaining m68k_rom page with game ROM
974fdb5b 1309 memcpy(Pico32xMem->m68k_rom + 0x100, Pico.rom + 0x100, sizeof(Pico32xMem->m68k_rom) - 0x100);
be2c4208 1310
83ff19ec 1311 // MSH2
1312 if (p32x_bios_m != NULL) {
1313 elprintf(EL_STATUS|EL_32X, "32x: using supplied master SH2 BIOS");
1314 Byteswap(Pico32xMem->sh2_rom_m, p32x_bios_m, sizeof(Pico32xMem->sh2_rom_m));
acd35d4c 1315 }
83ff19ec 1316 else {
1317 pl = (u32 *)Pico32xMem->sh2_rom_m;
1318
1319 // fill exception vector table to our trap address
1320 for (i = 0; i < 128; i++)
1321 pl[i] = HWSWAP(0x200);
1322
1323 // startup code
1324 memcpy(Pico32xMem->sh2_rom_m + 0x200, msh2_code, sizeof(msh2_code));
1325
1326 // reset SP
1327 pl[1] = pl[3] = HWSWAP(0x6040000);
1328 // start
1329 pl[0] = pl[2] = HWSWAP(0x204);
1330 }
1331
1332 // SSH2
1333 if (p32x_bios_s != NULL) {
1334 elprintf(EL_STATUS|EL_32X, "32x: using supplied slave SH2 BIOS");
1335 Byteswap(Pico32xMem->sh2_rom_s, p32x_bios_s, sizeof(Pico32xMem->sh2_rom_s));
1336 }
1337 else {
1338 pl = (u32 *)Pico32xMem->sh2_rom_s;
1339
1340 // fill exception vector table to our trap address
1341 for (i = 0; i < 128; i++)
1342 pl[i] = HWSWAP(0x200);
1343
1344 // startup code
1345 memcpy(Pico32xMem->sh2_rom_s + 0x200, ssh2_code, sizeof(ssh2_code));
1346
1347 // reset SP
1348 pl[1] = pl[3] = HWSWAP(0x603f800);
1349 // start
1350 pl[0] = pl[2] = HWSWAP(0x204);
1351 }
1352}
1353
bcf65fd6 1354#define MAP_MEMORY(m) ((uptr)(m) >> 1)
1355#define MAP_HANDLER(h) (((uptr)(h) >> 1) | (1 << 31))
1356
1357static sh2_memmap sh2_read8_map[0x20], sh2_read16_map[0x20];
1358static sh2_memmap sh2_write8_map[0x20], sh2_write16_map[0x20];
1359
1360void Pico32xSwapDRAM(int b)
1361{
1362 cpu68k_map_set(m68k_read8_map, 0x840000, 0x85ffff, Pico32xMem->dram[b], 0);
1363 cpu68k_map_set(m68k_read16_map, 0x840000, 0x85ffff, Pico32xMem->dram[b], 0);
1364 cpu68k_map_set(m68k_write8_map, 0x840000, 0x85ffff, Pico32xMem->dram[b], 0);
1365 cpu68k_map_set(m68k_write16_map, 0x840000, 0x85ffff, Pico32xMem->dram[b], 0);
1366
1367 // SH2
1368 sh2_read8_map[2].addr = sh2_read8_map[6].addr =
1369 sh2_read16_map[2].addr = sh2_read16_map[6].addr = MAP_MEMORY(Pico32xMem->dram[b]);
1370
1371 sh2_write8_map[2].addr = sh2_write8_map[6].addr = MAP_HANDLER(b ? sh2_write8_dram1 : sh2_write8_dram0);
1372 sh2_write16_map[2].addr = sh2_write16_map[6].addr = MAP_HANDLER(b ? sh2_write16_dram1 : sh2_write16_dram0);
1373}
1374
83ff19ec 1375void PicoMemSetup32x(void)
1376{
1377 unsigned int rs;
bcf65fd6 1378 int i;
83ff19ec 1379
1380 Pico32xMem = calloc(1, sizeof(*Pico32xMem));
1381 if (Pico32xMem == NULL) {
1382 elprintf(EL_STATUS, "OOM");
1383 return;
1384 }
1385
1386 dmac0 = (void *)&Pico32xMem->sh2_peri_regs[0][0x180 / 4];
1387
1388 get_bios();
acd35d4c 1389
be2c4208 1390 // cartridge area becomes unmapped
1391 // XXX: we take the easy way and don't unmap ROM,
1392 // so that we can avoid handling the RV bit.
1393 // m68k_map_unmap(0x000000, 0x3fffff);
1394
1395 // MD ROM area
974fdb5b 1396 rs = sizeof(Pico32xMem->m68k_rom);
1397 cpu68k_map_set(m68k_read8_map, 0x000000, rs - 1, Pico32xMem->m68k_rom, 0);
1398 cpu68k_map_set(m68k_read16_map, 0x000000, rs - 1, Pico32xMem->m68k_rom, 0);
1399 cpu68k_map_set(m68k_write8_map, 0x000000, rs - 1, PicoWrite8_hint, 1); // TODO verify
1400 cpu68k_map_set(m68k_write16_map, 0x000000, rs - 1, PicoWrite16_hint, 1);
1401
be2c4208 1402 // 32X ROM (unbanked, XXX: consider mirroring?)
5e49c3a8 1403 rs = (Pico.romsize + M68K_BANK_MASK) & ~M68K_BANK_MASK;
1404 if (rs > 0x80000)
1405 rs = 0x80000;
1406 cpu68k_map_set(m68k_read8_map, 0x880000, 0x880000 + rs - 1, Pico.rom, 0);
1407 cpu68k_map_set(m68k_read16_map, 0x880000, 0x880000 + rs - 1, Pico.rom, 0);
602c28ca 1408#ifdef EMU_F68K
1409 // setup FAME fetchmap
1410 PicoCpuFM68k.Fetch[0] = (u32)Pico32xMem->m68k_rom;
1411 for (rs = 0x88; rs < 0x90; rs++)
1412 PicoCpuFM68k.Fetch[rs] = (u32)Pico.rom - 0x880000;
1413#endif
be2c4208 1414
1415 // 32X ROM (banked)
5e49c3a8 1416 bank_switch(0);
b78efee2 1417
83ff19ec 1418 // SYS regs
1419 cpu68k_map_set(m68k_read8_map, 0xa10000, 0xa1ffff, PicoRead8_32x_on, 1);
1420 cpu68k_map_set(m68k_read16_map, 0xa10000, 0xa1ffff, PicoRead16_32x_on, 1);
1421 cpu68k_map_set(m68k_write8_map, 0xa10000, 0xa1ffff, PicoWrite8_32x_on, 1);
1422 cpu68k_map_set(m68k_write16_map, 0xa10000, 0xa1ffff, PicoWrite16_32x_on, 1);
1423
bcf65fd6 1424 // SH2 maps: A31,A30,A29,CS1,CS0
1425 // all unmapped by default
1426 for (i = 0; i < 0x20; i++) {
1427 sh2_read8_map[i].addr = MAP_HANDLER(sh2_read8_unmapped);
1428 sh2_read16_map[i].addr = MAP_HANDLER(sh2_read16_unmapped);
1429 sh2_write8_map[i].addr = MAP_HANDLER(sh2_write8_unmapped);
1430 sh2_write16_map[i].addr = MAP_HANDLER(sh2_write16_unmapped);
1431 }
1432
1433 // CS0
1434 sh2_read8_map[0].addr = sh2_read8_map[4].addr = MAP_HANDLER(sh2_read8_cs0);
1435 sh2_read16_map[0].addr = sh2_read16_map[4].addr = MAP_HANDLER(sh2_read16_cs0);
1436 sh2_write8_map[0].addr = sh2_write8_map[4].addr = MAP_HANDLER(sh2_write8_cs0);
1437 sh2_write16_map[0].addr = sh2_write16_map[4].addr = MAP_HANDLER(sh2_write16_cs0);
1438 // CS1 - ROM
1439 sh2_read8_map[1].addr = sh2_read8_map[5].addr =
1440 sh2_read16_map[1].addr = sh2_read16_map[5].addr = MAP_MEMORY(Pico.rom);
1441 sh2_read8_map[1].mask = sh2_read8_map[5].mask =
1442 sh2_read16_map[1].mask = sh2_read16_map[5].mask = 0x3fffff; // FIXME
1443 // CS2 - DRAM - done by Pico32xSwapDRAM()
1444 sh2_read8_map[2].mask = sh2_read8_map[6].mask =
1445 sh2_read16_map[2].mask = sh2_read16_map[6].mask = 0x01ffff;
1446 // CS3 - SDRAM
1447 sh2_read8_map[3].addr = sh2_read8_map[7].addr =
1448 sh2_read16_map[3].addr = sh2_read16_map[7].addr =
1449 sh2_write8_map[3].addr = sh2_write8_map[7].addr =
1450 sh2_write16_map[3].addr = sh2_write16_map[7].addr = MAP_MEMORY(Pico32xMem->sdram);
1451 sh2_read8_map[3].mask = sh2_read8_map[7].mask =
1452 sh2_read16_map[3].mask = sh2_read16_map[7].mask =
1453 sh2_write8_map[3].mask = sh2_write8_map[7].mask =
1454 sh2_write16_map[3].mask = sh2_write16_map[7].mask = 0x03ffff;
1455 // SH2 data array
1456 sh2_read8_map[0x18].addr = MAP_HANDLER(sh2_read8_da);
1457 sh2_read16_map[0x18].addr = MAP_HANDLER(sh2_read16_da);
1458 sh2_write8_map[0x18].addr = MAP_HANDLER(sh2_write8_da);
1459 sh2_write16_map[0x18].addr = MAP_HANDLER(sh2_write16_da);
1460 // SH2 IO
1461 sh2_read8_map[0x1f].addr = MAP_HANDLER(sh2_peripheral_read8);
1462 sh2_read16_map[0x1f].addr = MAP_HANDLER(sh2_peripheral_read16);
1463 sh2_write8_map[0x1f].addr = MAP_HANDLER(sh2_peripheral_write8);
1464 sh2_write16_map[0x1f].addr = MAP_HANDLER(sh2_peripheral_write16);
1465
1466 // map DRAM area, both 68k and SH2
1467 Pico32xSwapDRAM(1);
1468
1469 msh2.read8_map = ssh2.read8_map = sh2_read8_map;
1470 msh2.read16_map = ssh2.read16_map = sh2_read16_map;
1471 msh2.write8_map = ssh2.write8_map = sh2_write8_map;
1472 msh2.write16_map = ssh2.write16_map = sh2_write16_map;
1473
b78efee2 1474 // setup poll detector
1475 m68k_poll.flag = P32XF_68KPOLL;
be20816c 1476 m68k_poll.cyc_max = 64;
b78efee2 1477 sh2_poll[0].flag = P32XF_MSH2POLL;
1d7a28a7 1478 sh2_poll[0].cyc_max = 21;
b78efee2 1479 sh2_poll[1].flag = P32XF_SSH2POLL;
be20816c 1480 sh2_poll[1].cyc_max = 16;
be2c4208 1481}
1482
bcf65fd6 1483// vim:shiftwidth=2:expandtab