From: kub Date: Tue, 17 Sep 2024 22:17:45 +0000 (+0200) Subject: mcd, fixes and improvements for mcd-verificator X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=dd7c8c05dd56cc6429c10a469d478ca5a449d6d4;p=picodrive.git mcd, fixes and improvements for mcd-verificator --- diff --git a/pico/cd/cdc.c b/pico/cd/cdc.c index 1163cb28..be5a9c56 100644 --- a/pico/cd/cdc.c +++ b/pico/cd/cdc.c @@ -92,7 +92,7 @@ typedef struct //void (*dma_w)(unsigned int words); int dma_w; uint8 ram[0x4000 + 2352]; /* 16K external RAM (with one block overhead to handle buffer overrun) */ -} cdc_t; +} cdc_t; static cdc_t cdc; @@ -125,7 +125,7 @@ void cdc_reset(void) cdc.head[1][3] = 0x00; /* reset CDC cycle counter */ - cdc.cycles = 0; + cdc.cycles = SekCyclesDoneS68k(); /* DMA transfer disabled */ cdc.dma_w = 0; @@ -245,6 +245,16 @@ int cdc_context_load_old(uint8 *state) #undef old_load } +static int check_decoder_irq_pending(void) +{ + /* As per mcd-verificator, DECI is active for a phase of 49:72 per sector */ + /* 12500000/75 * 49/(49+72) = ~67500, but it sometimes fails with that */ + if (CYCLES_GE(SekCyclesDoneS68k(), cdc.cycles + 67250)) + cdc.ifstat |= BIT_DECI; + + return !(cdc.ifstat & BIT_DECI) && (cdc.ifctrl & BIT_DECIEN); +} + static void do_dma(enum dma_type type, int bytes_in) { int dma_addr = (Pico_mcd->s68k_regs[0x0a] << 8) | Pico_mcd->s68k_regs[0x0b]; @@ -368,7 +378,7 @@ void cdc_dma_update(void) cdc.ifstat &= ~BIT_DTEI; /* Data Transfer End interrupt enabled ? */ - if (cdc.ifctrl & BIT_DTEIEN) + if (!check_decoder_irq_pending() && (cdc.ifctrl & BIT_DTEIEN)) { /* level 5 interrupt enabled ? */ if (Pico_mcd->s68k_regs[0x32+1] & PCDS_IEN5) @@ -411,9 +421,10 @@ int cdc_decoder_update(uint8 header[4]) /* pending decoder interrupt */ cdc.ifstat &= ~BIT_DECI; + cdc.cycles = SekCyclesDoneS68k(); /* decoder interrupt enabled ? */ - if (cdc.ifctrl & BIT_DECIEN) + if (((cdc.ifstat & BIT_DTEI) || !(cdc.ifctrl & BIT_DTEIEN)) && (cdc.ifctrl & BIT_DECIEN)) { /* level 5 interrupt enabled ? */ if (Pico_mcd->s68k_regs[0x32+1] & PCDS_IEN5) @@ -455,7 +466,7 @@ int cdc_decoder_update(uint8 header[4]) return 1; } } - + /* keep decoding same data block if Buffer Write is disabled */ return 0; } @@ -473,6 +484,7 @@ void cdc_reg_w(unsigned char data) case 0x01: /* IFCTRL */ { /* pending interrupts ? */ + check_decoder_irq_pending(); if (((data & BIT_DTEIEN) && !(cdc.ifstat & BIT_DTEI)) || ((data & BIT_DECIEN) && !(cdc.ifstat & BIT_DECI))) { @@ -621,14 +633,13 @@ void cdc_reg_w(unsigned char data) /* clear DBCH bits 4-7 */ cdc.dbc &= 0x0fff; -#if 0 /* no pending decoder interrupt ? */ - if ((cdc.ifstat | BIT_DECI) || !(cdc.ifctrl & BIT_DECIEN)) + if (!check_decoder_irq_pending()) { /* clear pending level 5 interrupt */ pcd_irq_s68k(5, 0); } -#endif + Pico_mcd->s68k_regs[0x04+1] = 0x08; break; } @@ -648,16 +659,23 @@ void cdc_reg_w(unsigned char data) case 0x0a: /* CTRL0 */ { /* reset DECI if decoder turned off */ - if (!(data & BIT_DECEN)) + if (!(data & BIT_DECEN)) { cdc.ifstat |= BIT_DECI; + if ((cdc.ifstat & BIT_DTEI) || !(cdc.ifctrl & BIT_DTEIEN)) + { + /* clear pending level 5 interrupt */ + pcd_irq_s68k(5, 0); + } + } + /* update decoding mode */ if (data & BIT_AUTORQ) { /* set MODE bit according to CTRL1 register & clear FORM bit */ cdc.stat[2] = cdc.ctrl[1] & BIT_MODRQ; } - else + else { /* set MODE & FORM bits according to CTRL1 register */ cdc.stat[2] = cdc.ctrl[1] & (BIT_MODRQ | BIT_FORMRQ); @@ -676,7 +694,7 @@ void cdc_reg_w(unsigned char data) /* set MODE bit according to CTRL1 register & clear FORM bit */ cdc.stat[2] = data & BIT_MODRQ; } - else + else { /* set MODE & FORM bits according to CTRL1 register */ cdc.stat[2] = data & (BIT_MODRQ | BIT_FORMRQ); @@ -692,7 +710,7 @@ void cdc_reg_w(unsigned char data) cdc.pt |= data; Pico_mcd->s68k_regs[0x04+1] = 0x0d; break; - + case 0x0d: /* PTH */ cdc.pt &= 0x00ff; cdc.pt |= data << 8; @@ -722,6 +740,7 @@ unsigned char cdc_reg_r(void) case 0x01: /* IFSTAT */ Pico_mcd->s68k_regs[0x04+1] = 0x02; + check_decoder_irq_pending(); return cdc.ifstat; case 0x02: /* DBCL */ @@ -785,15 +804,13 @@ unsigned char cdc_reg_r(void) /* clear pending decoder interrupt */ cdc.ifstat |= BIT_DECI; - -#if 0 + /* no pending data transfer end interrupt */ - if ((cdc.ifstat | BIT_DTEI) || !(cdc.ifctrl & BIT_DTEIEN)) + if ((cdc.ifstat & BIT_DTEI) || !(cdc.ifctrl & BIT_DTEIEN)) { /* clear pending level 5 interrupt */ pcd_irq_s68k(5, 0); } -#endif Pico_mcd->s68k_regs[0x04+1] = 0x10; return data; @@ -805,8 +822,14 @@ unsigned char cdc_reg_r(void) } } -unsigned short cdc_host_r(void) +unsigned short cdc_host_r(int sub) { + int dir = Pico_mcd->s68k_regs[0x04+0] & 0x07; + + /* sync sub cpu if DSR bit not there (yet?) on main cpu */ + if (!(Pico_mcd->s68k_regs[0x04+0] & 0x40)) + if (!sub) pcd_sync_s68k(SekCyclesDone()+8, 0); /* HACK, mcd-verificator */ + /* check if data is available */ if (!(cdc.ifstat & BIT_DTEN)) { @@ -817,7 +840,11 @@ unsigned short cdc_host_r(void) #ifdef LOG_CDC error("CDC host read 0x%04x -> 0x%04x (dbc=0x%x) (%X)\n", cdc.dac, data, cdc.dbc, s68k.pc); #endif - + + /* only the configured cpu access advances the DMA */ + if ((sub && dir != 3) || (!sub && dir != 2)) + return data; + /* increment data address counter */ cdc.dac += 2; @@ -843,7 +870,7 @@ unsigned short cdc_host_r(void) cdc.ifstat &= ~BIT_DTEI; /* Data Transfer End interrupt enabled ? */ - if (cdc.ifctrl & BIT_DTEIEN) + if (!check_decoder_irq_pending() && (cdc.ifctrl & BIT_DTEIEN)) { /* level 5 interrupt enabled ? */ if (Pico_mcd->s68k_regs[0x32+1] & PCDS_IEN5) diff --git a/pico/cd/cdd.c b/pico/cd/cdd.c index 89ca183b..6f121f4d 100644 --- a/pico/cd/cdd.c +++ b/pico/cd/cdd.c @@ -720,6 +720,28 @@ void cdd_update(void) error("LBA = %d (track n°%d)(latency=%d)\n", cdd.lba, cdd.index, cdd.latency); #endif + /* update decoder, depending on track type */ + if (cdd.status == CD_PLAY && !is_audio(cdd.index)) + { + /* DATA sector header (CD-ROM Mode 1) */ + uint8 header[4]; + uint32 msf = cdd.lba + 150; + header[0] = lut_BCD_8[(msf / 75) / 60]; + header[1] = lut_BCD_8[(msf / 75) % 60]; + header[2] = lut_BCD_8[(msf % 75)]; + header[3] = 0x01; + + /* data track sector read is controlled by CDC */ + cdc_decoder_update(header); + } + else + { + uint8 header[4] = { 0, }; + + /* audio blocks are still sent to CDC as well as CD DAC/Fader */ + cdc_decoder_update(header); + } + /* drive latency */ if (cdd.latency > 0) { @@ -737,33 +759,11 @@ void cdd_update(void) return; } - /* track type */ - if (!is_audio(cdd.index)) + /* check against audio track start index */ + if (is_audio(cdd.index) && cdd.lba >= cdd.toc.tracks[cdd.index].start) { - /* DATA sector header (CD-ROM Mode 1) */ - uint8 header[4]; - uint32 msf = cdd.lba + 150; - header[0] = lut_BCD_8[(msf / 75) / 60]; - header[1] = lut_BCD_8[(msf / 75) % 60]; - header[2] = lut_BCD_8[(msf % 75)]; - header[3] = 0x01; - - /* data track sector read is controlled by CDC */ - cdc_decoder_update(header); - } - else - { - uint8 header[4] = { 0, }; - - /* check against audio track start index */ - if (cdd.lba >= cdd.toc.tracks[cdd.index].start) - { - /* audio track playing */ - Pico_mcd->s68k_regs[0x36+0] = 0x00; - } - - /* audio blocks are still sent to CDC as well as CD DAC/Fader */ - cdc_decoder_update(header); + /* audio track playing */ + Pico_mcd->s68k_regs[0x36+0] = 0x00; } /* next block is automatically read */ @@ -1005,8 +1005,15 @@ void cdd_process(void) (Pico_mcd->s68k_regs[0x46+0] * 10 + Pico_mcd->s68k_regs[0x46+1])) * 75 + (Pico_mcd->s68k_regs[0x48+0] * 10 + Pico_mcd->s68k_regs[0x48+1]) - 150; - /* if drive is currently reading, another block or 2 are decoded before the seek starts */ - if (cdd.status == CD_PLAY && !(Pico_mcd->m.state_flags & PCD_ST_CDD_CMD)) { + /* return track index in RS2-RS3 */ + set_reg16(0x38, (CD_SEEK << 8) | 0x0f); + set_reg16(0x3a, 0x0000); + set_reg16(0x3c, 0x0000); + set_reg16(0x3e, 0x0000); + set_reg16(0x40, ~(CD_SEEK + 0xf) & 0x0f); + + /* seek delayed by max 2 blocks before the seek starts */ + if (!(Pico_mcd->m.state_flags & PCD_ST_CDD_CMD)) { Pico_mcd->m.state_flags |= PCD_ST_CDD_CMD; return; } @@ -1051,12 +1058,6 @@ void cdd_process(void) /* update status */ cdd.status = CD_PLAY; - /* return track index in RS2-RS3 */ - set_reg16(0x38, (CD_SEEK << 8) | 0x0f); - set_reg16(0x3a, 0x0000); - set_reg16(0x3c, 0x0000); - set_reg16(0x3e, 0x0000); - set_reg16(0x40, ~(CD_SEEK + 0xf) & 0x0f); return; } @@ -1070,8 +1071,15 @@ void cdd_process(void) (Pico_mcd->s68k_regs[0x46+0] * 10 + Pico_mcd->s68k_regs[0x46+1])) * 75 + (Pico_mcd->s68k_regs[0x48+0] * 10 + Pico_mcd->s68k_regs[0x48+1]) - 150; - /* if drive is currently reading, another block or 2 are decoded before the seek starts */ - if (cdd.status == CD_PLAY && !(Pico_mcd->m.state_flags & PCD_ST_CDD_CMD)) { + /* unknown RS1-RS8 values (returning 0xF in RS1 invalidates track infos in RS2-RS8 and fixes Final Fight CD intro when seek time is emulated) */ + set_reg16(0x38, (CD_SEEK << 8) | 0x0f); + set_reg16(0x3a, 0x0000); + set_reg16(0x3c, 0x0000); + set_reg16(0x3e, 0x0000); + set_reg16(0x40, ~(CD_SEEK + 0xf) & 0x0f); + + /* seek delayed by max 2 blocks before the seek starts */ + if (!(Pico_mcd->m.state_flags & PCD_ST_CDD_CMD)) { Pico_mcd->m.state_flags |= PCD_ST_CDD_CMD; return; } @@ -1101,19 +1109,16 @@ void cdd_process(void) /* update status */ cdd.status = CD_READY; - /* unknown RS1-RS8 values (returning 0xF in RS1 invalidates track infos in RS2-RS8 and fixes Final Fight CD intro when seek time is emulated) */ - set_reg16(0x38, (CD_SEEK << 8) | 0x0f); - set_reg16(0x3a, 0x0000); - set_reg16(0x3c, 0x0000); - set_reg16(0x3e, 0x0000); - set_reg16(0x40, ~(CD_SEEK + 0xf) & 0x0f); return; } case 0x06: /* Pause */ { - /* if drive is currently reading, another block or 2 are decoded before the seek starts */ - if (cdd.status == CD_PLAY && !(Pico_mcd->m.state_flags & PCD_ST_CDD_CMD)) { + /* update status (RS1-RS8 unchanged) */ + cdd.status = Pico_mcd->s68k_regs[0x38+0] = CD_READY; + + /* seek delayed by max 2 blocks before the seek starts */ + if (!(Pico_mcd->m.state_flags & PCD_ST_CDD_CMD)) { Pico_mcd->m.state_flags |= PCD_ST_CDD_CMD; return; } @@ -1121,8 +1126,6 @@ void cdd_process(void) /* no audio track playing */ Pico_mcd->s68k_regs[0x36+0] = 0x01; - /* update status (RS1-RS8 unchanged) */ - cdd.status = Pico_mcd->s68k_regs[0x38+0] = CD_READY; break; } diff --git a/pico/cd/mcd.c b/pico/cd/mcd.c index ca94aab9..7086a178 100644 --- a/pico/cd/mcd.c +++ b/pico/cd/mcd.c @@ -58,7 +58,7 @@ PICO_INTERNAL void PicoPowerMCD(void) Pico_mcd->m.state_flags = PCD_ST_S68K_RST; Pico_mcd->m.busreq = 2; // busreq on, s68k in reset Pico_mcd->s68k_regs[3] = 1; // 2M word RAM mode, m68k access - if (Pico.romsize <= 0x20000) // hack to detect BIOS, no GA HINT vector for MSU + if (Pico.romsize == 0x20000) // hack to detect BIOS, no GA HINT vector for MSU memset(Pico.rom + 0x70, 0xff, 4); } @@ -149,11 +149,11 @@ static void pcd_cdc_event(unsigned int now) { /* reset CDD command wait flag */ Pico_mcd->s68k_regs[0x4b] = 0xf0; + } - if ((Pico_mcd->s68k_regs[0x33] & PCDS_IEN4) && (Pico_mcd->s68k_regs[0x37] & 4)) { - elprintf(EL_INTS|EL_CD, "s68k: cdd irq 4"); - pcd_irq_s68k(4, 1); - } + if ((Pico_mcd->s68k_regs[0x33] & PCDS_IEN4) && (Pico_mcd->s68k_regs[0x37] & 4)) { + elprintf(EL_INTS|EL_CD, "s68k: cdd irq 4"); + pcd_irq_s68k(4, 1); } pcd_event_schedule(now, PCD_EVENT_CDC, 12500000/75); @@ -312,8 +312,7 @@ static int SekSyncM68k(int once); void pcd_run_cpus_normal(int m68k_cycles) { - // TODO this is suspicious. ~1 cycle refresh delay every 256 cycles? - SekAimM68k(m68k_cycles, 0x42); // Fhey area + SekAimM68k(m68k_cycles, 0x108); while (CYCLES_GT(Pico.t.m68c_aim, Pico.t.m68c_cnt)) { if (SekShouldInterrupt()) { diff --git a/pico/cd/memory.c b/pico/cd/memory.c index 99c6610b..461dc0d0 100644 --- a/pico/cd/memory.c +++ b/pico/cd/memory.c @@ -68,7 +68,7 @@ static void remap_word_ram(u32 r3); // poller detection #define POLL_LIMIT 16 -#define POLL_CYCLES 64 +#define POLL_CYCLES 52 void m68k_comm_check(u32 a) { @@ -122,18 +122,20 @@ static u32 m68k_reg_read16(u32 a) elprintf(EL_CDREG3, "m68k_regs r3: %02x @%06x", (u8)d, SekPc); goto end; case 4: + pcd_sync_s68k(SekCyclesDone(), 0); d = Pico_mcd->s68k_regs[4]<<8; goto end; case 6: d = *(u16 *)(Pico.rom + 0x72); goto end; case 8: - d = cdc_host_r(); + d = cdc_host_r(0); goto end; case 0xa: elprintf(EL_UIO, "m68k FIXME: reserved read"); goto end; case 0xc: // 384 cycle stopwatch timer + pcd_sync_s68k(SekCyclesDone(), 0); d = pcd_stopwatch_read(0); elprintf(EL_CDREGS, "m68k stopwatch timer read (%04x)", d); goto end; @@ -238,7 +240,7 @@ void m68k_reg_write8(u32 a, u32 d) ((u16 *)Pico.rom)[0x70/2], ((u16 *)Pico.rom)[0x72/2]); return; case 8: - (void) cdc_host_r(); // acts same as reading + (void) cdc_host_r(0); // acts same as reading return; case 0x0f: a = 0x0e; @@ -338,7 +340,7 @@ u32 s68k_reg_read16(u32 a) d = cdc_reg_r(); goto end; case 8: - d = cdc_host_r(); + d = cdc_host_r(1); goto end; case 0xc: d = pcd_stopwatch_read(1); @@ -557,7 +559,7 @@ void s68k_reg_write16(u32 a, u32 d) // these are only byte registers, LDS/UDS ignored return s68k_reg_write8(a + 1, d); case 0x08: - return (void) cdc_host_r(); // acts same as reading + return (void) cdc_host_r(1); // acts same as reading case 0x0a: // DMA address r[0xa] = d >> 8; r[0xb] = d; @@ -1232,13 +1234,13 @@ PICO_INTERNAL void PicoMemSetupCD(void) Pico_mcd = plat_mmap(0x05000000, sizeof(mcd_state), 0, 0); memset(Pico_mcd, 0, sizeof(mcd_state)); } - pcd_base_address = (Pico.romsize > 0x20000 ? 0x400000 : 0x000000); + pcd_base_address = (Pico.romsize != 0x20000 ? 0x400000 : 0x000000); // setup default main68k map PicoMemSetup(); // main68k map (BIOS or MSU mapped by PicoMemSetup()): - if (Pico.romsize > 0x20000) { + if (pcd_base_address != 0) { // MSU cartridge. Fake BIOS detection cpu68k_map_set(m68k_read8_map, 0x400000, 0x41ffff, PicoReadM68k8_bios, 1); cpu68k_map_set(m68k_read16_map, 0x400000, 0x41ffff, PicoReadM68k16_bios, 1); diff --git a/pico/pico_int.h b/pico/pico_int.h index 7875b8a0..546e5ec3 100644 --- a/pico/pico_int.h +++ b/pico/pico_int.h @@ -763,7 +763,7 @@ void cdc_dma_update(void); int cdc_decoder_update(unsigned char header[4]); void cdc_reg_w(unsigned char data); unsigned char cdc_reg_r(void); -unsigned short cdc_host_r(void); +unsigned short cdc_host_r(int sub); // cd/cdd.c void cdd_reset(void);