/***************************************************************************************1* Genesis Plus2* CD data controller (LC89510 compatible)3*4* Copyright (C) 2012 Eke-Eke (Genesis Plus GX)5*6* Redistribution and use of this code or any derivative works are permitted7* provided that the following conditions are met:8*9* - Redistributions may not be sold, nor may they be used in a commercial10* product or activity.11*12* - Redistributions that are modified from the original source must include the13* complete source code, including the source code for all components used by a14* binary built from the modified sources. However, as a special exception, the15* source code distributed need not include anything that is normally distributed16* (in either source or binary form) with the major components (compiler, kernel,17* and so on) of the operating system on which the executable runs, unless that18* component itself accompanies the executable.19*20* - Redistributions must reproduce the above copyright notice, this list of21* conditions and the following disclaimer in the documentation and/or other22* materials provided with the distribution.23*24* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"25* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE26* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE27* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE28* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR29* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF30* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS31* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN32* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)33* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE34* POSSIBILITY OF SUCH DAMAGE.35*36****************************************************************************************/3738#include "shared.h"3940/* IFSTAT register bitmasks */41#define BIT_DTEI 0x4042#define BIT_DECI 0x2043#define BIT_DTBSY 0x0844#define BIT_DTEN 0x024546/* IFCTRL register bitmasks */47#define BIT_DTEIEN 0x4048#define BIT_DECIEN 0x2049#define BIT_DOUTEN 0x025051/* CTRL0 register bitmasks */52#define BIT_DECEN 0x8053#define BIT_E01RQ 0x2054#define BIT_AUTORQ 0x1055#define BIT_WRRQ 0x045657/* CTRL1 register bitmasks */58#define BIT_MODRQ 0x0859#define BIT_FORMRQ 0x0460#define BIT_SHDREN 0x016162/* CTRL2 register bitmask */63#define BIT_VALST 0x806465/* TODO: figure exact DMA transfer rate */66#define DMA_BYTES_PER_LINE 5126768void cdc_init(void)69{70memset(&cdc, 0, sizeof(cdc_t));71}7273void cdc_reset(void)74{75/* reset CDC register index */76scd.regs[0x04>>1].byte.l = 0x00;7778/* reset CDC registers */79cdc.ifstat = 0xff;80cdc.ifctrl = 0x00;81cdc.ctrl[0] = 0x00;82cdc.ctrl[1] = 0x00;83cdc.stat[0] = 0x00;84cdc.stat[1] = 0x00;85cdc.stat[2] = 0x00;86cdc.stat[3] = 0x80;87cdc.head[0][0] = 0x00;88cdc.head[0][1] = 0x00;89cdc.head[0][2] = 0x00;90cdc.head[0][3] = 0x01;91cdc.head[1][0] = 0x00;92cdc.head[1][1] = 0x00;93cdc.head[1][2] = 0x00;94cdc.head[1][3] = 0x00;9596/* reset CDC cycle counter */97cdc.cycles = 0;9899/* DMA transfer disabled */100cdc.dma_w = 0;101102/* clear any pending IRQ */103if (scd.pending & (1 << 5))104{105/* clear any pending interrupt level 5 */106scd.pending &= ~(1 << 5);107108/* update IRQ level */109s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);110}111}112113int cdc_context_save(uint8 *state)114{115uint8 tmp8;116int bufferptr = 0;117118if (cdc.dma_w == pcm_ram_dma_w)119{120tmp8 = 1;121}122else if (cdc.dma_w == prg_ram_dma_w)123{124tmp8 = 2;125}126else if (cdc.dma_w == word_ram_0_dma_w)127{128tmp8 = 3;129}130else if (cdc.dma_w == word_ram_1_dma_w)131{132tmp8 = 4;133}134else if (cdc.dma_w == word_ram_2M_dma_w)135{136tmp8 = 5;137}138else139{140tmp8 = 0;141}142143save_param(&cdc, sizeof(cdc));144save_param(&tmp8, 1);145146return bufferptr;147}148149int cdc_context_load(uint8 *state)150{151uint8 tmp8;152int bufferptr = 0;153154load_param(&cdc, sizeof(cdc));155load_param(&tmp8, 1);156157switch (tmp8)158{159case 1:160cdc.dma_w = pcm_ram_dma_w;161break;162case 2:163cdc.dma_w = prg_ram_dma_w;164break;165case 3:166cdc.dma_w = word_ram_0_dma_w;167break;168case 4:169cdc.dma_w = word_ram_1_dma_w;170break;171case 5:172cdc.dma_w = word_ram_2M_dma_w;173break;174default:175cdc.dma_w = 0;176break;177}178179return bufferptr;180}181182void cdc_dma_update(void)183{184/* maximal transfer length */185int length = DMA_BYTES_PER_LINE;186187/* end of DMA transfer ? */188if (cdc.dbc.w < DMA_BYTES_PER_LINE)189{190/* transfer remaining words using 16-bit DMA */191cdc.dma_w((cdc.dbc.w + 1) >> 1);192193/* reset data byte counter (DBCH bits 4-7 should be set to 1) */194cdc.dbc.w = 0xf000;195196/* clear !DTEN and !DTBSY */197cdc.ifstat |= (BIT_DTBSY | BIT_DTEN);198199/* pending Data Transfer End interrupt */200cdc.ifstat &= ~BIT_DTEI;201202/* Data Transfer End interrupt enabled ? */203if (cdc.ifctrl & BIT_DTEIEN)204{205/* pending level 5 interrupt */206scd.pending |= (1 << 5);207208/* level 5 interrupt enabled ? */209if (scd.regs[0x32>>1].byte.l & 0x20)210{211/* update IRQ level */212s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);213}214}215216/* clear DSR bit & set EDT bit (CD register $04) */217scd.regs[0x04>>1].byte.h = (scd.regs[0x04>>1].byte.h & 0x07) | 0x80;218219/* SUB-CPU idle on register $04 polling ? */220if (s68k.stopped & (1<<0x04))221{222/* sync SUB-CPU with CDC */223s68k.cycles = scd.cycles;224225/* restart SUB-CPU */226s68k.stopped = 0;227#ifdef LOG_SCD228error("s68k started from %d cycles\n", s68k.cycles);229#endif230}231232/* disable DMA transfer */233cdc.dma_w = 0;234}235else236{237/* transfer all words using 16-bit DMA */238cdc.dma_w(DMA_BYTES_PER_LINE >> 1);239240/* decrement data byte counter */241cdc.dbc.w -= length;242}243}244245int cdc_decoder_update(uint32 header)246{247/* data decoding enabled ? */248if (cdc.ctrl[0] & BIT_DECEN)249{250/* update HEAD registers */251*(uint32 *)(cdc.head[0]) = header;252253/* set !VALST */254cdc.stat[3] = 0x00;255256/* pending decoder interrupt */257cdc.ifstat &= ~BIT_DECI;258259/* decoder interrupt enabled ? */260if (cdc.ifctrl & BIT_DECIEN)261{262/* pending level 5 interrupt */263scd.pending |= (1 << 5);264265/* level 5 interrupt enabled ? */266if (scd.regs[0x32>>1].byte.l & 0x20)267{268/* update IRQ level */269s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);270}271}272273/* buffer RAM write enabled ? */274if (cdc.ctrl[0] & BIT_WRRQ)275{276uint16 offset;277278/* increment block pointer */279cdc.pt.w += 2352;280281/* increment write address */282cdc.wa.w += 2352;283284/* CDC buffer address */285offset = cdc.pt.w & 0x3fff;286287/* write CDD block header (4 bytes) */288*(uint32 *)(cdc.ram + offset) = header;289290/* write CDD block data (2048 bytes) */291cdd_read_data(cdc.ram + 4 + offset);292293/* take care of buffer overrun */294if (offset > (0x4000 - 2048 - 4))295{296/* data should be written at the start of buffer */297memcpy(cdc.ram, cdc.ram + 0x4000, offset + 2048 + 4 - 0x4000);298}299300/* read next data block */301return 1;302}303}304305/* keep decoding same data block if Buffer Write is disabled */306return 0;307}308309void cdc_reg_w(unsigned char data)310{311#ifdef LOG_CDC312error("CDC register %X write 0x%04x (%X)\n", scd.regs[0x04>>1].byte.l & 0x0F, data, s68k.pc);313#endif314switch (scd.regs[0x04>>1].byte.l & 0x0F)315{316case 0x01: /* IFCTRL */317{318/* pending interrupts ? */319if (((data & BIT_DTEIEN) && !(cdc.ifstat & BIT_DTEI)) ||320((data & BIT_DECIEN) && !(cdc.ifstat & BIT_DECI)))321{322/* pending level 5 interrupt */323scd.pending |= (1 << 5);324325/* level 5 interrupt enabled ? */326if (scd.regs[0x32>>1].byte.l & 0x20)327{328/* update IRQ level */329s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);330}331}332else if (scd.pending & (1 << 5))333{334/* clear pending level 5 interrupts */335scd.pending &= ~(1 << 5);336337/* update IRQ level */338s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);339}340341/* abort any data transfer if data output is disabled */342if (!(data & BIT_DOUTEN))343{344/* clear !DTBSY and !DTEN */345cdc.ifstat |= (BIT_DTBSY | BIT_DTEN);346}347348cdc.ifctrl = data;349scd.regs[0x04>>1].byte.l = 0x02;350break;351}352353case 0x02: /* DBCL */354cdc.dbc.byte.l = data;355scd.regs[0x04>>1].byte.l = 0x03;356break;357358case 0x03: /* DBCH */359cdc.dbc.byte.h = data;360scd.regs[0x04>>1].byte.l = 0x04;361break;362363case 0x04: /* DACL */364cdc.dac.byte.l = data;365scd.regs[0x04>>1].byte.l = 0x05;366break;367368case 0x05: /* DACH */369cdc.dac.byte.h = data;370scd.regs[0x04>>1].byte.l = 0x06;371break;372373case 0x06: /* DTRG */374{375/* start data transfer if data output is enabled */376if (cdc.ifctrl & BIT_DOUTEN)377{378/* set !DTBSY */379cdc.ifstat &= ~BIT_DTBSY;380381/* clear DBCH bits 4-7 */382cdc.dbc.byte.h &= 0x0f;383384/* clear EDT & DSR bits (SCD register $04) */385scd.regs[0x04>>1].byte.h &= 0x07;386387/* setup data transfer destination */388switch (scd.regs[0x04>>1].byte.h & 0x07)389{390case 2: /* MAIN-CPU host read */391case 3: /* SUB-CPU host read */392{393/* set !DTEN */394cdc.ifstat &= ~BIT_DTEN;395396/* set DSR bit (register $04) */397scd.regs[0x04>>1].byte.h |= 0x40;398break;399}400401case 4: /* PCM RAM DMA */402{403cdc.dma_w = pcm_ram_dma_w;404break;405}406407case 5: /* PRG-RAM DMA */408{409cdc.dma_w = prg_ram_dma_w;410break;411}412413case 7: /* WORD-RAM DMA */414{415/* check memory mode */416if (scd.regs[0x02 >> 1].byte.l & 0x04)417{418/* 1M mode */419if (scd.regs[0x02 >> 1].byte.l & 0x01)420{421/* Word-RAM bank 0 is assigned to SUB-CPU */422cdc.dma_w = word_ram_0_dma_w;423}424else425{426/* Word-RAM bank 1 is assigned to SUB-CPU */427cdc.dma_w = word_ram_1_dma_w;428}429}430else431{432/* 2M mode */433if (scd.regs[0x02 >> 1].byte.l & 0x02)434{435/* only process DMA if Word-RAM is assigned to SUB-CPU */436cdc.dma_w = word_ram_2M_dma_w;437}438}439break;440}441442default: /* invalid */443{444#ifdef LOG_CDC445error("invalid CDC tranfer destination (%d)\n", scd.regs[0x04>>1].byte.h & 0x07);446#endif447break;448}449}450}451452scd.regs[0x04>>1].byte.l = 0x07;453break;454}455456case 0x07: /* DTACK */457{458/* clear pending data transfer end interrupt */459cdc.ifstat |= BIT_DTEI;460461/* clear DBCH bits 4-7 */462cdc.dbc.byte.h &= 0x0f;463464#if 0465/* no pending decoder interrupt ? */466if ((cdc.ifstat | BIT_DECI) || !(cdc.ifctrl & BIT_DECIEN))467{468/* clear pending level 5 interrupt */469scd.pending &= ~(1 << 5);470471/* update IRQ level */472s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);473}474#endif475scd.regs[0x04>>1].byte.l = 0x08;476break;477}478479case 0x08: /* WAL */480cdc.wa.byte.l = data;481scd.regs[0x04>>1].byte.l = 0x09;482break;483484case 0x09: /* WAH */485cdc.wa.byte.h = data;486scd.regs[0x04>>1].byte.l = 0x0a;487break;488489case 0x0a: /* CTRL0 */490{491/* set CRCOK bit only if decoding is enabled */492cdc.stat[0] = data & BIT_DECEN;493494/* update decoding mode */495if (data & BIT_AUTORQ)496{497/* set MODE bit according to CTRL1 register & clear FORM bit */498cdc.stat[2] = cdc.ctrl[1] & BIT_MODRQ;499}500else501{502/* set MODE & FORM bits according to CTRL1 register */503cdc.stat[2] = cdc.ctrl[1] & (BIT_MODRQ | BIT_FORMRQ);504}505506cdc.ctrl[0] = data;507scd.regs[0x04>>1].byte.l = 0x0b;508break;509}510511case 0x0b: /* CTRL1 */512{513/* update decoding mode */514if (cdc.ctrl[0] & BIT_AUTORQ)515{516/* set MODE bit according to CTRL1 register & clear FORM bit */517cdc.stat[2] = data & BIT_MODRQ;518}519else520{521/* set MODE & FORM bits according to CTRL1 register */522cdc.stat[2] = data & (BIT_MODRQ | BIT_FORMRQ);523}524525cdc.ctrl[1] = data;526scd.regs[0x04>>1].byte.l = 0x0c;527break;528}529530case 0x0c: /* PTL */531cdc.pt.byte.l = data;532scd.regs[0x04>>1].byte.l = 0x0d;533break;534535case 0x0d: /* PTH */536cdc.pt.byte.h = data;537scd.regs[0x04>>1].byte.l = 0x0e;538break;539540case 0x0e: /* CTRL2 (unused) */541scd.regs[0x04>>1].byte.l = 0x0f;542break;543544case 0x0f: /* RESET */545cdc_reset();546break;547548default: /* by default, SBOUT is not used */549break;550}551}552553unsigned char cdc_reg_r(void)554{555switch (scd.regs[0x04>>1].byte.l & 0x0F)556{557case 0x01: /* IFSTAT */558scd.regs[0x04>>1].byte.l = 0x02;559return cdc.ifstat;560561case 0x02: /* DBCL */562scd.regs[0x04>>1].byte.l = 0x03;563return cdc.dbc.byte.l;564565case 0x03: /* DBCH */566scd.regs[0x04>>1].byte.l = 0x04;567return cdc.dbc.byte.h;568569case 0x04: /* HEAD0 */570scd.regs[0x04>>1].byte.l = 0x05;571return cdc.head[cdc.ctrl[1] & BIT_SHDREN][0];572573case 0x05: /* HEAD1 */574scd.regs[0x04>>1].byte.l = 0x06;575return cdc.head[cdc.ctrl[1] & BIT_SHDREN][1];576577case 0x06: /* HEAD2 */578scd.regs[0x04>>1].byte.l = 0x07;579return cdc.head[cdc.ctrl[1] & BIT_SHDREN][2];580581case 0x07: /* HEAD3 */582scd.regs[0x04>>1].byte.l = 0x08;583return cdc.head[cdc.ctrl[1] & BIT_SHDREN][3];584585case 0x08: /* PTL */586scd.regs[0x04>>1].byte.l = 0x09;587return cdc.pt.byte.l;588589case 0x09: /* PTH */590scd.regs[0x04>>1].byte.l = 0x0a;591return cdc.pt.byte.h;592593case 0x0a: /* WAL */594scd.regs[0x04>>1].byte.l = 0x0b;595return cdc.wa.byte.l;596597case 0x0b: /* WAH */598scd.regs[0x04>>1].byte.l = 0x0c;599return cdc.wa.byte.h;600601case 0x0c: /* STAT0 */602scd.regs[0x04>>1].byte.l = 0x0d;603return cdc.stat[0];604605case 0x0d: /* STAT1 (always return 0) */606scd.regs[0x04>>1].byte.l = 0x0e;607return 0x00;608609case 0x0e: /* STAT2 */610scd.regs[0x04>>1].byte.l = 0x0f;611return cdc.stat[2];612613case 0x0f: /* STAT3 */614{615uint8 data = cdc.stat[3];616617/* clear !VALST (note: this is not 100% correct but BIOS do not seem to care) */618cdc.stat[3] = BIT_VALST;619620/* clear pending decoder interrupt */621cdc.ifstat |= BIT_DECI;622623#if 0624/* no pending data transfer end interrupt */625if ((cdc.ifstat | BIT_DTEI) || !(cdc.ifctrl & BIT_DTEIEN))626{627/* clear pending level 5 interrupt */628scd.pending &= ~(1 << 5);629630/* update IRQ level */631s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);632}633#endif634635scd.regs[0x04>>1].byte.l = 0x00;636return data;637}638639default: /* by default, COMIN is always empty */640return 0xff;641}642}643644unsigned short cdc_host_r(void)645{646/* check if data is available */647if (!(cdc.ifstat & BIT_DTEN))648{649/* read data word from CDC RAM buffer */650uint16 data = *(uint16 *)(cdc.ram + (cdc.dac.w & 0x3ffe));651652#ifdef LSB_FIRST653/* source data is stored in big endian format */654data = ((data >> 8) | (data << 8)) & 0xffff;655#endif656657#ifdef LOG_CDC658error("CDC host read 0x%04x -> 0x%04x (dbc=0x%x) (%X)\n", cdc.dac.w, data, cdc.dbc.w, s68k.pc);659#endif660661/* increment data address counter */662cdc.dac.w += 2;663664/* decrement data byte counter */665cdc.dbc.w -= 2;666667/* end of transfer ? */668if ((int16)cdc.dbc.w <= 0)669{670/* reset data byte counter (DBCH bits 4-7 should be set to 1) */671cdc.dbc.w = 0xf000;672673/* clear !DTEN and !DTBSY */674cdc.ifstat |= (BIT_DTBSY | BIT_DTEN);675676/* pending Data Transfer End interrupt */677cdc.ifstat &= ~BIT_DTEI;678679/* Data Transfer End interrupt enabled ? */680if (cdc.ifctrl & BIT_DTEIEN)681{682/* pending level 5 interrupt */683scd.pending |= (1 << 5);684685/* level 5 interrupt enabled ? */686if (scd.regs[0x32>>1].byte.l & 0x20)687{688/* update IRQ level */689s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);690}691}692693/* clear DSR bit & set EDT bit (SCD register $04) */694scd.regs[0x04>>1].byte.h = (scd.regs[0x04>>1].byte.h & 0x07) | 0x80;695}696697return data;698}699700#ifdef LOG_CDC701error("error reading CDC host (data transfer disabled)\n");702#endif703return 0xffff;704}705706707