731 lines
18 KiB
C
731 lines
18 KiB
C
/***************************************************************************************
|
|
* Genesis Plus
|
|
* CD data controller (LC89510 compatible)
|
|
*
|
|
* Copyright (C) 2012 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 "../pico_int.h"
|
|
#include "genplus_macros.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_E01RQ 0x20
|
|
#define BIT_AUTORQ 0x10
|
|
#define BIT_WRRQ 0x04
|
|
|
|
/* CTRL1 register bitmasks */
|
|
#define BIT_MODRQ 0x08
|
|
#define BIT_FORMRQ 0x04
|
|
#define BIT_SHDREN 0x01
|
|
|
|
/* CTRL2 register bitmask */
|
|
#define BIT_VALST 0x80
|
|
|
|
/* PicoDrive: doing DMA at once, not using callbacks */
|
|
//#define DMA_BYTES_PER_LINE 512
|
|
|
|
enum dma_type {
|
|
word_ram_0_dma_w = 1,
|
|
word_ram_1_dma_w = 2,
|
|
word_ram_2M_dma_w = 3,
|
|
pcm_ram_dma_w = 4,
|
|
prg_ram_dma_w = 5,
|
|
};
|
|
|
|
/* CDC hardware */
|
|
typedef struct
|
|
{
|
|
uint8 ifstat;
|
|
uint8 ifctrl;
|
|
uint16 dbc;
|
|
uint16 dac;
|
|
uint16 pt;
|
|
uint16 wa;
|
|
uint8 ctrl[2];
|
|
uint8 head[2][4];
|
|
uint8 stat[4];
|
|
int cycles;
|
|
//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;
|
|
|
|
static cdc_t cdc;
|
|
|
|
void cdc_init(void)
|
|
{
|
|
memset(&cdc, 0, sizeof(cdc_t));
|
|
}
|
|
|
|
void cdc_reset(void)
|
|
{
|
|
/* reset CDC register index */
|
|
Pico_mcd->s68k_regs[0x04+1] = 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 cycle counter */
|
|
cdc.cycles = 0;
|
|
|
|
/* DMA transfer disabled */
|
|
cdc.dma_w = 0;
|
|
}
|
|
|
|
static void do_dma(enum dma_type type, int words_in)
|
|
{
|
|
int dma_addr = (Pico_mcd->s68k_regs[0x0a] << 8) | Pico_mcd->s68k_regs[0x0b];
|
|
int src_addr = cdc.dac & 0x3ffe;
|
|
int dst_addr = dma_addr;
|
|
int words = words_in;
|
|
int dst_limit = 0;
|
|
uint8 *dst;
|
|
int len;
|
|
|
|
elprintf(EL_CD, "dma %d %04x->%04x %x",
|
|
type, cdc.dac, dst_addr, words_in);
|
|
|
|
switch (type)
|
|
{
|
|
case pcm_ram_dma_w:
|
|
dst_addr = (dst_addr << 2) & 0xffc;
|
|
if (dst_addr + words * 2 > 0x1000) {
|
|
elprintf(EL_ANOMALY, "pcm dma oflow: %x %x", dst_addr, words);
|
|
words = (0x1000 - dst_addr) / 2;
|
|
}
|
|
dst = Pico_mcd->pcm_ram_b[Pico_mcd->pcm.bank];
|
|
dst = dst + dst_addr;
|
|
while (words > 0)
|
|
{
|
|
if (src_addr + words * 2 > 0x4000) {
|
|
len = 0x4000 - src_addr;
|
|
memcpy(dst, cdc.ram + src_addr, len);
|
|
dst += len;
|
|
src_addr = 0;
|
|
words -= len / 2;
|
|
continue;
|
|
}
|
|
memcpy(dst, cdc.ram + src_addr, words * 2);
|
|
break;
|
|
}
|
|
goto update_dma;
|
|
|
|
case prg_ram_dma_w:
|
|
dst_addr <<= 3;
|
|
dst = Pico_mcd->prg_ram + dst_addr;
|
|
dst_limit = 0x80000;
|
|
break;
|
|
|
|
case word_ram_0_dma_w:
|
|
dst_addr = (dst_addr << 3) & 0x1fffe;
|
|
dst = Pico_mcd->word_ram1M[0] + dst_addr;
|
|
dst_limit = 0x20000;
|
|
break;
|
|
|
|
case word_ram_1_dma_w:
|
|
dst_addr = (dst_addr << 3) & 0x1fffe;
|
|
dst = Pico_mcd->word_ram1M[1] + dst_addr;
|
|
dst_limit = 0x20000;
|
|
break;
|
|
|
|
case word_ram_2M_dma_w:
|
|
dst_addr = (dst_addr << 3) & 0x3fffe;
|
|
dst = Pico_mcd->word_ram2M + dst_addr;
|
|
dst_limit = 0x40000;
|
|
break;
|
|
|
|
default:
|
|
elprintf(EL_ANOMALY, "invalid dma: %d", type);
|
|
goto update_dma;
|
|
}
|
|
|
|
if (dst_addr + words * 2 > dst_limit) {
|
|
elprintf(EL_ANOMALY, "cd dma %d oflow: %x %x", type, dst_addr, words);
|
|
words = (dst_limit - dst_addr) / 2;
|
|
}
|
|
while (words > 0)
|
|
{
|
|
if (src_addr + words * 2 > 0x4000) {
|
|
len = 0x4000 - src_addr;
|
|
memcpy16bswap((void *)dst, cdc.ram + src_addr, len / 2);
|
|
dst += len;
|
|
src_addr = 0;
|
|
words -= len / 2;
|
|
continue;
|
|
}
|
|
memcpy16bswap((void *)dst, cdc.ram + src_addr, words);
|
|
break;
|
|
}
|
|
|
|
update_dma:
|
|
/* update DMA addresses */
|
|
cdc.dac += words_in * 2;
|
|
if (type == pcm_ram_dma_w)
|
|
dma_addr += words_in >> 1;
|
|
else
|
|
dma_addr += words_in >> 2;
|
|
|
|
Pico_mcd->s68k_regs[0x0a] = dma_addr >> 8;
|
|
Pico_mcd->s68k_regs[0x0b] = dma_addr;
|
|
}
|
|
|
|
void cdc_dma_update(void)
|
|
{
|
|
/* end of DMA transfer ? */
|
|
//if (cdc.dbc < DMA_BYTES_PER_LINE)
|
|
{
|
|
/* transfer remaining words using 16-bit DMA */
|
|
//cdc.dma_w((cdc.dbc + 1) >> 1);
|
|
do_dma(cdc.dma_w, (cdc.dbc + 1) >> 1);
|
|
|
|
/* reset data byte counter (DBCH bits 4-7 should be set to 1) */
|
|
cdc.dbc = 0xf000;
|
|
|
|
/* 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)
|
|
{
|
|
/* level 5 interrupt enabled ? */
|
|
if (Pico_mcd->s68k_regs[0x32+1] & PCDS_IEN5)
|
|
{
|
|
/* update IRQ level */
|
|
elprintf(EL_INTS, "cdc DTE irq 5");
|
|
SekInterruptS68k(5);
|
|
}
|
|
}
|
|
|
|
/* clear DSR bit & set EDT bit (SCD register $04) */
|
|
Pico_mcd->s68k_regs[0x04+0] = (Pico_mcd->s68k_regs[0x04+0] & 0x07) | 0x80;
|
|
|
|
/* disable DMA transfer */
|
|
cdc.dma_w = 0;
|
|
}
|
|
#if 0
|
|
else
|
|
{
|
|
/* transfer all words using 16-bit DMA */
|
|
cdc.dma_w(DMA_BYTES_PER_LINE >> 1);
|
|
|
|
/* decrement data byte counter */
|
|
cdc.dbc -= length;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
int cdc_decoder_update(uint8 header[4])
|
|
{
|
|
/* data decoding enabled ? */
|
|
if (cdc.ctrl[0] & BIT_DECEN)
|
|
{
|
|
/* update HEAD registers */
|
|
memcpy(cdc.head[0], header, sizeof(cdc.head[0]));
|
|
|
|
/* set !VALST */
|
|
cdc.stat[3] = 0x00;
|
|
|
|
/* pending decoder interrupt */
|
|
cdc.ifstat &= ~BIT_DECI;
|
|
|
|
/* decoder interrupt enabled ? */
|
|
if (cdc.ifctrl & BIT_DECIEN)
|
|
{
|
|
/* level 5 interrupt enabled ? */
|
|
if (Pico_mcd->s68k_regs[0x32+1] & PCDS_IEN5)
|
|
{
|
|
/* update IRQ level */
|
|
elprintf(EL_INTS, "cdc DEC irq 5");
|
|
SekInterruptS68k(5);
|
|
}
|
|
}
|
|
|
|
/* buffer RAM write enabled ? */
|
|
if (cdc.ctrl[0] & BIT_WRRQ)
|
|
{
|
|
uint16 offset;
|
|
|
|
/* increment block pointer */
|
|
cdc.pt += 2352;
|
|
|
|
/* increment write address */
|
|
cdc.wa += 2352;
|
|
|
|
/* CDC buffer address */
|
|
offset = cdc.pt & 0x3fff;
|
|
|
|
/* write CDD block header (4 bytes) */
|
|
memcpy(cdc.ram + offset, header, 4);
|
|
|
|
/* write CDD block data (2048 bytes) */
|
|
cdd_read_data(cdc.ram + 4 + offset);
|
|
|
|
/* take care of buffer overrun */
|
|
if (offset > (0x4000 - 2048 - 4))
|
|
{
|
|
/* data should be written at the start of buffer */
|
|
memcpy(cdc.ram, cdc.ram + 0x4000, offset + 2048 + 4 - 0x4000);
|
|
}
|
|
|
|
/* read next data block */
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/* keep decoding same data block if Buffer Write is disabled */
|
|
return 0;
|
|
}
|
|
|
|
void cdc_reg_w(unsigned char data)
|
|
{
|
|
#ifdef LOG_CDC
|
|
elprintf(EL_STATUS, "CDC register %X write 0x%04x", Pico_mcd->s68k_regs[0x04+1] & 0x0F, data);
|
|
#endif
|
|
switch (Pico_mcd->s68k_regs[0x04+1] & 0x0F)
|
|
{
|
|
case 0x01: /* IFCTRL */
|
|
{
|
|
/* pending interrupts ? */
|
|
if (((data & BIT_DTEIEN) && !(cdc.ifstat & BIT_DTEI)) ||
|
|
((data & BIT_DECIEN) && !(cdc.ifstat & BIT_DECI)))
|
|
{
|
|
/* level 5 interrupt enabled ? */
|
|
if (Pico_mcd->s68k_regs[0x32+1] & PCDS_IEN5)
|
|
{
|
|
/* update IRQ level */
|
|
elprintf(EL_INTS, "cdc pending irq 5");
|
|
SekInterruptS68k(5);
|
|
}
|
|
}
|
|
else // if (scd.pending & (1 << 5))
|
|
{
|
|
/* clear pending level 5 interrupts */
|
|
SekInterruptClearS68k(5);
|
|
}
|
|
|
|
/* abort any data transfer if data output is disabled */
|
|
if (!(data & BIT_DOUTEN))
|
|
{
|
|
/* clear !DTBSY and !DTEN */
|
|
cdc.ifstat |= (BIT_DTBSY | BIT_DTEN);
|
|
}
|
|
|
|
cdc.ifctrl = data;
|
|
Pico_mcd->s68k_regs[0x04+1] = 0x02;
|
|
break;
|
|
}
|
|
|
|
case 0x02: /* DBCL */
|
|
cdc.dbc &= 0xff00;
|
|
cdc.dbc |= data;
|
|
Pico_mcd->s68k_regs[0x04+1] = 0x03;
|
|
break;
|
|
|
|
case 0x03: /* DBCH */
|
|
cdc.dbc &= 0x00ff;
|
|
cdc.dbc |= data << 8;
|
|
Pico_mcd->s68k_regs[0x04+1] = 0x04;
|
|
break;
|
|
|
|
case 0x04: /* DACL */
|
|
cdc.dac &= 0xff00;
|
|
cdc.dac |= data;
|
|
Pico_mcd->s68k_regs[0x04+1] = 0x05;
|
|
break;
|
|
|
|
case 0x05: /* DACH */
|
|
cdc.dac &= 0x00ff;
|
|
cdc.dac |= data << 8;
|
|
Pico_mcd->s68k_regs[0x04+1] = 0x06;
|
|
break;
|
|
|
|
case 0x06: /* DTRG */
|
|
{
|
|
/* start data transfer if data output is enabled */
|
|
if (cdc.ifctrl & BIT_DOUTEN)
|
|
{
|
|
/* set !DTBSY */
|
|
cdc.ifstat &= ~BIT_DTBSY;
|
|
|
|
/* clear DBCH bits 4-7 */
|
|
cdc.dbc &= 0x0fff;
|
|
|
|
/* clear EDT & DSR bits (SCD register $04) */
|
|
Pico_mcd->s68k_regs[0x04+0] &= 0x07;
|
|
|
|
cdc.dma_w = 0;
|
|
|
|
/* setup data transfer destination */
|
|
switch (Pico_mcd->s68k_regs[0x04+0] & 0x07)
|
|
{
|
|
case 2: /* MAIN-CPU host read */
|
|
case 3: /* SUB-CPU host read */
|
|
{
|
|
/* set !DTEN */
|
|
cdc.ifstat &= ~BIT_DTEN;
|
|
|
|
/* set DSR bit (register $04) */
|
|
Pico_mcd->s68k_regs[0x04+0] |= 0x40;
|
|
break;
|
|
}
|
|
|
|
case 4: /* PCM RAM DMA */
|
|
{
|
|
cdc.dma_w = pcm_ram_dma_w;
|
|
break;
|
|
}
|
|
|
|
case 5: /* PRG-RAM DMA */
|
|
{
|
|
cdc.dma_w = prg_ram_dma_w;
|
|
break;
|
|
}
|
|
|
|
case 7: /* WORD-RAM DMA */
|
|
{
|
|
/* check memory mode */
|
|
if (Pico_mcd->s68k_regs[0x02+1] & 0x04)
|
|
{
|
|
/* 1M mode */
|
|
if (Pico_mcd->s68k_regs[0x02+1] & 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
|
|
{
|
|
/* 2M mode */
|
|
if (Pico_mcd->s68k_regs[0x02+1] & 0x02)
|
|
{
|
|
/* only process DMA if Word-RAM is assigned to SUB-CPU */
|
|
cdc.dma_w = word_ram_2M_dma_w;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
default: /* invalid */
|
|
{
|
|
elprintf(EL_ANOMALY, "invalid CDC tranfer destination (%d)",
|
|
Pico_mcd->s68k_regs[0x04+0] & 0x07);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (cdc.dma_w)
|
|
pcd_event_schedule_s68k(PCD_EVENT_DMA, cdc.dbc / 2);
|
|
}
|
|
|
|
Pico_mcd->s68k_regs[0x04+1] = 0x07;
|
|
break;
|
|
}
|
|
|
|
case 0x07: /* DTACK */
|
|
{
|
|
/* clear pending data transfer end interrupt */
|
|
cdc.ifstat |= BIT_DTEI;
|
|
|
|
/* clear DBCH bits 4-7 */
|
|
cdc.dbc &= 0x0fff;
|
|
|
|
#if 0
|
|
/* no pending decoder interrupt ? */
|
|
if ((cdc.ifstat | BIT_DECI) || !(cdc.ifctrl & BIT_DECIEN))
|
|
{
|
|
/* clear pending level 5 interrupt */
|
|
SekInterruptClearS68k(5);
|
|
}
|
|
#endif
|
|
Pico_mcd->s68k_regs[0x04+1] = 0x08;
|
|
break;
|
|
}
|
|
|
|
case 0x08: /* WAL */
|
|
cdc.wa &= 0xff00;
|
|
cdc.wa |= data;
|
|
Pico_mcd->s68k_regs[0x04+1] = 0x09;
|
|
break;
|
|
|
|
case 0x09: /* WAH */
|
|
cdc.wa &= 0x00ff;
|
|
cdc.wa |= data << 8;
|
|
Pico_mcd->s68k_regs[0x04+1] = 0x0a;
|
|
break;
|
|
|
|
case 0x0a: /* CTRL0 */
|
|
{
|
|
/* set CRCOK bit only if decoding is enabled */
|
|
cdc.stat[0] = data & BIT_DECEN;
|
|
|
|
/* 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
|
|
{
|
|
/* set MODE & FORM bits according to CTRL1 register */
|
|
cdc.stat[2] = cdc.ctrl[1] & (BIT_MODRQ | BIT_FORMRQ);
|
|
}
|
|
|
|
cdc.ctrl[0] = data;
|
|
Pico_mcd->s68k_regs[0x04+1] = 0x0b;
|
|
break;
|
|
}
|
|
|
|
case 0x0b: /* CTRL1 */
|
|
{
|
|
/* update decoding mode */
|
|
if (cdc.ctrl[0] & BIT_AUTORQ)
|
|
{
|
|
/* set MODE bit according to CTRL1 register & clear FORM bit */
|
|
cdc.stat[2] = data & BIT_MODRQ;
|
|
}
|
|
else
|
|
{
|
|
/* set MODE & FORM bits according to CTRL1 register */
|
|
cdc.stat[2] = data & (BIT_MODRQ | BIT_FORMRQ);
|
|
}
|
|
|
|
cdc.ctrl[1] = data;
|
|
Pico_mcd->s68k_regs[0x04+1] = 0x0c;
|
|
break;
|
|
}
|
|
|
|
case 0x0c: /* PTL */
|
|
cdc.pt &= 0xff00;
|
|
cdc.pt |= data;
|
|
Pico_mcd->s68k_regs[0x04+1] = 0x0d;
|
|
break;
|
|
|
|
case 0x0d: /* PTH */
|
|
cdc.pt &= 0x00ff;
|
|
cdc.pt |= data << 8;
|
|
Pico_mcd->s68k_regs[0x04+1] = 0x0e;
|
|
break;
|
|
|
|
case 0x0e: /* CTRL2 (unused) */
|
|
Pico_mcd->s68k_regs[0x04+1] = 0x0f;
|
|
break;
|
|
|
|
case 0x0f: /* RESET */
|
|
cdc_reset();
|
|
break;
|
|
|
|
default: /* by default, SBOUT is not used */
|
|
break;
|
|
}
|
|
}
|
|
|
|
unsigned char cdc_reg_r(void)
|
|
{
|
|
switch (Pico_mcd->s68k_regs[0x04+1] & 0x0F)
|
|
{
|
|
case 0x01: /* IFSTAT */
|
|
Pico_mcd->s68k_regs[0x04+1] = 0x02;
|
|
return cdc.ifstat;
|
|
|
|
case 0x02: /* DBCL */
|
|
Pico_mcd->s68k_regs[0x04+1] = 0x03;
|
|
return cdc.dbc & 0xff;
|
|
|
|
case 0x03: /* DBCH */
|
|
Pico_mcd->s68k_regs[0x04+1] = 0x04;
|
|
return (cdc.dbc >> 8) & 0xff;
|
|
|
|
case 0x04: /* HEAD0 */
|
|
Pico_mcd->s68k_regs[0x04+1] = 0x05;
|
|
return cdc.head[cdc.ctrl[1] & BIT_SHDREN][0];
|
|
|
|
case 0x05: /* HEAD1 */
|
|
Pico_mcd->s68k_regs[0x04+1] = 0x06;
|
|
return cdc.head[cdc.ctrl[1] & BIT_SHDREN][1];
|
|
|
|
case 0x06: /* HEAD2 */
|
|
Pico_mcd->s68k_regs[0x04+1] = 0x07;
|
|
return cdc.head[cdc.ctrl[1] & BIT_SHDREN][2];
|
|
|
|
case 0x07: /* HEAD3 */
|
|
Pico_mcd->s68k_regs[0x04+1] = 0x08;
|
|
return cdc.head[cdc.ctrl[1] & BIT_SHDREN][3];
|
|
|
|
case 0x08: /* PTL */
|
|
Pico_mcd->s68k_regs[0x04+1] = 0x09;
|
|
return cdc.pt & 0xff;
|
|
|
|
case 0x09: /* PTH */
|
|
Pico_mcd->s68k_regs[0x04+1] = 0x0a;
|
|
return (cdc.pt >> 8) & 0xff;
|
|
|
|
case 0x0a: /* WAL */
|
|
Pico_mcd->s68k_regs[0x04+1] = 0x0b;
|
|
return cdc.wa & 0xff;
|
|
|
|
case 0x0b: /* WAH */
|
|
Pico_mcd->s68k_regs[0x04+1] = 0x0c;
|
|
return (cdc.wa >> 8) & 0xff;
|
|
|
|
case 0x0c: /* STAT0 */
|
|
Pico_mcd->s68k_regs[0x04+1] = 0x0d;
|
|
return cdc.stat[0];
|
|
|
|
case 0x0d: /* STAT1 (always return 0) */
|
|
Pico_mcd->s68k_regs[0x04+1] = 0x0e;
|
|
return 0x00;
|
|
|
|
case 0x0e: /* STAT2 */
|
|
Pico_mcd->s68k_regs[0x04+1] = 0x0f;
|
|
return cdc.stat[2];
|
|
|
|
case 0x0f: /* STAT3 */
|
|
{
|
|
uint8 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;
|
|
|
|
#if 0
|
|
/* no pending data transfer end interrupt */
|
|
if ((cdc.ifstat | BIT_DTEI) || !(cdc.ifctrl & BIT_DTEIEN))
|
|
{
|
|
/* clear pending level 5 interrupt */
|
|
SekInterruptClearS68k(5);
|
|
}
|
|
#endif
|
|
|
|
Pico_mcd->s68k_regs[0x04+1] = 0x00;
|
|
return data;
|
|
}
|
|
|
|
default: /* by default, COMIN is always empty */
|
|
return 0xff;
|
|
}
|
|
}
|
|
|
|
unsigned short cdc_host_r(void)
|
|
{
|
|
/* check if data is available */
|
|
if (!(cdc.ifstat & BIT_DTEN))
|
|
{
|
|
/* read data word from CDC RAM buffer */
|
|
uint8 *datap = cdc.ram + (cdc.dac & 0x3ffe);
|
|
uint16 data = (datap[0] << 8) | datap[1];
|
|
|
|
#ifdef LOG_CDC
|
|
error("CDC host read 0x%04x -> 0x%04x (dbc=0x%x) (%X)\n", cdc.dac, data, cdc.dbc, s68k.pc);
|
|
#endif
|
|
|
|
/* increment data address counter */
|
|
cdc.dac += 2;
|
|
|
|
/* decrement data byte counter */
|
|
cdc.dbc -= 2;
|
|
|
|
/* end of transfer ? */
|
|
if ((int16)cdc.dbc <= 0)
|
|
{
|
|
/* reset data byte counter (DBCH bits 4-7 should be set to 1) */
|
|
cdc.dbc = 0xf000;
|
|
|
|
/* 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)
|
|
{
|
|
/* level 5 interrupt enabled ? */
|
|
if (Pico_mcd->s68k_regs[0x32+1] & PCDS_IEN5)
|
|
{
|
|
/* update IRQ level */
|
|
elprintf(EL_INTS, "cdc DTE irq 5");
|
|
SekInterruptS68k(5);
|
|
}
|
|
}
|
|
|
|
/* clear DSR bit & set EDT bit (SCD register $04) */
|
|
Pico_mcd->s68k_regs[0x04+0] = (Pico_mcd->s68k_regs[0x04+0] & 0x07) | 0x80;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
#ifdef LOG_CDC
|
|
error("error reading CDC host (data transfer disabled)\n");
|
|
#endif
|
|
return 0xffff;
|
|
}
|