diff --git a/include/ultra64/bcp.h b/include/ultra64/bcp.h index 78c4584fe7..f66fee2f02 100644 --- a/include/ultra64/bcp.h +++ b/include/ultra64/bcp.h @@ -190,6 +190,16 @@ */ #define PI_NAND_CTRL_REG (PI_BASE_REG + 0x48) +/** + * PI internal buffer DMA read length. Writes initiate a DMA from RDRAM to the PI buffer. + */ +#define PI_EX_RD_LEN_REG (PI_BASE_REG + 0x58) + +/** + * PI internal buffer DMA write length. Writes initiate a DMA from the PI buffer to RDRAM. + */ +#define PI_EX_WR_LEN_REG (PI_BASE_REG + 0x5C) + /** * [31:16] Box ID * [31:30] Hardware Revision? (osInitialize checks this and sets __osBbIsBb to 2 if != 0) diff --git a/src/libultra/io/devmgr.c b/src/libultra/io/devmgr.c index d0e7d5289a..05dcb99519 100644 --- a/src/libultra/io/devmgr.c +++ b/src/libultra/io/devmgr.c @@ -2,6 +2,8 @@ #include "ultra64/internal.h" #include "ultra64/leodrive.h" +#define TEMP_BUFFER ((void*)0x80600000) + // os.h #define LEO_BLOCK_MODE 1 #define LEO_TRACK_MODE 2 @@ -14,6 +16,9 @@ void __osDevMgrMain(void* arg) { s32 ret; OSDevMgr* dm = (OSDevMgr*)arg; s32 messageSend; +#ifdef BBPLAYER + s32 check = false; +#endif while (true) { osRecvMesg(dm->cmdQueue, (OSMesg*)&ioMesg, OS_MESG_BLOCK); @@ -78,6 +83,13 @@ void __osDevMgrMain(void* arg) { switch (ioMesg->hdr.type) { case OS_MESG_TYPE_DMAREAD: osRecvMesg(dm->acsQueue, &dummy, OS_MESG_BLOCK); +#ifdef BBPLAYER + if (__osBbIsBb == 1 && ((u32)ioMesg->dramAddr & 0x7F) >= 0x60) { + check = true; + ret = dm->dma(OS_READ, ioMesg->devAddr, TEMP_BUFFER, ioMesg->size); + break; + } +#endif ret = dm->dma(OS_READ, ioMesg->devAddr, ioMesg->dramAddr, ioMesg->size); break; case OS_MESG_TYPE_DMAWRITE: @@ -86,6 +98,13 @@ void __osDevMgrMain(void* arg) { break; case OS_MESG_TYPE_EDMAREAD: osRecvMesg(dm->acsQueue, &dummy, OS_MESG_BLOCK); +#ifdef BBPLAYER + if (__osBbIsBb == 1 && ((u32)ioMesg->dramAddr & 0x7F) >= 0x60) { + check = true; + ret = dm->edma(ioMesg->piHandle, OS_READ, ioMesg->devAddr, TEMP_BUFFER, ioMesg->size); + break; + } +#endif ret = dm->edma(ioMesg->piHandle, OS_READ, ioMesg->devAddr, ioMesg->dramAddr, ioMesg->size); break; case OS_MESG_TYPE_EDMAWRITE: @@ -103,6 +122,14 @@ void __osDevMgrMain(void* arg) { if (ret == 0) { osRecvMesg(dm->evtQueue, &em, OS_MESG_BLOCK); +#ifdef BBPLAYER + if (__osBbIsBb == 1 && check) { + osInvalDCache(TEMP_BUFFER, (ioMesg->size + DCACHE_LINEMASK) & ~DCACHE_LINEMASK); + bcopy(TEMP_BUFFER, ioMesg->dramAddr, ioMesg->size); + check = false; + osWritebackDCache(ioMesg->dramAddr, ioMesg->size); + } +#endif osSendMesg(ioMesg->hdr.retQueue, (OSMesg)ioMesg, OS_MESG_NOBLOCK); osSendMesg(dm->acsQueue, NULL, OS_MESG_NOBLOCK); } diff --git a/src/libultra/io/epirawdma.c b/src/libultra/io/epirawdma.c index ff6bb9a653..dbc072fbb2 100644 --- a/src/libultra/io/epirawdma.c +++ b/src/libultra/io/epirawdma.c @@ -1,8 +1,18 @@ #include "global.h" +#include "ultra64/bcp.h" s32 __osEPiRawStartDma(OSPiHandle* handle, s32 direction, u32 cartAddr, void* dramAddr, size_t size) { - s32 status; +#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)) { @@ -53,9 +63,102 @@ s32 __osEPiRawStartDma(OSPiHandle* handle, s32 direction, u32 cartAddr, void* dr 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); @@ -66,5 +169,6 @@ s32 __osEPiRawStartDma(OSPiHandle* handle, s32 direction, u32 cartAddr, void* dr default: return -1; } +#endif return 0; } diff --git a/src/libultra/io/pimgr.c b/src/libultra/io/pimgr.c index e8aa98d01b..7a0b68f8dc 100644 --- a/src/libultra/io/pimgr.c +++ b/src/libultra/io/pimgr.c @@ -40,8 +40,8 @@ void osCreatePiManager(OSPri pri, OSMesgQueue* cmdQueue, OSMesg* cmdBuf, s32 cmd prevInt = __osDisableInt(); __osPiDevMgr.active = true; - __osPiDevMgr.cmdQueue = cmdQueue; __osPiDevMgr.thread = &piThread; + __osPiDevMgr.cmdQueue = cmdQueue; __osPiDevMgr.evtQueue = &piEventQueue; __osPiDevMgr.acsQueue = &__osPiAccessQueue; __osPiDevMgr.dma = __osPiRawStartDma;