/************************************************************************************* * simulation.c * * synopsis: A collection of routines which simulate the host & slave DSP's responses * to various Master/Slave DSP signals. The intent is to remove from the * rest of the code as many #defines as possible (to improve readability) and to * automate some of the more complex responses in a transparent fashion to the * rest of the code. * * in this file: * * Douglas Ferguson, UW Madison (510)486-5230 dpferguson@lbl.gov ************************************************************************************/ #include #include #include #include #include #include #if ( (defined(I_AM_MASTER_DSP))||((defined(REV_B))||(defined(REV_C))) ) #include #elif (defined(REV_E)) #include #endif #include #include "resources.h" #include "simulation.h" #include "peripheralMap.h" #include "comRegDfns.h" #include "histogram.h" #if defined(I_AM_MASTER_DSP) #include "registerIndices.h" #include "accessRegister.h" #include "rodMemoryMap.h" #elif defined(I_AM_SLAVE_DSP) // #include "eventHandler.h" #endif #pragma CODE_SECTION(simRod, "xcode"); void simRod(void); #ifndef SIM void simRod(void) {} /************************************************************************************/ #else #pragma CODE_SECTION(simPreInit, "xcode"); #pragma CODE_SECTION(simInit1, "xcode"); #pragma CODE_SECTION(simInit, "xcode"); #pragma CODE_SECTION(simSetup, "xcode"); #pragma CODE_SECTION(async, "icode"); /* external global variables */ extern char genStr[]; extern TIMER_Handle timer1; /* general purpose timer, started in main() */ extern UINT32 intrDspListSendState; /* hi-jack timer 0 for use as an asynchronous scheduling routine */ extern TIMER_Handle hHeartbeatTimerCh; extern far CommRegs commRegs; UINT32 simLast= 0; UINT32 heartbeatEvtId; #if (defined(I_AM_MASTER_DSP)) extern RodConfig rodConfig; extern far RodModeCfg rodModeCfg[]; extern far MasterHistoCtrl hc; UINT32 asyncPeriod= 0x140; // 8 us #pragma CODE_SECTION(simSlaves, "xcode"); #pragma CODE_SECTION(copySdspRegs, "xcode"); #pragma CODE_SECTION(remapSdspPtr, "xcode"); void simSlaves(void); #pragma CODE_SECTION(simFpgaCheck, "xcode"); #pragma CODE_SECTION(simTriggerArm, "xcode"); #pragma CODE_SECTION(simTriggers, "xcode"); #pragma CODE_SECTION(simSdspEvtStart, "xcode"); #pragma CODE_SECTION(simSdspEvtEnd, "xcode"); #pragma CODE_SECTION(simSdspEvtProc, "xcode"); void simTriggers(); void simSdspEvtStart(UINT32 sdsp); void simSdspEvtEnd(UINT32 sdsp); void simSdspEvtProc(UINT32 sdsp); #elif (defined(I_AM_SLAVE_DSP)) extern far TaskMgrCtrl taskMgrCtrl; extern far struct EvtMgrCtrl evtMgrCtrl; extern far HistoCtrl histoCtrl; #if (defined(REV_B)||defined(REV_C)) extern DMA_Handle hBurstDataDmaCh; extern DMA_Config burstDmaConfig; #elif (defined(REV_E)) extern EDMA_Handle hBurstDataDmaCh; extern EDMA_Config burstDmaConfig; #endif extern char currentFrame; UINT32 asyncPeriod= 0x380; //16 us #if (defined(REV_B)||defined(REV_C)) #define ROUTER_BASE 0x03000000 #elif (defined(REV_E)) #define ROUTER_BASE 0xb7000000 #endif void cacheOn(void); void cacheOff(void); #define ROUTER_CMD_REG (ROUTER_BASE) /* bottom of router area, data at +0x20 */ #define SIMRTR_DATACHK 0 #define SIMRTR_DATARDY 1 #define SIMRTR_DMATRIG 2 #define SIMRTR_DMADONE 3 struct RouterData { UINT32 nRouterFrames, getRegs, *b0f, *e0f, calcLength, fixLength; UINT32 trapEnable, pin4Set; UINT32 *routerCmdReg, *routerFramesReg, *trapEnableReg, *pin4Reg; UINT32 currentFrame, *base, state; } routerData; #pragma CODE_SECTION(simRouter, "xcode"); void simRouter(void); #pragma CODE_SECTION(oddSCTLinkFix, "xcode"); #endif /************************************************************************************ * simSetup * synopsis: Hi-jack timer 0 for our own nefarious purposes. ************************************************************************************/ void simSetup() { UINT32 timerCtl; TIMER_close(hHeartbeatTimerCh); hHeartbeatTimerCh= TIMER_open(HEARTBEAT_TIMER_CH, TIMER_OPEN_RESET); timerCtl= TIMER_CTL_RMK(TIMER_CTL_INVINP_NO, TIMER_CTL_CLKSRC_CPUOVR4, TIMER_CTL_CP_PULSE, TIMER_CTL_HLD_NO, TIMER_CTL_GO_YES, TIMER_CTL_PWID_ONE, TIMER_CTL_DATOUT_0, TIMER_CTL_INVOUT_NO, TIMER_CTL_FUNC_TOUT); /* Configure with a larger period at init to get to main-loop code. Problems also develop when the timer 0 channel IRQ is enabled, if the period is small and the IRQ code is in running out of slow memory (which it is)- simulator gets stuck in infinite loop in async. The async function will set up the actual period the when it executes & discovers itself in the main loop. */ TIMER_configArgs(hHeartbeatTimerCh, timerCtl, 0x1000, 0x1); //dpsf 260706: sdsp sim prob. TIMER_configArgs(hHeartbeatTimerCh, timerCtl, 0x500, 0x1); TIMER_setCount(hHeartbeatTimerCh, 0x1); heartbeatEvtId = TIMER_getEventId(hHeartbeatTimerCh); #if (defined(I_AM_MASTER_DSP)) IRQ_clear(heartbeatEvtId); IRQ_enable(heartbeatEvtId); IRQ_nmiEnable(); IRQ_globalEnable(); #elif (defined(I_AM_SLAVE_DSP)) IRQ_clear(heartbeatEvtId); IRQ_enable(heartbeatEvtId); #endif } /************************************************************************************ * async * synopsis: Interrupt which triggers off the hi-jacked timer 0; transparently * allows different reponses on the ROD to be simulated. The routine * will only execute its functions if the main loop has also gotten some time; * otherwise functions like simRouter (which takes a considerable amount of time * to handle its tasks) would send async into an endless loop. ************************************************************************************/ interrupt void async() { UINT32 reg, deltaLoop= 6; static UINT8 change= TRUE; pauseTimer(1); pauseTimer(0); /* To change the async period, force the change var. to TRUE using the CCS quick watch window & a breakpoint at the if statement. The read of the loop register forces async to wait until it's in the main loop to begin triggering. */ if ((change) && (READ_REG(LOOP_REG) > 0)) { change= FALSE; TIMER_setCount(hHeartbeatTimerCh, 0x1); TIMER_setPeriod(hHeartbeatTimerCh, asyncPeriod); } #if (defined(I_AM_MASTER_DSP)) //Regardless of other async functions, handle any sim events: simTriggers(); #endif /* Sending inter-dsp lists is a special case, since they run inside the idspSend routine (i.e. the main loop is not running). Pretend that it is by incrementing the loop register. Increase the delta between checks as well since the routine is a bit slower */ if (intrDspListSendState != 0) { reg= READ_REG(LOOP_REG); WRITE_REG(LOOP_REG, reg +1); deltaLoop= 18; } reg= READ_REG(LOOP_REG); if (reg > (simLast +deltaLoop)) { simLast= reg; //Only simulate host environment (main loop) if idsp is idle: if (intrDspListSendState == 0) simRod(); #if (defined(I_AM_MASTER_DSP)) simSlaves(); #elif (defined(I_AM_SLAVE_DSP)) simRouter(); #endif } resumeTimer(0); resumeTimer(1); } #if (defined(I_AM_MASTER_DSP)) /************************************************************************************ * simPreInit * synopsis: Performs any needed modifications to the ROD registers before the main * initialization routines run. ************************************************************************************/ void simPreInit() { /* Have no access to the rodRegister array yet, so use constants. The 1st is to set the ROD board type, and the 2nd indicates that all 4 SDSP are present. */ WRITE_REG((REG_BASE)+(((RCF_BASE)+(0x0103))<<2), 0xe21); WRITE_REG((REG_BASE)+(((RTR_BASE)+(0x0043))<<2), 0xe2a); WRITE_REG((REG_BASE)+(((EFB_BASE)+(0x0087))<<2), 0xe2b); #if defined(SCT_ROD) WRITE_REG((REG_BASE)+(((FMT_BASE)+(0x0022))<<2), 0x0e25); #elif defined(PIXEL_ROD) WRITE_REG((REG_BASE)+(((FMT_BASE)+(0x0022))<<2), 0x8e25); #endif WRITE_REG((REG_BASE)+(((RCF_BASE)+(0x0109))<<2), 0x79000000); //Quick test for BOC: WRITE_REG((REG_BASE)+(((BOC_BASE)+(0x03d3))<<2), 0x67); WRITE_REG((REG_BASE)+(((BOC_BASE)+(0x03d8))<<2), 0x63); } /************************************************************************************ * simInit1 * synopsis: Debugging tool for quick tests upon startup. ************************************************************************************/ void simInit1() { UINT32 t0, stat, a= 4; //setLinkMasks(0xfff0, 0x0ff0000f, 0, DATA_LINK, 0, 1); //setLinkMasks(0x000f, 0xf00ffff0, 1, DATA_LINK, 0, 1); //setLinkMasks(0xfff0, 0x0ff0000f, 0, DATA_LINK, 0, 1); } /************************************************************************************ * simInit * synopsis: Initializes the ROD simulation routines. ************************************************************************************/ void simInit() { simRod(); simSlaves(); } /************************************************************************************ * simRod * synopsis: Simulates the asychronous responses from different parts of the * DSP's environment using a collection of hacks. ************************************************************************************/ void simRod() { UINT8 i; if (GET_RBIT(COMMAND_REG_0,CR_IN_LIST_RDY)) { if (GET_RBIT(STATUS_REG_0, SR_DSP_ACK)) { RST_RBIT(COMMAND_REG_0,CR_IN_LIST_RDY); } } for (i=0; i MDSP signal ("interrupt") register. When the SDSP drives its pin (ext pin 5) high, the corresponding bit in this register goes low, so 0xf => all ok: */ writeRegister(INTRPT_FROM_SLV, 4, 0, 0xf); } } else if ((reg == FE_MASK_LUT_SELECT)) { status= readRegister(CMND_MASK_LUT(val, 0, 0), 32, 0, &v[0]); status= readRegister(CMND_MASK_LUT(val, 0, 1), 16, 0, &v[1]); writeRegister(FE_CMND_MASK_0_LO, 32, 0, v[0]); writeRegister(FE_CMND_MASK_0_HI, 16, 0, v[1]); status= readRegister(CMND_MASK_LUT(val, 1, 0), 32, 0, &v[0]); status= readRegister(CMND_MASK_LUT(val, 1, 1), 16, 0, &v[1]); writeRegister(FE_CMND_MASK_1_LO, 32, 0, v[0]); writeRegister(FE_CMND_MASK_1_HI, 16, 0, v[1]); } } } /************************************************************************************ * simTriggerArm, * simTriggers * synopsis: The arming routine sets up the simulation routines so that the will * simulate passage of an 'event' through the ROD. It does this by * temporarily lowering the period for the async interrupt so that it can * set the EFB registers rapidly for the watching scan routines; at the end * of the data 'transmission' the SDSP registers are updated. * * Once armed, the simTriggers routine is run until the event is finished. The * event length is normally set by a quick calculation (below) involving the * current bin number & length; this can be overridden though if the flag below * is set (using CCS's quick watch window, for example). ************************************************************************************/ //Bitfields (hex) & other variables shared by the cooperating sim-trigger routines: UINT32 simTriggerSent= 0x0, simTriggerInit= 0x0, simFmtXmit=0x0, simFmtWait= 0x0, simFmtXfer= 0x0, simFmtXferDone= 0x0, simEfbWait= 0x0, simEfbXfer= 0x0, simRtrXferInit= 0x0, simRtrXfer= 0x0, simEvtReceived= 0x0; UINT32 simFmtXferQueue[20], simEfbXferQueue[20], fmtXferCnt= 0, efbXferCnt= 0; UINT32 simEvtLenAvg= 0x185; //Arbitrary. UINT32 setSimEvtLen= FALSE, fixedSimEvtLen= FALSE; float simSigmaLen= 0.1; UINT8 fastAsync= FALSE; //Flag indicating that async is executing frequently. //Event Length in bits for modules => formatters, words for transit through Rod. UINT32 simEvtLen[N_SDSP][2], simXmitStart[N_SDSP][2], simXmitTime[N_SDSP][2]; //Processing times on SDSPs: UINT32 simProcStart[N_SDSP]= {0, 0, 0, 0}, simProcTime[N_SDSP]= {0, 0, 0, 0}, simProcLen[N_SDSP]= {0, 0, 0, 0}; float usPerWord; UINT32 simEventProcQueue[N_SDSP]= {0, 0, 0, 0}; UINT32 simTriggerCnt[N_SDSP]= {0, 0, 0, 0}, simEvtCount[N_SDSP]= {0, 0, 0, 0}; UINT8 simErrFlag[N_SDSP]= {FALSE, FALSE, FALSE, FALSE}; //Crude 3 sigma double-sided error fxn approx: float errf[]= {0.0013f, 0.021f, 0.158f, 0.5f, 0.8413f, 0.977f, 0.9986f}; /************************************************************************************/ void simTriggerArm(UINT32 sdsp) { static UINT8 first= TRUE; int i, dLen, nLinks, nMod, nHits; float sigma, del; //Seed the random number generator on 1st pass: if (first) {first= FALSE; srand48(TIMER_getCount(timer1)); } /* The bitfields serve as state-machines for the routines. Trigger sending & transmission are decoupled for greater flexibility. */ simTriggerSent|= (1<rodSetup.routineType == HISTO_ROUTINE_C) { if (hc.scan->rodSetup.opt[0]) usPerWord= 2.0f; else usPerWord= 1.0f; } else { if (hc.scan->rodSetup.opt[0]) usPerWord= 0.093f; else usPerWord= 0.05f; } #elif (defined(PIXEL_ROD)) #endif if (fixedSimEvtLen) del= 0.0; else { sigma= (float) drand48(); for (i=0; i<7; ++i) if (sigma <= errf[i]) break; if (i == 7) --i; del= 1.0 -2.0*errf[i]; } if (setSimEvtLen) { //Fixed event length/module: simEvtLen[sdsp][0]= simEvtLenAvg; simEvtLen[sdsp][1]= simEvtLenAvg>>5; // simply convert bits => words } else { //Find using current bin: nMod= hc.dspInfo[sdsp].nModules; #if (defined(SCT_ROD)) nLinks= 2*nMod; //Header +Trailer & sync bits: simEvtLen[sdsp][0]= 5 +1 +4 +8 +1 +16; simEvtLen[sdsp][1]= 0x0; #elif (defined(PIXEL_ROD)) nLinks= nMod; //40 MHz. //Header +Trailer & sync, +16*fe-id bits: simEvtLen[sdsp][0]= RodModeCfg[0].evtsPerL1A*(5 +8 +1 +8 +1 +22 +16*9); //Each link gives header +trailer (1 w ea.) => 2 w/module: simEvtLen[sdsp][1]= 2*RodModeCfg[0].evtsPerL1A; #endif #if (defined(SCT_ROD)) if (hc.cfgReg[0] == ST_NMASK) { fixedSimEvtLen= TRUE; /* len= (17 bits 1st channel +127*4 subsequent hits)*6 chips/link => approx 100 words for bin 0; this -> 0 words for bin 128, where instead a no-hit data packet is sent. */ if (hc.status->currentBin[0] == 128) { nHits= 0; dLen= 6*3; } else { nHits= 6*(128 -hc.status->currentBin[0]); dLen= 6*(17 +4*(127 -hc.status->currentBin[0])); } simEvtLen[sdsp][0]+= dLen; //clustered hits => formatters convert to 2 hits/half-word. simEvtLen[sdsp][1]+= nHits>>2; } else if (hc.cfgReg[0] == ST_VTHR) { //another frequent one: fixedSimEvtLen= FALSE; /* len = (17 bits * 32 chan * occupancy)*6 chips here we arbitrarily decide (can add more detail later if needed) that bin 0 => 0, above/at bin 32 => 100% : */ if (hc.status->currentBin[0] >= 32) nHits= 6*32; else nHits= 6*hc.status->currentBin[0]; del= del*simSigmaLen*(1.0*nHits); nHits+= (int) del; if (nHits < 0) nHits= 0; if (nHits == 0) dLen= 6*3; else dLen= 17*nHits; simEvtLen[sdsp][0]+= dLen; //non-clustered hits => formatters convert to 1 hit/half-word. simEvtLen[sdsp][1]+= nHits>>1; } else { //Arbitrary & fixed for others: if (hc.status->currentBin[0] == 0) {nHits= 0; dLen= 6*3; } else { nHits= hc.status->currentBin[0]*2; dLen= 17*nHits; } simEvtLen[sdsp][0]+= dLen; simEvtLen[sdsp][1]+= nHits>>1; } #elif (defined(PIXEL_ROD)) if (hc.cfgReg[0] == SCAN_VCAL) { //frequently: fixedSimEvtLen= FALSE; /* len = (22 bits * 90 pixels * occupancy)*16 chips here we arbitrarily decide (can add more detail later if needed) that bin 0 => 0, above/at bin 32 => 100% : */ if (hc.status->currentBin[0] >= 32) nHits= 16*90; else nHits= 16*90*hc.status->currentBin[0]>>5; } else { //Arbitrary for others: } del= del*simSigmaLen*(1.0*nHits); nHits+= (int) del; if (nHits < 0) nHits= 0; dLen= 22*nHits; simEvtLen[sdsp][0]+= dLen; simEvtLen[sdsp][1]+= nHits; //formatters convert to 1 hit/word. #endif } //Choose nHits based on bin. simEvtLen[sdsp][1]*= nLinks; #if (defined(SCT_ROD)) //If hits present, each link gives half-word header, 2 links => 1 w/module. if (nHits > 0) simEvtLen[sdsp][1]+= 1; #endif simEvtLen[sdsp][1]+= 0x10; //0x10 => header +trailer. simXmitStart[sdsp][0]= TIMER_getCount(timer1); simXmitTime[sdsp][0]= (8*simEvtLen[sdsp][0])>>5; // .8 us/w. in 1/10th us simXmitTime[sdsp][1]= (8*simEvtLen[sdsp][1])>>5; // .8 us/32 w. (1/10th us) simProcTime[sdsp]= (int) (10.0*usPerWord*(1.0*simEvtLen[sdsp][1])); } /************************************************************************************/ void simTriggers() { //simTriggers is called by async UINT32 sdsp, fmt, i, j, dt, t0, cnt, inc, efbCntEnabled, lut, val, v[2]; INT32 status; status= readRegister(EFB_CMND_0, 1, EFB_GROUP_COUNTER_EN_O, &efbCntEnabled); //Update the bandwidth counters: if (efbCntEnabled) { t0= TIMER_getCount(timer1);; dt= t0 -lastEfbCntTime; lastEfbCntTime= t0; cnt= dt; // => 40/us //cnt= dt/40; // => 1/us /* The bandwidth counter has two half-word fields: The upper field always increments while it's enabled; the lower field only increments when the formatters are transmitting data into the EFB. Since if the formatters are getting data transmitted into them, at least one link (the 1st one which is enabled that receives the token) will also be playing out into the EFB unless forced to wait (i.e. by a previous event), the counter is allowed to run if the formatters are gathering data as well. */ if (simFmtXmit || simFmtXfer) inc= (cnt<<16) +cnt; else inc= (cnt<<16); status= readRegister(EFB_BANDWIDTH_CNT, 32, 0, &cnt); writeRegisterDirect(EFB_BANDWIDTH_CNT, 32, 0, (cnt+= inc)); } //Exit if no triggers being sent (nothing left to do): if ((!simTriggerSent) && (fastAsync)) { //Restore the previous period. fastAsync= FALSE; TIMER_setCount(hHeartbeatTimerCh, 0x1); TIMER_setPeriod(hHeartbeatTimerCh, asyncPeriod); return; } for (sdsp=0; sdsp formatters: for (fmt=0; fmt Formatters if (simFmtXmit & (1<= simXmitTime[sdsp][0]) { simFmtXmit&= ~(1<= simXmitTime[sdsp][1]) { simFmtXfer&= ~(1< Formatters => EFB if (simEfbWait & (1<= simXmitTime[sdsp][1]) { simEfbXfer&= ~(1< Formatters => EFB => Router if (simRtrXferInit & (1<= simXmitTime[sdsp][1]) { simRtrXferInit&= ~(1<= simXmitTime[sdsp][1]) { simRtrXfer&= ~(1< Formatters => EFB => Router => SDSP if (simEvtReceived & (1<= simProcTime[sdsp]) { --simEventProcQueue[sdsp]; simSdspEvtProc(sdsp); simProcStart[sdsp]= simProcLen[sdsp]= 0; rstSlvRegBit(sdsp, SDSP_HSTATUS_REG_0, HSR0_SLV_PROC); } } } //Event processing loop. } /************************************************************************************ * simSdspEvtStart, simSdspEvtEnd * synopsis: Update the simulated sdsp's trapping communication registers to * signal event start & end. ************************************************************************************/ void simSdspEvtStart(UINT32 sdsp) { UINT32 tcmd, tstat[3], tseries[2], cf, cnt; tcmd= getSlvReg(sdsp, TRAP_CMD_REG1); tstat[0]= getSlvReg(sdsp, TRAPSTAT_REG1_0); tstat[1]= getSlvReg(sdsp, TRAPSTAT_REG1_1); tstat[2]= getSlvReg(sdsp, TRAPSTAT_REG1_2); tseries[0]= GET_VFLD(tcmd, TCMD_EVTSERIES, TCMD_EVTSERIES_W); tseries[1]= GET_VFLD(tstat[0], TSR0_EVTSERIES, TSR0_EVTSERIES_W); if (tseries[1] != tseries[0]) { tstat[1]= 0; ASGN_VFLD(tstat[0], TSR0_EVT_WORD_CNT, TSR0_EVT_WORD_CNT_W, 0); ASGN_VFLD(tstat[0], TSR0_EVTSERIES, TSR0_EVTSERIES_W, tseries[0]); } ASGN_VFLD(tstat[0], TSR0_EVTSERIES, TSR0_EVTSERIES_W, tseries[0]); ASGN_VFLD(tstat[0], TSR0_TRAILER, 4, 0xe); //active +header +xmit setSlvReg(sdsp, TRAPSTAT_REG1_0, tstat[0]); setSlvReg(sdsp, TRAPSTAT_REG1_1, tstat[1]); setSlvReg(sdsp, TRAPSTAT_REG1_2, tstat[2]); } /************************************************************************************/ void simSdspEvtEnd(UINT32 sdsp) { UINT32 tstat[3], fLen, cf, cnt; tstat[0]= getSlvReg(sdsp, TRAPSTAT_REG1_0); tstat[1]= getSlvReg(sdsp, TRAPSTAT_REG1_1); tstat[2]= getSlvReg(sdsp, TRAPSTAT_REG1_2); fLen= (simEvtLen[sdsp][1]>>8) +1; //256 w/frame. cf= GET_VFLD(tstat[2], TSR2_IFRAME_TAIL, TSR2_IFRAME_TAIL_W); cf+= fLen; if (cf > 31) cf-= 32; ASGN_VFLD(tstat[2], TSR2_IFRAME_TAIL, TSR2_IFRAME_TAIL_W, cf); cnt= GET_VFLD(tstat[1], TSR1_EVT_COUNT, TSR1_EVT_COUNT_W); ASGN_VFLD(tstat[1], TSR1_EVT_COUNT, TSR1_EVT_COUNT_W, cnt +1); if (simErrFlag[sdsp]) { cnt= GET_VFLD(tstat[1], TSR1_ERR_COUNT, TSR1_ERR_COUNT_W); ASGN_VFLD(tstat[1], TSR1_ERR_COUNT, TSR1_ERR_COUNT_W, cnt +1); } cnt= GET_VFLD(tstat[0], TSR0_EVT_WORD_CNT, TSR0_EVT_WORD_CNT_W); cnt+= simEvtLen[sdsp][1]; ASGN_VFLD(tstat[0], TSR0_EVT_WORD_CNT, TSR0_EVT_WORD_CNT_W, cnt); ASGN_VFLD(tstat[0], TSR0_TRAILER, 4, 0x5); //header +trailer setSlvReg(sdsp, TRAPSTAT_REG1_0, tstat[0]); setSlvReg(sdsp, TRAPSTAT_REG1_1, tstat[1]); setSlvReg(sdsp, TRAPSTAT_REG1_2, tstat[2]); } /************************************************************************************/ void simSdspEvtProc(UINT32 sdsp) { UINT32 tstat2, procTime, fLen, cf, cnt; tstat2= getSlvReg(sdsp, TRAPSTAT_REG1_2); fLen= (simProcLen[sdsp]>>8) +1; //256 w/frame. cf= GET_VFLD(tstat2, TSR2_IFRAME_HEAD, TSR2_IFRAME_HEAD_W); cf+= fLen; if (cf > 31) cf-= 32; ASGN_VFLD(tstat2, TSR2_IFRAME_HEAD, TSR2_IFRAME_HEAD_W, cf); cnt= getSlvReg(sdsp, SDSP_HSTATUS_REG_1); setSlvReg(sdsp, TRAPSTAT_REG1_2, tstat2); setSlvReg(sdsp, SDSP_HSTATUS_REG_1, (++cnt)); setSlvReg(sdsp, SDSP_HSTATUS_REG_3, simProcTime[sdsp] /* in 1/10th us */); } /************************************************************************************ * simSlaves * synopsis: Simulates the responses from the slave DSPs. ************************************************************************************/ void simSlaves() { static UINT8 first= TRUE, iDspRunning[]= {FALSE, FALSE, FALSE, FALSE}; static UINT32 iDspInit[4]; UINT8 slv, iDspILR, iDspAck; UINT32 val; if (first) { first= FALSE; /* Turn SDSPs on, and then let them be 'histogramming'. Space for the SDSP communication registers is reserved in SDRAM on the MDSP in simulation. The different SDSPs are separated by a line of 0xffffffff. */ for (slv= 0; slvEXP? if ( (getSlvRegBit(slv, HCMD_STAT_REG_0, HCMD_SLV_NEWBIN)) &&(!getSlvRegBit(slv, SDSP_HSTATUS_REG_0, HSR0_SLV_EXP)) ){ setSlvReg(slv, HCMD_STAT_REG_1, 0); setSlvRegBit(slv, SDSP_HSTATUS_REG_0, HSR0_SLV_EXP); rstSlvRegBit(slv, SDSP_HSTATUS_REG_0, HSR0_SLV_DONE); } //If in the waiting state of the scan task, assume SDSPs are finished: if (getTaskState(HISTOGRAM_CTRL_TASK) == 6) { //Waiting for SDSPs //Simply assume that SDSPs are also done: rstSlvRegBit(slv, SDSP_HSTATUS_REG_0, HSR0_SLV_EXP); setSlvRegBit(slv, SDSP_HSTATUS_REG_0, HSR0_SLV_DONE); } //Is this slave processing an inter-DSP list? if (getSlvRegBit(slv, COMMAND_REG_0, CR_IDLP_ACTIVE)) { /* Note that as we're simulating a SDSP while actually running the MDSP, the definitions of the read/write handshake registers will be reversed for the SDSP. */ iDspILR= getSlvRegBit(slv, INTR_DSP_HSHK_WR, INTR_DSP_IN_LIST_RDY); //The iDspILR is also checked as a precaution, in case MDSP winds up //doing something once the slave ack goes low & this routine runs //again. if ((!iDspRunning[slv])&&(iDspILR)) { iDspRunning[slv]= TRUE; iDspInit[slv]= TIMER_getCount(timer1); } else { iDspAck= getSlvRegBit(slv, INTR_DSP_HSHK_RD, INTR_DSP_ACK); //List "finishes" in 20 microseconds. if ((iDspILR)&&(!iDspAck)&&(delta_t(iDspInit[slv]) > 200)) { setSlvRegBit(slv, INTR_DSP_HSHK_RD, INTR_DSP_ACK); setSlvRegBit(slv, INTR_DSP_HSHK_RD, INTR_DSP_OUT_LIST_RDY); } else if ((iDspAck)&&(!iDspILR)) { rstSlvRegBit(slv, INTR_DSP_HSHK_RD, INTR_DSP_ACK); iDspRunning[slv]= FALSE; } } } //End of inter-DSP list processing. } } } /************************************************************************************* * copySdspRegs * * synopsis: Copies the SDSP communication section to or from SDSP IDRAM. ************************************************************************************/ void copySdspRegs(UINT32 sdsp, UINT32 toIdram) { UINT32 *src, *dest; if (toIdram) { src= (UINT32 *) SIM_SDSP_REG_BASE(sdsp); dest= (UINT32 *) ((SIM_SDSP_IMEM_BASE(sdsp)) +SDSP_IDRAM_BASE_REVE); } else { src= (UINT32 *) ((SIM_SDSP_IMEM_BASE(sdsp)) +SDSP_IDRAM_BASE_REVE); dest= (UINT32 *) SIM_SDSP_REG_BASE(sdsp); } copyMem(src, dest, SIZEOF(CommRegs)); } /************************************************************************************* * remapSdspPtr * * synopsis: The simulated SDSP memory contains 3 sections: * 1) simulated SDSP communications registers, * 2) a set of 4 "internal memories" with the realistic 265 KB sizes, and * 3) a set of 4 "external memories" which are 2 MB each. * * The grouping is done in order to facilitate easy viewing of (esp.) the SDSP * communication registers while running the simulator. The Ptr routine is * for getting blocks of data from the SDSP-- it is called esp. by the read & * write sdsp block functions. These functions maintain the consistency between * the convenient set (1) and the SRAM block by copying set 1 to & from set 2 * during an access. * ************************************************************************************/ UINT32 *remapSdspPtr(UINT32 sdsp, UINT32 *sdspPtr) { UINT32 ptr= (UINT32) sdspPtr, mask; //Quick convert from Rev. B/C Rod: if ((ptr >= 0x80000000) && (ptr < 0x80010000)) ptr-= (0x80000000); if ((ptr >= 0x02000000) && (ptr < 0x04000000)) ptr+= (0xa0000000 -0x02000000); if (ptr < 0x00040000) return (UINT32 *) (SIM_SDSP_IMEM_BASE(sdsp) +ptr); else if ((ptr >= 0xa0000000) && (ptr < 0xa0200000)) { return (UINT32 *) (SIM_SDSP_XMEM0_BASE(sdsp) +ptr -0xa0000000); } else if (ptr >= 0xa0200000) { //Beyond the 1st 2 MB the sim SDSP memories wrap. mask= 0x000fffff; ptr&= mask; return (UINT32 *) (SIM_SDSP_XMEM1_BASE(sdsp) +ptr); } else return (UINT32 *) SIM_SDSP_XMEM1_BASE(sdsp); } #if 0 uint32 *remapSdspCReg(uint32 sdsp, uint32 *sdspPtr) { uint32 ptr= (uint32) sdspPtr; ptr&= 0x7f; // the mask removes any part of the address which is > 32 words. return (uint32 *) (SIM_SDSP_REG_BASE(sdsp) +ptr); } #endif #elif (defined(I_AM_SLAVE_DSP)) /************************************************************************************ * simPreInit * synopsis: Performs any needed modifications to the SDSP environment before the * main initialization routines run. ************************************************************************************/ void simPreInit() { } /************************************************************************************ * simInit1 * synopsis: Debugging tool for quick tests upon startup. ************************************************************************************/ #if 1 void simInit1() {return; } #else void simInit1() { //short coefs[10][4]; //int optr[10][2]= {1,1, 2,2, 3,3, 4,4, 5,5, 6,6, 7,7, 8,8, 9,9, 0xa,0xa}; //int state[2]= {0xa, 0xa}; struct EventData data; INT32 returnCode; UINT32 dataType[2]= {0x2a,0x2a}, nBins= 0xa; UINT32 stage, bin, ptr[2]; UINT32 t0, t1, t2, t3, dt_c, dt_asm, dt_asm2; //SCT: UINT32 opt[]= {TRUE, HISTOGRAM_CONDENSED, 0, 0}; //UINT32 validModules[2]= {0xfffffff1, 0x0000ffff}, *base= (UINT32 *) 0xffffffff; //Pixel: //UINT8 opt[]= {TRUE, TRUE, 0x10, 16}; //UINT32 opt[]= {TRUE, TRUE, 0x00, 16}; //UINT32 validModules[2]= {0x00001111, 0x0}; #if defined(SCT_ROD) UINT32 binSize= HISTOGRAM_32BIT, routineType= HISTO_ROUTINE_ASM; UINT32 validModules[2]= {0x00000056, 0x0000}; //modules 0, 2, 4 & 6 //UINT32 validModules[2]= {0x00000055, 0x0000}; //modules 0, 2, 4 & 6 //UINT32 validModules[2]= {0xffffffff, 0xffff}; //All modules #elif defined(PIXEL_ROD) UINT32 binSize= HISTOGRAM_16BIT, routineType= HISTO_ROUTINE_ASM; UINT32 validModules[2]= {0x00000080, 0x0}; #endif UINT32 *base= (UINT32 *) 0xffffffff; UINT32 moduleRangeMap[2][2]= {{0x00000056, 0x0000}, {0,0}}; //UINT32 moduleRangeMap[2][2]= {{0x00000055, 0x0000}, {0,0}}; //UINT32 moduleRangeMap[2][2]= {{0xffffffff, 0xffff}, {0,0}}; #if (defined(REV_B)||defined(REV_C)) MDAT32 *xPtr[2]= {(MDAT32 *) 0x0201f000, (MDAT32 *) 0x0201f000}; PrimData primData= {(UINT32 *) 0x02061020, 0x78, (UINT32 *) 0x02061820, 0x0, (UINT32 *) 0x02061ffc}; #elif (defined(REV_E)) MDAT32 *xPtr[2]= {(MDAT32 *) 0xa001f000, (MDAT32 *) 0xa001f000}; PrimData primData= {(UINT32 *) 0xa0061020, 0x78, (UINT32 *) 0xa0061820, 0x0, (UINT32 *) 0xa0061ffc}; #endif evtMgrCtrl.buffPtr[0]= (UINT32 *) 0x00018000; evtMgrCtrl.buffPtr[1]= (UINT32 *) 0xa00a2000; evtMgrCtrl.buffLen[0]= 0x08000; evtMgrCtrl.buffLen[1]= 0x38000; //fit(); //asmFxn(); //The mask data must be loaded directly into the IDSP proc. buffer moduleMask(&primData); returnCode= histoSetup(base, nBins, binSize, routineType, dataType, opt, validModules, moduleRangeMap, xPtr); if (returnCode != SUCCESS) return; setHistoModuleBase(FALSE /* init */, 0); /* debug: asm function will now place its data into CE3 at these locations (when the lutBase is offset by one as below). The odd time-slice address is computed so that slice 7 begins at 0xb2000000 */ //setHistoModuleBase(FALSE /* init */, 0); histoCtrl.lutBase[0x13-1]= 0xb0000000; histoCtrl.lutBase[0x17-1]= 0xb1ec5000; #ifdef COMMENTED setHistoModuleBase(FALSE /* init */, histoCtrl.nBins -1); setHistoModuleBase(FALSE /* init */, 5); #endif #if defined(SCT_ROD) #if 1 //single frame, normal event from rodSim: data.length= 0xea; data.data1= 0x00012100; //1 internal frame starting at frame 0. data.data2= 0x000100ea; //trap= histo, len= 0x00ea data.data3= 0; data.error= FALSE; data.startFrame= 0; data.nFrames= 1; data.iStartFrame= 0; data.iFrameCnt= 1; data.xStartFrame= 0x21; data.xFrameCnt= 0; t0= TIMER_getCount(timer1); histoEvent_c_chipocc(&data); t1= TIMER_getCount(timer1); histoEvent_asm_chipocc(&data); t2= TIMER_getCount(timer1); histoEvent_asm(&data); t3= TIMER_getCount(timer1); dt_c= t1 -t0; dt_asm= t2 -t1; dt_asm2= t3 -t2; cacheOn(); t0= TIMER_getCount(timer1); histoEvent_c_chipocc(&data); t1= TIMER_getCount(timer1); histoEvent_asm_chipocc(&data); t2= TIMER_getCount(timer1); histoEvent_asm(&data); t3= TIMER_getCount(timer1); dt_c= t1 -t0; dt_asm= t2 -t1; dt_asm2= t3 -t2; t0= TIMER_getCount(timer1); histoEvent_c_chipocc(&data); t1= TIMER_getCount(timer1); histoEvent_asm_chipocc(&data); t2= TIMER_getCount(timer1); histoEvent_asm(&data); t3= TIMER_getCount(timer1); dt_c= t1 -t0; dt_asm= t2 -t1; dt_asm2= t3 -t2; #endif #if 0 //single frame nmask event, starting at frame 1: data.length= 0x47; data.data1= 0x01012100; //1 internal frame starting at frame 1. data.data2= 0x00010047; //trap= histo, len= 0x0047 data.data3= 0; data.error= FALSE; data.startFrame= 1; data.nFrames= 1; data.iStartFrame= 1; data.iFrameCnt= 1; data.xStartFrame= 0x21; data.xFrameCnt= 0; histoEvent_c(&data); histoEvent_asm(&data); #endif #if 0 //2 frame nmask events: data.length= 0x131; data.data1= 0x00022100; //2 internal frames starting at frame 0. data.data2= 0x00010131; //trap= histo, len= 0x0131 data.data3= 0; data.error= FALSE; data.startFrame= 0; data.nFrames= 2; data.iStartFrame= 0; data.iFrameCnt= 2; data.xStartFrame= 0x21; data.xFrameCnt= 0; t0= TIMER_getCount(timer1); histoEvent_c_chipocc(&data); t1= TIMER_getCount(timer1); histoEvent_asm_chipocc(&data); t2= TIMER_getCount(timer1); //histoEvent_asm(&data); t3= TIMER_getCount(timer1); dt_c= t1 -t0; dt_asm= t2 -t1; dt_asm2= t3 -t2; #endif #if 0 //5 frame nmask events, 1st starts at frame 30 and then another at frame 3: data.length= 0x493; data.data1= 0x1e052100; //5 internal frames starting at frame 30. data.data2= 0x00010493; //trap= histo, len= 0x0493 data.data3= 0; data.error= FALSE; data.startFrame= 30; data.nFrames= 5; data.iStartFrame= 30; data.iFrameCnt= 5; data.xStartFrame= 0x21; data.xFrameCnt= 0; t0= TIMER_getCount(timer1); histoEvent_c_chipocc(&data); t1= TIMER_getCount(timer1); histoEvent_asm_chipocc(&data); t2= TIMER_getCount(timer1); //histoEvent_asm(&data); t3= TIMER_getCount(timer1); dt_c= t1 -t0; dt_asm= t2 -t1; dt_asm2= t3 -t2; data.length= 0x493; data.data1= 0x03052100; //5 internal frames starting at frame 3. data.data2= 0x00010493; //trap= histo, len= 0x0493 data.data3= 0; data.error= FALSE; data.startFrame= 3; data.nFrames= 5; data.iStartFrame= 3; data.iFrameCnt= 5; data.xStartFrame= 0x21; data.xFrameCnt= 0; t0= TIMER_getCount(timer1); histoEvent_c_chipocc(&data); t1= TIMER_getCount(timer1); histoEvent_asm_chipocc(&data); t2= TIMER_getCount(timer1); //histoEvent_asm(&data); t3= TIMER_getCount(timer1); dt_c= t1 -t0; dt_asm= t2 -t1; dt_asm2= t3 -t2; #endif #elif defined(PIXEL_ROD) stage= 31; bin= 2; setHistoModuleBase(FALSE /* init */, bin); ptr[0]= ((UINT32) histoCtrl.base) +(32/histoCtrl.binSize)*( bin*histoCtrl.deltaBin +stage*histoCtrl.deltaHash); ptr[1]= ptr[0] +(32/histoCtrl.binSize)*histoCtrl.deltaHash; histoCtrl.occLim[0]= (UINT32 *) ptr[0]; histoCtrl.occLim[1]= (UINT32 *) ptr[1]; data.error= FALSE; data.data1= 0x00062100; //6 internal frame starting at frame 0. data.data2= 0x00010584; //trap= histo, len= 0x0593 data.data3= 0; data.iStartFrame= 0; data.iFrameCnt= 6; data.xStartFrame= 0x21; data.xFrameCnt= 0; data.length= 0x0584; data.startFrame= 0; data.nFrames= 6; //histoEvent_asm(&data); histoEvent_c(&data); --histoCtrl.lutBase; histoEvent_asm(&data); ++histoCtrl.lutBase; data.error= FALSE; data.data1= 0x01012100; //1 internal frame starting at frame 1. data.data2= 0x00010088; //trap= histo, len= 0x0088 data.data3= 0; data.iStartFrame= 1; data.iFrameCnt= 1; data.xStartFrame= 0x21; data.xFrameCnt= 0; data.length= 0x88; data.startFrame= 1; data.nFrames= 1; histoEvent_c(&data); --histoCtrl.lutBase; histoEvent_asm(&data); ++histoCtrl.lutBase; #endif } #endif //toggle between empty/complete routine. /************************************************************************************ * simInit * synopsis: Initializes the ROD simulation routines. ************************************************************************************/ void simInit() { //simRod(); } /************************************************************************************ * simRod * synopsis: Simulates the asychronous responses from different parts of the * DSP's environment using a collection of hacks. ************************************************************************************/ void simRod() { UINT8 i; if (taskMgrCtrl.taskIterations > 0) { // Task is waiting for initialization /* set the override bit to allow setup; it will be reset below */ if (getTaskState(HISTOGRAM_TASK) == TASK_INIT) // Histogram task INIT SET_RBIT(COMMAND_REG_0, CR_HISTO_OVERRIDE); } if (getTaskState(HISTOGRAM_TASK) == 2) { //READY /* set the override bit to allow setup; it will be reset when EXPECTING. */ SET_RBIT(COMMAND_REG_0, CR_HISTO_OVERRIDE); SET_RBIT(HCMD_STAT_REG_0, HCSR0_SLV_NEWBIN); ASGN_RFLD(HCMD_STAT_REG_1, HCSR0_SLV_BIN, HCSR0_SLV_BIN_W, 200); } else if (getTaskState(HISTOGRAM_TASK) == 3) { //EXPECTING RST_RBIT(COMMAND_REG_0, CR_HISTO_OVERRIDE); RST_RBIT(HCMD_STAT_REG_0, HCSR0_SLV_NEWBIN); RST_RBIT(HCMD_STAT_REG_0, HCSR0_SLV_NEWCAL); } if (GET_RBIT(COMMAND_REG_0,CR_IN_LIST_RDY)) { if (GET_RBIT(STATUS_REG_0, SR_DSP_ACK)) { RST_RBIT(COMMAND_REG_0,CR_IN_LIST_RDY); } } for (i=0; i 0 and the routerDataRdy bit is not set (indicating new input data), set the routerDataRdy bit. */ else if (routerData.state== SIMRTR_DATACHK) { routerData.nRouterFrames= 0x7f; addr= (UINT32 *) (ROUTER_BASE +0x1fc1c); while ((*addr == 0) && (addr > routerData.base) ) { --routerData.nRouterFrames; addr-= 0x100; } routerData.nRouterFrames-= routerData.currentFrame; *routerData.routerFramesReg= routerData.nRouterFrames; /* search for the eof and then the bof to get the event length for pseudo- events, insert that into the lower half-word of the 0x40ff word. */ if ((routerData.fixLength)&&(routerData.nRouterFrames>0)) { routerData.fixLength= FALSE; routerData.e0f= addr; routerData.b0f= addr -0xff; while ((*routerData.e0f & 0xffffffff)!=0xe0f00000) --routerData.e0f; while ((*routerData.b0f & 0xffffffc0)!=0xb0f00000) routerData.b0f-= 0x100; routerData.calcLength= ((UINT32) (routerData.e0f -routerData.b0f +1)); (*addr) &= 0xffff0000; (*addr) |= routerData.calcLength; } if (routerData.nRouterFrames>0) { routerData.state= SIMRTR_DATARDY; RST_RBIT(ROUTER_CMD_REG, SIMRTR_DATACHK); SET_RBIT(ROUTER_CMD_REG, SIMRTR_DATARDY); } } /* end of ready for dma/idle if/else */ } /* trapping enabled in router */ //if (routerData.getRegs) getRegisters(); /* sigh */ } /************************************************************************************ * oddSCTLinkFix: * * synopsis: Fixes the bad data (all SCT chips are from 0 to 5) generated by * old versions of simRod. ************************************************************************************/ void oddSCTLinkFix(struct EventData *data) { UINT16 *dataPtr, * dp2, *startPtr, *endPtr; UINT32 wData; UINT8 hw= 1, nDataFrames, lMod, dataFramesDone= 0, frame, module, oddLink; nDataFrames= ((lMod= data->length%0x100) > 6)? data->nFrames : data->nFrames-1; frame= data->startFrame; while (dataFramesDone < nDataFrames) { /* +2 ==> begin with the high half-word. */ startPtr= (UINT16 *) (getFramePtr(frame) +2); endPtr= startPtr +0x200; /* pointer arithmetic */ if (frame== data->startFrame) { startPtr+= 18; /* skip header */ } if (dataFramesDone == nDataFrames -1) { if (lMod <= 6) endPtr-= (0x00c -2*lMod); else endPtr-= (0x20c -2*lMod); /* skip trailer */ } /* the router gives words with the half-words swapped from what the DSP would naively expect, hence the juggling of pointers. Data begins on the high half-word, proceeds to the low half-word, then jumps to the next high half-word. */ for (dataPtr= startPtr; dataPtr 0x7fff) { /* link data */ if (oddLink) *dp2= *dataPtr | 0x4000; else *dp2= *dataPtr; } else if (_extu(wData, 16, 25) == 0x10) { *dp2= *dataPtr; module= (*dataPtr & 0x7f); oddLink= module & 1; } //Link header processing. } //Loop over data words in frame. frame= getNextFrame(data, frame, TRAP_FXN_HISTOGRAM); ++dataFramesDone; } } #endif /* defined(I_AM_SLAVE_DSP) */ #endif /* defined(SIM) */