2019-02-15 00:08:50 -05:00
# include "stdafx.h"
# include "DmaController.h"
2019-10-10 23:54:38 -04:00
# include "DmaControllerTypes.h"
2019-02-15 00:08:50 -05:00
# include "MemoryManager.h"
2019-02-17 14:42:35 -05:00
# include "MessageManager.h"
2019-03-12 09:15:57 -04:00
# include "../Utilities/Serializer.h"
2019-02-15 00:08:50 -05:00
2020-12-19 23:30:09 +03:00
static constexpr uint8_t _transferByteCount [ 8 ] = { 1 , 2 , 2 , 4 , 4 , 4 , 2 , 4 } ;
2019-03-31 14:50:12 -04:00
static constexpr uint8_t _transferOffset [ 8 ] [ 4 ] = {
2020-12-19 23:30:09 +03:00
{ 0 , 0 , 0 , 0 } , { 0 , 1 , 0 , 1 } , { 0 , 0 , 0 , 0 } , { 0 , 0 , 1 , 1 } ,
{ 0 , 1 , 2 , 3 } , { 0 , 1 , 0 , 1 } , { 0 , 0 , 0 , 0 } , { 0 , 0 , 1 , 1 }
2019-03-31 14:50:12 -04:00
} ;
2020-12-19 23:30:09 +03:00
DmaController : : DmaController ( MemoryManager * memoryManager )
2019-02-15 00:08:50 -05:00
{
_memoryManager = memoryManager ;
2019-03-16 12:20:18 -04:00
Reset ( ) ;
2020-12-19 23:30:09 +03:00
for ( int j = 0 ; j < 8 ; j + + )
{
for ( int i = 0 ; i < = 0x0A ; i + + )
{
2019-03-16 12:20:18 -04:00
Write ( 0x4300 | i | ( j < < 4 ) , 0xFF ) ;
}
}
}
void DmaController : : Reset ( )
{
_hdmaChannels = 0 ;
2019-07-08 21:55:59 -04:00
_hdmaPending = false ;
_hdmaInitPending = false ;
_dmaStartDelay = false ;
_dmaPending = false ;
_needToProcess = false ;
2020-12-19 23:30:09 +03:00
for ( int i = 0 ; i < 8 ; i + + )
{
2019-07-08 21:55:59 -04:00
_channel [ i ] . DmaActive = false ;
}
2019-02-15 00:08:50 -05:00
}
2019-03-09 14:27:32 -05:00
void DmaController : : CopyDmaByte ( uint32_t addressBusA , uint16_t addressBusB , bool fromBtoA )
{
2020-12-19 23:30:09 +03:00
if ( fromBtoA )
{
if ( addressBusB ! = 0x2180 | | ! _memoryManager - > IsWorkRam ( addressBusA ) )
{
2019-03-16 16:36:58 -04:00
uint8_t valToWrite = _memoryManager - > ReadDma ( addressBusB , false ) ;
_memoryManager - > WriteDma ( addressBusA , valToWrite , true ) ;
2020-12-19 23:30:09 +03:00
}
else
{
2019-03-09 14:27:32 -05:00
//$2180->WRAM do cause a write to occur (but no read), but the value written is invalid
2019-07-12 23:55:18 -04:00
_memoryManager - > IncMasterClock4 ( ) ;
2019-03-16 16:36:58 -04:00
_memoryManager - > WriteDma ( addressBusA , 0xFF , true ) ;
2019-03-09 14:27:32 -05:00
}
2020-12-19 23:30:09 +03:00
}
else
{
if ( addressBusB ! = 0x2180 | | ! _memoryManager - > IsWorkRam ( addressBusA ) )
{
2019-03-16 16:36:58 -04:00
uint8_t valToWrite = _memoryManager - > ReadDma ( addressBusA , true ) ;
_memoryManager - > WriteDma ( addressBusB , valToWrite , false ) ;
2020-12-19 23:30:09 +03:00
}
else
{
2019-03-09 14:27:32 -05:00
//WRAM->$2180 does not cause a write to occur
2019-07-12 23:55:18 -04:00
_memoryManager - > IncMasterClock8 ( ) ;
2019-03-09 14:27:32 -05:00
}
}
}
2020-12-19 23:30:09 +03:00
void DmaController : : RunDma ( DmaChannelConfig & channel )
2019-02-15 00:08:50 -05:00
{
2020-12-19 23:30:09 +03:00
if ( ! channel . DmaActive )
{
2019-07-06 18:07:09 -04:00
return ;
}
//"Then perform the DMA: 8 master cycles overhead and 8 master cycles per byte per channel"
2019-07-12 23:55:18 -04:00
_memoryManager - > IncMasterClock8 ( ) ;
2019-07-06 18:07:09 -04:00
ProcessPendingTransfers ( ) ;
2020-12-19 23:30:09 +03:00
const uint8_t * transferOffsets = _transferOffset [ channel . TransferMode ] ;
2019-02-15 00:08:50 -05:00
2019-02-16 00:47:02 -05:00
uint8_t i = 0 ;
2020-12-19 23:30:09 +03:00
do
{
2019-07-06 18:07:09 -04:00
//Manual DMA transfers run to the end of the transfer when started
2019-03-09 14:27:32 -05:00
CopyDmaByte (
( channel . SrcBank < < 16 ) | channel . SrcAddress ,
2019-07-06 18:07:09 -04:00
0x2100 | ( channel . DestAddress + transferOffsets [ i & 0x03 ] ) ,
2019-03-09 14:27:32 -05:00
channel . InvertDirection
) ;
2019-02-15 00:08:50 -05:00
2020-12-19 23:30:09 +03:00
if ( ! channel . FixedTransfer )
{
2019-02-19 21:09:12 -05:00
channel . SrcAddress + = channel . Decrement ? - 1 : 1 ;
2019-02-15 00:08:50 -05:00
}
2019-02-19 21:09:12 -05:00
channel . TransferSize - - ;
2019-02-16 00:47:02 -05:00
i + + ;
2019-07-06 18:07:09 -04:00
ProcessPendingTransfers ( ) ;
2020-12-19 23:30:09 +03:00
}
while ( channel . TransferSize > 0 & & channel . DmaActive ) ;
2019-02-15 00:08:50 -05:00
2019-07-06 18:07:09 -04:00
channel . DmaActive = false ;
2019-02-19 21:09:12 -05:00
}
2019-02-17 14:42:35 -05:00
2019-07-06 18:07:09 -04:00
bool DmaController : : InitHdmaChannels ( )
2019-02-19 21:09:12 -05:00
{
2019-07-06 18:07:09 -04:00
_hdmaInitPending = false ;
2020-12-19 23:30:09 +03:00
for ( int i = 0 ; i < 8 ; i + + )
{
2019-04-11 19:55:06 -04:00
//Reset internal flags on every frame, whether or not the channels are enabled
_channel [ i ] . HdmaFinished = false ;
2020-12-19 23:30:09 +03:00
_channel [ i ] . DoTransfer = false ;
//not resetting this causes graphical glitches in some games (Aladdin, Super Ghouls and Ghosts)
2019-03-22 21:10:27 -04:00
}
2020-12-19 23:30:09 +03:00
if ( ! _hdmaChannels )
{
2019-04-11 19:55:06 -04:00
//No channels are enabled, no more processing needs to be done
2019-07-06 18:07:09 -04:00
UpdateNeedToProcessFlag ( ) ;
return false ;
}
bool needSync = ! HasActiveDmaChannel ( ) ;
2020-12-19 23:30:09 +03:00
if ( needSync )
{
2019-07-06 18:07:09 -04:00
SyncStartDma ( ) ;
2019-04-11 19:55:06 -04:00
}
2019-07-12 23:55:18 -04:00
_memoryManager - > IncMasterClock8 ( ) ;
2019-04-11 19:55:06 -04:00
2020-12-19 23:30:09 +03:00
for ( int i = 0 ; i < 8 ; i + + )
{
DmaChannelConfig & ch = _channel [ i ] ;
2019-04-11 19:55:06 -04:00
//Set DoTransfer to true for all channels if any HDMA channel is enabled
ch . DoTransfer = true ;
2019-03-03 13:53:00 -05:00
2020-12-19 23:30:09 +03:00
if ( _hdmaChannels & ( 1 < < i ) )
{
2019-02-19 21:09:12 -05:00
//"1. Copy AAddress into Address."
ch . HdmaTableAddress = ch . SrcAddress ;
2019-07-06 18:07:09 -04:00
ch . DmaActive = false ;
2019-02-19 21:09:12 -05:00
//"2. Load $43xA (Line Counter and Repeat) from the table. I believe $00 will terminate this channel immediately."
2019-03-16 16:36:58 -04:00
ch . HdmaLineCounterAndRepeat = _memoryManager - > ReadDma ( ( ch . SrcBank < < 16 ) | ch . HdmaTableAddress , true ) ;
2019-07-12 23:55:18 -04:00
_memoryManager - > IncMasterClock4 ( ) ;
2019-04-20 09:30:51 -04:00
2019-02-19 21:09:12 -05:00
ch . HdmaTableAddress + + ;
2020-12-19 23:30:09 +03:00
if ( ch . HdmaLineCounterAndRepeat = = 0 )
{
2019-02-19 21:09:12 -05:00
ch . HdmaFinished = true ;
}
//3. Load Indirect Address, if necessary.
2020-12-19 23:30:09 +03:00
if ( ch . HdmaIndirectAddressing )
{
2019-03-16 16:36:58 -04:00
uint8_t lsb = _memoryManager - > ReadDma ( ( ch . SrcBank < < 16 ) | ch . HdmaTableAddress + + , true ) ;
2019-07-12 23:55:18 -04:00
_memoryManager - > IncMasterClock4 ( ) ;
2019-03-16 16:36:58 -04:00
uint8_t msb = _memoryManager - > ReadDma ( ( ch . SrcBank < < 16 ) | ch . HdmaTableAddress + + , true ) ;
2019-07-12 23:55:18 -04:00
_memoryManager - > IncMasterClock4 ( ) ;
2019-04-20 09:30:51 -04:00
ch . TransferSize = ( msb < < 8 ) | lsb ;
2019-02-19 21:09:12 -05:00
}
}
}
2019-04-11 22:34:28 -04:00
2020-12-19 23:30:09 +03:00
if ( needSync )
{
2019-07-06 18:07:09 -04:00
SyncEndDma ( ) ;
}
UpdateNeedToProcessFlag ( ) ;
return true ;
2019-02-19 21:09:12 -05:00
}
2020-12-19 23:30:09 +03:00
void DmaController : : RunHdmaTransfer ( DmaChannelConfig & channel )
2019-02-19 21:09:12 -05:00
{
2020-12-19 23:30:09 +03:00
const uint8_t * transferOffsets = _transferOffset [ channel . TransferMode ] ;
2019-02-19 21:09:12 -05:00
uint8_t transferByteCount = _transferByteCount [ channel . TransferMode ] ;
2019-07-06 18:07:09 -04:00
channel . DmaActive = false ;
2019-03-09 12:01:36 -05:00
2019-02-19 21:09:12 -05:00
uint8_t i = 0 ;
2020-12-19 23:30:09 +03:00
if ( channel . HdmaIndirectAddressing )
{
do
{
2019-03-16 16:36:58 -04:00
CopyDmaByte (
( channel . HdmaBank < < 16 ) | channel . TransferSize ,
2019-03-31 14:50:12 -04:00
0x2100 | ( channel . DestAddress + transferOffsets [ i ] ) ,
2019-03-16 16:36:58 -04:00
channel . InvertDirection
) ;
2019-03-25 18:29:37 -04:00
channel . TransferSize + + ;
2019-03-16 16:36:58 -04:00
i + + ;
2020-12-19 23:30:09 +03:00
}
while ( i < transferByteCount ) ;
}
else
{
do
{
2019-03-16 16:36:58 -04:00
CopyDmaByte (
( channel . SrcBank < < 16 ) | channel . HdmaTableAddress ,
2019-03-31 14:50:12 -04:00
0x2100 | ( channel . DestAddress + transferOffsets [ i ] ) ,
2019-03-16 16:36:58 -04:00
channel . InvertDirection
) ;
2019-03-25 18:29:37 -04:00
channel . HdmaTableAddress + + ;
2019-03-16 16:36:58 -04:00
i + + ;
2020-12-19 23:30:09 +03:00
}
while ( i < transferByteCount ) ;
2019-02-19 21:09:12 -05:00
}
}
2019-04-11 22:34:28 -04:00
void DmaController : : SyncStartDma ( )
{
//"after the pause, wait 2-8 master cycles to reach a whole multiple of 8 master cycles since reset"
2019-04-20 09:30:51 -04:00
_dmaStartClock = _memoryManager - > GetMasterClock ( ) ;
2019-04-11 22:34:28 -04:00
_memoryManager - > IncrementMasterClockValue ( 8 - ( _memoryManager - > GetMasterClock ( ) & 0x07 ) ) ;
}
void DmaController : : SyncEndDma ( )
{
//"Then wait 2-8 master cycles to reach a whole number of CPU Clock cycles since the pause"
2019-04-20 09:30:51 -04:00
uint8_t cpuSpeed = _memoryManager - > GetCpuSpeed ( ) ;
2020-12-19 23:30:09 +03:00
_memoryManager - > IncrementMasterClockValue (
cpuSpeed - ( ( _memoryManager - > GetMasterClock ( ) - _dmaStartClock ) % cpuSpeed ) ) ;
2019-04-11 22:34:28 -04:00
}
2019-07-06 18:07:09 -04:00
bool DmaController : : HasActiveDmaChannel ( )
2019-02-19 21:09:12 -05:00
{
2020-12-19 23:30:09 +03:00
for ( int i = 0 ; i < 8 ; i + + )
{
if ( _channel [ i ] . DmaActive )
{
2019-07-06 18:07:09 -04:00
return true ;
}
}
return false ;
}
bool DmaController : : ProcessHdmaChannels ( )
{
_hdmaPending = false ;
2020-12-19 23:30:09 +03:00
if ( ! _hdmaChannels )
{
2019-07-06 18:07:09 -04:00
UpdateNeedToProcessFlag ( ) ;
return false ;
2019-04-11 19:55:06 -04:00
}
2019-07-06 18:07:09 -04:00
bool needSync = ! HasActiveDmaChannel ( ) ;
2020-12-19 23:30:09 +03:00
if ( needSync )
{
2019-07-06 18:07:09 -04:00
SyncStartDma ( ) ;
}
2019-07-12 23:55:18 -04:00
_memoryManager - > IncMasterClock8 ( ) ;
2019-07-06 18:07:09 -04:00
uint8_t originalActiveChannel = _activeChannel ;
2019-04-11 19:55:06 -04:00
//Run all the DMA transfers for each channel first, before fetching data for the next scanline
2020-12-19 23:30:09 +03:00
for ( int i = 0 ; i < 8 ; i + + )
{
DmaChannelConfig & ch = _channel [ i ] ;
if ( ( _hdmaChannels & ( 1 < < i ) ) = = 0 )
{
2019-04-11 19:55:06 -04:00
continue ;
}
2019-02-19 21:09:12 -05:00
2019-07-06 18:07:09 -04:00
ch . DmaActive = false ;
2019-03-09 12:01:36 -05:00
2020-12-19 23:30:09 +03:00
if ( ch . HdmaFinished )
{
2019-07-06 18:07:09 -04:00
continue ;
}
2020-12-19 23:30:09 +03:00
2019-04-11 19:55:06 -04:00
//1. If DoTransfer is false, skip to step 3.
2020-12-19 23:30:09 +03:00
if ( ch . DoTransfer )
{
2019-04-11 19:55:06 -04:00
//2. For the number of bytes (1, 2, or 4) required for this Transfer Mode...
2019-10-10 23:54:38 -04:00
_activeChannel = DmaController : : HdmaChannelFlag | i ;
2019-04-11 19:55:06 -04:00
RunHdmaTransfer ( ch ) ;
}
}
2019-02-21 23:35:51 -05:00
2019-04-11 19:55:06 -04:00
//Update the channel's state & fetch data for the next scanline
2020-12-19 23:30:09 +03:00
for ( int i = 0 ; i < 8 ; i + + )
{
DmaChannelConfig & ch = _channel [ i ] ;
if ( ( _hdmaChannels & ( 1 < < i ) ) = = 0 | | ch . HdmaFinished )
{
2019-04-11 19:55:06 -04:00
continue ;
}
2019-02-21 23:35:51 -05:00
2019-04-11 19:55:06 -04:00
//3. Decrement $43xA.
ch . HdmaLineCounterAndRepeat - - ;
//4. Set DoTransfer to the value of Repeat.
ch . DoTransfer = ( ch . HdmaLineCounterAndRepeat & 0x80 ) ! = 0 ;
2019-02-19 21:09:12 -05:00
2019-04-20 09:30:51 -04:00
//"a. Read the next byte from Address into $43xA (thus, into both Line Counter and Repeat)."
//This value is discarded if the line counter isn't 0
uint8_t newCounter = _memoryManager - > ReadDma ( ( ch . SrcBank < < 16 ) | ch . HdmaTableAddress , true ) ;
2019-07-12 23:55:18 -04:00
_memoryManager - > IncMasterClock4 ( ) ;
2019-04-20 09:30:51 -04:00
2019-04-11 19:55:06 -04:00
//5. If Line Counter is zero...
2020-12-19 23:30:09 +03:00
if ( ( ch . HdmaLineCounterAndRepeat & 0x7F ) = = 0 )
{
2019-04-20 09:30:51 -04:00
ch . HdmaLineCounterAndRepeat = newCounter ;
ch . HdmaTableAddress + + ;
2019-04-11 19:55:06 -04:00
//"b. If Addressing Mode is Indirect, read two bytes from Address into Indirect Address(and increment Address by two bytes)."
2020-12-19 23:30:09 +03:00
if ( ch . HdmaIndirectAddressing )
{
if ( ch . HdmaLineCounterAndRepeat = = 0 & & IsLastActiveHdmaChannel ( i ) )
{
2019-04-11 19:55:06 -04:00
//"One oddity: if $43xA is 0 and this is the last active HDMA channel for this scanline, only load one byte for Address,
//and use the $00 for the low byte.So Address ends up incremented one less than otherwise expected, and one less CPU Cycle is used."
uint8_t msb = _memoryManager - > ReadDma ( ( ch . SrcBank < < 16 ) | ch . HdmaTableAddress + + , true ) ;
2019-07-12 23:55:18 -04:00
_memoryManager - > IncMasterClock4 ( ) ;
2019-04-11 19:55:06 -04:00
ch . TransferSize = ( msb < < 8 ) ;
2020-12-19 23:30:09 +03:00
}
else
{
2019-04-20 09:30:51 -04:00
//"If a new indirect address is required, 16 master cycles are taken to load it."
2019-04-11 19:55:06 -04:00
uint8_t lsb = _memoryManager - > ReadDma ( ( ch . SrcBank < < 16 ) | ch . HdmaTableAddress + + , true ) ;
2019-07-12 23:55:18 -04:00
_memoryManager - > IncMasterClock4 ( ) ;
2020-12-19 23:30:09 +03:00
2019-04-11 19:55:06 -04:00
uint8_t msb = _memoryManager - > ReadDma ( ( ch . SrcBank < < 16 ) | ch . HdmaTableAddress + + , true ) ;
2019-07-12 23:55:18 -04:00
_memoryManager - > IncMasterClock4 ( ) ;
2019-02-19 21:09:12 -05:00
2019-04-20 09:30:51 -04:00
ch . TransferSize = ( msb < < 8 ) | lsb ;
2020-12-19 23:30:09 +03:00
}
2019-04-11 19:55:06 -04:00
}
//"c. If $43xA is zero, terminate this HDMA channel for this frame. The bit in $420c is not cleared, though, so it may be automatically restarted next frame."
2020-12-19 23:30:09 +03:00
if ( ch . HdmaLineCounterAndRepeat = = 0 )
{
2019-04-11 19:55:06 -04:00
ch . HdmaFinished = true ;
2019-02-19 21:09:12 -05:00
}
2019-04-04 17:49:47 -04:00
2019-04-11 19:55:06 -04:00
//"d. Set DoTransfer to true."
ch . DoTransfer = true ;
}
2019-02-15 00:08:50 -05:00
}
2019-04-11 19:55:06 -04:00
2020-12-19 23:30:09 +03:00
if ( needSync )
{
2019-04-11 22:34:28 -04:00
//If we ran a HDMA transfer, sync
SyncEndDma ( ) ;
}
2019-07-06 18:07:09 -04:00
_activeChannel = originalActiveChannel ;
UpdateNeedToProcessFlag ( ) ;
return true ;
}
2020-06-10 18:06:02 -04:00
bool DmaController : : IsLastActiveHdmaChannel ( uint8_t channel )
{
2020-12-19 23:30:09 +03:00
for ( int i = channel + 1 ; i < 8 ; i + + )
{
if ( ( _hdmaChannels & ( 1 < < i ) ) & & ! _channel [ i ] . HdmaFinished )
{
2020-06-10 18:06:02 -04:00
return false ;
}
}
return true ;
}
2019-07-06 18:07:09 -04:00
void DmaController : : UpdateNeedToProcessFlag ( )
{
//Slightly faster execution time by doing this rather than processing all 4 flags on each cycle
_needToProcess = _hdmaPending | | _hdmaInitPending | | _dmaStartDelay | | _dmaPending ;
2019-02-15 00:08:50 -05:00
}
2019-04-11 22:34:28 -04:00
void DmaController : : BeginHdmaTransfer ( )
2019-02-15 00:08:50 -05:00
{
2020-12-19 23:30:09 +03:00
if ( _hdmaChannels )
{
2020-01-18 13:11:24 -05:00
_hdmaPending = true ;
UpdateNeedToProcessFlag ( ) ;
}
2019-04-11 22:34:28 -04:00
}
2019-03-09 12:01:36 -05:00
2019-04-20 09:30:51 -04:00
void DmaController : : BeginHdmaInit ( )
{
_hdmaInitPending = true ;
2019-07-06 18:07:09 -04:00
UpdateNeedToProcessFlag ( ) ;
2019-04-20 09:30:51 -04:00
}
2019-07-05 19:18:30 -04:00
bool DmaController : : ProcessPendingTransfers ( )
2019-04-11 22:34:28 -04:00
{
2020-12-19 23:30:09 +03:00
if ( ! _needToProcess )
{
2019-07-06 18:07:09 -04:00
return false ;
}
2020-12-19 23:30:09 +03:00
if ( _dmaStartDelay )
{
2019-06-30 19:47:12 -04:00
_dmaStartDelay = false ;
2019-07-05 19:18:30 -04:00
return false ;
2019-04-11 22:34:28 -04:00
}
2020-12-19 23:30:09 +03:00
if ( _hdmaPending )
{
2019-07-06 18:07:09 -04:00
return ProcessHdmaChannels ( ) ;
2020-12-19 23:30:09 +03:00
}
else if ( _hdmaInitPending )
{
2019-07-06 18:07:09 -04:00
return InitHdmaChannels ( ) ;
2020-12-19 23:30:09 +03:00
}
else if ( _dmaPending )
{
2019-07-06 18:07:09 -04:00
_dmaPending = false ;
2019-04-04 17:49:47 -04:00
2019-04-11 22:34:28 -04:00
SyncStartDma ( ) ;
2019-07-12 23:55:18 -04:00
_memoryManager - > IncMasterClock8 ( ) ;
2019-07-06 18:07:09 -04:00
ProcessPendingTransfers ( ) ;
2020-12-19 23:30:09 +03:00
for ( int i = 0 ; i < 8 ; i + + )
{
if ( _channel [ i ] . DmaActive )
{
2019-05-04 20:13:31 -04:00
_activeChannel = i ;
2020-12-19 23:30:09 +03:00
RunDma ( _channel [ i ] ) ;
2019-02-15 00:08:50 -05:00
}
2019-04-11 22:34:28 -04:00
}
2020-12-19 23:30:09 +03:00
2019-04-11 22:34:28 -04:00
SyncEndDma ( ) ;
2019-07-06 18:07:09 -04:00
UpdateNeedToProcessFlag ( ) ;
2019-07-05 19:18:30 -04:00
return true ;
2019-04-11 22:34:28 -04:00
}
2019-07-05 19:18:30 -04:00
return false ;
2019-04-11 22:34:28 -04:00
}
void DmaController : : Write ( uint16_t addr , uint8_t value )
{
2020-12-19 23:30:09 +03:00
switch ( addr )
{
case 0x420B :
{
2019-04-11 22:34:28 -04:00
//MDMAEN - DMA Enable
2020-12-19 23:30:09 +03:00
for ( int i = 0 ; i < 8 ; i + + )
{
if ( value & ( 1 < < i ) )
{
2019-07-06 18:07:09 -04:00
_channel [ i ] . DmaActive = true ;
}
}
2019-07-25 22:22:09 -04:00
2020-12-19 23:30:09 +03:00
if ( value )
{
2019-07-25 22:22:09 -04:00
_dmaPending = true ;
_dmaStartDelay = true ;
UpdateNeedToProcessFlag ( ) ;
}
2019-02-15 00:08:50 -05:00
break ;
2019-02-21 23:35:51 -05:00
}
2019-02-15 00:08:50 -05:00
2020-12-19 23:30:09 +03:00
case 0x420C :
//HDMAEN - HDMA Enable
_hdmaChannels = value ;
break ;
2019-02-17 14:42:35 -05:00
2020-12-19 23:30:09 +03:00
case 0x4300 :
case 0x4310 :
case 0x4320 :
case 0x4330 :
case 0x4340 :
case 0x4350 :
case 0x4360 :
case 0x4370 :
2019-02-15 00:08:50 -05:00
{
//DMAPx - DMA Control for Channel x
2020-12-19 23:30:09 +03:00
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
2019-02-15 00:08:50 -05:00
channel . InvertDirection = ( value & 0x80 ) ! = 0 ;
2019-02-19 21:09:12 -05:00
channel . HdmaIndirectAddressing = ( value & 0x40 ) ! = 0 ;
2019-02-21 07:55:53 -05:00
channel . UnusedFlag = ( value & 0x20 ) ! = 0 ;
2019-02-15 00:08:50 -05:00
channel . Decrement = ( value & 0x10 ) ! = 0 ;
channel . FixedTransfer = ( value & 0x08 ) ! = 0 ;
channel . TransferMode = value & 0x07 ;
break ;
}
2020-12-19 23:30:09 +03:00
case 0x4301 :
case 0x4311 :
case 0x4321 :
case 0x4331 :
case 0x4341 :
case 0x4351 :
case 0x4361 :
case 0x4371 :
2019-02-15 00:08:50 -05:00
{
//BBADx - DMA Destination Register for Channel x
2020-12-19 23:30:09 +03:00
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
2019-02-15 00:08:50 -05:00
channel . DestAddress = value ;
break ;
}
2020-12-19 23:30:09 +03:00
case 0x4302 :
case 0x4312 :
case 0x4322 :
case 0x4332 :
case 0x4342 :
case 0x4352 :
case 0x4362 :
case 0x4372 :
2019-02-19 21:09:12 -05:00
{
2020-12-19 23:30:09 +03:00
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
2019-02-19 21:09:12 -05:00
channel . SrcAddress = ( channel . SrcAddress & 0xFF00 ) | value ;
break ;
}
2020-12-19 23:30:09 +03:00
case 0x4303 :
case 0x4313 :
case 0x4323 :
case 0x4333 :
case 0x4343 :
case 0x4353 :
case 0x4363 :
case 0x4373 :
2019-02-19 21:09:12 -05:00
{
2020-12-19 23:30:09 +03:00
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
2019-02-19 21:09:12 -05:00
channel . SrcAddress = ( channel . SrcAddress & 0xFF ) | ( value < < 8 ) ;
break ;
}
2020-12-19 23:30:09 +03:00
case 0x4304 :
case 0x4314 :
case 0x4324 :
case 0x4334 :
case 0x4344 :
case 0x4354 :
case 0x4364 :
case 0x4374 :
2019-02-19 21:09:12 -05:00
{
2020-12-19 23:30:09 +03:00
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
2019-02-19 21:09:12 -05:00
channel . SrcBank = value ;
break ;
}
2020-12-19 23:30:09 +03:00
case 0x4305 :
case 0x4315 :
case 0x4325 :
case 0x4335 :
case 0x4345 :
case 0x4355 :
case 0x4365 :
case 0x4375 :
2019-02-15 00:08:50 -05:00
{
//DASxL - DMA Size / HDMA Indirect Address low byte(x = 0 - 7)
2020-12-19 23:30:09 +03:00
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
2019-02-15 00:08:50 -05:00
channel . TransferSize = ( channel . TransferSize & 0xFF00 ) | value ;
break ;
}
2020-12-19 23:30:09 +03:00
case 0x4306 :
case 0x4316 :
case 0x4326 :
case 0x4336 :
case 0x4346 :
case 0x4356 :
case 0x4366 :
case 0x4376 :
2019-02-15 00:08:50 -05:00
{
//DASxL - DMA Size / HDMA Indirect Address low byte(x = 0 - 7)
2020-12-19 23:30:09 +03:00
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
2019-02-15 00:08:50 -05:00
channel . TransferSize = ( channel . TransferSize & 0xFF ) | ( value < < 8 ) ;
break ;
}
2020-12-19 23:30:09 +03:00
case 0x4307 :
case 0x4317 :
case 0x4327 :
case 0x4337 :
case 0x4347 :
case 0x4357 :
case 0x4367 :
case 0x4377 :
2019-02-15 00:08:50 -05:00
{
2019-02-19 21:09:12 -05:00
//DASBx - HDMA Indirect Address bank byte (x=0-7)
2020-12-19 23:30:09 +03:00
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
2019-02-19 21:09:12 -05:00
channel . HdmaBank = value ;
2019-02-15 00:08:50 -05:00
break ;
}
2020-12-19 23:30:09 +03:00
case 0x4308 :
case 0x4318 :
case 0x4328 :
case 0x4338 :
case 0x4348 :
case 0x4358 :
case 0x4368 :
case 0x4378 :
2019-02-15 00:08:50 -05:00
{
2019-02-19 21:09:12 -05:00
//A2AxL - HDMA Table Address low byte (x=0-7)
2020-12-19 23:30:09 +03:00
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
2019-02-19 21:09:12 -05:00
channel . HdmaTableAddress = ( channel . HdmaTableAddress & 0xFF00 ) | value ;
2019-02-15 00:08:50 -05:00
break ;
}
2020-12-19 23:30:09 +03:00
case 0x4309 :
case 0x4319 :
case 0x4329 :
case 0x4339 :
case 0x4349 :
case 0x4359 :
case 0x4369 :
case 0x4379 :
2019-02-19 21:09:12 -05:00
{
//A2AxH - HDMA Table Address high byte (x=0-7)
2020-12-19 23:30:09 +03:00
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
2019-02-19 21:09:12 -05:00
channel . HdmaTableAddress = ( value < < 8 ) | ( channel . HdmaTableAddress & 0xFF ) ;
break ;
}
2020-12-19 23:30:09 +03:00
case 0x430A :
case 0x431A :
case 0x432A :
case 0x433A :
case 0x434A :
case 0x435A :
case 0x436A :
case 0x437A :
2019-02-15 00:08:50 -05:00
{
2019-02-19 21:09:12 -05:00
//DASBx - HDMA Indirect Address bank byte (x=0-7)
2020-12-19 23:30:09 +03:00
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
2019-02-19 21:09:12 -05:00
channel . HdmaLineCounterAndRepeat = value ;
2019-02-15 00:08:50 -05:00
break ;
}
2020-10-06 01:04:38 -04:00
2020-12-19 23:30:09 +03:00
case 0x430B :
case 0x431B :
case 0x432B :
case 0x433B :
case 0x434B :
case 0x435B :
case 0x436B :
case 0x437B :
case 0x430F :
case 0x431F :
case 0x432F :
case 0x433F :
case 0x434F :
case 0x435F :
case 0x436F :
case 0x437F :
2020-10-06 01:04:38 -04:00
{
//UNUSEDx - HDMA Indirect Address bank byte (x=0-7)
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
channel . UnusedByte = value ;
}
2019-02-15 00:08:50 -05:00
}
}
2019-02-21 07:55:53 -05:00
uint8_t DmaController : : Read ( uint16_t addr )
{
2020-12-19 23:30:09 +03:00
switch ( addr )
{
case 0x4300 :
case 0x4310 :
case 0x4320 :
case 0x4330 :
case 0x4340 :
case 0x4350 :
case 0x4360 :
case 0x4370 :
2019-02-21 07:55:53 -05:00
{
//DMAPx - DMA Control for Channel x
2020-12-19 23:30:09 +03:00
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
2019-02-21 07:55:53 -05:00
return (
( channel . InvertDirection ? 0x80 : 0 ) |
( channel . HdmaIndirectAddressing ? 0x40 : 0 ) |
( channel . UnusedFlag ? 0x20 : 0 ) |
( channel . Decrement ? 0x10 : 0 ) |
( channel . FixedTransfer ? 0x08 : 0 ) |
( channel . TransferMode & 0x07 )
) ;
}
2020-12-19 23:30:09 +03:00
case 0x4301 :
case 0x4311 :
case 0x4321 :
case 0x4331 :
case 0x4341 :
case 0x4351 :
case 0x4361 :
case 0x4371 :
2019-02-21 07:55:53 -05:00
{
//BBADx - DMA Destination Register for Channel x
2020-12-19 23:30:09 +03:00
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
2019-02-21 07:55:53 -05:00
return channel . DestAddress ;
}
2020-12-19 23:30:09 +03:00
case 0x4302 :
case 0x4312 :
case 0x4322 :
case 0x4332 :
case 0x4342 :
case 0x4352 :
case 0x4362 :
case 0x4372 :
2019-02-21 07:55:53 -05:00
{
2020-12-19 23:30:09 +03:00
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
2019-02-21 07:55:53 -05:00
return channel . SrcAddress & 0xFF ;
}
2020-12-19 23:30:09 +03:00
case 0x4303 :
case 0x4313 :
case 0x4323 :
case 0x4333 :
case 0x4343 :
case 0x4353 :
case 0x4363 :
case 0x4373 :
2019-02-21 07:55:53 -05:00
{
2020-12-19 23:30:09 +03:00
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
2019-02-21 07:55:53 -05:00
return ( channel . SrcAddress > > 8 ) & 0xFF ;
}
2020-12-19 23:30:09 +03:00
case 0x4304 :
case 0x4314 :
case 0x4324 :
case 0x4334 :
case 0x4344 :
case 0x4354 :
case 0x4364 :
case 0x4374 :
2019-02-21 07:55:53 -05:00
{
2020-12-19 23:30:09 +03:00
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
2019-02-21 07:55:53 -05:00
return channel . SrcBank ;
}
2020-12-19 23:30:09 +03:00
case 0x4305 :
case 0x4315 :
case 0x4325 :
case 0x4335 :
case 0x4345 :
case 0x4355 :
case 0x4365 :
case 0x4375 :
2019-02-21 07:55:53 -05:00
{
//DASxL - DMA Size / HDMA Indirect Address low byte(x = 0 - 7)
2020-12-19 23:30:09 +03:00
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
2019-02-21 07:55:53 -05:00
return channel . TransferSize & 0xFF ;
}
2020-12-19 23:30:09 +03:00
case 0x4306 :
case 0x4316 :
case 0x4326 :
case 0x4336 :
case 0x4346 :
case 0x4356 :
case 0x4366 :
case 0x4376 :
2019-02-21 07:55:53 -05:00
{
//DASxL - DMA Size / HDMA Indirect Address low byte(x = 0 - 7)
2020-12-19 23:30:09 +03:00
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
2019-02-21 07:55:53 -05:00
return ( channel . TransferSize > > 8 ) & 0xFF ;
}
2020-12-19 23:30:09 +03:00
case 0x4307 :
case 0x4317 :
case 0x4327 :
case 0x4337 :
case 0x4347 :
case 0x4357 :
case 0x4367 :
case 0x4377 :
2019-02-21 07:55:53 -05:00
{
//DASBx - HDMA Indirect Address bank byte (x=0-7)
2020-12-19 23:30:09 +03:00
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
2019-02-21 07:55:53 -05:00
return channel . HdmaBank ;
}
2020-12-19 23:30:09 +03:00
case 0x4308 :
case 0x4318 :
case 0x4328 :
case 0x4338 :
case 0x4348 :
case 0x4358 :
case 0x4368 :
case 0x4378 :
2019-02-21 07:55:53 -05:00
{
//A2AxL - HDMA Table Address low byte (x=0-7)
2020-12-19 23:30:09 +03:00
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
2019-02-21 07:55:53 -05:00
return channel . HdmaTableAddress & 0xFF ;
}
2020-12-19 23:30:09 +03:00
case 0x4309 :
case 0x4319 :
case 0x4329 :
case 0x4339 :
case 0x4349 :
case 0x4359 :
case 0x4369 :
case 0x4379 :
2019-02-21 07:55:53 -05:00
{
//A2AxH - HDMA Table Address high byte (x=0-7)
2020-12-19 23:30:09 +03:00
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
2019-02-21 07:55:53 -05:00
return ( channel . HdmaTableAddress > > 8 ) & 0xFF ;
}
2020-12-19 23:30:09 +03:00
case 0x430A :
case 0x431A :
case 0x432A :
case 0x433A :
case 0x434A :
case 0x435A :
case 0x436A :
case 0x437A :
2019-02-21 07:55:53 -05:00
{
//DASBx - HDMA Indirect Address bank byte (x=0-7)
2020-12-19 23:30:09 +03:00
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
2019-02-21 07:55:53 -05:00
return channel . HdmaLineCounterAndRepeat ;
}
2020-10-06 01:04:38 -04:00
2020-12-19 23:30:09 +03:00
case 0x430B :
case 0x431B :
case 0x432B :
case 0x433B :
case 0x434B :
case 0x435B :
case 0x436B :
case 0x437B :
case 0x430F :
case 0x431F :
case 0x432F :
case 0x433F :
case 0x434F :
case 0x435F :
case 0x436F :
case 0x437F :
2020-10-06 01:04:38 -04:00
{
//UNUSEDx - HDMA Indirect Address bank byte (x=0-7)
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
return channel . UnusedByte ;
}
2019-02-21 07:55:53 -05:00
}
2019-03-12 09:15:57 -04:00
return _memoryManager - > GetOpenBus ( ) ;
}
2019-05-04 20:13:31 -04:00
uint8_t DmaController : : GetActiveChannel ( )
{
return _activeChannel ;
}
DmaChannelConfig DmaController : : GetChannelConfig ( uint8_t channel )
{
return _channel [ channel ] ;
}
2020-12-19 23:30:09 +03:00
void DmaController : : Serialize ( Serializer & s )
2019-03-12 09:15:57 -04:00
{
2019-07-06 18:07:09 -04:00
s . Stream ( _hdmaPending , _hdmaChannels , _dmaPending , _dmaStartClock , _hdmaInitPending , _dmaStartDelay , _needToProcess ) ;
2020-12-19 23:30:09 +03:00
for ( int i = 0 ; i < 8 ; i + + )
{
2019-03-12 09:15:57 -04:00
s . Stream (
_channel [ i ] . Decrement , _channel [ i ] . DestAddress , _channel [ i ] . DoTransfer , _channel [ i ] . FixedTransfer ,
_channel [ i ] . HdmaBank , _channel [ i ] . HdmaFinished , _channel [ i ] . HdmaIndirectAddressing ,
2019-07-06 18:07:09 -04:00
_channel [ i ] . HdmaLineCounterAndRepeat , _channel [ i ] . HdmaTableAddress ,
2019-03-12 09:15:57 -04:00
_channel [ i ] . InvertDirection , _channel [ i ] . SrcAddress , _channel [ i ] . SrcBank , _channel [ i ] . TransferMode ,
2020-10-06 01:04:38 -04:00
_channel [ i ] . TransferSize , _channel [ i ] . UnusedFlag , _channel [ i ] . DmaActive ,
_channel [ i ] . UnusedByte
2019-03-12 09:15:57 -04:00
) ;
}
}