/* Copyright 2006 yopyop Copyright 2007 shash Copyright 2007-2012 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the this software. If not, see . */ #include #include "FIFO.h" #include "armcpu.h" //#include "debug.h" #include "mem.h" #include "MMU.h" #include "NDSSystem.h" //#include "gfx3d.h" // ========================================================= IPC FIFO IPC_FIFO ipc_fifo[2]; // 0 - ARM9 // 1 - ARM7 void IPC_FIFOinit(uint8_t proc) { memset(&ipc_fifo[proc], 0, sizeof(IPC_FIFO)); T1WriteWord(MMU.MMU_MEM[proc][0x40], 0x184, 0x00000101); } void IPC_FIFOsend(uint8_t proc, uint32_t val) { uint16_t cnt_l = T1ReadWord(MMU.MMU_MEM[proc][0x40], 0x184); if (!(cnt_l & IPCFIFOCNT_FIFOENABLE)) return; // FIFO disabled uint8_t proc_remote = proc ^ 1; if (ipc_fifo[proc].size > 15) { cnt_l |= IPCFIFOCNT_FIFOERROR; T1WriteWord(MMU.MMU_MEM[proc][0x40], 0x184, cnt_l); return; } uint16_t cnt_r = T1ReadWord(MMU.MMU_MEM[proc_remote][0x40], 0x184); //LOG("IPC%s send FIFO 0x%08X size %03i (l 0x%X, tail %02i) (r 0x%X, tail %02i)\n", // proc?"7":"9", val, ipc_fifo[proc].size, cnt_l, ipc_fifo[proc].tail, cnt_r, ipc_fifo[proc^1].tail); cnt_l &= 0xBFFC; // clear send empty bit & full cnt_r &= 0xBCFF; // set recv empty bit & full ipc_fifo[proc].buf[ipc_fifo[proc].tail] = val; ipc_fifo[proc].tail++; ipc_fifo[proc].size++; if (ipc_fifo[proc].tail > 15) ipc_fifo[proc].tail = 0; if (ipc_fifo[proc].size > 15) { cnt_l |= IPCFIFOCNT_SENDFULL; // set send full bit cnt_r |= IPCFIFOCNT_RECVFULL; // set recv full bit } T1WriteWord(MMU.MMU_MEM[proc][0x40], 0x184, cnt_l); T1WriteWord(MMU.MMU_MEM[proc_remote][0x40], 0x184, cnt_r); if (cnt_r & IPCFIFOCNT_RECVIRQEN) NDS_makeIrq(proc_remote, IRQ_BIT_IPCFIFO_RECVNONEMPTY); NDS_Reschedule(); } uint32_t IPC_FIFOrecv(uint8_t proc) { uint16_t cnt_l = T1ReadWord(MMU.MMU_MEM[proc][0x40], 0x184); if (!(cnt_l & IPCFIFOCNT_FIFOENABLE)) return 0; // FIFO disabled uint8_t proc_remote = proc ^ 1; uint32_t val = 0; if ( ipc_fifo[proc_remote].size == 0 ) // remote FIFO error { cnt_l |= IPCFIFOCNT_FIFOERROR; T1WriteWord(MMU.MMU_MEM[proc][0x40], 0x184, cnt_l); return 0; } uint16_t cnt_r = T1ReadWord(MMU.MMU_MEM[proc_remote][0x40], 0x184); cnt_l &= 0xBCFF; // clear send full bit & empty cnt_r &= 0xBFFC; // set recv full bit & empty val = ipc_fifo[proc_remote].buf[ipc_fifo[proc_remote].head]; ipc_fifo[proc_remote].head++; ipc_fifo[proc_remote].size--; if (ipc_fifo[proc_remote].head > 15) ipc_fifo[proc_remote].head = 0; //LOG("IPC%s recv FIFO 0x%08X size %03i (l 0x%X, tail %02i) (r 0x%X, tail %02i)\n", // proc?"7":"9", val, ipc_fifo[proc].size, cnt_l, ipc_fifo[proc].tail, cnt_r, ipc_fifo[proc^1].tail); if ( ipc_fifo[proc_remote].size == 0 ) // FIFO empty { cnt_l |= IPCFIFOCNT_RECVEMPTY; cnt_r |= IPCFIFOCNT_SENDEMPTY; if (cnt_r & IPCFIFOCNT_SENDIRQEN) NDS_makeIrq(proc_remote, IRQ_BIT_IPCFIFO_SENDEMPTY); } T1WriteWord(MMU.MMU_MEM[proc][0x40], 0x184, cnt_l); T1WriteWord(MMU.MMU_MEM[proc_remote][0x40], 0x184, cnt_r); NDS_Reschedule(); return val; } void IPC_FIFOcnt(uint8_t proc, uint16_t val) { uint16_t cnt_l = T1ReadWord(MMU.MMU_MEM[proc][0x40], 0x184); uint16_t cnt_r = T1ReadWord(MMU.MMU_MEM[proc^1][0x40], 0x184); if (val & IPCFIFOCNT_FIFOERROR) { //at least SPP uses this, maybe every retail game cnt_l &= ~IPCFIFOCNT_FIFOERROR; } if (val & IPCFIFOCNT_SENDCLEAR) { ipc_fifo[proc].head = 0; ipc_fifo[proc].tail = 0; ipc_fifo[proc].size = 0; cnt_l |= IPCFIFOCNT_SENDEMPTY; cnt_r |= IPCFIFOCNT_RECVEMPTY; cnt_l &= ~IPCFIFOCNT_SENDFULL; cnt_r &= ~IPCFIFOCNT_RECVFULL; } cnt_l &= ~IPCFIFOCNT_WRITEABLE; cnt_l |= val & IPCFIFOCNT_WRITEABLE; // IPCFIFOCNT_SENDIRQEN may have been set (and/or the fifo may have been cleared) so we may need to trigger this irq // (this approach is used by libnds fifo system on occasion in fifoInternalSend, and began happening frequently for value32 with r4326) if (cnt_l & IPCFIFOCNT_SENDIRQEN) if (cnt_l & IPCFIFOCNT_SENDEMPTY) NDS_makeIrq(proc, IRQ_BIT_IPCFIFO_SENDEMPTY); // IPCFIFOCNT_RECVIRQEN may have been set so we may need to trigger this irq if(cnt_l & IPCFIFOCNT_RECVIRQEN) if (!(cnt_l & IPCFIFOCNT_RECVEMPTY)) NDS_makeIrq(proc, IRQ_BIT_IPCFIFO_RECVNONEMPTY); T1WriteWord(MMU.MMU_MEM[proc][0x40], 0x184, cnt_l); T1WriteWord(MMU.MMU_MEM[proc^1][0x40], 0x184, cnt_r); NDS_Reschedule(); } // ========================================================= GFX FIFO //GFX_PIPE gxPIPE; //GFX_FIFO gxFIFO; /*void GFX_PIPEclear() { gxPIPE.head = 0; gxPIPE.tail = 0; gxPIPE.size = 0; }*/ /*void GFX_FIFOclear() { gxFIFO.head = 0; gxFIFO.tail = 0; gxFIFO.size = 0; }*/ /*static void GXF_FIFO_handleEvents() { bool low = gxFIFO.size <= 127; bool lowchange = MMU_new.gxstat.fifo_low ^ low; MMU_new.gxstat.fifo_low = low; if(low) triggerDma(EDMAMode_GXFifo); bool empty = gxFIFO.size == 0; bool emptychange = MMU_new.gxstat.fifo_empty ^ empty; MMU_new.gxstat.fifo_empty = empty; if(emptychange||lowchange) NDS_Reschedule(); }*/ /*void GFX_FIFOsend(uint8_t cmd, uint32_t param) { if(cmd==0x41) { //int zzz=9; } //INFO("gxFIFO: send 0x%02X = 0x%08X (size %03i/0x%02X) gxstat 0x%08X\n", cmd, param, gxFIFO.size, gxFIFO.size, gxstat); //printf("fifo recv: %02X: %08X upto:%d\n",cmd,param,gxFIFO.size+1); //TODO - WOAH ! NOT HANDLING A TOO-BIG FIFO RIGHT NOW! //if (gxFIFO.size > 255) //{ // GXF_FIFO_handleEvents(); // //NEED TO HANDLE THIS!!!!!!!!!!!!!!!!!!!!!!!!!! // //gxstat |= 0x08000000; // busy // NDS_RescheduleGXFIFO(1); // //INFO("ERROR: gxFIFO is full (cmd 0x%02X = 0x%08X) (prev cmd 0x%02X = 0x%08X)\n", cmd, param, gxFIFO.cmd[255], gxFIFO.param[255]); // return; //} gxFIFO.cmd[gxFIFO.tail] = cmd; gxFIFO.param[gxFIFO.tail] = param; gxFIFO.tail++; gxFIFO.size++; if (gxFIFO.tail > HACK_GXIFO_SIZE-1) gxFIFO.tail = 0; if(gxFIFO.size>=HACK_GXIFO_SIZE) { printf("--FIFO FULL-- : %d\n",gxFIFO.size); } //gxstat |= 0x08000000; // set busy flag GXF_FIFO_handleEvents(); NDS_RescheduleGXFIFO(1); }*/ // this function used ONLY in gxFIFO /*bool GFX_PIPErecv(uint8_t *cmd, uint32_t *param) { //gxstat &= 0xF7FFFFFF; // clear busy flag if (gxFIFO.size == 0) { GXF_FIFO_handleEvents(); return false; } *cmd = gxFIFO.cmd[gxFIFO.head]; *param = gxFIFO.param[gxFIFO.head]; gxFIFO.head++; gxFIFO.size--; if (gxFIFO.head > HACK_GXIFO_SIZE-1) gxFIFO.head = 0; GXF_FIFO_handleEvents(); return true; }*/ /*void GFX_FIFOcnt(uint32_t val) { ////INFO("gxFIFO: write cnt 0x%08X (prev 0x%08X) FIFO size %03i PIPE size %03i\n", val, gxstat, gxFIFO.size, gxPIPE.size); if (val & (1<<29)) // clear? (only in homebrew?) { GFX_PIPEclear(); GFX_FIFOclear(); return; } //zeromus says: what happened to clear stack? //if (val & (1<<15)) // projection stack pointer reset //{ // gfx3d_ClearStack(); // val &= 0xFFFF5FFF; // clear reset (bit15) & stack level (bit13) //} T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600, val); }*/ // ========================================================= DISP FIFO //DISP_FIFO disp_fifo; /*void DISP_FIFOinit() { memset(&disp_fifo, 0, sizeof(DISP_FIFO)); }*/ /*void DISP_FIFOsend(uint32_t val) { //INFO("DISP_FIFO send value 0x%08X (head 0x%06X, tail 0x%06X)\n", val, disp_fifo.head, disp_fifo.tail); disp_fifo.buf[disp_fifo.tail] = val; disp_fifo.tail++; if (disp_fifo.tail > 0x5FFF) disp_fifo.tail = 0; }*/ /*uint32_t DISP_FIFOrecv() { //if (disp_fifo.tail == disp_fifo.head) return 0; // FIFO is empty uint32_t val = disp_fifo.buf[disp_fifo.head]; disp_fifo.head++; if (disp_fifo.head > 0x5FFF) disp_fifo.head = 0; return val; }*/