#include "ultra64.h" #include "ultra64/bcp.h" s32 __osEPiRawStartDma(OSPiHandle* handle, s32 direction, u32 cartAddr, void* dramAddr, size_t size) { #ifdef BBPLAYER u64 dummybuf[2]; #endif u32 status; OSPiHandle* curHandle; #ifdef BBPLAYER u32 buffer; u32 pgsize; u16* adr; u32 i; #endif status = IO_READ(PI_STATUS_REG); while (status & (PI_STATUS_DMA_BUSY | PI_STATUS_IO_BUSY)) { status = IO_READ(PI_STATUS_REG); } if (__osCurrentHandle[handle->domain]->type != handle->type) { curHandle = __osCurrentHandle[handle->domain]; if (handle->domain == 0) { if (curHandle->latency != handle->latency) { IO_WRITE(PI_BSD_DOM1_LAT_REG, handle->latency); } if (curHandle->pageSize != handle->pageSize) { IO_WRITE(PI_BSD_DOM1_PGS_REG, handle->pageSize); } if (curHandle->relDuration != handle->relDuration) { IO_WRITE(PI_BSD_DOM1_RLS_REG, handle->relDuration); } if (curHandle->pulse != handle->pulse) { IO_WRITE(PI_BSD_DOM1_PWD_REG, handle->pulse); } } else { if (curHandle->latency != handle->latency) { IO_WRITE(PI_BSD_DOM2_LAT_REG, handle->latency); } if (curHandle->pageSize != handle->pageSize) { IO_WRITE(PI_BSD_DOM2_PGS_REG, handle->pageSize); } if (curHandle->relDuration != handle->relDuration) { IO_WRITE(PI_BSD_DOM2_RLS_REG, handle->relDuration); } if (curHandle->pulse != handle->pulse) { IO_WRITE(PI_BSD_DOM2_PWD_REG, handle->pulse); } } curHandle->type = handle->type; curHandle->latency = handle->latency; curHandle->pageSize = handle->pageSize; curHandle->relDuration = handle->relDuration; curHandle->pulse = handle->pulse; } #ifdef BBPLAYER if (direction == OS_READ) { // Device page size in bytes pgsize = 1; for (i = 1; i <= (u32)handle->pageSize + 2; i++) { pgsize *= 2; } // If the initial cart address mod pgsize is at the last u16 in the page, // need to do some manual DMAs? if ((cartAddr & (pgsize - 1)) == pgsize - sizeof(u16)) { // Read 32 bits starting 2 bytes before the target DMA address, // so that the lower 16 bits of the result are the first 2 bytes // of the requested data. __osEPiRawReadIo(handle, cartAddr - sizeof(u16), &buffer); // Poke the lower 16 bits into the destination address adr = (u16*)PHYS_TO_K1(dramAddr); *(adr++) = (u16)buffer; // Update DMA parameters cartAddr += sizeof(u16); dramAddr = adr; size -= sizeof(u16); // If the remaining size is >= 4 if (size >= sizeof(u32)) { // Read another 32 bits at the cart addr __osEPiRawReadIo(handle, cartAddr, &buffer); // Store all 32 bits to RAM adr = (u16*)dramAddr; *(adr++) = buffer >> 16; *(adr++) = (u16)buffer; // Update DMA parameters again cartAddr += sizeof(u32); dramAddr = adr; size -= sizeof(u32); // If we're not at the end of the DMA if (size != 0) { // Read 32 bits again __osEPiRawReadIo(handle, cartAddr, &buffer); // Store just the upper 16 bits adr = (u16*)PHYS_TO_K1(dramAddr); *(adr++) = buffer >> 16; // Update DMA parameters once more cartAddr += sizeof(u16); dramAddr = adr; size -= sizeof(u16); } } } // If the end cart address mod pgsize is just 2 bytes into a page or the remaining data size is just 1x u16 if (((((cartAddr + size) & (pgsize - 1)) == sizeof(u16)) | (size == sizeof(u16))) != 0) { if ((cartAddr + size) & 2) { // Read 32 bits at end - 2, store the upper 16 bits __osEPiRawReadIo(handle, cartAddr + size - sizeof(u16), &buffer); adr = (u16*)PHYS_TO_K1(dramAddr) + (size - sizeof(u16)) / sizeof(u16); *adr = buffer >> 16; } else { // Read 32 bits at end - 4, store the lower 16 bits __osEPiRawReadIo(handle, cartAddr + size - sizeof(u32), &buffer); adr = (u16*)PHYS_TO_K1(dramAddr) + (size - sizeof(u16)) / sizeof(u16); *adr = (u16)buffer; } size -= sizeof(u16); } if (size == 0) { // If size ended up 0 following the adjustments, run an 8-byte dummy DMA anyway size = 8; dramAddr = (void*)dummybuf; cartAddr = 0; } } #endif IO_WRITE(PI_DRAM_ADDR_REG, osVirtualToPhysical(dramAddr)); IO_WRITE(PI_CART_ADDR_REG, K1_TO_PHYS(handle->baseAddress | cartAddr)); #ifdef BBPLAYER if (direction != OS_READ && direction != OS_WRITE) { return -1; } if ((handle->baseAddress | cartAddr) <= 0x400) { IO_WRITE((direction == OS_READ) ? PI_EX_WR_LEN_REG : PI_EX_RD_LEN_REG, size - 1); } else { IO_WRITE((direction == OS_READ) ? PI_WR_LEN_REG : PI_RD_LEN_REG, size - 1); } #else switch (direction) { case OS_READ: IO_WRITE(PI_WR_LEN_REG, size - 1); break; case OS_WRITE: IO_WRITE(PI_RD_LEN_REG, size - 1); break; default: return -1; } #endif return 0; }