/************************************************************************************* * accessComRegs.c * * synopsis: Access routines for CPU to CPU communication registers. These are the * STATUS, COMMAND, RESERVED and IDSP (Inter-DSP) Comm. registers. The STATUS * and command registers are used mostly to handshake and communicate * status while a DSP is executing a primitive list. The slave and master * communicate via the register block on the slave while the slave executes * a primitive list from the master or the host. The master and host * communicate via the register block on the master while the master * executes a list from the host. * INTR_DSP_HSHK_WR and INTR_DSP_HSHK_RD are used only on the slaves. They * are used for the handshake between slave and master when either sends a * primitive list to the other. * * in this file: initComRegs, setRunning, setBusy, rstBusy, setExecuting, rstExecuting, * setPaused, rstPaused, assignOutListRdy, setDspAck, rstDspAck, * setTxtBuffNE, rstTxtBuffNE, setTxtBuffProc, rstTxtBuffProc, * loadPrimListIndex, loadPrimIndex, * getInListRdy, getPause, getResume, getAbort, getTxtBuffRR, getSlvID, * setSlvInListRdy, rstSlvInListRdy, setSlvPause, rstSlvPause, * setSlvAbort, rstSlvAbort, toggleSlvResume, setSlvID, * setSlvTxtBuffRR, rstSlvTxtBuffRR, getSlvRunning, getSlvPaused, * getSlvAck, getSlvOutListRdy, getSlvResume, getSlvTxtBuffNE, * setSlvRegBit, rstSlvRegBit, getSlvRegBit, setSlvReg, getSlvReg * * related files: * comRegDfns.h: defines the bit fields inside the command & status registers. * * Damon Fasching, UW Madison fasching@wisconsin.cern.ch * Douglas Ferguson, UW Madison (510)486-5230 dpferguson@lbl.gov * * modifications/bugs * - Reserved bits in the command register and added routines for master DSP * to set a slave's ID, and for slaves to read their IDs 05.05.02 dpsf * - Added histogram command and status registers, for use with register * communication with setTrigger (*much* faster than primitive communication. * HPI writes are approximately 1 word / 2 microseconds). 20.05.02 dpsf * - Placed communication registers at the base of IDRAM. They are declared * in and (will be- for now is a kludge) accessed through a structure and * then placed into the IDREGS memory segment (defined in the configuration * database file) using the DATA_SECTION #pragma linker directive.04.06.02 dpsf * - Added a debug register. 06.06.02 dpsf ************************************************************************************/ #include "resources.h" #include "memoryPartitions.h" #include "comRegDfns.h" #pragma CODE_SECTION(setRunning, "xcode"); #pragma CODE_SECTION(initCommRegs, "xcode"); #pragma CODE_SECTION(setBusy, "xcode"); #pragma CODE_SECTION(rstBusy, "xcode"); #pragma CODE_SECTION(setExecuting, "xcode"); #pragma CODE_SECTION(rstExecuting, "xcode"); #pragma CODE_SECTION(setPaused, "xcode"); #pragma CODE_SECTION(rstPaused, "xcode"); #pragma CODE_SECTION(assignOutListRdy, "xcode"); #pragma CODE_SECTION(setDspAck, "xcode"); #pragma CODE_SECTION(rstDspAck, "xcode"); #pragma CODE_SECTION(setTxtBuffNE, "xcode"); #pragma CODE_SECTION(rstTxtBuffNE, "xcode"); #pragma CODE_SECTION(setTxtBuffProc, "xcode"); #pragma CODE_SECTION(rstTxtBuffProc, "xcode"); #pragma CODE_SECTION(loadPrimListIndex, "xcode"); #pragma CODE_SECTION(loadPrimIndex, "xcode"); #pragma CODE_SECTION(getInListRdy, "xcode"); #pragma CODE_SECTION(getPause, "xcode"); #pragma CODE_SECTION(getResume, "xcode"); #pragma CODE_SECTION(getAbort, "xcode"); #pragma CODE_SECTION(getTxtBuffRR, "xcode"); #if defined(I_AM_SLAVE_DSP) #pragma CODE_SECTION(getSlvID, "xcode"); #elif defined(I_AM_MASTER_DSP) #pragma CODE_SECTION(setSlvInListRdy, "xcode"); #pragma CODE_SECTION(rstSlvInListRdy, "xcode"); #pragma CODE_SECTION(setSlvPause, "xcode"); #pragma CODE_SECTION(rstSlvPause, "xcode"); #pragma CODE_SECTION(setSlvAbort, "xcode"); #pragma CODE_SECTION(rstSlvAbort, "xcode"); #pragma CODE_SECTION(toggleSlvResume, "xcode"); #pragma CODE_SECTION(setSlvID, "xcode"); #pragma CODE_SECTION(setSlvTxtBuffRR, "xcode"); #pragma CODE_SECTION(rstSlvTxtBuffRR, "xcode"); #pragma CODE_SECTION(getSlvRunning, "xcode"); #pragma CODE_SECTION(getSlvPaused, "xcode"); #pragma CODE_SECTION(getSlvAck, "xcode"); #pragma CODE_SECTION(getSlvOutListRdy, "xcode"); #pragma CODE_SECTION(getSlvResume, "xcode"); #pragma CODE_SECTION(getSlvTxtBuffNE, "xcode"); #ifndef SIM #pragma CODE_SECTION(convertAddr, "icode"); #endif #pragma CODE_SECTION(initSdspRegAddr, "xcode"); #pragma CODE_SECTION(setSlvRegBit, "icode"); #pragma CODE_SECTION(rstSlvRegBit, "icode"); #pragma CODE_SECTION(getSlvRegBit, "icode"); #pragma CODE_SECTION(setSlvReg, "icode"); #pragma CODE_SECTION(getSlvReg, "icode"); #pragma CODE_SECTION(getSdspReg, "icode"); #endif extern TIMER_Handle timer1; /* general purpose timer, started in main() */ #pragma DATA_SECTION(commRegs, "commRegs"); CommRegs commRegs; //The DSP's communication registers CommRegs sdspReg; //The members of this structure contain SDSP comm. reg. addresses //dpsf: convert to using the sdspRe struct & remove convertAddr & relatives. /* file level function prototype: */ UINT32 convertAddr(UINT32 addr); /************************************************************************************ * initComRegs * synopsis: Clears the communication registers, and sets the addresses in the * sdspRegAddr structure. The sdspRegAddr structure is used for * transparent access to the SDSPs from the MDSP, since the physical addresses * may be different. ************************************************************************************/ void initCommRegs(void) { #if defined(I_AM_SLAVE_DSP) UINT32 cmdReg; cmdReg= READ_REG(COMMAND_REG_0); //Preserve the SDSP's ID (in the command reg.) #endif setMem((UINT32 *) &commRegs, SIZEOF(commRegs), 0x00000000); #if defined(I_AM_SLAVE_DSP) WRITE_REG(COMMAND_REG_0, cmdReg); #endif } /************************************************************************************ * functions to set and reset status register bits ************************************************************************************/ void setRunning(void) { SET_RBIT(STATUS_REG_0, SR_RUNNING); return; } void setBusy(void) { SET_RBIT(STATUS_REG_0, SR_BUSY); return; } void rstBusy(void) { RST_RBIT(STATUS_REG_0, SR_BUSY); return; } void setExecuting(void) { SET_RBIT(STATUS_REG_0, SR_EXECUTING); return; } void rstExecuting(void) { RST_RBIT(STATUS_REG_0, SR_EXECUTING); return; } void setPaused(void) { SET_RBIT(STATUS_REG_0, SR_PAUSED); return; } void rstPaused(void) { RST_RBIT(STATUS_REG_0, SR_PAUSED); return; } void assignOutListRdy(UINT32 outListRdy) { ASGN_RBIT(STATUS_REG_0, SR_OUT_LIST_RDY, outListRdy); return; } void setDspAck(void) { SET_RBIT(STATUS_REG_0, SR_DSP_ACK); return; } void rstDspAck(void) { RST_RBIT(STATUS_REG_0, SR_DSP_ACK); return; } void setTxtBuffNE(UINT32 txtBuffNum) { SET_RBIT(STATUS_REG_0, SR_TXT_BUFF_NE(txtBuffNum)); return; } void rstTxtBuffNE(UINT32 txtBuffNum) { RST_RBIT(STATUS_REG_0, SR_TXT_BUFF_NE(txtBuffNum)); return; } void setTxtBuffProc(UINT32 txtBuffNum) { SET_RBIT(STATUS_REG_0, SR_TXT_BUFF_PROC(txtBuffNum)); return; } void rstTxtBuffProc(UINT32 txtBuffNum) { RST_RBIT(STATUS_REG_0, SR_TXT_BUFF_PROC(txtBuffNum)); return; } /************************************************************************************ * functions to set SR_PRIM_LIST_INDEX and SR_PRIM_INDEX ************************************************************************************/ void loadPrimListIndex(UINT32 value) { ASGN_RFLD(STATUS_REG_1, SR_PRIM_LIST_INDEX, SR_PRIM_LIST_INDEX_W, value); return; } void loadPrimIndex(UINT32 value) { ASGN_RFLD(STATUS_REG_1, SR_PRIM_INDEX, SR_PRIM_INDEX_W, value); return; } /************************************************************************************ * functions to read the command register bits ************************************************************************************/ UINT32 getInListRdy(void) { return GET_RBIT(COMMAND_REG_0, CR_IN_LIST_RDY); } UINT32 getPause(void) { return GET_RBIT(COMMAND_REG_0, CR_PAUSE); } UINT32 getResume(void) { return GET_RBIT(COMMAND_REG_0, CR_RESUME); } UINT32 getAbort(void) { return GET_RBIT(COMMAND_REG_0, CR_ABORT); } UINT32 getTxtBuffRR(UINT32 txtBuffNum) { return GET_RBIT(COMMAND_REG_0, CR_TXT_BUFF_RR(txtBuffNum)); } #ifdef I_AM_SLAVE_DSP UINT32 getSlvID(void) { return GET_RBIT(COMMAND_REG_0, CR_ID) +2*GET_RBIT(COMMAND_REG_0, CR_ID+1); } #endif #if defined(I_AM_MASTER_DSP) /* set and reset bits in the slave command registers */ void setSlvInListRdy(UINT32 slvDspNum) { setSlvRegBit(slvDspNum, (UINT32)(COMMAND_REG_0), (UINT32)(CR_IN_LIST_RDY)); return; } void rstSlvInListRdy(UINT32 slvDspNum) { rstSlvRegBit(slvDspNum, (UINT32)(COMMAND_REG_0), (UINT32)(CR_IN_LIST_RDY)); return; } void setSlvPause(UINT32 slvDspNum) { setSlvRegBit(slvDspNum, (UINT32)(COMMAND_REG_0), (UINT32)(CR_PAUSE)); return; } void rstSlvPause(UINT32 slvDspNum) { rstSlvRegBit(slvDspNum, (UINT32)(COMMAND_REG_0), (UINT32)(CR_PAUSE)); return; } void setSlvAbort(UINT32 slvDspNum) { setSlvRegBit(slvDspNum, (UINT32)(COMMAND_REG_0), (UINT32)(CR_ABORT)); return; } void rstSlvAbort(UINT32 slvDspNum) { rstSlvRegBit(slvDspNum, (UINT32)(COMMAND_REG_0), (UINT32)(CR_ABORT)); return; } void toggleSlvResume(UINT32 slvDspNum) { if (getSlvResume(slvDspNum)) { rstSlvRegBit(slvDspNum, (UINT32)(COMMAND_REG_0), (UINT32)(CR_RESUME)); } else { setSlvRegBit(slvDspNum, (UINT32)(COMMAND_REG_0), (UINT32)(CR_RESUME)); } return; } void setSlvID(UINT32 slvDspNum) { if (slvDspNum==0) { rstSlvRegBit(slvDspNum, (UINT32)(COMMAND_REG_0), (UINT32)(CR_ID)); rstSlvRegBit(slvDspNum, (UINT32)(COMMAND_REG_0), (UINT32)(CR_ID+1)); } else if (slvDspNum==1) { setSlvRegBit(slvDspNum, (UINT32)(COMMAND_REG_0), (UINT32)(CR_ID)); rstSlvRegBit(slvDspNum, (UINT32)(COMMAND_REG_0), (UINT32)(CR_ID+1)); } else if (slvDspNum==2) { rstSlvRegBit(slvDspNum, (UINT32)(COMMAND_REG_0), (UINT32)(CR_ID)); setSlvRegBit(slvDspNum, (UINT32)(COMMAND_REG_0), (UINT32)(CR_ID+1)); } else if (slvDspNum==3) { setSlvRegBit(slvDspNum, (UINT32)(COMMAND_REG_0), (UINT32)(CR_ID)); setSlvRegBit(slvDspNum, (UINT32)(COMMAND_REG_0), (UINT32)(CR_ID+1)); } return; } void setSlvTxtBuffRR(UINT32 slvDspNum, UINT32 buffer) { setSlvRegBit(slvDspNum, (UINT32)(COMMAND_REG_0), (UINT32)(CR_TXT_BUFF_RR(buffer))); return; } void rstSlvTxtBuffRR(UINT32 slvDspNum, UINT32 buffer) { rstSlvRegBit(slvDspNum, (UINT32)(COMMAND_REG_0), (UINT32)(CR_TXT_BUFF_RR(buffer))); return; } /* read bits from the slave status and command registers */ UINT32 getSlvRunning(UINT32 slvDspNum) { return getSlvRegBit(slvDspNum, (UINT32)(STATUS_REG_0), SR_RUNNING); } UINT32 getSlvPaused(UINT32 slvDspNum) { return getSlvRegBit(slvDspNum, (UINT32)(STATUS_REG_0), SR_PAUSED); } UINT32 getSlvAck(UINT32 slvDspNum) { return getSlvRegBit(slvDspNum, (UINT32)(STATUS_REG_0), SR_DSP_ACK); } UINT32 getSlvOutListRdy(UINT32 slvDspNum) { return getSlvRegBit(slvDspNum, (UINT32)(STATUS_REG_0), SR_OUT_LIST_RDY); } UINT32 getSlvResume(UINT32 slvDspNum) { return getSlvRegBit(slvDspNum, (UINT32)(COMMAND_REG_0), CR_RESUME); } UINT32 getSlvTxtBuffNE(UINT32 slvDspNum, UINT32 buffer) { return getSlvRegBit(slvDspNum, (UINT32)(STATUS_REG_0), SR_TXT_BUFF_NE(buffer)); } void initSdspRegAddr(void) { UINT32 addr, *sdspAddr, i; UINT8 rodRev; addr= (UINT32) &commRegs; sdspAddr= (UINT32 *) &sdspReg; rodRev= getRodRev(); if (rodRev >= 0xe) {addr+= 0x10000; addr&= (~0x80000000); } /* Will set up the sdspRegAddr structure so that sdspRegAddr.status[0] etc. will contain the physical addresses of the corresponding SDSP communication register: */ for (i=0; i= 0x80000000)&&(addr < 0x80010000)) return ((addr & 0x7fffffff) +0x00010000); else if ((addr >= 0x02000000)&&(addr < 0x03000000)) return ((addr - 0x02000000) +0xa0000000); else if ((addr >= 0x03000000)&&(addr < 0x04000000)) return ((addr - 0x03000000) +0xb0000000); else return addr; } void setSlvRegBit(UINT32 slvDspNum, UINT32 regAddress, UINT32 bitNum) { UINT32 regContents; if (firstConv) { firstConv= FALSE; if (getRodRev() == 0xe) rodRevisionInt= 0xe; else rodRevisionInt= 0xc; } if (rodRevisionInt == 0xe) regAddress= convertAddr(regAddress); writeSlvHPIA(slvDspNum, regAddress); regContents = readSlvHPID(slvDspNum); delay(30); regContents = readSlvHPID(slvDspNum); //dpsf harden by reading twice. SET_VBIT(regContents, bitNum); writeSlvHPID(slvDspNum, regContents); return; } void rstSlvRegBit(UINT32 slvDspNum, UINT32 regAddress, UINT32 bitNum) { UINT32 regContents; if (firstConv) { firstConv= FALSE; if (getRodRev() == 0xe) rodRevisionInt= 0xe; else rodRevisionInt= 0xc; } if (rodRevisionInt == 0xe) regAddress= convertAddr(regAddress); writeSlvHPIA(slvDspNum, regAddress); regContents = readSlvHPID(slvDspNum); delay(30); regContents = readSlvHPID(slvDspNum); //dpsf harden by reading twice. RST_VBIT(regContents, bitNum); writeSlvHPID(slvDspNum, regContents); return; } UINT32 getSlvRegBit(UINT32 slvDspNum, UINT32 regAddress, UINT32 bitNum) { UINT32 regContents; if (firstConv) { firstConv= FALSE; if (getRodRev() == 0xe) rodRevisionInt= 0xe; else rodRevisionInt= 0xc; } if (rodRevisionInt == 0xe) regAddress= convertAddr(regAddress); writeSlvHPIA(slvDspNum, regAddress); regContents = readSlvHPID(slvDspNum); delay(30); //dpsf harden by reading twice. return ((readSlvHPID(slvDspNum) >> bitNum) & 1); } void setSlvReg(UINT32 slvDspNum, UINT32 regAddress, UINT32 val) { if (firstConv) { firstConv= FALSE; if (getRodRev() == 0xe) rodRevisionInt= 0xe; else rodRevisionInt= 0xc; } if (rodRevisionInt == 0xe) regAddress= convertAddr(regAddress); writeSlvHPIA(slvDspNum, regAddress); writeSlvHPID(slvDspNum, val); return; } UINT32 getSlvReg(UINT32 slvDspNum, UINT32 regAddress) { UINT32 regContents; if (firstConv) { firstConv= FALSE; if (getRodRev() == 0xe) rodRevisionInt= 0xe; else rodRevisionInt= 0xc; } if (rodRevisionInt == 0xe) regAddress= convertAddr(regAddress); writeSlvHPIA(slvDspNum, regAddress); regContents = readSlvHPID(slvDspNum); delay(30); //dpsf harden by reading twice. return readSlvHPID(slvDspNum); } uint32 getSdspReg(UINT32 sdsp, UINT32 addr) { writeSlvHPIA(sdsp, addr); return readSlvHPID(sdsp); } #else //Simulator /* When running in CCS must usin a simulated MDSP, fake the SDSPs. Set up the simulated MDSP with 16 MB memory in CE0, and put the SDSP communication register block on top of the FPGA register block. The simulation routines handle some of the MDSP/SDSP handshake, others must be handled manually, for ex. by setting a bit using the memory edit fxns. of CCS. */ void setSlvRegBit(UINT32 slvDspNum, UINT32 regAddress, UINT32 bitNum) { UINT32 regContents; regAddress = SIM_SDSP_REG_BASE(slvDspNum) + (regAddress - STATUS_REG_0); regContents = *((UINT32 *)regAddress); SET_VBIT(regContents, bitNum); *((UINT32 *)regAddress) = regContents; return; } void rstSlvRegBit(UINT32 slvDspNum, UINT32 regAddress, UINT32 bitNum) { UINT32 regContents; regAddress = SIM_SDSP_REG_BASE(slvDspNum) + (regAddress - STATUS_REG_0); regContents = *((UINT32 *)regAddress); RST_VBIT(regContents, bitNum); *((UINT32 *)regAddress) = regContents; return; } UINT32 getSlvRegBit(UINT32 slvDspNum, UINT32 regAddress, UINT32 bitNum) { UINT32 regContents; regAddress = SIM_SDSP_REG_BASE(slvDspNum) + (regAddress - STATUS_REG_0); regContents = *((UINT32 *)regAddress); return ((regContents >> bitNum) & 1); } void setSlvReg(UINT32 slvDspNum, UINT32 regAddress, UINT32 val) { // regAddress= convertAddr(regAddress); regAddress = SIM_SDSP_REG_BASE(slvDspNum) + (regAddress - STATUS_REG_0); *((UINT32 *)regAddress) = val; return; } UINT32 getSlvReg(UINT32 slvDspNum, UINT32 regAddress) { regAddress = SIM_SDSP_REG_BASE(slvDspNum) + (regAddress - STATUS_REG_0); return *((UINT32 *)regAddress); } //inlined versions are in simulation.h: uint32 getSdspReg(UINT32 sdsp, UINT32 addr) { uint32 *sdspAddr; //the mask removes any part of the address which is > 32 words: sdspAddr= (UINT32 *) (SIM_SDSP_REG_BASE(sdsp) +(addr & 0x7f)); return *sdspAddr; } #endif // Rod/Simulation #endif // MDSP