BizHawk/waterbox/ngp/dma.cpp

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;
}
}
}