void DMA_Power(void) { lastts = 0; memset(DMACH, 0, sizeof(DMACH)); DMACycleCounter = 128; DMAControl = 0; DMAIntControl = 0; DMAIntStatus = 0; RecalcIRQOut(); }
static INLINE void RunChannelT(pscpu_timestamp_t timestamp, int32 clocks) { //const uint32 dc = (DMAControl >> (ch * 4)) & 0xF; DMACH[ch].ClockCounter += clocks; while(DMACH[ch].ClockCounter > 0) { if(!DMACH[ch].WordCounter) { if(!(DMACH[ch].ChanControl & (1 << 24))) { break; } if(DMACH[ch].NextAddr & 0x800000) { //if(ch == 2) // PSX_WARNING("[DMA] LL Channel 2 ended normally: %d\n", GPU->GetScanlineNum()); DMACH[ch].ChanControl &= ~(0x11 << 24); if(DMAIntControl & (1 << (16 + ch))) { DMAIntStatus |= 1 << ch; RecalcIRQOut(); } break; } if(!ChCan<ch, write_mode>()) break; if((DMACH[ch].ChanControl & (1 << 10)) && write_mode) { uint32 header; DMACH[ch].CurAddr = DMACH[ch].NextAddr & 0x1FFFFC; header = MainRAM.ReadU32(DMACH[ch].CurAddr); DMACH[ch].CurAddr = (DMACH[ch].CurAddr + 4) & 0x1FFFFF; DMACH[ch].WordCounter = header >> 24; DMACH[ch].NextAddr = header & 0xFFFFFF; /* if(DMACH[ch].WordCounter > 0x10) printf("What the lala? 0x%02x @ 0x%08x\n", DMACH[ch].WordCounter, DMACH[ch].CurAddr - 4); */ if(DMACH[ch].WordCounter) DMACH[ch].ClockCounter -= 15; else DMACH[ch].ClockCounter -= 10; continue; } else { DMACH[ch].CurAddr = DMACH[ch].NextAddr & 0x1FFFFC; DMACH[ch].WordCounter = DMACH[ch].BlockControl & 0xFFFF; DMACH[ch].BlockCounter--; if(!DMACH[ch].BlockCounter || ch == 6 || ch == 3) DMACH[ch].NextAddr = 0xFFFFFF; else DMACH[ch].NextAddr = (DMACH[ch].CurAddr + ((DMACH[ch].BlockControl & 0xFFFF) << 2)) & 0x1FFFFF; } }
// // Remember to handle an end condition on the same iteration of the while(DMACH[ch].ClockCounter > 0) loop that caused it, // otherwise RecalcHalt() might take the CPU out of a halted state before the end-of-DMA is signaled(especially a problem considering our largeish // DMA update timing granularity). // static INLINE void RunChannelI(const unsigned ch, const uint32_t CRModeCache, int32_t clocks) { //const uint32_t dc = (DMAControl >> (ch * 4)) & 0xF; DMACH[ch].ClockCounter += clocks; while(MDFN_LIKELY(DMACH[ch].ClockCounter > 0)) { if(DMACH[ch].WordCounter == 0) // Begin WordCounter reload. { if(!(DMACH[ch].ChanControl & (1 << 24))) // Needed for the forced-DMA-stop kludge(see DMA_Write()). break; if(!ChCan(ch, CRModeCache)) break; DMACH[ch].CurAddr = DMACH[ch].BaseAddr; if(CRModeCache & (1U << 10)) { uint32_t header; if(MDFN_UNLIKELY(DMACH[ch].CurAddr & 0x800000)) { DMACH[ch].ChanControl &= ~(0x11 << 24); DMAIntControl |= 0x8000; RecalcIRQOut(); break; } header = MainRAM.ReadU32(DMACH[ch].CurAddr & 0x1FFFFC); DMACH[ch].CurAddr = (DMACH[ch].CurAddr + 4) & 0xFFFFFF; DMACH[ch].WordCounter = header >> 24; DMACH[ch].BaseAddr = header & 0xFFFFFF; // printf to debug Soul Reaver ;) //if(DMACH[ch].WordCounter > 0x10) // printf("What the lala? 0x%02x @ 0x%08x\n", DMACH[ch].WordCounter, DMACH[ch].CurAddr - 4); if(DMACH[ch].WordCounter) DMACH[ch].ClockCounter -= 15; else DMACH[ch].ClockCounter -= 10; goto SkipPayloadStuff; // 3 cheers for gluten-free spaghetticode(necessary because the newly-loaded WordCounter might be 0, and we actually // want 0 to mean 0 and not 65536 in this context)! } else { DMACH[ch].WordCounter = DMACH[ch].BlockControl & 0xFFFF; if(CRModeCache & (1U << 9)) { if(ch == 2) // Technically should apply to all channels, but since we don't implement CPU read penalties for channels other than 2 yet, it's like this to avoid making DMA longer than what games can handle. DMACH[ch].ClockCounter -= 7; DMACH[ch].BlockControl = (DMACH[ch].BlockControl & 0xFFFF) | ((DMACH[ch].BlockControl - (1U << 16)) & 0xFFFF0000); } } } // End WordCounter reload.