mirror of
https://github.com/libretro/NP2kai.git
synced 2024-10-07 14:53:33 +00:00
435 lines
9.1 KiB
C
Executable File
435 lines
9.1 KiB
C
Executable File
/**
|
|
* @file dmac.c
|
|
* @brief Implementation of the DMA controller
|
|
*/
|
|
|
|
#include "compiler.h"
|
|
#include "dmac.h"
|
|
#include "cpucore.h"
|
|
#include "iocore.h"
|
|
#include "sound.h"
|
|
#include "cs4231.h"
|
|
#include "sasiio.h"
|
|
|
|
void DMACCALL dma_dummyout(REG8 data) {
|
|
|
|
TRACEOUT(("dma_dummyout"));
|
|
(void)data;
|
|
}
|
|
|
|
REG8 DMACCALL dma_dummyin(void) {
|
|
TRACEOUT(("dma_dummyin"));
|
|
return(0xff);
|
|
}
|
|
|
|
REG8 DMACCALL dma_dummyproc(REG8 func) {
|
|
|
|
(void)func;
|
|
return(0);
|
|
}
|
|
|
|
static const DMAPROC dmaproc[] = {
|
|
{dma_dummyout, dma_dummyin, dma_dummyproc}, // NONE
|
|
{fdc_datawrite, fdc_dataread, fdc_dmafunc}, // 2HD
|
|
{fdc_datawrite, fdc_dataread, fdc_dmafunc}, // 2DD
|
|
#if defined(SUPPORT_SASI)
|
|
{sasi_datawrite, sasi_dataread, sasi_dmafunc}, // SASI
|
|
#else
|
|
{dma_dummyout, dma_dummyin, dma_dummyproc}, // SASI
|
|
#endif
|
|
{dma_dummyout, dma_dummyin, dma_dummyproc}, // SCSI
|
|
#if !defined(DISABLE_SOUND)
|
|
{dma_dummyout, dma_dummyin, cs4231dmafunc}, // CS4231
|
|
#else
|
|
{dma_dummyout, dma_dummyin, dma_dummyproc}, // SASI
|
|
#endif
|
|
};
|
|
|
|
|
|
// ----
|
|
UINT8 bank;
|
|
UINT8 bank2;
|
|
void dmac_check(void) {
|
|
|
|
BOOL workchg;
|
|
DMACH ch;
|
|
REG8 bit;
|
|
|
|
workchg = FALSE;
|
|
ch = dmac.dmach;
|
|
bit = 1;
|
|
do {
|
|
if ((!(dmac.mask & bit)) && (ch->ready)) {
|
|
if (!(dmac.work & bit)) {
|
|
dmac.work |= bit;
|
|
if (ch->proc.extproc(DMAEXT_START)) {
|
|
dmac.stat &= ~bit;
|
|
dmac.working |= bit;
|
|
workchg = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (dmac.work & bit) {
|
|
dmac.work &= ~bit;
|
|
dmac.working &= ~bit;
|
|
ch->proc.extproc(DMAEXT_BREAK);
|
|
workchg = TRUE;
|
|
}
|
|
}
|
|
bit <<= 1;
|
|
ch++;
|
|
} while(bit & 0x0f);
|
|
if (workchg) {
|
|
nevent_forceexit();
|
|
}
|
|
}
|
|
|
|
UINT dmac_getdatas(DMACH dmach, UINT8 *buf, UINT size) {
|
|
|
|
UINT leng;
|
|
UINT32 addr;
|
|
UINT i;
|
|
|
|
leng = np2min(dmach->leng.w, size);
|
|
if (leng) {
|
|
addr = dmach->adrs.d; // + mask
|
|
if (!(dmach->mode & 0x20)) { // dir +
|
|
for (i=0; i<leng; i++) {
|
|
buf[i] = MEMP_READ8(addr + i);
|
|
}
|
|
dmach->adrs.d += leng;
|
|
}
|
|
else { // dir -
|
|
for (i=0; i<leng; i++) {
|
|
buf[i] = MEMP_READ8(addr - i);
|
|
}
|
|
dmach->adrs.d -= leng;
|
|
}
|
|
dmach->leng.w -= leng;
|
|
if (dmach->leng.w == 0) {
|
|
dmach->proc.extproc(DMAEXT_END);
|
|
}
|
|
}
|
|
return(leng);
|
|
}
|
|
|
|
// ---- I/O
|
|
|
|
static void IOOUTCALL dmac_o01(UINT port, REG8 dat) {
|
|
|
|
DMACH dmach;
|
|
int lh;
|
|
|
|
dmach = dmac.dmach + ((port >> 2) & 3);
|
|
lh = dmac.lh;
|
|
dmac.lh = (UINT8)(lh ^ 1);
|
|
dmach->adrs.b[lh + DMA32_LOW] = dat;
|
|
dmach->adrsorg.b[lh] = dat;
|
|
dmach->startaddr = dmach->adrs.d;
|
|
}
|
|
|
|
static void IOOUTCALL dmac_o03(UINT port, REG8 dat) {
|
|
|
|
int ch;
|
|
DMACH dmach;
|
|
int lh;
|
|
|
|
ch = (port >> 2) & 3;
|
|
dmach = dmac.dmach + ch;
|
|
lh = dmac.lh;
|
|
dmac.lh = lh ^ 1;
|
|
dmach->leng.b[lh] = dat;
|
|
dmach->lengorg.b[lh] = dat;
|
|
dmac.stat &= ~(1 << ch);
|
|
//dmach->startcount =dmach->leng.w;
|
|
//dmach->lastaddr = dmach->startaddr + dmach->leng.w;
|
|
dmach->startcount = dmach->leng.w;
|
|
dmach->lastaddr = dmach->startaddr + dmach->leng.w;
|
|
}
|
|
|
|
static void IOOUTCALL dmac_o13_(UINT port, REG8 dat) {
|
|
if (dat& 4)
|
|
dmac.stat |= 1 << ((dat & 3) +4);
|
|
else
|
|
dmac.stat &= ~(1 << ((dat & 3) +4));
|
|
dmac.stat &=~(1 << (dat & 3));
|
|
dmac_check();
|
|
(void)port;
|
|
}
|
|
|
|
|
|
static void IOOUTCALL dmac_o13(UINT port, REG8 dat) {
|
|
dmac.dmach[dat & 3].sreq = dat;
|
|
dmac_check();
|
|
(void)port;
|
|
}
|
|
|
|
static void IOOUTCALL dmac_o15(UINT port, REG8 dat) {
|
|
|
|
if (dat & 4) {
|
|
dmac.mask |= (1 << (dat & 3));
|
|
}
|
|
else {
|
|
dmac.mask &= ~(1 << (dat & 3));
|
|
}
|
|
dmac_check();
|
|
(void)port;
|
|
}
|
|
|
|
static void IOOUTCALL dmac_o17(UINT port, REG8 dat) {
|
|
|
|
dmac.dmach[dat & 3].mode = dat;
|
|
(void)port;
|
|
}
|
|
|
|
static void IOOUTCALL dmac_o19(UINT port, REG8 dat) {
|
|
|
|
dmac.lh = DMA16_LOW;
|
|
(void)port;
|
|
(void)dat;
|
|
}
|
|
|
|
static void IOOUTCALL dmac_o1b(UINT port, REG8 dat) {
|
|
|
|
dmac.mask = 0x0f;
|
|
dmac.dmach[0].adrs.d = 0;
|
|
dmac.dmach[0].leng.w = 0;
|
|
dmac.dmach[1].adrs.d = 0;
|
|
dmac.dmach[1].leng.w = 0;
|
|
dmac.dmach[2].adrs.d = 0;
|
|
dmac.dmach[2].leng.w = 0;
|
|
dmac.dmach[3].adrs.d = 0;
|
|
dmac.dmach[3].leng.w = 0;
|
|
(void)port;
|
|
(void)dat;
|
|
}
|
|
|
|
static void IOOUTCALL dmac_o1d(UINT port, REG8 dat) {
|
|
|
|
dmac.mask = 0;
|
|
dmac_check();
|
|
(void)port;
|
|
(void)dat;
|
|
}
|
|
|
|
static void IOOUTCALL dmac_o1f(UINT port, REG8 dat) {
|
|
|
|
dmac.mask = dat;
|
|
dmac_check();
|
|
(void)port;
|
|
}
|
|
|
|
static void IOOUTCALL dmac_o21(UINT port, REG8 dat) {//バンク設定
|
|
|
|
DMACH dmach;
|
|
dmach = dmac.dmach + (((port >> 1) + 1) & 3);
|
|
#if defined(CPUCORE_IA32)
|
|
dmach->adrs.b[DMA32_HIGH + DMA16_LOW] = dat;
|
|
#else
|
|
// IA16では ver0.75で無効、ver0.76で修正
|
|
dmach->adrs.b[DMA32_HIGH + DMA16_LOW] = dat & 0x0f;//V30は20bitまで
|
|
#endif
|
|
dmach->adrs.b[DMA32_HIGH + DMA16_HIGH] = 0;//25bitより上はここでは転送できない→0E05
|
|
bank = dat;
|
|
if (dmach->bound != 3){
|
|
dmach->startaddr = dmach->adrs.d;
|
|
dmach->lastaddr = (bank <<16 | dmach->lastaddr);
|
|
}
|
|
else
|
|
{
|
|
dmach->startaddr = bank << 16 | dmach->adrs.d;
|
|
dmach->lastaddr = (bank <<16 | dmach->lastaddr);
|
|
TRACEOUT(("port =%x ch=%x bank = %x dma_address = %x\n",port,((port >> 1) + 1) & 3, dat, dmach->adrs.d));
|
|
}
|
|
}
|
|
|
|
static void IOOUTCALL dmac_o29(UINT port, REG8 dat) {
|
|
|
|
DMACH dmach;
|
|
|
|
dmach = dmac.dmach + (dat & 3);
|
|
// dmach = dmac.dmach + (dat & 0xf);
|
|
// TRACEOUT (("dmach %x",dat));// PC-98は4chしか持ってない
|
|
dmach->bound = (dat >> 2) & 3;
|
|
(void)port;
|
|
TRACEOUT(("port =%x ch= %x dma bound =%x\n",port,dat & 03 ,dmach->bound));
|
|
}
|
|
|
|
static REG8 IOINPCALL dmac_i01(UINT port) {
|
|
|
|
DMACH dmach;
|
|
int lh;
|
|
|
|
dmach = dmac.dmach + ((port >> 2) & 3);
|
|
lh = dmac.lh;
|
|
dmac.lh = lh ^ 1;
|
|
return(dmach->adrs.b[lh + DMA32_LOW]);
|
|
}
|
|
|
|
static REG8 IOINPCALL dmac_i03(UINT port) {
|
|
|
|
DMACH dmach;
|
|
int lh;
|
|
|
|
dmach = dmac.dmach + ((port >> 2) & 3);
|
|
lh = dmac.lh;
|
|
dmac.lh = lh ^ 1;
|
|
return(dmach->leng.b[lh]);
|
|
}
|
|
|
|
static REG8 IOINPCALL dmac_i11(UINT port) {
|
|
|
|
(void)port;
|
|
return(dmac.stat &= 0xf0); // ToDo!!
|
|
}
|
|
static void IOOUTCALL dmac_oe05(UINT port, REG8 dat) {
|
|
|
|
DMACH dmach;
|
|
|
|
// dmach = dmac.dmach + (((port >> 1) - 2) & 3);//qemu
|
|
// dmach = dmac.dmach + ((port >> 1) & 0x07) - 2;//np21/w
|
|
|
|
char channel;
|
|
//switch(port){//シフト計算は頭がおかしくなるのでswitchでごまかしました
|
|
// case 0xe05:channel = 0;break;
|
|
// case 0xe07:channel = 1;break;
|
|
// case 0xe09:channel = 2;break;
|
|
// case 0xe0b:channel = 3;
|
|
//}
|
|
channel = ((port - 0x05) & 0x07) >> 1;
|
|
dmach = dmac.dmach + channel;
|
|
dmach->adrs.b[DMA32_HIGH + DMA16_HIGH] = dat;
|
|
bank2 = dat;
|
|
dmach->startaddr = ((bank2 &0x7f) << 24) | dmach->adrs.d;
|
|
dmach->lastaddr = ((bank2 &0x7f) << 24) | (dmach->lastaddr);
|
|
TRACEOUT(("32bit DMA ch %x bank %x\n",channel, dmach->adrs.b[3]));
|
|
}
|
|
static void IOOUTCALL dmac_o2b(UINT port, REG8 dat) {
|
|
(void)port;
|
|
}
|
|
|
|
// ---- I/F
|
|
|
|
static const IOOUT dmaco00[16] = {
|
|
dmac_o01, dmac_o03, dmac_o01, dmac_o03,
|
|
dmac_o01, dmac_o03, dmac_o01, dmac_o03,
|
|
NULL, dmac_o13, dmac_o15, dmac_o17,
|
|
dmac_o19, dmac_o1b, dmac_o1d, dmac_o1f};
|
|
|
|
static const IOINP dmaci00[16] = {
|
|
dmac_i01, dmac_i03, dmac_i01, dmac_i03,
|
|
dmac_i01, dmac_i03, dmac_i01, dmac_i03,
|
|
dmac_i11, NULL, NULL, NULL,
|
|
NULL, NULL, NULL, NULL};
|
|
|
|
static const IOOUT dmaco21[8] = {
|
|
dmac_o21, dmac_o21, dmac_o21, dmac_o21,
|
|
dmac_o29, NULL, NULL, NULL};
|
|
|
|
void dmac_reset(const NP2CFG *pConfig) {
|
|
|
|
ZeroMemory(&dmac, sizeof(dmac));
|
|
dmac.lh = DMA16_LOW;
|
|
dmac.mask = 0xf;
|
|
dmac_procset();
|
|
TRACEOUT(("sizeof(_DMACH) = %d", sizeof(_DMACH)));
|
|
(void)pConfig;
|
|
}
|
|
|
|
void dmac_bind(void) {
|
|
|
|
iocore_attachsysoutex(0x0001, 0x0ce1, dmaco00, 16);
|
|
iocore_attachsysinpex(0x0001, 0x0ce1, dmaci00, 16);
|
|
iocore_attachsysoutex(0x0021, 0x0cf1, dmaco21, 8);
|
|
iocore_attachout(0x0e05, dmac_oe05); //DMA ch.0
|
|
iocore_attachout(0x0e07, dmac_oe05); //DMA ch.1
|
|
iocore_attachout(0x0e09, dmac_oe05); //DMA ch.2
|
|
iocore_attachout(0x0e0b, dmac_oe05); //DMA ch.3
|
|
//0x489はnecio.cで使ってる
|
|
//PC-H98??? EMM386.exeを組み込むと現れる
|
|
// iocore_attachout(0x2b,dmac_o11);
|
|
// iocore_attachinp(0x2d,dmac_i11);//when 0x2b = c8???
|
|
}
|
|
|
|
|
|
// ----
|
|
|
|
static void dmacset(REG8 channel) {
|
|
|
|
DMADEV *dev;
|
|
DMADEV *devterm;
|
|
UINT dmadev;
|
|
|
|
dev = dmac.device;
|
|
devterm = dev + dmac.devices;
|
|
dmadev = DMADEV_NONE;
|
|
while(dev < devterm) {
|
|
if (dev->channel == channel) {
|
|
dmadev = dev->device;
|
|
}
|
|
dev++;
|
|
}
|
|
if (dmadev >= NELEMENTS(dmaproc)) {
|
|
dmadev = 0;
|
|
}
|
|
|
|
switch(dmadev){
|
|
case 0:TRACEOUT(("dmac set %d - dummy", channel));break;
|
|
case 1:TRACEOUT(("dmac set %d - 2HD", channel));break;
|
|
case 2:TRACEOUT(("dmac set %d - 2DD", channel));break;
|
|
case 3:TRACEOUT(("dmac set %d - SASI", channel));break;
|
|
case 4:TRACEOUT(("dmac set %d - SCSI", channel));break;
|
|
case 5:TRACEOUT(("dmac set %d - cs4231p", channel));break;
|
|
}
|
|
dmac.dmach[channel].proc = dmaproc[dmadev];
|
|
}
|
|
|
|
void dmac_procset(void) {
|
|
|
|
REG8 i;
|
|
|
|
for (i=0; i<4; i++) {
|
|
dmacset(i);
|
|
}
|
|
}
|
|
|
|
void dmac_attach(REG8 device, REG8 channel) {
|
|
|
|
dmac_detach(device);
|
|
|
|
if (dmac.devices < NELEMENTS(dmac.device)) {
|
|
dmac.device[dmac.devices].device = device;
|
|
dmac.device[dmac.devices].channel = channel;
|
|
dmac.devices++;
|
|
dmacset(channel);
|
|
}
|
|
}
|
|
|
|
void dmac_detach(REG8 device) {
|
|
|
|
DMADEV *dev;
|
|
DMADEV *devterm;
|
|
REG8 ch;
|
|
|
|
dev = dmac.device;
|
|
devterm = dev + dmac.devices;
|
|
while(dev < devterm) {
|
|
if (dev->device == device) {
|
|
break;
|
|
}
|
|
dev++;
|
|
}
|
|
if (dev < devterm) {
|
|
ch = dev->channel;
|
|
dev++;
|
|
while(dev < devterm) {
|
|
*(dev - 1) = *dev;
|
|
dev++;
|
|
}
|
|
dmac.devices--;
|
|
//if (ch < 5)
|
|
dmacset(ch);
|
|
}
|
|
}
|