mirror of
https://github.com/ekeeke/Genesis-Plus-GX.git
synced 2024-12-26 19:21:49 +01:00
961 lines
25 KiB
C
961 lines
25 KiB
C
/***************************************************************************************
|
|
* Genesis Plus
|
|
* CD data controller (LC8951x compatible)
|
|
*
|
|
* Copyright (C) 2012-2024 Eke-Eke (Genesis Plus GX)
|
|
*
|
|
* Redistribution and use of this code or any derivative works are permitted
|
|
* provided that the following conditions are met:
|
|
*
|
|
* - Redistributions may not be sold, nor may they be used in a commercial
|
|
* product or activity.
|
|
*
|
|
* - Redistributions that are modified from the original source must include the
|
|
* complete source code, including the source code for all components used by a
|
|
* binary built from the modified sources. However, as a special exception, the
|
|
* source code distributed need not include anything that is normally distributed
|
|
* (in either source or binary form) with the major components (compiler, kernel,
|
|
* and so on) of the operating system on which the executable runs, unless that
|
|
* component itself accompanies the executable.
|
|
*
|
|
* - Redistributions must reproduce the above copyright notice, this list of
|
|
* conditions and the following disclaimer in the documentation and/or other
|
|
* materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
****************************************************************************************/
|
|
|
|
#include "shared.h"
|
|
|
|
/* IFSTAT register bitmasks */
|
|
#define BIT_DTEI 0x40
|
|
#define BIT_DECI 0x20
|
|
#define BIT_DTBSY 0x08
|
|
#define BIT_DTEN 0x02
|
|
|
|
/* IFCTRL register bitmasks */
|
|
#define BIT_DTEIEN 0x40
|
|
#define BIT_DECIEN 0x20
|
|
#define BIT_DOUTEN 0x02
|
|
|
|
/* CTRL0 register bitmasks */
|
|
#define BIT_DECEN 0x80
|
|
#define BIT_AUTORQ 0x10
|
|
#define BIT_WRRQ 0x04
|
|
|
|
/* CTRL1 register bitmasks */
|
|
#define BIT_MODRQ 0x08
|
|
#define BIT_FORMRQ 0x04
|
|
#define BIT_SHDREN 0x01
|
|
|
|
/* STAT3 register bitmask */
|
|
#define BIT_VALST 0x80
|
|
|
|
/* DMA transfer rate */
|
|
/* min. 4 x SUB-CPU cycles (i.e 16 x SCD cycles) per byte (cf https://github.com/MiSTer-devel/MegaCD_MiSTer/tree/master/docs/mcd%20logs) */
|
|
/* additional delays caused by SUB-CPU access & periodic refresh (all RAM), GPU operation (Word-RAM only) or PCM playback (PCM RAM only) */
|
|
/* are not emulated */
|
|
#define DMA_CYCLES_PER_BYTE 16
|
|
|
|
void cdc_init(void)
|
|
{
|
|
memset(&cdc, 0, sizeof(cdc_t));
|
|
|
|
/* autodetect CDC configuration */
|
|
if ((scd.type == CD_TYPE_WONDERMEGA_M2) || (scd.type == CD_TYPE_CDX))
|
|
{
|
|
/* LC89513K chip (Wondermega M2 / X'Eye / CDX / Multi-Mega) */
|
|
cdc.ar_mask = 0x1f;
|
|
}
|
|
else
|
|
{
|
|
/* LC8951 or LC89515 chip (default)*/
|
|
cdc.ar_mask = 0x0f;
|
|
}
|
|
}
|
|
|
|
void cdc_reset(void)
|
|
{
|
|
/* reset CDC register index */
|
|
scd.regs[0x04>>1].byte.l = 0x00;
|
|
|
|
/* reset CDC registers */
|
|
cdc.ifstat = 0xff;
|
|
cdc.ifctrl = 0x00;
|
|
cdc.ctrl[0] = 0x00;
|
|
cdc.ctrl[1] = 0x00;
|
|
cdc.stat[0] = 0x00;
|
|
cdc.stat[1] = 0x00;
|
|
cdc.stat[2] = 0x00;
|
|
cdc.stat[3] = 0x80;
|
|
cdc.head[0][0] = 0x00;
|
|
cdc.head[0][1] = 0x00;
|
|
cdc.head[0][2] = 0x00;
|
|
cdc.head[0][3] = 0x01;
|
|
cdc.head[1][0] = 0x00;
|
|
cdc.head[1][1] = 0x00;
|
|
cdc.head[1][2] = 0x00;
|
|
cdc.head[1][3] = 0x00;
|
|
|
|
/* reset CDC DMA & decoder cycle counters */
|
|
cdc.cycles[0] = cdc.cycles[1] = 0;
|
|
|
|
/* disable CDC DMA */
|
|
cdc.dma_w = cdc.halted_dma_w = 0;
|
|
|
|
/* reset CDC IRQ state */
|
|
cdc.irq = 0;
|
|
|
|
/* clear any pending IRQ */
|
|
if (scd.pending & (1 << 5))
|
|
{
|
|
/* clear any pending interrupt level 5 */
|
|
scd.pending &= ~(1 << 5);
|
|
|
|
/* update IRQ level */
|
|
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);
|
|
}
|
|
}
|
|
|
|
int cdc_context_save(uint8 *state)
|
|
{
|
|
uint8 tmp8;
|
|
int bufferptr = 0;
|
|
|
|
if (cdc.dma_w == pcm_ram_dma_w)
|
|
{
|
|
tmp8 = 1;
|
|
}
|
|
else if (cdc.dma_w == prg_ram_dma_w)
|
|
{
|
|
tmp8 = 2;
|
|
}
|
|
else if (cdc.dma_w == word_ram_0_dma_w)
|
|
{
|
|
tmp8 = 3;
|
|
}
|
|
else if (cdc.dma_w == word_ram_1_dma_w)
|
|
{
|
|
tmp8 = 4;
|
|
}
|
|
else if (cdc.dma_w == word_ram_2M_dma_w)
|
|
{
|
|
tmp8 = 5;
|
|
}
|
|
else if (cdc.halted_dma_w == prg_ram_dma_w)
|
|
{
|
|
tmp8 = 6;
|
|
}
|
|
else if (cdc.halted_dma_w == word_ram_2M_dma_w)
|
|
{
|
|
tmp8 = 7;
|
|
}
|
|
else
|
|
{
|
|
tmp8 = 0;
|
|
}
|
|
|
|
save_param(&cdc.ifstat, sizeof(cdc.ifstat));
|
|
save_param(&cdc.ifctrl, sizeof(cdc.ifctrl));
|
|
save_param(&cdc.dbc, sizeof(cdc.dbc));
|
|
save_param(&cdc.dac, sizeof(cdc.dac));
|
|
save_param(&cdc.pt, sizeof(cdc.pt));
|
|
save_param(&cdc.wa, sizeof(cdc.wa));
|
|
save_param(&cdc.ctrl, sizeof(cdc.ctrl));
|
|
save_param(&cdc.head, sizeof(cdc.head));
|
|
save_param(&cdc.stat, sizeof(cdc.stat));
|
|
save_param(&cdc.cycles, sizeof(cdc.cycles));
|
|
save_param(&cdc.ram, sizeof(cdc.ram));
|
|
save_param(&tmp8, 1);
|
|
|
|
return bufferptr;
|
|
}
|
|
|
|
int cdc_context_load(uint8 *state)
|
|
{
|
|
uint8 tmp8;
|
|
int bufferptr = 0;
|
|
|
|
load_param(&cdc.ifstat, sizeof(cdc.ifstat));
|
|
load_param(&cdc.ifctrl, sizeof(cdc.ifctrl));
|
|
load_param(&cdc.dbc, sizeof(cdc.dbc));
|
|
load_param(&cdc.dac, sizeof(cdc.dac));
|
|
load_param(&cdc.pt, sizeof(cdc.pt));
|
|
load_param(&cdc.wa, sizeof(cdc.wa));
|
|
load_param(&cdc.ctrl, sizeof(cdc.ctrl));
|
|
load_param(&cdc.head, sizeof(cdc.head));
|
|
load_param(&cdc.stat, sizeof(cdc.stat));
|
|
load_param(&cdc.cycles, sizeof(cdc.cycles));
|
|
load_param(&cdc.ram, sizeof(cdc.ram));
|
|
|
|
load_param(&tmp8, 1);
|
|
|
|
switch (tmp8)
|
|
{
|
|
case 1:
|
|
cdc.dma_w = pcm_ram_dma_w;
|
|
cdc.halted_dma_w = 0;
|
|
break;
|
|
case 2:
|
|
cdc.dma_w = prg_ram_dma_w;
|
|
cdc.halted_dma_w = 0;
|
|
break;
|
|
case 3:
|
|
cdc.dma_w = word_ram_0_dma_w;
|
|
cdc.halted_dma_w = 0;
|
|
break;
|
|
case 4:
|
|
cdc.dma_w = word_ram_1_dma_w;
|
|
cdc.halted_dma_w = 0;
|
|
break;
|
|
case 5:
|
|
cdc.dma_w = word_ram_2M_dma_w;
|
|
cdc.halted_dma_w = 0;
|
|
break;
|
|
case 6:
|
|
cdc.dma_w = 0;
|
|
cdc.halted_dma_w = prg_ram_dma_w;
|
|
break;
|
|
case 7:
|
|
cdc.dma_w = 0;
|
|
cdc.halted_dma_w = word_ram_2M_dma_w;
|
|
break;
|
|
default:
|
|
cdc.dma_w = 0;
|
|
cdc.halted_dma_w = 0;
|
|
break;
|
|
}
|
|
|
|
cdc.irq = ~cdc.ifstat & cdc.ifctrl & (BIT_DTEIEN | BIT_DECIEN);
|
|
|
|
return bufferptr;
|
|
}
|
|
|
|
void cdc_dma_init(void)
|
|
{
|
|
/* no effect if data transfer is not started */
|
|
if (cdc.ifstat & BIT_DTEN)
|
|
return;
|
|
|
|
/* disable DMA by default */
|
|
cdc.dma_w = cdc.halted_dma_w = 0;
|
|
|
|
/* check data transfer destination */
|
|
switch (scd.regs[0x04>>1].byte.h & 0x07)
|
|
{
|
|
case 2: /* MAIN-CPU host read */
|
|
case 3: /* SUB-CPU host read */
|
|
{
|
|
/* read 16-bit word from CDC RAM buffer (big-endian format) into gate-array register $08 */
|
|
/* Note: on real-hardware, 16-bit word is not immediately available, cf. https://github.com/MiSTer-devel/MegaCD_MiSTer/blob/master/docs/mcd%20logs/dma_sub_read.jpg for transfer timings */
|
|
scd.regs[0x08>>1].w = READ_WORD(cdc.ram, cdc.dac.w & 0x3ffe);
|
|
#ifdef LOG_CDC
|
|
error("CDC host read 0x%04x -> 0x%04x (dbc=0x%x) (%X)\n", cdc.dac.w, scd.regs[0x08>>1].w, cdc.dbc.w, s68k.pc);
|
|
#endif
|
|
|
|
/* set DSR bit (gate-array register $04) */
|
|
scd.regs[0x04>>1].byte.h |= 0x40;
|
|
|
|
/* increment data address counter */
|
|
cdc.dac.w += 2;
|
|
|
|
/* decrement data byte counter */
|
|
cdc.dbc.w -= 2;
|
|
|
|
/* end of transfer ? */
|
|
if ((int16)cdc.dbc.w < 0)
|
|
{
|
|
/* reset data byte counter (DBCH bits 4-7 should also be set to 1) */
|
|
cdc.dbc.w = 0xffff;
|
|
|
|
/* clear !DTEN and !DTBSY */
|
|
cdc.ifstat |= (BIT_DTBSY | BIT_DTEN);
|
|
|
|
/* pending Data Transfer End interrupt */
|
|
cdc.ifstat &= ~BIT_DTEI;
|
|
|
|
/* Data Transfer End interrupt enabled ? */
|
|
if (cdc.ifctrl & BIT_DTEIEN)
|
|
{
|
|
/* check end of CDC decoder active period */
|
|
if ((cdc.irq & BIT_DECI) && (cdc.cycles[0] > cdc.cycles[1]))
|
|
{
|
|
/* clear pending decoder interrupt */
|
|
cdc.ifstat |= BIT_DECI;
|
|
|
|
/* update CDC IRQ state */
|
|
cdc.irq &= ~BIT_DECI;
|
|
}
|
|
|
|
/* level 5 interrupt triggered only on CDC /INT falling edge with interrupt enabled on gate-array side */
|
|
if (!cdc.irq && (scd.regs[0x32>>1].byte.l & 0x20))
|
|
{
|
|
/* pending level 5 interrupt */
|
|
scd.pending |= (1 << 5);
|
|
|
|
/* update IRQ level */
|
|
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);
|
|
}
|
|
|
|
/* update CDC IRQ state */
|
|
cdc.irq |= BIT_DTEI;
|
|
}
|
|
|
|
/* set EDT bit (gate-array register $04) */
|
|
scd.regs[0x04>>1].byte.h |= 0x80;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case 4: /* PCM RAM DMA */
|
|
{
|
|
cdc.dma_w = pcm_ram_dma_w;
|
|
break;
|
|
}
|
|
|
|
case 5: /* PRG-RAM DMA */
|
|
{
|
|
/* check if MAIN-CPU has access to PRG-RAM */
|
|
if (scd.regs[0x00].byte.l & 0x02)
|
|
{
|
|
/* halt DMA to PRG-RAM */
|
|
cdc.halted_dma_w = prg_ram_dma_w;
|
|
}
|
|
else
|
|
{
|
|
/* enable DMA to PRG-RAM */
|
|
cdc.dma_w = prg_ram_dma_w;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 7: /* Word-RAM DMA */
|
|
{
|
|
/* check memory mode */
|
|
if (scd.regs[0x02 >> 1].byte.l & 0x04)
|
|
{
|
|
/* 1M mode */
|
|
if (scd.regs[0x02 >> 1].byte.l & 0x01)
|
|
{
|
|
/* Word-RAM bank 0 is assigned to SUB-CPU */
|
|
cdc.dma_w = word_ram_0_dma_w;
|
|
}
|
|
else
|
|
{
|
|
/* Word-RAM bank 1 is assigned to SUB-CPU */
|
|
cdc.dma_w = word_ram_1_dma_w;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* check if MAIN-CPU has access to 2M Word-RAM */
|
|
if (scd.regs[0x02 >> 1].byte.l & 0x01)
|
|
{
|
|
/* halt DMA to 2M Word-RAM */
|
|
cdc.halted_dma_w = word_ram_2M_dma_w;
|
|
}
|
|
else
|
|
{
|
|
/* enable DMA to 2M Word-RAM */
|
|
cdc.dma_w = word_ram_2M_dma_w;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
default: /* invalid */
|
|
{
|
|
#ifdef LOG_CDC
|
|
error("invalid CDC transfer destination (%d)\n", scd.regs[0x04>>1].byte.h & 0x07);
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void cdc_dma_update(unsigned int cycles)
|
|
{
|
|
/* max number of bytes that can be transfered */
|
|
int dma_bytes = (cycles - cdc.cycles[0] + DMA_CYCLES_PER_BYTE - 1) / DMA_CYCLES_PER_BYTE;
|
|
|
|
/* always process blocks of 8 bytes */
|
|
dma_bytes = (dma_bytes / 8) * 8;
|
|
|
|
/* end of DMA transfer ? */
|
|
if (cdc.dbc.w < dma_bytes)
|
|
{
|
|
/* transfer remaining bytes using DMA */
|
|
cdc.dma_w(cdc.dbc.w + 1);
|
|
|
|
/* update DMA cycle counter */
|
|
cdc.cycles[0] += (cdc.dbc.w + 1) * DMA_CYCLES_PER_BYTE;
|
|
|
|
/* reset data byte counter (DBCH bits 4-7 should also be set to 1) */
|
|
cdc.dbc.w = 0xffff;
|
|
|
|
/* clear !DTEN and !DTBSY */
|
|
cdc.ifstat |= (BIT_DTBSY | BIT_DTEN);
|
|
|
|
/* pending Data Transfer End interrupt */
|
|
cdc.ifstat &= ~BIT_DTEI;
|
|
|
|
/* Data Transfer End interrupt enabled ? */
|
|
if (cdc.ifctrl & BIT_DTEIEN)
|
|
{
|
|
/* check end of CDC decoder active period */
|
|
if ((cdc.irq & BIT_DECI) && (cdc.cycles[0] > cdc.cycles[1]))
|
|
{
|
|
/* clear pending decoder interrupt */
|
|
cdc.ifstat |= BIT_DECI;
|
|
|
|
/* update CDC IRQ state */
|
|
cdc.irq &= ~BIT_DECI;
|
|
}
|
|
|
|
/* level 5 interrupt triggered only on CDC /INT falling edge with interrupt enabled on gate-array side*/
|
|
if (!cdc.irq && (scd.regs[0x32>>1].byte.l & 0x20))
|
|
{
|
|
/* pending level 5 interrupt */
|
|
scd.pending |= (1 << 5);
|
|
|
|
/* update IRQ level */
|
|
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);
|
|
}
|
|
|
|
/* update CDC IRQ state */
|
|
cdc.irq |= BIT_DTEI;
|
|
}
|
|
|
|
/* clear DSR bit & set EDT bit (CD register $04) */
|
|
scd.regs[0x04>>1].byte.h = (scd.regs[0x04>>1].byte.h & 0x07) | 0x80;
|
|
|
|
/* SUB-CPU idle on register $04 polling ? */
|
|
if (s68k.stopped & (1<<0x04))
|
|
{
|
|
/* sync SUB-CPU with CDC DMA (only if not already ahead) */
|
|
if (s68k.cycles < cdc.cycles[0])
|
|
{
|
|
s68k.cycles = cdc.cycles[0];
|
|
}
|
|
|
|
/* restart SUB-CPU */
|
|
s68k.stopped = 0;
|
|
#ifdef LOG_SCD
|
|
error("s68k started from %d cycles\n", s68k.cycles);
|
|
#endif
|
|
}
|
|
|
|
/* disable DMA */
|
|
cdc.dma_w = cdc.halted_dma_w = 0;
|
|
}
|
|
else if (dma_bytes > 0)
|
|
{
|
|
/* transfer limited amount of bytes using DMA */
|
|
cdc.dma_w(dma_bytes);
|
|
|
|
/* decrement data byte counter */
|
|
cdc.dbc.w -= dma_bytes;
|
|
|
|
/* update DMA cycle counter */
|
|
cdc.cycles[0] += dma_bytes * DMA_CYCLES_PER_BYTE;
|
|
}
|
|
}
|
|
|
|
void cdc_decoder_update(uint32 header)
|
|
{
|
|
/* data decoding enabled ? */
|
|
if (cdc.ctrl[0] & BIT_DECEN)
|
|
{
|
|
/* update HEADx registers with current block header */
|
|
*(uint32 *)(cdc.head[0]) = header;
|
|
|
|
/* set !VALST */
|
|
cdc.stat[3] = 0x00;
|
|
|
|
/* pending decoder interrupt */
|
|
cdc.ifstat &= ~BIT_DECI;
|
|
|
|
/* update CDC decoder end cycle (value adjusted for MCD-verificator CDC FLAGS Tests #40 & #41) */
|
|
cdc.cycles[1] = s68k.cycles + 269000;
|
|
|
|
/* decoder interrupt enabled ? */
|
|
if (cdc.ifctrl & BIT_DECIEN)
|
|
{
|
|
/* level 5 interrupt triggered only on CDC /INT falling edge with interrupt enabled on gate-array side */
|
|
/* note: only check DTEI as DECI is cleared automatically between decoder interrupt triggering */
|
|
if (!(cdc.irq & BIT_DTEI) && (scd.regs[0x32>>1].byte.l & 0x20))
|
|
{
|
|
/* pending level 5 interrupt */
|
|
scd.pending |= (1 << 5);
|
|
|
|
/* update IRQ level */
|
|
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);
|
|
}
|
|
|
|
/* update CDC IRQ state */
|
|
cdc.irq |= BIT_DECI;
|
|
}
|
|
|
|
/* buffer RAM write enabled ? */
|
|
if (cdc.ctrl[0] & BIT_WRRQ)
|
|
{
|
|
int offset;
|
|
|
|
/* increment block pointer */
|
|
cdc.pt.w += 2352;
|
|
|
|
/* increment write address */
|
|
cdc.wa.w += 2352;
|
|
|
|
/* CDC buffer address */
|
|
offset = cdc.pt.w & 0x3fff;
|
|
|
|
/* write current block header to RAM buffer (4 bytes) */
|
|
*(uint32 *)(cdc.ram + offset) = header;
|
|
offset += 4;
|
|
|
|
/* check decoded block mode */
|
|
if (cdc.head[0][3] == 0x01)
|
|
{
|
|
/* write Mode 1 user data to RAM buffer (2048 bytes) */
|
|
cdd_read_data(cdc.ram + offset, NULL);
|
|
offset += 2048;
|
|
}
|
|
else
|
|
{
|
|
/* check if CD-ROM Mode 2 decoding is enabled */
|
|
if (cdc.ctrl[1] & BIT_MODRQ)
|
|
{
|
|
/* update HEADx registers with current block sub-header & write Mode 2 user data to RAM buffer (max 2328 bytes) */
|
|
cdd_read_data(cdc.ram + offset + 8, cdc.head[1]);
|
|
|
|
/* write current block sub-header to RAM buffer (4 bytes x 2) */
|
|
*(uint32 *)(cdc.ram + offset) = *(uint32 *)(cdc.head[1]);
|
|
*(uint32 *)(cdc.ram + offset + 4) = *(uint32 *)(cdc.head[1]);
|
|
offset += 2336;
|
|
}
|
|
else
|
|
{
|
|
/* update HEADx registers with current block sub-header & write Mode 2 user data to RAM buffer (max 2328 bytes) */
|
|
/* NB: when Mode 2 decoding is disabled, sub-header is apparently not written to RAM buffer (required by Wonder Library) */
|
|
cdd_read_data(cdc.ram + offset, cdc.head[1]);
|
|
offset += 2328;
|
|
}
|
|
|
|
/* set STAT2 register FORM bit according to sub-header FORM bit when CTRL0 register AUTORQ bit is set */
|
|
if (cdc.ctrl[0] & BIT_AUTORQ)
|
|
{
|
|
cdc.stat[2] = (cdc.ctrl[1] & BIT_MODRQ) | ((cdc.head[1][2] & 0x20) >> 3);
|
|
}
|
|
}
|
|
|
|
/* take care of buffer overrun */
|
|
if (offset > 0x4000)
|
|
{
|
|
/* data should be written at the start of buffer */
|
|
memcpy(cdc.ram, cdc.ram + 0x4000, offset - 0x4000);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void cdc_reg_w(unsigned char data)
|
|
{
|
|
#ifdef LOG_CDC
|
|
error("CDC register %d write 0x%04x (%X)\n", scd.regs[0x04>>1].byte.l, data, s68k.pc);
|
|
#endif
|
|
switch (scd.regs[0x04>>1].byte.l)
|
|
{
|
|
case 0x01: /* IFCTRL */
|
|
{
|
|
/* previous CDC IRQ state */
|
|
uint8 prev_irq = cdc.irq;
|
|
|
|
/* check end of CDC decoder active period */
|
|
if (s68k.cycles > cdc.cycles[1])
|
|
{
|
|
/* clear pending decoder interrupt */
|
|
cdc.ifstat |= BIT_DECI;
|
|
|
|
/* update previous CDC IRQ state */
|
|
prev_irq &= ~BIT_DECI;
|
|
}
|
|
|
|
/* update CDC IRQ state according to DTEIEN and DECIEN bits */
|
|
cdc.irq = ~cdc.ifstat & data & (BIT_DTEIEN | BIT_DECIEN);
|
|
|
|
/* level 5 interrupt is triggered on CDC /INT falling edge if interrupt enabled on gate-array side */
|
|
if (cdc.irq && !prev_irq && (scd.regs[0x32>>1].byte.l & 0x20))
|
|
{
|
|
/* pending level 5 interrupt */
|
|
scd.pending |= (1 << 5);
|
|
|
|
/* update IRQ level */
|
|
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);
|
|
}
|
|
|
|
/* abort any data transfer if data output is disabled */
|
|
if (!(data & BIT_DOUTEN))
|
|
{
|
|
/* clear !DTBSY and !DTEN */
|
|
cdc.ifstat |= (BIT_DTBSY | BIT_DTEN);
|
|
|
|
/* disable DMA */
|
|
cdc.dma_w = cdc.halted_dma_w = 0;
|
|
}
|
|
|
|
cdc.ifctrl = data;
|
|
break;
|
|
}
|
|
|
|
case 0x02: /* DBCL */
|
|
cdc.dbc.byte.l = data;
|
|
break;
|
|
|
|
case 0x03: /* DBCH */
|
|
cdc.dbc.byte.h = data & 0x0f;
|
|
break;
|
|
|
|
case 0x04: /* DACL */
|
|
cdc.dac.byte.l = data;
|
|
break;
|
|
|
|
case 0x05: /* DACH */
|
|
cdc.dac.byte.h = data;
|
|
break;
|
|
|
|
case 0x06: /* DTRG */
|
|
{
|
|
/* start data transfer if data output is enabled */
|
|
if (cdc.ifctrl & BIT_DOUTEN)
|
|
{
|
|
/* set !DTBSY and !DTEN */
|
|
cdc.ifstat &= ~(BIT_DTBSY | BIT_DTEN);
|
|
|
|
/* clear EDT & DSR bits (gate-array register $04) */
|
|
scd.regs[0x04>>1].byte.h &= 0x07;
|
|
|
|
/* initialize data transfer destination */
|
|
cdc_dma_init();
|
|
|
|
/* initialize DMA cycle counter */
|
|
cdc.cycles[0] = s68k.cycles;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case 0x07: /* DTACK */
|
|
{
|
|
/* clear pending data transfer end interrupt */
|
|
cdc.ifstat |= BIT_DTEI;
|
|
|
|
/* update CDC IRQ state */
|
|
cdc.irq &= ~BIT_DTEI;
|
|
break;
|
|
}
|
|
|
|
case 0x08: /* WAL */
|
|
cdc.wa.byte.l = data;
|
|
break;
|
|
|
|
case 0x09: /* WAH */
|
|
cdc.wa.byte.h = data;
|
|
break;
|
|
|
|
case 0x0a: /* CTRL0 */
|
|
{
|
|
/* set CRCOK bit only if decoding is enabled */
|
|
cdc.stat[0] = data & BIT_DECEN;
|
|
|
|
/* decoding disabled ? */
|
|
if (!(data & BIT_DECEN))
|
|
{
|
|
/* clear pending decoder interrupt */
|
|
cdc.ifstat |= BIT_DECI;
|
|
|
|
/* update CDC IRQ state */
|
|
cdc.irq &= ~BIT_DECI;
|
|
}
|
|
|
|
/* update STAT2 register */
|
|
if (data & BIT_AUTORQ)
|
|
{
|
|
/* set MODE bit according to CTRL1 register MODRQ bit & set FORM bit according to sub-header FORM bit*/
|
|
cdc.stat[2] = (cdc.ctrl[1] & BIT_MODRQ) | ((cdc.head[1][2] & 0x20) >> 3);
|
|
}
|
|
else
|
|
{
|
|
/* set MODE & FORM bits according to CTRL1 register MODRQ & FORMRQ bits */
|
|
cdc.stat[2] = cdc.ctrl[1] & (BIT_MODRQ | BIT_FORMRQ);
|
|
}
|
|
|
|
cdc.ctrl[0] = data;
|
|
break;
|
|
}
|
|
|
|
case 0x0b: /* CTRL1 */
|
|
{
|
|
/* update STAT2 register */
|
|
if (cdc.ctrl[0] & BIT_AUTORQ)
|
|
{
|
|
/* set MODE bit according to CTRL1 register MODRQ bit & set FORM bit according to sub-header FORM bit*/
|
|
cdc.stat[2] = (data & BIT_MODRQ) | ((cdc.head[1][2] & 0x20) >> 3);
|
|
}
|
|
else
|
|
{
|
|
/* set MODE & FORM bits according to CTRL1 register MODRQ & FORMRQ bits */
|
|
cdc.stat[2] = data & (BIT_MODRQ | BIT_FORMRQ);
|
|
}
|
|
|
|
cdc.ctrl[1] = data;
|
|
break;
|
|
}
|
|
|
|
case 0x0c: /* PTL */
|
|
cdc.pt.byte.l = data;
|
|
break;
|
|
|
|
case 0x0d: /* PTH */
|
|
cdc.pt.byte.h = data;
|
|
break;
|
|
|
|
case 0x0f: /* RESET */
|
|
cdc_reset();
|
|
break;
|
|
|
|
default: /* unemulated registers */
|
|
break;
|
|
}
|
|
|
|
/* increment address register (except when register #0 is selected) */
|
|
if (scd.regs[0x04>>1].byte.l)
|
|
{
|
|
scd.regs[0x04>>1].byte.l = (scd.regs[0x04>>1].byte.l + 1) & cdc.ar_mask;
|
|
}
|
|
}
|
|
|
|
unsigned char cdc_reg_r(void)
|
|
{
|
|
uint8 data;
|
|
|
|
switch (scd.regs[0x04>>1].byte.l)
|
|
{
|
|
case 0x01: /* IFSTAT */
|
|
{
|
|
/* check end of CDC decoder active period */
|
|
if (s68k.cycles > cdc.cycles[1])
|
|
{
|
|
/* clear pending decoder interrupt */
|
|
cdc.ifstat |= BIT_DECI;
|
|
|
|
/* update CDC IRQ state */
|
|
cdc.irq &= ~BIT_DECI;
|
|
}
|
|
|
|
data = cdc.ifstat;
|
|
break;
|
|
}
|
|
|
|
case 0x02: /* DBCL */
|
|
{
|
|
data = cdc.dbc.byte.l;
|
|
break;
|
|
}
|
|
|
|
case 0x03: /* DBCH */
|
|
{
|
|
data = cdc.dbc.byte.h;
|
|
break;
|
|
}
|
|
|
|
case 0x04: /* HEAD0 */
|
|
{
|
|
data = cdc.head[cdc.ctrl[1] & BIT_SHDREN][0];
|
|
break;
|
|
}
|
|
|
|
case 0x05: /* HEAD1 */
|
|
{
|
|
data = cdc.head[cdc.ctrl[1] & BIT_SHDREN][1];
|
|
break;
|
|
}
|
|
|
|
case 0x06: /* HEAD2 */
|
|
{
|
|
data = cdc.head[cdc.ctrl[1] & BIT_SHDREN][2];
|
|
break;
|
|
}
|
|
|
|
case 0x07: /* HEAD3 */
|
|
{
|
|
data = cdc.head[cdc.ctrl[1] & BIT_SHDREN][3];
|
|
break;
|
|
}
|
|
|
|
case 0x08: /* PTL */
|
|
{
|
|
data = cdc.pt.byte.l;
|
|
break;
|
|
}
|
|
|
|
case 0x09: /* PTH */
|
|
{
|
|
data = cdc.pt.byte.h;
|
|
break;
|
|
}
|
|
|
|
case 0x0a: /* WAL */
|
|
{
|
|
data = cdc.wa.byte.l;
|
|
break;
|
|
}
|
|
|
|
case 0x0b: /* WAH */
|
|
{
|
|
data = cdc.wa.byte.h;
|
|
break;
|
|
}
|
|
|
|
case 0x0c: /* STAT0 */
|
|
{
|
|
data = cdc.stat[0];
|
|
break;
|
|
}
|
|
|
|
case 0x0d: /* STAT1 (always return 0) */
|
|
{
|
|
data = 0x00;
|
|
break;
|
|
}
|
|
|
|
case 0x0e: /* STAT2 */
|
|
{
|
|
data = cdc.stat[2];
|
|
break;
|
|
}
|
|
|
|
case 0x0f: /* STAT3 */
|
|
{
|
|
data = cdc.stat[3];
|
|
|
|
/* clear !VALST (note: this is not 100% correct but BIOS do not seem to care) */
|
|
cdc.stat[3] = BIT_VALST;
|
|
|
|
/* clear pending decoder interrupt */
|
|
cdc.ifstat |= BIT_DECI;
|
|
|
|
/* update CDC IRQ state */
|
|
cdc.irq &= ~BIT_DECI;
|
|
break;
|
|
}
|
|
|
|
default: /* unemulated registers */
|
|
{
|
|
data = 0xff;
|
|
break;
|
|
}
|
|
}
|
|
|
|
#ifdef LOG_CDC
|
|
error("CDC register %d read 0x%02X (%X)\n", scd.regs[0x04>>1].byte.l, data, s68k.pc);
|
|
#endif
|
|
|
|
/* increment address register (except when register #0 is selected) */
|
|
if (scd.regs[0x04>>1].byte.l)
|
|
{
|
|
scd.regs[0x04>>1].byte.l = (scd.regs[0x04>>1].byte.l + 1) & cdc.ar_mask;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
unsigned short cdc_host_r(uint8 cpu_access)
|
|
{
|
|
/* read CDC buffered data (gate-array register $08) */
|
|
uint16 data = scd.regs[0x08>>1].w;
|
|
|
|
/* check if host data transfer is started for selected CPU */
|
|
if ((scd.regs[0x04>>1].byte.h & 0x47) == cpu_access)
|
|
{
|
|
/* check if EDT bit (gate-array register $04) is set (host data transfer is finished) */
|
|
if (scd.regs[0x04>>1].byte.h & 0x80)
|
|
{
|
|
/* clear DSR bit (gate-array register $04) */
|
|
scd.regs[0x04>>1].byte.h &= ~0x40;
|
|
}
|
|
else
|
|
{
|
|
/* read next 16-bit word from CDC RAM buffer (big-endian format) into gate-array register $08 */
|
|
/* Note: on real-hardware, 16-bit word is not immediately available, cf. https://github.com/MiSTer-devel/MegaCD_MiSTer/blob/master/docs/mcd%20logs/dma_sub_read.jpg for transfer timings */
|
|
scd.regs[0x08>>1].w = READ_WORD(cdc.ram, cdc.dac.w & 0x3ffe);
|
|
#ifdef LOG_CDC
|
|
error("CDC host read 0x%04x -> 0x%04x (dbc=0x%x) (%X)\n", cdc.dac.w, scd.regs[0x08>>1].w, cdc.dbc.w, s68k.pc);
|
|
#endif
|
|
|
|
/* increment data address counter */
|
|
cdc.dac.w += 2;
|
|
|
|
/* decrement data byte counter */
|
|
cdc.dbc.w -= 2;
|
|
|
|
/* end of transfer ? */
|
|
if ((int16)cdc.dbc.w < 0)
|
|
{
|
|
/* reset data byte counter (DBCH bits 4-7 should also be set to 1) */
|
|
cdc.dbc.w = 0xffff;
|
|
|
|
/* clear !DTEN and !DTBSY */
|
|
cdc.ifstat |= (BIT_DTBSY | BIT_DTEN);
|
|
|
|
/* pending Data Transfer End interrupt */
|
|
cdc.ifstat &= ~BIT_DTEI;
|
|
|
|
/* Data Transfer End interrupt enabled ? */
|
|
if (cdc.ifctrl & BIT_DTEIEN)
|
|
{
|
|
/* check end of CDC decoder active period */
|
|
if ((cdc.irq & BIT_DECI) && (cdc.cycles[0] > cdc.cycles[1]))
|
|
{
|
|
/* clear pending decoder interrupt */
|
|
cdc.ifstat |= BIT_DECI;
|
|
|
|
/* update CDC IRQ state */
|
|
cdc.irq &= ~BIT_DECI;
|
|
}
|
|
|
|
/* level 5 interrupt triggered only on CDC /INT falling edge with interrupt enabled on gate-array side */
|
|
if (!cdc.irq && (scd.regs[0x32>>1].byte.l & 0x20))
|
|
{
|
|
/* pending level 5 interrupt */
|
|
scd.pending |= (1 << 5);
|
|
|
|
/* update IRQ level */
|
|
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);
|
|
}
|
|
|
|
/* update CDC IRQ state */
|
|
cdc.irq |= BIT_DTEI;
|
|
}
|
|
|
|
/* set EDT bit (gate-array register $04) */
|
|
scd.regs[0x04>>1].byte.h |= 0x80;
|
|
}
|
|
}
|
|
}
|
|
|
|
return data;
|
|
}
|