380 lines
7.5 KiB
C++
380 lines
7.5 KiB
C++
//---------------------------------------------------------------------------
|
|
// NEOPOP : Emulator as in Dreamland
|
|
//
|
|
// Copyright (c) 2001-2002 by neopop_uk
|
|
//---------------------------------------------------------------------------
|
|
|
|
//---------------------------------------------------------------------------
|
|
// This program is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation; either version 2 of the License, or
|
|
// (at your option) any later version. See also the license.txt file for
|
|
// additional informations.
|
|
//---------------------------------------------------------------------------
|
|
|
|
/*
|
|
//---------------------------------------------------------------------------
|
|
//=========================================================================
|
|
|
|
dma.c
|
|
|
|
//=========================================================================
|
|
//---------------------------------------------------------------------------
|
|
|
|
History of changes:
|
|
===================
|
|
|
|
20 JUL 2002 - neopop_uk
|
|
=======================================
|
|
- Cleaned and tidied up for the source release
|
|
|
|
25 JUL 2002 - neopop_uk
|
|
=======================================
|
|
- Removed incorrect quick-fix code and added new DMA_update functions
|
|
to process the dma values.
|
|
- Fixed setting of C and M registers
|
|
- Added source copy byte and word mode DMA, seems to be only ones used.
|
|
|
|
26 JUL 2002 - neopop_uk
|
|
=======================================
|
|
- Added more DMA modes - "Kikouseki Unitron (J)" uses counter mode
|
|
and 4 byte memory to I/O transfer.
|
|
- Added load *from* dma control register.
|
|
|
|
30 JUL 2002 - neopop_uk
|
|
=======================================
|
|
- Made DMA_update more secure in it's ability to detect unknown DMA modes.
|
|
- DMA mode and count are printed in decimal, for internal consistancy.
|
|
|
|
01 AUG 2002 - neopop_uk
|
|
=======================================
|
|
- Re-written DMA_update for clarity, and added missing modes,
|
|
fixes "Super Real Mahjong"
|
|
|
|
//---------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include "neopop.h"
|
|
#include "dma.h"
|
|
#include "mem.h"
|
|
#include "interrupt.h"
|
|
|
|
namespace MDFN_IEN_NGP
|
|
{
|
|
|
|
//=============================================================================
|
|
|
|
static uint32 dmaS[4], dmaD[4];
|
|
static uint16 dmaC[4];
|
|
static uint8 dmaM[4];
|
|
|
|
//=============================================================================
|
|
|
|
void reset_dma(void)
|
|
{
|
|
memset(dmaS, 0, sizeof(dmaS));
|
|
memset(dmaD, 0, sizeof(dmaD));
|
|
memset(dmaC, 0, sizeof(dmaC));
|
|
memset(dmaM, 0, sizeof(dmaM));
|
|
}
|
|
|
|
//=============================================================================
|
|
|
|
void DMA_update(int channel)
|
|
{
|
|
uint8 mode = (dmaM[channel] & 0x1C) >> 2;
|
|
uint8 size = (dmaM[channel] & 0x03); //byte, word or long
|
|
|
|
// Correct?
|
|
if (dmaC[channel] == 0)
|
|
return;
|
|
|
|
switch (mode)
|
|
{
|
|
case 0: // Destination INC mode, I/O to Memory transfer
|
|
switch (size)
|
|
{
|
|
case 0:
|
|
storeB(dmaD[channel], loadB(dmaS[channel]));
|
|
dmaD[channel] += 1; //Byte increment
|
|
break;
|
|
|
|
case 1:
|
|
storeW(dmaD[channel], loadW(dmaS[channel]));
|
|
dmaD[channel] += 2; //Word increment
|
|
break;
|
|
|
|
case 2:
|
|
storeL(dmaD[channel], loadL(dmaS[channel]));
|
|
dmaD[channel] += 4; //Long increment
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 1: // Destination DEC mode, I/O to Memory transfer
|
|
switch (size)
|
|
{
|
|
case 0:
|
|
storeB(dmaD[channel], loadB(dmaS[channel]));
|
|
dmaD[channel] -= 1; //Byte decrement
|
|
break;
|
|
|
|
case 1:
|
|
storeW(dmaD[channel], loadW(dmaS[channel]));
|
|
dmaD[channel] -= 2; //Word decrement
|
|
break;
|
|
|
|
case 2:
|
|
storeL(dmaD[channel], loadL(dmaS[channel]));
|
|
dmaD[channel] -= 4; //Long decrement
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 2: // Source INC mode, Memory to I/O transfer
|
|
switch (size)
|
|
{
|
|
case 0:
|
|
storeB(dmaD[channel], loadB(dmaS[channel]));
|
|
dmaS[channel] += 1; //Byte increment
|
|
break;
|
|
|
|
case 1:
|
|
storeW(dmaD[channel], loadW(dmaS[channel]));
|
|
dmaS[channel] += 2; //Word increment
|
|
break;
|
|
|
|
case 2:
|
|
storeL(dmaD[channel], loadL(dmaS[channel]));
|
|
dmaS[channel] += 4; //Long increment
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 3: // Source DEC mode, Memory to I/O transfer
|
|
switch (size)
|
|
{
|
|
case 0:
|
|
storeB(dmaD[channel], loadB(dmaS[channel]));
|
|
dmaS[channel] -= 1; //Byte decrement
|
|
break;
|
|
|
|
case 1:
|
|
storeW(dmaD[channel], loadW(dmaS[channel]));
|
|
dmaS[channel] -= 2; //Word decrement
|
|
break;
|
|
|
|
case 2:
|
|
storeL(dmaD[channel], loadL(dmaS[channel]));
|
|
dmaS[channel] -= 4; //Long decrement
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 4: // Fixed Address Mode
|
|
switch (size)
|
|
{
|
|
case 0:
|
|
storeB(dmaD[channel], loadB(dmaS[channel]));
|
|
break;
|
|
|
|
case 1:
|
|
storeW(dmaD[channel], loadW(dmaS[channel]));
|
|
break;
|
|
|
|
case 2:
|
|
storeL(dmaD[channel], loadL(dmaS[channel]));
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 5: // Counter Mode
|
|
dmaS[channel]++;
|
|
break;
|
|
|
|
default:
|
|
MDFN_printf("Bad DMA mode %d\nPlease report this to the author.", dmaM[channel]);
|
|
return;
|
|
}
|
|
|
|
// Perform common counter decrement,
|
|
// vector clearing, and interrupt handling.
|
|
|
|
dmaC[channel]--;
|
|
if (dmaC[channel] == 0)
|
|
{
|
|
interrupt(14 + channel);
|
|
storeB(0x7C + channel, 0);
|
|
}
|
|
}
|
|
|
|
//=============================================================================
|
|
|
|
void dmaStoreB(uint8 cr, uint8 data)
|
|
{
|
|
switch (cr)
|
|
{
|
|
case 0x22:
|
|
dmaM[0] = data;
|
|
break;
|
|
case 0x26:
|
|
dmaM[1] = data;
|
|
break;
|
|
case 0x2A:
|
|
dmaM[2] = data;
|
|
break;
|
|
case 0x2E:
|
|
dmaM[3] = data;
|
|
break;
|
|
|
|
default:
|
|
MDFN_printf("dmaStoreB: Unknown register 0x%02X <- %02X\nPlease report this to the author.\n", cr, data);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void dmaStoreW(uint8 cr, uint16 data)
|
|
{
|
|
switch (cr)
|
|
{
|
|
case 0x20:
|
|
dmaC[0] = data;
|
|
break;
|
|
case 0x24:
|
|
dmaC[1] = data;
|
|
break;
|
|
case 0x28:
|
|
dmaC[2] = data;
|
|
break;
|
|
case 0x2C:
|
|
dmaC[3] = data;
|
|
break;
|
|
|
|
default:
|
|
MDFN_printf("dmaStoreW: Unknown register 0x%02X <- %04X\nPlease report this to the author.\n", cr, data);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void dmaStoreL(uint8 cr, uint32 data)
|
|
{
|
|
switch (cr)
|
|
{
|
|
case 0x00:
|
|
dmaS[0] = data;
|
|
break;
|
|
case 0x04:
|
|
dmaS[1] = data;
|
|
break;
|
|
case 0x08:
|
|
dmaS[2] = data;
|
|
break;
|
|
case 0x0C:
|
|
dmaS[3] = data;
|
|
break;
|
|
|
|
case 0x10:
|
|
dmaD[0] = data;
|
|
break;
|
|
case 0x14:
|
|
dmaD[1] = data;
|
|
break;
|
|
case 0x18:
|
|
dmaD[2] = data;
|
|
break;
|
|
case 0x1C:
|
|
dmaD[3] = data;
|
|
break;
|
|
|
|
default:
|
|
MDFN_printf("dmaStoreL: Unknown register 0x%02X <- %08X\nPlease report this to the author.\n", cr, data);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//=============================================================================
|
|
|
|
uint8 dmaLoadB(uint8 cr)
|
|
{
|
|
|
|
switch (cr)
|
|
{
|
|
case 0x22:
|
|
return dmaM[0];
|
|
break;
|
|
case 0x26:
|
|
return dmaM[1];
|
|
break;
|
|
case 0x2A:
|
|
return dmaM[2];
|
|
break;
|
|
case 0x2E:
|
|
return dmaM[3];
|
|
break;
|
|
|
|
default:
|
|
MDFN_printf("dmaLoadB: Unknown register 0x%02X\nPlease report this to the author.", cr);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
uint16 dmaLoadW(uint8 cr)
|
|
{
|
|
switch (cr)
|
|
{
|
|
case 0x20:
|
|
return dmaC[0];
|
|
break;
|
|
case 0x24:
|
|
return dmaC[1];
|
|
break;
|
|
case 0x28:
|
|
return dmaC[2];
|
|
break;
|
|
case 0x2C:
|
|
return dmaC[3];
|
|
break;
|
|
|
|
default:
|
|
MDFN_printf("dmaLoadW: Unknown register 0x%02X\nPlease report this to the author.", cr);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
uint32 dmaLoadL(uint8 cr)
|
|
{
|
|
switch (cr)
|
|
{
|
|
case 0x00:
|
|
return dmaS[0];
|
|
break;
|
|
case 0x04:
|
|
return dmaS[1];
|
|
break;
|
|
case 0x08:
|
|
return dmaS[2];
|
|
break;
|
|
case 0x0C:
|
|
return dmaS[3];
|
|
break;
|
|
|
|
case 0x10:
|
|
return dmaD[0];
|
|
break;
|
|
case 0x14:
|
|
return dmaD[1];
|
|
break;
|
|
case 0x18:
|
|
return dmaD[2];
|
|
break;
|
|
case 0x1C:
|
|
return dmaD[3];
|
|
break;
|
|
|
|
default:
|
|
MDFN_printf("dmaLoadL: Unknown register 0x%02X\nPlease report this to the author.", cr);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|