/***************************************************************************************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}112113void cdc_dma_update(void)114{115/* maximal transfer length */116int length = DMA_BYTES_PER_LINE;117118/* end of DMA transfer ? */119if (cdc.dbc.w < DMA_BYTES_PER_LINE)120{121/* transfer remaining words using 16-bit DMA */122cdc.dma_w((cdc.dbc.w + 1) >> 1);123124/* reset data byte counter (DBCH bits 4-7 should be set to 1) */125cdc.dbc.w = 0xf000;126127/* clear !DTEN and !DTBSY */128cdc.ifstat |= (BIT_DTBSY | BIT_DTEN);129130/* pending Data Transfer End interrupt */131cdc.ifstat &= ~BIT_DTEI;132133/* Data Transfer End interrupt enabled ? */134if (cdc.ifctrl & BIT_DTEIEN)135{136/* pending level 5 interrupt */137scd.pending |= (1 << 5);138139/* level 5 interrupt enabled ? */140if (scd.regs[0x32>>1].byte.l & 0x20)141{142/* update IRQ level */143s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);144}145}146147/* clear DSR bit & set EDT bit (CD register $04) */148scd.regs[0x04>>1].byte.h = (scd.regs[0x04>>1].byte.h & 0x07) | 0x80;149150/* SUB-CPU idle on register $04 polling ? */151if (s68k.stopped & (1<<0x04))152{153/* sync SUB-CPU with CDC */154s68k.cycles = scd.cycles;155156/* restart SUB-CPU */157s68k.stopped = 0;158#ifdef LOG_SCD159error("s68k started from %d cycles\n", s68k.cycles);160#endif161}162163/* disable DMA transfer */164cdc.dma_w = 0;165}166else167{168/* transfer all words using 16-bit DMA */169cdc.dma_w(DMA_BYTES_PER_LINE >> 1);170171/* decrement data byte counter */172cdc.dbc.w -= length;173}174}175176int cdc_decoder_update(uint32 header)177{178/* data decoding enabled ? */179if (cdc.ctrl[0] & BIT_DECEN)180{181/* update HEAD registers */182*(uint32 *)(cdc.head[0]) = header;183184/* set !VALST */185cdc.stat[3] = 0x00;186187/* pending decoder interrupt */188cdc.ifstat &= ~BIT_DECI;189190/* decoder interrupt enabled ? */191if (cdc.ifctrl & BIT_DECIEN)192{193/* pending level 5 interrupt */194scd.pending |= (1 << 5);195196/* level 5 interrupt enabled ? */197if (scd.regs[0x32>>1].byte.l & 0x20)198{199/* update IRQ level */200s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);201}202}203204/* buffer RAM write enabled ? */205if (cdc.ctrl[0] & BIT_WRRQ)206{207uint16 offset;208209/* increment block pointer */210cdc.pt.w += 2352;211212/* increment write address */213cdc.wa.w += 2352;214215/* CDC buffer address */216offset = cdc.pt.w & 0x3fff;217218/* write CDD block header (4 bytes) */219*(uint32 *)(cdc.ram + offset) = header;220221/* write CDD block data (2048 bytes) */222cdd_read_data(cdc.ram + 4 + offset);223224/* take care of buffer overrun */225if (offset > (0x4000 - 2048 - 4))226{227/* data should be written at the start of buffer */228memcpy(cdc.ram, cdc.ram + 0x4000, offset + 2048 + 4 - 0x4000);229}230231/* read next data block */232return 1;233}234}235236/* keep decoding same data block if Buffer Write is disabled */237return 0;238}239240void cdc_reg_w(unsigned char data)241{242#ifdef LOG_CDC243error("CDC register %X write 0x%04x (%X)\n", scd.regs[0x04>>1].byte.l & 0x0F, data, s68k.pc);244#endif245switch (scd.regs[0x04>>1].byte.l & 0x0F)246{247case 0x01: /* IFCTRL */248{249/* pending interrupts ? */250if (((data & BIT_DTEIEN) && !(cdc.ifstat & BIT_DTEI)) ||251((data & BIT_DECIEN) && !(cdc.ifstat & BIT_DECI)))252{253/* pending level 5 interrupt */254scd.pending |= (1 << 5);255256/* level 5 interrupt enabled ? */257if (scd.regs[0x32>>1].byte.l & 0x20)258{259/* update IRQ level */260s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);261}262}263else if (scd.pending & (1 << 5))264{265/* clear pending level 5 interrupts */266scd.pending &= ~(1 << 5);267268/* update IRQ level */269s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);270}271272/* abort any data transfer if data output is disabled */273if (!(data & BIT_DOUTEN))274{275/* clear !DTBSY and !DTEN */276cdc.ifstat |= (BIT_DTBSY | BIT_DTEN);277}278279cdc.ifctrl = data;280scd.regs[0x04>>1].byte.l = 0x02;281break;282}283284case 0x02: /* DBCL */285cdc.dbc.byte.l = data;286scd.regs[0x04>>1].byte.l = 0x03;287break;288289case 0x03: /* DBCH */290cdc.dbc.byte.h = data;291scd.regs[0x04>>1].byte.l = 0x04;292break;293294case 0x04: /* DACL */295cdc.dac.byte.l = data;296scd.regs[0x04>>1].byte.l = 0x05;297break;298299case 0x05: /* DACH */300cdc.dac.byte.h = data;301scd.regs[0x04>>1].byte.l = 0x06;302break;303304case 0x06: /* DTRG */305{306/* start data transfer if data output is enabled */307if (cdc.ifctrl & BIT_DOUTEN)308{309/* set !DTBSY */310cdc.ifstat &= ~BIT_DTBSY;311312/* clear DBCH bits 4-7 */313cdc.dbc.byte.h &= 0x0f;314315/* clear EDT & DSR bits (SCD register $04) */316scd.regs[0x04>>1].byte.h &= 0x07;317318/* setup data transfer destination */319switch (scd.regs[0x04>>1].byte.h & 0x07)320{321case 2: /* MAIN-CPU host read */322case 3: /* SUB-CPU host read */323{324/* set !DTEN */325cdc.ifstat &= ~BIT_DTEN;326327/* set DSR bit (register $04) */328scd.regs[0x04>>1].byte.h |= 0x40;329break;330}331332case 4: /* PCM RAM DMA */333{334cdc.dma_w = pcm_ram_dma_w;335break;336}337338case 5: /* PRG-RAM DMA */339{340cdc.dma_w = prg_ram_dma_w;341break;342}343344case 7: /* WORD-RAM DMA */345{346/* check memory mode */347if (scd.regs[0x02 >> 1].byte.l & 0x04)348{349/* 1M mode */350if (scd.regs[0x02 >> 1].byte.l & 0x01)351{352/* Word-RAM bank 0 is assigned to SUB-CPU */353cdc.dma_w = word_ram_0_dma_w;354}355else356{357/* Word-RAM bank 1 is assigned to SUB-CPU */358cdc.dma_w = word_ram_1_dma_w;359}360}361else362{363/* 2M mode */364if (scd.regs[0x02 >> 1].byte.l & 0x02)365{366/* only process DMA if Word-RAM is assigned to SUB-CPU */367cdc.dma_w = word_ram_2M_dma_w;368}369}370break;371}372373default: /* invalid */374{375#ifdef LOG_CDC376error("invalid CDC tranfer destination (%d)\n", scd.regs[0x04>>1].byte.h & 0x07);377#endif378break;379}380}381}382383scd.regs[0x04>>1].byte.l = 0x07;384break;385}386387case 0x07: /* DTACK */388{389/* clear pending data transfer end interrupt */390cdc.ifstat |= BIT_DTEI;391392/* clear DBCH bits 4-7 */393cdc.dbc.byte.h &= 0x0f;394395#if 0396/* no pending decoder interrupt ? */397if ((cdc.ifstat | BIT_DECI) || !(cdc.ifctrl & BIT_DECIEN))398{399/* clear pending level 5 interrupt */400scd.pending &= ~(1 << 5);401402/* update IRQ level */403s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);404}405#endif406scd.regs[0x04>>1].byte.l = 0x08;407break;408}409410case 0x08: /* WAL */411cdc.wa.byte.l = data;412scd.regs[0x04>>1].byte.l = 0x09;413break;414415case 0x09: /* WAH */416cdc.wa.byte.h = data;417scd.regs[0x04>>1].byte.l = 0x0a;418break;419420case 0x0a: /* CTRL0 */421{422/* set CRCOK bit only if decoding is enabled */423cdc.stat[0] = data & BIT_DECEN;424425/* update decoding mode */426if (data & BIT_AUTORQ)427{428/* set MODE bit according to CTRL1 register & clear FORM bit */429cdc.stat[2] = cdc.ctrl[1] & BIT_MODRQ;430}431else432{433/* set MODE & FORM bits according to CTRL1 register */434cdc.stat[2] = cdc.ctrl[1] & (BIT_MODRQ | BIT_FORMRQ);435}436437cdc.ctrl[0] = data;438scd.regs[0x04>>1].byte.l = 0x0b;439break;440}441442case 0x0b: /* CTRL1 */443{444/* update decoding mode */445if (cdc.ctrl[0] & BIT_AUTORQ)446{447/* set MODE bit according to CTRL1 register & clear FORM bit */448cdc.stat[2] = data & BIT_MODRQ;449}450else451{452/* set MODE & FORM bits according to CTRL1 register */453cdc.stat[2] = data & (BIT_MODRQ | BIT_FORMRQ);454}455456cdc.ctrl[1] = data;457scd.regs[0x04>>1].byte.l = 0x0c;458break;459}460461case 0x0c: /* PTL */462cdc.pt.byte.l = data;463scd.regs[0x04>>1].byte.l = 0x0d;464break;465466case 0x0d: /* PTH */467cdc.pt.byte.h = data;468scd.regs[0x04>>1].byte.l = 0x0e;469break;470471case 0x0e: /* CTRL2 (unused) */472scd.regs[0x04>>1].byte.l = 0x0f;473break;474475case 0x0f: /* RESET */476cdc_reset();477break;478479default: /* by default, SBOUT is not used */480break;481}482}483484unsigned char cdc_reg_r(void)485{486switch (scd.regs[0x04>>1].byte.l & 0x0F)487{488case 0x01: /* IFSTAT */489scd.regs[0x04>>1].byte.l = 0x02;490return cdc.ifstat;491492case 0x02: /* DBCL */493scd.regs[0x04>>1].byte.l = 0x03;494return cdc.dbc.byte.l;495496case 0x03: /* DBCH */497scd.regs[0x04>>1].byte.l = 0x04;498return cdc.dbc.byte.h;499500case 0x04: /* HEAD0 */501scd.regs[0x04>>1].byte.l = 0x05;502return cdc.head[cdc.ctrl[1] & BIT_SHDREN][0];503504case 0x05: /* HEAD1 */505scd.regs[0x04>>1].byte.l = 0x06;506return cdc.head[cdc.ctrl[1] & BIT_SHDREN][1];507508case 0x06: /* HEAD2 */509scd.regs[0x04>>1].byte.l = 0x07;510return cdc.head[cdc.ctrl[1] & BIT_SHDREN][2];511512case 0x07: /* HEAD3 */513scd.regs[0x04>>1].byte.l = 0x08;514return cdc.head[cdc.ctrl[1] & BIT_SHDREN][3];515516case 0x08: /* PTL */517scd.regs[0x04>>1].byte.l = 0x09;518return cdc.pt.byte.l;519520case 0x09: /* PTH */521scd.regs[0x04>>1].byte.l = 0x0a;522return cdc.pt.byte.h;523524case 0x0a: /* WAL */525scd.regs[0x04>>1].byte.l = 0x0b;526return cdc.wa.byte.l;527528case 0x0b: /* WAH */529scd.regs[0x04>>1].byte.l = 0x0c;530return cdc.wa.byte.h;531532case 0x0c: /* STAT0 */533scd.regs[0x04>>1].byte.l = 0x0d;534return cdc.stat[0];535536case 0x0d: /* STAT1 (always return 0) */537scd.regs[0x04>>1].byte.l = 0x0e;538return 0x00;539540case 0x0e: /* STAT2 */541scd.regs[0x04>>1].byte.l = 0x0f;542return cdc.stat[2];543544case 0x0f: /* STAT3 */545{546uint8 data = cdc.stat[3];547548/* clear !VALST (note: this is not 100% correct but BIOS do not seem to care) */549cdc.stat[3] = BIT_VALST;550551/* clear pending decoder interrupt */552cdc.ifstat |= BIT_DECI;553554#if 0555/* no pending data transfer end interrupt */556if ((cdc.ifstat | BIT_DTEI) || !(cdc.ifctrl & BIT_DTEIEN))557{558/* clear pending level 5 interrupt */559scd.pending &= ~(1 << 5);560561/* update IRQ level */562s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);563}564#endif565566scd.regs[0x04>>1].byte.l = 0x00;567return data;568}569570default: /* by default, COMIN is always empty */571return 0xff;572}573}574575unsigned short cdc_host_r(void)576{577/* check if data is available */578if (!(cdc.ifstat & BIT_DTEN))579{580/* read data word from CDC RAM buffer */581uint16 data = *(uint16 *)(cdc.ram + (cdc.dac.w & 0x3ffe));582583#ifdef LSB_FIRST584/* source data is stored in big endian format */585data = ((data >> 8) | (data << 8)) & 0xffff;586#endif587588#ifdef LOG_CDC589error("CDC host read 0x%04x -> 0x%04x (dbc=0x%x) (%X)\n", cdc.dac.w, data, cdc.dbc.w, s68k.pc);590#endif591592/* increment data address counter */593cdc.dac.w += 2;594595/* decrement data byte counter */596cdc.dbc.w -= 2;597598/* end of transfer ? */599if ((int16)cdc.dbc.w <= 0)600{601/* reset data byte counter (DBCH bits 4-7 should be set to 1) */602cdc.dbc.w = 0xf000;603604/* clear !DTEN and !DTBSY */605cdc.ifstat |= (BIT_DTBSY | BIT_DTEN);606607/* pending Data Transfer End interrupt */608cdc.ifstat &= ~BIT_DTEI;609610/* Data Transfer End interrupt enabled ? */611if (cdc.ifctrl & BIT_DTEIEN)612{613/* pending level 5 interrupt */614scd.pending |= (1 << 5);615616/* level 5 interrupt enabled ? */617if (scd.regs[0x32>>1].byte.l & 0x20)618{619/* update IRQ level */620s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);621}622}623624/* clear DSR bit & set EDT bit (SCD register $04) */625scd.regs[0x04>>1].byte.h = (scd.regs[0x04>>1].byte.h & 0x07) | 0x80;626}627628return data;629}630631#ifdef LOG_CDC632error("error reading CDC host (data transfer disabled)\n");633#endif634return 0xffff;635}636637638