| 211 | } |
| 212 | |
| 213 | static __ri void DmaExec( void (*func)(), u32 mem, u32 value ) |
| 214 | { |
| 215 | DMACh& reg = (DMACh&)psHu32(mem); |
| 216 | tDMA_CHCR chcr(value); |
| 217 | |
| 218 | //It's invalid for the hardware to write a DMA while it is active, not without Suspending the DMAC |
| 219 | if (reg.chcr.STR) |
| 220 | { |
| 221 | const uint channel = ChannelNumber(mem); |
| 222 | |
| 223 | //As the manual states "Fields other than STR can only be written to when the DMA is stopped" |
| 224 | //Also "The DMA may not stop properly just by writing 0 to STR" |
| 225 | //So the presumption is that STR can be written to (ala force stop the DMA) but nothing else |
| 226 | //If the developer wishes to alter any of the other fields, it must be done AFTER the STR has been written, |
| 227 | //it will not work before or during this event. |
| 228 | if(chcr.STR == 0) |
| 229 | { |
| 230 | //DevCon.Warning(L"32bit Force Stopping %s (Current CHCR %x) while DMA active", ChcrName(mem), reg.chcr._u32, chcr._u32); |
| 231 | reg.chcr.STR = 0; |
| 232 | //We need to clear any existing DMA loops that are in progress else they will continue! |
| 233 | |
| 234 | if(channel == 1) |
| 235 | { |
| 236 | cpuClearInt( 10 ); |
| 237 | QueuedDMA._u16 &= ~(1 << 10); //Clear any queued DMA requests for this channel |
| 238 | } |
| 239 | else if (channel == 2) |
| 240 | { |
| 241 | cpuClearInt( 11 ); |
| 242 | QueuedDMA._u16 &= ~(1 << 11); //Clear any queued DMA requests for this channel |
| 243 | } |
| 244 | |
| 245 | cpuClearInt( channel ); |
| 246 | QueuedDMA._u16 &= ~(1 << channel); //Clear any queued DMA requests for this channel |
| 247 | } |
| 248 | //else DevCon.Warning(L"32bit Attempted to change %s CHCR (Currently %x) with %x while DMA active, ignoring QWC = %x", ChcrName(mem), reg.chcr._u32, chcr._u32, reg.qwc); |
| 249 | return; |
| 250 | } |
| 251 | |
| 252 | //if(reg.chcr.TAG != chcr.TAG && chcr.MOD == CHAIN_MODE) DevCon.Warning(L"32bit CHCR Tag on %s changed to %x from %x QWC = %x Channel Not Active", ChcrName(mem), chcr.TAG, reg.chcr.TAG, reg.qwc); |
| 253 | |
| 254 | reg.chcr.set(value); |
| 255 | |
| 256 | //Final Fantasy XII sets the DMA Mode to 3 which doesn't exist. On some channels (like SPR) this will break logic completely. so lets assume they mean chain. |
| 257 | if (reg.chcr.MOD == 0x3) |
| 258 | { |
| 259 | static bool warned; //Check if the warning has already been output to console, to prevent constant spam. |
| 260 | if (!warned) |
| 261 | { |
| 262 | DevCon.Warning("%s CHCR.MOD set to 3, assuming 1 (chain)", ChcrName(mem)); |
| 263 | warned = true; |
| 264 | } |
| 265 | reg.chcr.MOD = 0x1; |
| 266 | } |
| 267 | |
| 268 | // As tested on hardware, if NORMAL mode is started with 0 QWC it will actually transfer 1 QWC then underflows and transfer another 0xFFFF QWC's |
| 269 | // The easiest way to handle this is to just say 0x10000 QWC |
| 270 | if (reg.chcr.STR && !reg.chcr.MOD && reg.qwc == 0) |
no test coverage detected