/************************************************************************************ * rodRun.c * * synopsis: Main routines for master & slave DSPs on the SCT & pixel RODs. * * modifications/bugs: * * To make the program work using DSP-BIOS, added two new subroutines: chipInit * and mainLoop. chipInit is called as the first subroutine by TI's BIOS_Init * routine; it contains all the most basic initialization code needed to get the * DSP (esp. the master DSP) up & running from boot (& before the BIOS code runs). * The main() routine then finishes up any needed initializations. Under DSP-BIOS, * the main program must end before interrupts are enabled. The BIOS then starts * up a tasking system which uses software interrupts to schedule tasks; mainLoop * runs as a task under this. 04.03.02 dpsf * * Added general purpose string for routines which need to send * information back; re-using this string will help to keep program * size down. 08.06.02 dpsf * * Added call to the new Task Manager, which handles ongoing chores * (data analysis by slaves, monitoring by master) 09.06.02 dpsf * * Found a way to remove the DSP-BIOS & still have interrupts: BIOS uses up a * significant amount (~20%) of the DSP's internal memory. Interrupts are enabled * through the calls to the (badly documented) IER & CSR registers. chipInit and * mainLoop are now subroutines called by main(). 01.09.02 dpsf * * All subroutine calls inside the main polling loop are now tested beforehand * to see if they really need to be entered. At the expense of some added * complexity in the command & status registers (a set of new bits which are set * & reset by the different subroutines as needed), the main loop has been sped * up by approximately a factor of 15 on the master DSP (was over 100 micro- * seconds, now runs in just under 8- dominated by reads to slave DSP registers), * and a factor of over 50 on the slave DSPs (the main loop now idles at ~0.5 * microseconds). Subroutine calls are expensive since the DSP registers must all * be pushed onto & popped off the stack. 10.10.02 dpsf * * Now start timer 1 with the maximum period (0xffffffff) in main(), and measure * delta-time via successive calls to TIMER_getCount. This allows any function * to quickly set up & get a delta, without worrying about interference with any * other function. The timer handle is available as an external global variable * in the other project files. 09.01.03 dpsf * * Added function extInit to finish off the initializations, running out * of the external memory 28.02.03 dpsf ************************************************************************************/ #include /* must be included 1st */ #include #include #include #include #include #include #include "resources.h" #include "simulation.h" #include "comRegDfns.h" #pragma CODE_SECTION(chipInit, "icode"); #pragma CODE_SECTION(main, "icode"); #pragma CODE_SECTION(extInit, "xcode"); #pragma CODE_SECTION(mainLoop, "icode"); #pragma DATA_SECTION(versionStr, "idata"); char genStr[400]; //General purpose string. TIMER_Handle timer1= NULL; //General purpose timer #pragma DATA_SECTION(heap, "heap"); UINT8 heap[0x100000]; //Heap for misc. *temporary* data. #if defined(SCT_ROD) char versionStr[40]= "Version 1.2.1 "; #elif defined(PIXEL_ROD) char versionStr[40]= "Version 1.4.2 "; #endif UINT32 auxCtl; #if ((defined(I_AM_SLAVE_DSP))&&(defined(REV_E))) #pragma CODE_SECTION(cacheOn, "icode"); void cacheOn(void); #pragma CODE_SECTION(cacheOff, "icode"); void cacheOff(void); UINT32 cache_on= FALSE; #pragma CODE_SECTION(flushL2Range, "icode"); void flushL2Range(UINT32 *ptr, UINT32 len); #endif /************************************************************************************ * chipInit, main & mainLoop: The first c routine called by c_int00 (the program * start) is main. Its subroutine chipInit initializes * the chip support library, sets up the DSP chip external memories & on the * master DSP, loads the external code from the boot ROM into external SDRAM. * The main routine then finishes initializations and jumps into mainLoop, which * never returns. ************************************************************************************/ void chipInit(){ INT32 errorCode; WRITE_REG(STATUS_REG_0, 0); //Clear the status register of its previous value CSL_init(); //Initialize the chip support library IRQ_resetAll(); //Disable all interrupts #if ( (defined(I_AM_MASTER_DSP))||((defined(REV_B))||(defined(REV_C))) ) auxCtl= DMA_AUXCTL_RMK(DMA_AUXCTL_AUXPRI_DMA, DMA_AUXCTL_CHPRI_LOWEST); DMA_setAuxCtl(auxCtl); /* set up DMA auxiliary control to give HPI (which uses it) the lowest priority. DMAs get priority over CPU. */ #elif (defined(REV_E)) //Not needed on Rev. E #endif /* Initialize the EMIF; if successful, on master load the non-IPRAM code sections. * If still no errors, the external initialization routines are called. * If there were errors, bits in status register 0 are set & the program halts. */ #if (defined(I_AM_MASTER_DSP)||defined(SIM)) errorCode= initEmif(); if (errorCode!= SUCCESS) { /* DSP is toast. */ SET_RBIT(STATUS_REG_0, SR_EMIF_ERROR); exit(1); } #endif #ifdef I_AM_MASTER_DSP errorCode= loadCode(); if (errorCode!= SUCCESS) { /* DSP is toast. */ SET_RBIT(STATUS_REG_0, SR_INIT_ERROR); SET_RBIT(STATUS_REG_2, errorCode); exit(1); } #endif } /************************************************************************************/ void main() { INT32 errorCode; chipInit(); errorCode= extInit(); mainLoop(); } /************************************************************************************ * extInit performs the rest of the initializations, running from slow memory. */ INT32 extInit() { INT32 errorCode, returnCode= SUCCESS; UINT32 rcm, t0, dt; UINT8 slv; strcat(versionStr, __DATE__); strcat(versionStr, " "); strcat(versionStr, __TIME__); /* Start timer1 using the maximum possible period. Timer1 will be used in the program to calculate delta-t, and using the maximum possible period allows us to simply subtract the two timer values since the answer will then be correct even if the timer wraps. (Note that timer1 is used in an initialization routine). See utilities.h for an explanation of the different periods. */ #if ( (defined(I_AM_MASTER_DSP))||((defined(REV_B))||(defined(REV_C))) ) timer1= startUserTimer(0xffffffff); #elif (defined(REV_E)) timer1= startUserTimer(0x3fffffff); #endif t0= TIMER_getCount(timer1); #if (!defined(REV_E)) #ifndef SIM /* clear the burst buffer & SDRAM */ rcm= setMem((UINT32 *) BURST_BFR_BASE, BURST_SZ/4, 0x0); #ifndef COMPACT rcm= setMem((UINT32 *) ERR_BFR_BASE, (SDRAM0_SZ -(XPROG_SZ))/4, 0x0); rcm= setMem((UINT32 *) (SDRAM1_BASE), (SDRAM1_SZ/4), 0x0); #endif #endif #endif //This little routine is used for quick DSP tests: #ifdef SIM simPreInit(); simInit1(); #endif errorCode = initialize(); if (errorCode != SUCCESS) { addError(&returnCode, errorCode, "main", "initialize", __FILE__, __LINE__); //The program will halt if anything goes wrong here; thus the text buffer //state machines will not work: the appropriate bit is set manually. setTxtBuffNE(ERR_BUFF); } /* enable interrupts on the DSP */ #if (defined(I_AM_SLAVE_DSP)) IRQ_nmiEnable(); IRQ_enable(IRQ_EVT_EXTINT4); //For ISR assoc. to ext. pin 4 (from router FPGA). IRQ_enable(IRQ_EVT_EXTINT5); //For ISR assoc. to ext. pin 5 (from controller FPGA). IRQ_enable(IRQ_EVT_DMAINT0); //For the DMA from the router. IRQ_globalEnable(); #endif #if (defined(I_AM_MASTER_DSP) && (!defined(SIM)) && (!defined(TI_EVM))) setLedState(RED_LED, OFF); delay(5000000); setLedState(YELLOW_LED, OFF); delay(2500000); setLedState(GREEN_LED, OFF); /* On Rev. E RODs, the SDSPs must have the bus address lines held high while the PRM resets them. For details see the discussion in resetRod.c in the resetSlave routine. Then initialize all the slaves' EMIF registers so that their SDRAM can be accessed (even if slave has not been started yet). On a Rev. E ROD, set the running rate of the SDSP clocks to 200 MHz (routine has no effect on other ROD Rev). This sequence is done inside the routine resetSlaveSync. Additionally, on a Rev. C ROD, check the synchronization of the clock on SDSP #3 and, if necessary, force it to be in phase with SDSP #0 (with which it shares the clock); this will help the router. */ for (slv= 0; slv < N_SDSP; ++slv) { if (!slvPresent(slv)) continue; resetSlaveSync(slv, FALSE, 1, 0x00800000, FALSE); } if (getRodRev() == 0xc) resetSlaveSync(3, TRUE, 10, 0x00800000, TRUE); #endif if (errorCode != SUCCESS) {startHeartbeatTimer(0x00400000); exit(errorCode); } else {startHeartbeatTimer(0x04000000); } codeVersion(); //Print out some useful information. setRunning(); //Set the running bit in status register 0. #if defined(SIM) simSetup(); simInit(); #endif dt= delta_t(t0); WRITE_REG(RESERVED_REG_0, dt); return returnCode; } /************************************************************************************ * mainLoop contains the (infinite) main polling loop. The polling loop tests the * DSP's main status & command registers and executes the associated state machine * code if the registers indicate that it's necessary. On the MDSP, the loop polls * the SDSPs at regular intervals to check if they need to transfer data, etc. */ void mainLoop() { INT32 status, returnCode; #if defined(I_AM_MASTER_DSP) UINT8 slv; UINT32 slvStat, statReg2; #endif static UINT32 loop= 0, t0= 0; UINT32 statReg0, cmdReg0, diagReg; while(1) { diagReg= READ_REG(DIAGNOSTIC_REG); if (diagReg & FIELD_MASK(DR_MAINLOOP_TOGGLE,1)) { #if defined(I_AM_MASTER_DSP) yellowLed_toggle; #elif defined(I_AM_SLAVE_DSP) fsxp0_toggle; #endif WRITE_REG(RESERVED_REG_3, delta_t(t0)+2); t0= TIMER_getCount(timer1); } #if ((defined(I_AM_SLAVE_DSP))&&(defined(REV_E))) //6713 Cache testing. Must remain here until prim buffer is moved into //non-cachable memory. if (diagReg & FIELD_MASK(DR_CACHE_FLUSH,1)) { RST_RBIT(DIAGNOSTIC_REG, DR_CACHE_FLUSH); newInformation(__FILE__, __LINE__, "cache flush!\n"); fsrp0_on; CACHE_flush(CACHE_L2ALL, (void*) 0x0, 0x0); fsrp0_off; } if (diagReg & FIELD_MASK(DR_CACHE_RANGE_FLUSH,1)) { RST_RBIT(DIAGNOSTIC_REG, DR_CACHE_RANGE_FLUSH); { UINT32 *ptr, len; ptr= (UINT32 *) READ_REG(RESERVED_REG_0); len= READ_REG(RESERVED_REG_1); flushL2Range(ptr, len); } } if (diagReg & FIELD_MASK(DR_CACHE_TOGGLE,1)) { RST_RBIT(DIAGNOSTIC_REG, DR_CACHE_TOGGLE); if (!cache_on) { newInformation(__FILE__, __LINE__, "caching on!\n"); cache_on= TRUE; fsrp0_on; cacheOn(); fsrp0_off; SET_RBIT(STATUS_REG_0, SR_CACHE_ACTIVE); } else { cache_on= FALSE; fsrp0_on; cacheOff(); fsrp0_off; newInformation(__FILE__, __LINE__, "caching off!\n"); RST_RBIT(STATUS_REG_0, SR_CACHE_ACTIVE); } } #endif statReg0= READ_REG(STATUS_REG_0); cmdReg0= READ_REG(COMMAND_REG_0); ++loop; WRITE_REG(LOOP_REG, loop); #if defined(I_AM_MASTER_DSP) statReg2= READ_REG(STATUS_REG_2); //needed later to check SDSP comm. status #endif /* The master DSP watches for slave DMA access requests from the host (for transfers of large blocks of data to the host); if one is requested, it turns off all slave communications until the handshake is complete. */ #if defined(I_AM_MASTER_DSP) /* The host makes a DMA request by setting a bit in the command register; if ACK is low, then the MDSP turns off all SDSP communications and sets ACK high */ if (cmdReg0 & FIELD_MASK(CR_DMA_ACCESS_REQ,1)) { if (!(statReg0 & FIELD_MASK(SR_DMA_ACCESS_ACK,1)) ) { ASGN_RFLD(STATUS_REG_2,SR_SLVCOMM(0),N_SDSP,0); SET_RBIT(STATUS_REG_0, SR_DMA_ACCESS_ACK); } } /* Host will reset the CR DMA request bit when DMA access is finished; during normal running nothing will be done here since the DMA access acknowledge bit won't have been set. If ACK is high, restore SDSP communications and reset ACK. */ else if (statReg0 & FIELD_MASK(SR_DMA_ACCESS_ACK,1)) { for (slv= 0; slv < N_SDSP; ++slv) { if (slaveIsOn(slv)) SET_RBIT(STATUS_REG_2, SR_SLVCOMM(slv)); } RST_RBIT(STATUS_REG_0, SR_DMA_ACCESS_ACK); } #endif /* execute any ongoing tasks */ if (statReg0 & FIELD_MASK(SR_NTASKS,SR_NTASKS_W)) { status= taskManager(); if (status != SUCCESS) { addError(&returnCode, status, "main", "taskManager", __FILE__, __LINE__); } } /* State machine which gets and executes host primitive lists */ if ( (statReg0 & FIELD_MASK(SR_DSP_ACK,1)) ||(cmdReg0 & FIELD_MASK(CR_IN_LIST_RDY,1)) ) { status= smHostListProc(); if (status != SUCCESS) { addError(&returnCode, status, "main", "smHostListProc", __FILE__, __LINE__); } #if (defined(I_AM_MASTER_DSP)) SET_RBIT(STATUS_REG_2, SR_SLVATTEND); //Watch SDSPs while list executes. #endif } /* S.M. to make text buffer contents available to host: 1 S.M. per buffer */ if (statReg0 & FIELD_MASK(SR_TXT_BUFF_PROC(0),N_TXT_BUFFS)) { status= sendTxtBuffs(); if (status != SUCCESS) { addError(&returnCode, status, "main", "sendTxtBuffs", __FILE__, __LINE__); } } /* Both MDSP & SDSP execute (if necessary) their inter-DSP list handling state machines. However, the MDSP does so only if it is actually communicating with a SDSP (as normally occurs when the SDSPs are running, except when a host initiated SDSP DMA transfer is running); communication is indicated by a bitfield (SR_SLVCOMM) within a status register. The MDSP must also check the slave DSPs every 32nd cycle; if they require further attention (by one of the MDSP state machines), it sets a flag in the status register, which will allow the MDSP to process the SDSPs on every loop until the flag is reset */ #if defined(I_AM_MASTER_DSP) //if ( (statReg2 & FIELD_MASK(SR_SLVCOMM(0),N_SDSP)) // &&((!(loop & 0x1f)) || (statReg2 & FIELD_MASK(SR_SLVATTEND,1))) ) { if ( (statReg2 & FIELD_MASK(SR_SLVCOMM(0),N_SDSP)) ) { #endif #if defined(I_AM_MASTER_DSP) RST_RBIT(STATUS_REG_2, SR_SLVATTEND); RST_RBIT(STATUS_REG_0, SR_IDLP_ACTIVE); for (slv= 0; slv < N_SDSP; ++slv) { if (!statReg2 & FIELD_MASK(SR_SLVCOMM(slv),1)) continue; /* get the slave's status register */ slvStat= getSlvReg(slv, STATUS_REG_0); /* now that we've retrieved the slave's status register, turn on the master DSP's own inter-DSP list processing flag if there is a list waiting. (set if any slave has a list waiting) */ if (slvStat & FIELD_MASK(SR_IDLS_ACTIVE,1)) { SET_RBIT(STATUS_REG_2, SR_SLVATTEND); SET_RBIT(STATUS_REG_0, SR_IDLP_ACTIVE); } /* S.M. which coordinates execution of a host primitive list which has been sent to a SDSP */ if (statReg2 & FIELD_MASK(SR_HLTS(slv),1)) { SET_RBIT(STATUS_REG_2, SR_SLVATTEND); status= smHostListToSlave(slv); if (status != SUCCESS) { addError(&returnCode, status, "main", "smHostListToSlave", __FILE__, __LINE__); } } /* Calls S.M.s which copy contents of a SDSP text buffer to the MDSP xferBuffer: 1 S.M. per text buffer per slave. */ if (slvStat & FIELD_MASK(SR_TXT_BUFF_PROC(0),N_TXT_BUFFS)) { SET_RBIT(STATUS_REG_2, SR_SLVATTEND); status= getSlvTxtBuffs(slv); if (status != SUCCESS) { addError(&returnCode, status, "main", "getSlvTxtBuffs", __FILE__, __LINE__); } } } /* loop over slaves */ #endif /* State machine which gets & executes prim lists from another DSP: note that the SDSP must be notified of this by the MDSP setting a bit within its status register, whereas the MDSP polls the SDSPs to see if they have lists to send, and sets a bit within its own status reg. if so. */ #if defined(I_AM_MASTER_DSP) if (statReg0 & FIELD_MASK(SR_IDLP_ACTIVE,1)) { status= smIntrDspListProc(); if (status != SUCCESS) { addError(&returnCode, status, "main", "smIntrDspListProc", __FILE__, __LINE__); } } #elif defined(I_AM_SLAVE_DSP) if (cmdReg0 & FIELD_MASK(CR_IDLP_ACTIVE,1)) { status= smIntrDspListProc(); if (status != SUCCESS) { addError(&returnCode, status, "main", "smIntrDspListProc", __FILE__, __LINE__); } } #endif /* State machine which sends a prim list to another DSP to execute */ if (statReg0 & FIELD_MASK(SR_IDLS_ACTIVE,1)) { status = smIntrDspListSend(); if (status != SUCCESS) { addError(&returnCode, status, "main", "smIntrDspListSend", __FILE__,__LINE__); } } #if defined(I_AM_MASTER_DSP) } /* communication with SDSPs is enabled */ #endif #ifdef COMMENTED #if ((defined(I_AM_SLAVE_DSP))&&(!defined(COMPACT))) /* On a SDSP, check for new & handle processed events */ #ifndef NEWISR /* SR bit set when event manager is running, then speed up inside the EM to shorten work when no new evts. */ if (statReg0 & FIELD_MASK(SR_EVM,1)) { status= eventManager(); if (status != SUCCESS) { addError(&returnCode, status, "main", "eventManager", __FILE__, __LINE__); } } #endif #endif #endif } /* main polling loop */ } #if ((defined(I_AM_SLAVE_DSP))&&(defined(REV_E))) void flushL2Range(UINT32 *ptr, UINT32 len) { // UINT32 // CACHE_clean(CACHE_L2, (void*) cacheTest->range, cacheTest->rsize); } void cacheOn() { CACHE_enableCaching(CACHE_CE20); CACHE_enableCaching(CACHE_CE21); CACHE_enableCaching(CACHE_CE22); CACHE_enableCaching(CACHE_CE23); CACHE_enableCaching(CACHE_CE30); CACHE_enableCaching(CACHE_CE31); CACHE_enableCaching(CACHE_CE32); CACHE_enableCaching(CACHE_CE33); CACHE_setL2Mode(CACHE_64KCACHE); } void cacheOff() { CACHE_clean(CACHE_L2ALL, (void*) 0x0, 0x0); //CACHE_flush(CACHE_L2ALL, (void*) 0x0, 0x0); CACHE_setL2Mode(CACHE_0KCACHE); CACHE_reset(); } #endif