2019-02-15 00:08:50 -05:00
# include "stdafx.h"
# include "DmaController.h"
# 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
2019-03-31 14:50:12 -04:00
static constexpr uint8_t _transferByteCount [ 8 ] = { 1 , 2 , 2 , 4 , 4 , 4 , 2 , 4 } ;
static constexpr uint8_t _transferOffset [ 8 ] [ 4 ] = {
{ 0 , 0 , 0 , 0 } , { 0 , 1 , 0 , 0 } , { 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-02-16 01:16:57 -05:00
DmaController : : DmaController ( MemoryManager * memoryManager )
2019-02-15 00:08:50 -05:00
{
_memoryManager = memoryManager ;
2019-03-16 12:20:18 -04:00
Reset ( ) ;
//Power on values
for ( int j = 0 ; j < 8 ; j + + ) {
for ( int i = 0 ; i < = 0x0A ; i + + ) {
Write ( 0x4300 | i | ( j < < 4 ) , 0xFF ) ;
}
}
}
void DmaController : : Reset ( )
{
2019-06-30 19:47:12 -04:00
_dmaStartDelay = false ;
2019-03-16 12:20:18 -04:00
_hdmaChannels = 0 ;
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 )
{
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 ) ;
2019-03-09 14:27:32 -05:00
} else {
//$2180->WRAM do cause a write to occur (but no read), but the value written is invalid
_memoryManager - > IncrementMasterClockValue < 4 > ( ) ;
2019-03-16 16:36:58 -04:00
_memoryManager - > WriteDma ( addressBusA , 0xFF , true ) ;
2019-03-09 14:27:32 -05: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 ) ;
2019-03-09 14:27:32 -05:00
} else {
//WRAM->$2180 does not cause a write to occur
_memoryManager - > IncrementMasterClockValue < 8 > ( ) ;
}
}
}
2019-02-19 21:09:12 -05:00
void DmaController : : RunSingleTransfer ( DmaChannelConfig & channel )
2019-02-15 00:08:50 -05:00
{
2019-02-16 00:47:02 -05:00
const uint8_t * transferOffsets = _transferOffset [ channel . TransferMode ] ;
uint8_t transferByteCount = _transferByteCount [ channel . TransferMode ] ;
2019-02-15 00:08:50 -05:00
2019-02-16 00:47:02 -05:00
uint8_t i = 0 ;
2019-02-19 21:09:12 -05:00
do {
2019-03-09 14:27:32 -05:00
CopyDmaByte (
( channel . SrcBank < < 16 ) | channel . SrcAddress ,
2019-03-31 14:50:12 -04:00
0x2100 | ( channel . DestAddress + transferOffsets [ i ] ) ,
2019-03-09 14:27:32 -05:00
channel . InvertDirection
) ;
2019-02-15 00:08:50 -05:00
2019-02-16 00:47:02 -05: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
transferByteCount - - ;
i + + ;
2019-03-09 12:01:36 -05:00
} while ( channel . TransferSize > 0 & & transferByteCount > 0 & & ! channel . InterruptedByHdma ) ;
2019-02-16 00:47:02 -05:00
}
2019-02-15 00:08:50 -05:00
2019-02-16 00:47:02 -05:00
void DmaController : : RunDma ( DmaChannelConfig & channel )
{
2019-03-09 12:01:36 -05:00
if ( channel . InterruptedByHdma ) {
return ;
}
2019-02-19 21:09:12 -05:00
do {
//Manual DMA transfers run to the end of the transfer when started
RunSingleTransfer ( channel ) ;
2019-03-09 12:01:36 -05:00
} while ( channel . TransferSize > 0 & & ! channel . InterruptedByHdma ) ;
2019-02-19 21:09:12 -05:00
}
2019-02-17 14:42:35 -05:00
2019-02-19 21:09:12 -05:00
void DmaController : : InitHdmaChannels ( )
{
2019-04-11 19:55:06 -04:00
for ( int i = 0 ; i < 8 ; i + + ) {
//Reset internal flags on every frame, whether or not the channels are enabled
_channel [ i ] . HdmaFinished = false ;
_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
}
2019-04-11 19:55:06 -04:00
if ( ! _hdmaChannels ) {
//No channels are enabled, no more processing needs to be done
return ;
}
2019-04-11 22:34:28 -04:00
SyncStartDma ( ) ;
2019-04-11 19:55:06 -04:00
2019-02-19 21:09:12 -05: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
2019-02-19 21:09:12 -05:00
if ( _hdmaChannels & ( 1 < < i ) ) {
//"1. Copy AAddress into Address."
ch . HdmaTableAddress = ch . SrcAddress ;
2019-03-09 12:01:36 -05:00
ch . InterruptedByHdma = true ;
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-04-20 09:30:51 -04:00
_memoryManager - > IncrementMasterClockValue < 4 > ( ) ;
2019-02-19 21:09:12 -05:00
ch . HdmaTableAddress + + ;
if ( ch . HdmaLineCounterAndRepeat = = 0 ) {
ch . HdmaFinished = true ;
}
//3. Load Indirect Address, if necessary.
if ( ch . HdmaIndirectAddressing ) {
2019-03-16 16:36:58 -04:00
uint8_t lsb = _memoryManager - > ReadDma ( ( ch . SrcBank < < 16 ) | ch . HdmaTableAddress + + , true ) ;
2019-04-20 09:30:51 -04:00
_memoryManager - > IncrementMasterClockValue < 4 > ( ) ;
2019-03-16 16:36:58 -04:00
uint8_t msb = _memoryManager - > ReadDma ( ( ch . SrcBank < < 16 ) | ch . HdmaTableAddress + + , true ) ;
2019-03-26 19:07:06 -04:00
_memoryManager - > IncrementMasterClockValue < 4 > ( ) ;
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
SyncEndDma ( ) ;
2019-02-19 21:09:12 -05:00
}
void DmaController : : RunHdmaTransfer ( DmaChannelConfig & channel )
{
const uint8_t * transferOffsets = _transferOffset [ channel . TransferMode ] ;
uint8_t transferByteCount = _transferByteCount [ channel . TransferMode ] ;
2019-03-09 12:01:36 -05:00
channel . InterruptedByHdma = true ;
2019-02-19 21:09:12 -05:00
uint8_t i = 0 ;
if ( channel . HdmaIndirectAddressing ) {
2019-03-16 16:36:58 -04:00
do {
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
transferByteCount - - ;
i + + ;
} while ( transferByteCount > 0 ) ;
2019-02-19 21:09:12 -05:00
} else {
2019-03-16 16:36:58 -04:00
do {
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
transferByteCount - - ;
i + + ;
} while ( transferByteCount > 0 ) ;
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 ) ) ;
//"and an extra 8 master cycles overhead for the whole thing"
//"Best guess at this point is that 2-4 of the "whole DMA overhead" is before the transfer and the rest after"
_memoryManager - > IncrementMasterClockValue < 2 > ( ) ;
}
void DmaController : : SyncEndDma ( )
{
//Last part of the 8 cycle overhead
_memoryManager - > IncrementMasterClockValue < 6 > ( ) ;
//"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 ( ) ;
_memoryManager - > IncrementMasterClockValue ( cpuSpeed - ( ( _memoryManager - > GetMasterClock ( ) - _dmaStartClock ) % cpuSpeed ) ) ;
2019-04-11 22:34:28 -04:00
}
void DmaController : : ProcessHdmaChannels ( bool applyOverhead )
2019-02-19 21:09:12 -05:00
{
2019-04-11 19:55:06 -04:00
if ( ! _hdmaChannels ) {
return ;
}
//Run all the DMA transfers for each channel first, before fetching data for the next scanline
2019-02-21 23:35:51 -05:00
bool needOverhead = true ;
2019-04-11 19:55:06 -04:00
for ( int i = 0 ; i < 8 ; i + + ) {
DmaChannelConfig & ch = _channel [ i ] ;
if ( ( _hdmaChannels & ( 1 < < i ) ) = = 0 | | ch . HdmaFinished ) {
continue ;
}
2019-02-19 21:09:12 -05:00
2019-04-11 22:34:28 -04:00
if ( applyOverhead & & needOverhead ) {
SyncStartDma ( ) ;
2019-04-11 19:55:06 -04:00
needOverhead = false ;
2019-03-09 12:01:36 -05:00
}
2019-04-11 19:55:06 -04:00
//1. If DoTransfer is false, skip to step 3.
if ( ch . DoTransfer ) {
//2. For the number of bytes (1, 2, or 4) required for this Transfer Mode...
2019-05-04 20:13:31 -04:00
_activeChannel = 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
for ( int i = 0 ; i < 8 ; i + + ) {
DmaChannelConfig & ch = _channel [ i ] ;
if ( ( _hdmaChannels & ( 1 < < i ) ) = = 0 | | ch . HdmaFinished ) {
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 ) ;
_memoryManager - > IncrementMasterClockValue < 4 > ( ) ;
2019-04-11 19:55:06 -04:00
//5. If Line Counter is zero...
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)."
if ( ch . HdmaIndirectAddressing ) {
2019-02-19 21:09:12 -05:00
if ( ch . HdmaLineCounterAndRepeat = = 0 ) {
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-04-20 09:30:51 -04:00
_memoryManager - > IncrementMasterClockValue < 4 > ( ) ;
2019-04-11 19:55:06 -04:00
ch . TransferSize = ( msb < < 8 ) ;
} 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-04-20 09:30:51 -04:00
_memoryManager - > IncrementMasterClockValue < 4 > ( ) ;
2019-04-11 19:55:06 -04:00
uint8_t msb = _memoryManager - > ReadDma ( ( ch . SrcBank < < 16 ) | ch . HdmaTableAddress + + , true ) ;
2019-04-20 09:30:51 -04:00
_memoryManager - > IncrementMasterClockValue < 4 > ( ) ;
2019-02-19 21:09:12 -05:00
2019-04-20 09:30:51 -04:00
ch . TransferSize = ( msb < < 8 ) | lsb ;
}
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."
if ( ch . HdmaLineCounterAndRepeat = = 0 ) {
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
2019-04-11 22:34:28 -04:00
if ( applyOverhead & & ! needOverhead ) {
//If we ran a HDMA transfer, sync
SyncEndDma ( ) ;
}
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
{
2019-04-11 22:34:28 -04:00
_hdmaPending = true ;
2019-02-21 23:35:51 -05:00
2019-04-11 22:34:28 -04:00
for ( int i = 0 ; i < 8 ; i + + ) {
if ( _hdmaChannels & ( 1 < < i ) ) {
_channel [ i ] . InterruptedByHdma = true ;
}
}
}
2019-03-09 12:01:36 -05:00
2019-04-20 09:30:51 -04:00
void DmaController : : BeginHdmaInit ( )
{
_hdmaPending = true ;
_hdmaInitPending = true ;
}
2019-04-11 22:34:28 -04:00
void DmaController : : ProcessPendingTransfers ( )
{
2019-06-30 19:47:12 -04:00
if ( _inDma | | _dmaStartDelay ) {
_dmaStartDelay = false ;
2019-04-11 22:34:28 -04:00
return ;
}
if ( _hdmaPending ) {
_inDma = true ;
2019-04-20 09:30:51 -04:00
if ( _hdmaInitPending ) {
InitHdmaChannels ( ) ;
_hdmaInitPending = false ;
} else {
ProcessHdmaChannels ( true ) ;
}
2019-04-11 22:34:28 -04:00
_inDma = false ;
_hdmaPending = false ;
} else if ( _requestedDmaChannels ) {
_inDma = true ;
2019-04-04 17:49:47 -04:00
2019-04-11 22:34:28 -04:00
SyncStartDma ( ) ;
for ( int i = 0 ; i < 8 ; i + + ) {
_channel [ i ] . InterruptedByHdma = false ;
}
for ( int i = 0 ; i < 8 ; i + + ) {
if ( _requestedDmaChannels & ( 1 < < i ) ) {
//"Then perform the DMA: 8 master cycles overhead and 8 master cycles per byte per channel"
_memoryManager - > IncrementMasterClockValue < 8 > ( ) ;
2019-05-04 20:13:31 -04:00
_activeChannel = i ;
2019-04-11 22:34:28 -04:00
RunDma ( _channel [ i ] ) ;
2019-02-15 00:08:50 -05:00
}
2019-04-11 22:34:28 -04:00
}
if ( _hdmaPending ) {
//If DMA was interrupted by a HDMA transfer, run it (but don't add the cycle alignment overhead at the end and the start)
ProcessHdmaChannels ( false ) ;
_hdmaPending = false ;
}
SyncEndDma ( ) ;
_requestedDmaChannels = 0 ;
_inDma = false ;
}
}
void DmaController : : Write ( uint16_t addr , uint8_t value )
{
switch ( addr ) {
case 0x420B : {
//MDMAEN - DMA Enable
_requestedDmaChannels = value ;
2019-06-30 19:47:12 -04:00
_dmaStartDelay = true ;
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
2019-02-17 14:42:35 -05:00
case 0x420C :
//HDMAEN - HDMA Enable
2019-02-19 21:09:12 -05:00
_hdmaChannels = value ;
2019-02-17 14:42:35 -05:00
break ;
2019-02-15 00:08:50 -05:00
case 0x4300 : case 0x4310 : case 0x4320 : case 0x4330 : case 0x4340 : case 0x4350 : case 0x4360 : case 0x4370 :
{
//DMAPx - DMA Control for Channel x
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
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 ;
}
case 0x4301 : case 0x4311 : case 0x4321 : case 0x4331 : case 0x4341 : case 0x4351 : case 0x4361 : case 0x4371 :
{
//BBADx - DMA Destination Register for Channel x
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
channel . DestAddress = value ;
break ;
}
2019-02-19 21:09:12 -05:00
case 0x4302 : case 0x4312 : case 0x4322 : case 0x4332 : case 0x4342 : case 0x4352 : case 0x4362 : case 0x4372 :
{
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
channel . SrcAddress = ( channel . SrcAddress & 0xFF00 ) | value ;
break ;
}
case 0x4303 : case 0x4313 : case 0x4323 : case 0x4333 : case 0x4343 : case 0x4353 : case 0x4363 : case 0x4373 :
{
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
channel . SrcAddress = ( channel . SrcAddress & 0xFF ) | ( value < < 8 ) ;
break ;
}
case 0x4304 : case 0x4314 : case 0x4324 : case 0x4334 : case 0x4344 : case 0x4354 : case 0x4364 : case 0x4374 :
{
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
channel . SrcBank = value ;
break ;
}
2019-02-15 00:08:50 -05:00
case 0x4305 : case 0x4315 : case 0x4325 : case 0x4335 : case 0x4345 : case 0x4355 : case 0x4365 : case 0x4375 :
{
//DASxL - DMA Size / HDMA Indirect Address low byte(x = 0 - 7)
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
channel . TransferSize = ( channel . TransferSize & 0xFF00 ) | value ;
break ;
}
case 0x4306 : case 0x4316 : case 0x4326 : case 0x4336 : case 0x4346 : case 0x4356 : case 0x4366 : case 0x4376 :
{
//DASxL - DMA Size / HDMA Indirect Address low byte(x = 0 - 7)
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
channel . TransferSize = ( channel . TransferSize & 0xFF ) | ( value < < 8 ) ;
break ;
}
2019-02-19 21:09:12 -05: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)
2019-02-15 00:08:50 -05: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 ;
}
2019-02-19 21:09:12 -05: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)
2019-02-15 00:08:50 -05: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 ;
}
2019-02-19 21:09:12 -05:00
case 0x4309 : case 0x4319 : case 0x4329 : case 0x4339 : case 0x4349 : case 0x4359 : case 0x4369 : case 0x4379 :
{
//A2AxH - HDMA Table Address high byte (x=0-7)
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
channel . HdmaTableAddress = ( value < < 8 ) | ( channel . HdmaTableAddress & 0xFF ) ;
break ;
}
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)
2019-02-15 00:08:50 -05: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 ;
}
}
}
2019-02-21 07:55:53 -05:00
uint8_t DmaController : : Read ( uint16_t addr )
{
switch ( addr ) {
case 0x4300 : case 0x4310 : case 0x4320 : case 0x4330 : case 0x4340 : case 0x4350 : case 0x4360 : case 0x4370 :
{
//DMAPx - DMA Control for Channel x
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
return (
( channel . InvertDirection ? 0x80 : 0 ) |
( channel . HdmaIndirectAddressing ? 0x40 : 0 ) |
( channel . UnusedFlag ? 0x20 : 0 ) |
( channel . Decrement ? 0x10 : 0 ) |
( channel . FixedTransfer ? 0x08 : 0 ) |
( channel . TransferMode & 0x07 )
) ;
}
case 0x4301 : case 0x4311 : case 0x4321 : case 0x4331 : case 0x4341 : case 0x4351 : case 0x4361 : case 0x4371 :
{
//BBADx - DMA Destination Register for Channel x
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
return channel . DestAddress ;
}
case 0x4302 : case 0x4312 : case 0x4322 : case 0x4332 : case 0x4342 : case 0x4352 : case 0x4362 : case 0x4372 :
{
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
return channel . SrcAddress & 0xFF ;
}
case 0x4303 : case 0x4313 : case 0x4323 : case 0x4333 : case 0x4343 : case 0x4353 : case 0x4363 : case 0x4373 :
{
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
return ( channel . SrcAddress > > 8 ) & 0xFF ;
}
case 0x4304 : case 0x4314 : case 0x4324 : case 0x4334 : case 0x4344 : case 0x4354 : case 0x4364 : case 0x4374 :
{
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
return channel . SrcBank ;
}
case 0x4305 : case 0x4315 : case 0x4325 : case 0x4335 : case 0x4345 : case 0x4355 : case 0x4365 : case 0x4375 :
{
//DASxL - DMA Size / HDMA Indirect Address low byte(x = 0 - 7)
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
return channel . TransferSize & 0xFF ;
}
case 0x4306 : case 0x4316 : case 0x4326 : case 0x4336 : case 0x4346 : case 0x4356 : case 0x4366 : case 0x4376 :
{
//DASxL - DMA Size / HDMA Indirect Address low byte(x = 0 - 7)
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
return ( channel . TransferSize > > 8 ) & 0xFF ;
}
case 0x4307 : case 0x4317 : case 0x4327 : case 0x4337 : case 0x4347 : case 0x4357 : case 0x4367 : case 0x4377 :
{
//DASBx - HDMA Indirect Address bank byte (x=0-7)
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
return channel . HdmaBank ;
}
case 0x4308 : case 0x4318 : case 0x4328 : case 0x4338 : case 0x4348 : case 0x4358 : case 0x4368 : case 0x4378 :
{
//A2AxL - HDMA Table Address low byte (x=0-7)
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
return channel . HdmaTableAddress & 0xFF ;
}
case 0x4309 : case 0x4319 : case 0x4329 : case 0x4339 : case 0x4349 : case 0x4359 : case 0x4369 : case 0x4379 :
{
//A2AxH - HDMA Table Address high byte (x=0-7)
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
return ( channel . HdmaTableAddress > > 8 ) & 0xFF ;
}
case 0x430A : case 0x431A : case 0x432A : case 0x433A : case 0x434A : case 0x435A : case 0x436A : case 0x437A :
{
//DASBx - HDMA Indirect Address bank byte (x=0-7)
DmaChannelConfig & channel = _channel [ ( addr & 0x70 ) > > 4 ] ;
return channel . HdmaLineCounterAndRepeat ;
}
}
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 ] ;
}
2019-03-12 09:15:57 -04:00
void DmaController : : Serialize ( Serializer & s )
{
2019-06-30 19:47:12 -04:00
uint8_t unused_nmiIrqDelayCounter = 0 ;
s . Stream ( _hdmaPending , _hdmaChannels , unused_nmiIrqDelayCounter , _requestedDmaChannels , _inDma , _dmaStartClock , _hdmaInitPending , _dmaStartDelay ) ;
2019-03-12 09:15:57 -04:00
for ( int i = 0 ; i < 8 ; i + + ) {
s . Stream (
_channel [ i ] . Decrement , _channel [ i ] . DestAddress , _channel [ i ] . DoTransfer , _channel [ i ] . FixedTransfer ,
_channel [ i ] . HdmaBank , _channel [ i ] . HdmaFinished , _channel [ i ] . HdmaIndirectAddressing ,
_channel [ i ] . HdmaLineCounterAndRepeat , _channel [ i ] . HdmaTableAddress , _channel [ i ] . InterruptedByHdma ,
_channel [ i ] . InvertDirection , _channel [ i ] . SrcAddress , _channel [ i ] . SrcBank , _channel [ i ] . TransferMode ,
_channel [ i ] . TransferSize , _channel [ i ] . UnusedFlag
) ;
}
}