/************************************************************************************ * masterTasks_sct.c * * synopsis: This file contains tasks which run on the MDSP, and are optimized * for SCT use. Typically these coordinate and monitor the SDSPs as * they process data. * * in this file: histoCtrlInit, histoCtrlNewBin, histoCtrlWaitExp, histoCtrlWaiting, * histoCtrlPrep, histoCtrlDone, histoCtrlTask. * * related files: * masterTasks.c: MDSP tasks common to both SCT & Pixels. * taskManager.c: Contains routines for starting, stopping & managing tasks. * slaveTasks.c: Contains the slave DSP tasks. * histogram.h: Contains the definitions for the histogram control structures * on the master & slave DSPs. ************************************************************************************/ #include #include #include #include #include #include "resources.h" #include "comRegDfns.h" #include "registerIndices.h" #include "accessSlave.h" #include "histogram.h" #include "accessRegister.h" extern char genStr[]; extern far unsigned char heap[]; extern TIMER_Handle timer1; /* general purpose timer, started in main() */ extern far struct TaskMgrCtrl taskMgrCtrl; extern far RodModeCfg rodModeCfg[]; extern far Module moduleConfigSet[N_MODULE_CONFIG_SETS][N_TOTMODULES]; extern far CmdBuff cmdBuffer[]; extern far CfgTiming cfgTiming; extern far MaskConfigData maskConfigData[]; #pragma CODE_SECTION(addDspInfo, "icode"); #pragma CODE_SECTION(getDspStatus, "icode"); //#pragma CODE_SECTION(updateEventStats, "icode"); #pragma CODE_SECTION(initSerialStreams, "xcode"); //#pragma CODE_SECTION(setPending, "xcode"); #pragma CODE_SECTION(scanWait, "xcode"); #pragma CODE_SECTION(getTaskCtrlBits, "xcode"); #pragma CODE_SECTION(resetModules, "xcode"); #pragma CODE_SECTION(buildScanTrigger, "icode"); #pragma CODE_SECTION(modifyTriggerDelay, "icode"); #pragma CODE_SECTION(newTrapSeries, "icode"); #pragma CODE_SECTION(scanAttnHandle, "icode"); #pragma CODE_SECTION(scanEventCheck, "icode"); #pragma CODE_SECTION(scanErrHandle, "icode"); #pragma CODE_SECTION(updateScanStatistics, "icode"); #pragma CODE_SECTION(scanExtrapolate, "icode"); #pragma CODE_SECTION(histoCtrlInit, "xcode"); #pragma CODE_SECTION(histoCtrlSdspSetup, "icode"); #pragma CODE_SECTION(histoCtrlNewBin, "icode"); #pragma CODE_SECTION(histoCtrlWaitExp, "icode"); #pragma CODE_SECTION(histoCtrlWaiting, "icode"); #pragma CODE_SECTION(histoCtrlPrep, "icode"); #pragma CODE_SECTION(histoCtrlDone, "icode"); //#pragma CODE_SECTION(histoCtrlWaitExp, "icode"); #pragma CODE_SECTION(histoCtrlTask, "icode"); #pragma CODE_SECTION(scanTaskOp, "xcode"); #pragma CODE_SECTION(scanTaskStates, "xcode"); #pragma DATA_SECTION(hc, "idata"); #pragma DATA_SECTION(scanStatus, "xpdata"); #pragma DATA_SECTION(varRange, "xpdata"); MasterHistoCtrl hc; ScanStatus scanStatus; MDAT32 varRange[2][HISTOGRAM_BIN_MAX]; //Structures needed for SDSP initialization: #pragma DATA_SECTION(hc_ets_i, "xpdata"); #pragma DATA_SECTION(hc_ets_o, "xpdata"); #pragma DATA_SECTION(hc_hsetup_i, "xpdata"); #pragma DATA_SECTION(hc_hsetup_o, "xpdata"); #pragma DATA_SECTION(hc_htask_i, "xpdata"); EventTrapSetupIn hc_ets_i; EventTrapSetupOut hc_ets_o; HistogramSetupIn hc_hsetup_i; HistogramSetupOut hc_hsetup_o; StartTaskIn hc_htask_i; //dpsf: make this an ETS sub-structure: RouterTrapParams trapParams[2]; /* file-level function declarations */ void resetModules(UINT8 sdsp, UINT8 ecr, UINT8 bcr, UINT8 send, UINT8 makeTrig); void buildScanTrigger(UINT8 init); void modifyTriggerDelay(UINT8 scanParam); INT32 startHistoSlaves(UINT8 slvBits); void addDspInfo(UINT8 buffer, UINT8 sdsp); INT32 getDspStatus(UINT8 slv, UINT8 nTrigPending); void updateEventStats(UINT8 slv); INT32 initSerialStreams(void); void getTaskCtrlBits(void); void scanWait(UINT32 messageId, UINT32 sdsp); void setPending(UINT8 sdsp); void newTrapSeries(void); INT32 scanEventCheck(UINT8 wait); INT32 scanErrHandle(void); void updateScanStatistics(void); void scanExtrapolate(void); //Scan task states: INT32 histoCtrlInit(TaskInput *tsi); INT32 histoCtrlSdspSetup(TaskInput *tsi); INT32 histoCtrlNewBin(void); INT32 histoCtrlWaitExp(void); /* event loop is time sensitive & done in the histoCtrlTask */ INT32 histoCtrlWaiting(void); UINT8 histoCtrlPrep(void); INT32 histoCtrlDone(void); INT32 scanTaskOp(union TASK_STRUCTURES_OUT *tso, UINT32 opFlags, UINT8 *state); INT32 scanTaskStates(union TASK_STRUCTURES_IN *tsi, UINT8 *state); /* Histogram Control Task state-machine states: */ /* TASK_INIT == 1 */ #define HCTRL_SDSP_SETUP 2 #define HCTRL_NEWBIN 3 #define HCTRL_WAITEXP 4 #define HCTRL_TRIGGERS 5 #define HCTRL_WAITING 6 #define HCTRL_PREP 7 #define HCTRL_TIMEOUT 0x00990000 //~1 sec. #define MAX_RECOVER_ATTEMPTS 10 UINT32 efbEvtCnt[N_MODULE_GROUPS]= {0,0,0,0, 0,0,0,0}; /* Three extra (internally used) configuration parameters which define actions which the MDSP scanning routine will take: */ #define CONFIG_BOC 29 #define CONFIG_NONE 30 #define CONFIG_ROD_TRIGGER 31 //dpsf patch: re-do SP code. CmdList nullCmdList, *trigPtr[2]; /* Message IDs for scanWait: */ enum { SCAN_INIT_CFG= 0, SCAN_END_INIT, SCAN_NB_INIT= 10, SCAN_SDSP_SETUP, SCAN_STAGE_CFG, SCAN_STAGE_SEND, SCAN_CFG_VARIABLE, SCAN_SEND_CFG, SCAN_NB_ECR_BCR, SCAN_WAITEXP, SCAN_WAITEXP_GOOD, SCAN_DATA_PREP_INIT= 50, SCAN_DATA_PREP_ADD, SCAN_DATA_PREP_SEND, SCAN_RESET_SETMASKS= 100, SCAN_RESET_SEND, SCAN_RESET_EXIT, SCAN_TRIGGER_ENTRY= 150, SCAN_SDSP_READY_CHECK, SCAN_SDSP_READY, SCAN_TRIGGER, SCAN_EVENT_CHECK_START= 200, SCAN_REXMIT_MASKS_SET, SCAN_ERROR_RECOVERY, SCAN_AUTO_STALL, SCAN_EVENT_CHECK, SCAN_EVENT_CORRECT }; /************************************************************************************ * getTaskCtrlBits: Retrieve run-time task control bits. ************************************************************************************/ void getTaskCtrlBits(void) { /* Get expert run-time flags. */ hc.manual= hc.soft_bc_reset= hc.autoStall= hc.trigPause= hc.binPause= hc.stagePause= FALSE; if (GET_RBIT(DIAGNOSTIC_REG, DR_STEP_CTRL)) hc.manual= TRUE; if (GET_RBIT(DIAGNOSTIC_REG, DR_SOFT_BC_RESET)) hc.soft_bc_reset= TRUE; if (GET_RBIT(DIAGNOSTIC_REG, DR_AUTO_STALL)) hc.autoStall= TRUE; if (GET_RBIT(DIAGNOSTIC_REG, DR_TRIG_PAUSE)) hc.trigPause= TRUE; if (GET_RBIT(DIAGNOSTIC_REG, DR_BIN_PAUSE)) hc.binPause= TRUE; if (GET_RBIT(DIAGNOSTIC_REG, DR_STAGE_PAUSE)) hc.stagePause= TRUE; } /************************************************************************************ * scanWait: scanWait prints out a message and waits for the operator to set a bit * in the diagnostic register before continuing. Note that during the * waitRegister routine input from primitive lists is possible so long as the * primitive list containing the start-task primitive has finished executing; * generally this means any state except the INIT state. ************************************************************************************/ void scanWait(UINT32 messageId, UINT32 sdsp) { switch(messageId) { case SCAN_INIT_CFG: sprintf(genStr, "INIT: Pause after module reconfig.\n"); break; case SCAN_END_INIT: //histoReport(); sprintf(genStr, "Pause before leaving INIT.\n"); break; case SCAN_NB_INIT: sprintf(genStr, "NEWBIN: Pausing.\n"); break; case SCAN_SDSP_SETUP: //histoReport(); sprintf(genStr, "NEWBIN: about to set SDSP histogramming control registers.\n"); break; case SCAN_STAGE_CFG: sprintf(genStr, "NEWBIN: setting new mask stage in modules.\n"); break; case SCAN_STAGE_SEND: sprintf(genStr, "NEWBIN: sending new mask stage to modules.\n"); break; case SCAN_CFG_VARIABLE: sprintf(genStr, "NEWBIN: load scan variable.\n"); break; case SCAN_SEND_CFG: sprintf(genStr, "NEWBIN: sending module configuration data.\n"); break; case SCAN_WAITEXP: sprintf(genStr, "WAITEXP: dammit.\n"); break; case SCAN_WAITEXP_GOOD: sprintf(genStr, "WAITEXP: leaving.\n"); break; case SCAN_RESET_SETMASKS: sprintf(genStr, "resetModules: setting masks next.\n"); break; case SCAN_RESET_SEND: sprintf(genStr, "resetModules: sending reset command.\n"); break; case SCAN_RESET_EXIT: sprintf(genStr, "resetModules: exit.\n"); break; case SCAN_NB_ECR_BCR: sprintf(genStr, "NEWBIN: about to send soft & BC reset.\n"); break; case SCAN_TRIGGER_ENTRY: sprintf(genStr, "PULSING: paused.\n"); break; case SCAN_SDSP_READY_CHECK: //histoDspReport(sdsp); if (hc.dspInfo[sdsp].paired) histoDspReport(hc.dspInfo[sdsp].pair); sprintf(genStr, "PULSING: checking SDSP #%d condition.\n", sdsp); break; case SCAN_SDSP_READY: sprintf(genStr, "PULSING: SDSP #%d ready for trigger, set Rod Registers.\n", sdsp); break; case SCAN_TRIGGER: sprintf(genStr, "PULSING for SDSP #%d.\n", sdsp); break; case SCAN_EVENT_CHECK_START: //histoDspReport(sdsp); if (hc.dspInfo[sdsp].paired) histoDspReport(hc.dspInfo[sdsp].pair); sprintf(genStr, "PULSING: checking event(s) on SDSP #%d\n", sdsp); break; case SCAN_REXMIT_MASKS_SET: sprintf(genStr, "PULSING: set masks for SDSP %d, will send ECR-BCR next.\n", sdsp); break; case SCAN_ERROR_RECOVERY: sprintf(genStr, "PULSING: sent ECR-BCR to SDSP #%d, will send CAL-L1A next.\n", sdsp); break; case SCAN_AUTO_STALL: //histoGroupReport(sdsp); histoDspReport(sdsp); sprintf(genStr, "PULSING: Pause for error event inspection on SDSP #%d\n", sdsp); break; case SCAN_EVENT_CHECK: //histoGroupReport(sdsp); histoDspReport(sdsp); sprintf(genStr, "PULSING: pause after checking event on SDSP #%d.\n", sdsp); break; case SCAN_EVENT_CORRECT: sprintf(genStr, "PULSING: pause before correcting missing trailer on SDSP #%d.\n", sdsp); break; default: sprintf(genStr, "Pause.\n"); break; } newInformation(__FILE__, __LINE__, genStr); waitRegister(DIAGNOSTIC_REG, DR_STEP_TRIGGER, CONTEXT_TASK); } /************************************************************************************ * resetModules: Reset (all) the modules by sending a soft-BC reset combination to * them. Afterward, re-build the trigger stream(s). ************************************************************************************/ void resetModules(UINT8 sdsp, UINT8 ecr, UINT8 bcr, UINT8 send, UINT8 makeTrig) { INT32 errorCode, j, k; if (send) { if (hc.manual) scanWait(SCAN_RESET_SETMASKS, sdsp); //switchLinkMasks(((DATA_LINK)+(COMMAND_LINK)), MASK_SET_INIT); setLinkMasks(0, SP_BOTH, COMMAND_LINK, INIT_MASK, MASK_SET_WORK1); for (j= 0; j < N_MODULE_GROUPS; ++j) { for (k=0; kserial.port == SP_BOTH) {spi= 0; spf= SP_BOTH; } else {spi= hc.scan->serial.port; spf= spi +1; } for (i=spi; iserial.port == SP_BOTH) { hc.triggerSequence[i].cmd[0]= DELAY; hc.triggerSequence[i].data[0]= i*10; } hc.triggerSequence[i].cmd[1]= CALIBRATION_PULSE; hc.triggerSequence[i].cmd[2]= DELAY; hc.triggerSequence[i].data[2]= hc.status->currentDelay; hc.triggerSequence[i].cmd[3]= L1_TRIGGER; } } /************************************************************************************ * modifyTriggerDelay: Finds & modifies the trigger delay(s) inside the user-defined * trigger sequences. ************************************************************************************/ void modifyTriggerDelay(UINT8 scanParam) { UINT8 sp, i, cnt, spi, spf; if (hc.scan->serial.port == SP_BOTH) {spi= 0; spf= SP_BOTH; } else {spi= hc.scan->serial.port; spf= spi +1; } for (sp=spi; spcurrentDelay; } } } } #define DSP_BUSY -1 #define DSP_READY 1 /************************************************************************************ * addDspInfo * * synopsis: Place information about current status of the MDSP histogramming * control and of the SDSP trapping into one of the text buffers. ************************************************************************************/ void addDspInfo(UINT8 buffer, UINT8 sdsp) { UINT8 idSdsp, port; if (hc.dspInfo[sdsp].active) idSdsp= sdsp; else idSdsp= hc.dspInfo[sdsp].pair; if (hc.dspInfo[idSdsp].ports == 2) port= SP1; else port= SP0; sprintf(genStr, "\n %s%d%s%d%s%d%s%d%s%d%s %s0x%08x%s %s0x%08x%s %s0x%08x%s %s0x%08x%s", " MDSP: bin #", hc.status->currentBin[0], " SDSP #", sdsp, " evt. #", hc.dspInfo[idSdsp].nEvents, " err. #", hc.dspInfo[idSdsp].nErrors, " (L1-ID ", hc.dspInfo[idSdsp].L1id[port], ").\n\n", " TCmd= ", hc.dspInfo[sdsp].trapCmd, ",\n", " Current TS0= ", getSlvReg(sdsp, TRAPSTAT_REG1_0), ".\n", " Current TS1= ", getSlvReg(sdsp, TRAPSTAT_REG1_1), ".\n", " Current TS2= ", getSlvReg(sdsp, TRAPSTAT_REG1_2), ".\n"); if (buffer == ERR_BUFF) addErrorInfo(__FILE__, __LINE__, genStr); else addInformation(__FILE__, __LINE__, genStr); } /************************************************************************************ * getDspStatus * * synopsis: Retrieves the number of frames currently waiting to be proccessed * inside a slave DSP via pointers, and returns a status indicating * whether or not a new event (or events) would be likely to force the DSP to * use slow memory. Other variables inside the hc (histogram control) structure * are set as well, for later reference. ************************************************************************************/ INT32 getDspStatus(UINT8 sdsp, UINT8 nTriggers) { INT32 status; static UINT32 cnt= 0; register UINT32 a, b, c, d; register UINT32 x, y, z; //dpsf: If the appropriate bit is set in the DR, check to make sure proc flag //dpsf: is down before allowing ready. If not, increment RR3: if (GET_RBIT(DIAGNOSTIC_REG, DR_PROCWAIT)) { x= getSlvRegBit(sdsp, HSTATUS_REG_0, HSR0_SLV_PROC); if (x) return DSP_BUSY; } x= getSlvReg(sdsp, TRAPSTAT_REG1_2); z= hc.dspInfo[sdsp].avgEvtLen>>8; hc.dspInfo[sdsp].iTail= a= GET_VFLD(x, TSR2_IFRAME_TAIL, TSR2_IFRAME_TAIL_W); hc.dspInfo[sdsp].xTail= b= GET_VFLD(x, TSR2_XFRAME_TAIL, TSR2_XFRAME_TAIL_W); hc.dspInfo[sdsp].iHead= c= GET_VFLD(x, TSR2_IFRAME_HEAD, TSR2_IFRAME_HEAD_W); hc.dspInfo[sdsp].xHead= d= GET_VFLD(x, TSR2_XFRAME_HEAD, TSR2_XFRAME_HEAD_W); if (a < c) a+= 32; if (b < d) b+= 224; hc.dspInfo[sdsp].nIdram= a= a -c; hc.dspInfo[sdsp].nSdram= b= b -d; hc.dspInfo[sdsp].trapStat[2]= x; status= ( (a == 0) || ((a +nTriggers*z)<28) )? DSP_READY:DSP_BUSY; //if (!status) greenLed_toggle; if (status) { WRITE_REG(RESERVED_REG_2, a); WRITE_REG(RESERVED_REG_1, cnt); cnt= 0; } else { if (cnt == 0) WRITE_REG(RESERVED_REG_3, a); ++cnt; } return status; } #if 0 /************************************************************************************ * setPending * * synopsis: Sets the pending bit in the trap command register on the selected * SDSP (and its paired twin, if any). The pending bit then resets the * event counters on the SDSP(s) upon arrival of the next event. ************************************************************************************/ void setPending(UINT8 sdsp) { UINT8 twin; twin= hc.dspInfo[sdsp].pair; /* shouldn't need doing-- check & make more efficient */ //while (getSlvRegBit(slv, TRAP_CMD_STAT, TCSR_ISR_ACTIVE)); setSlvReg(sdsp, TRAP_CMD_STAT, ( (hc.dspInfo[sdsp].trapCmdStat | (1< no issues) so first we invert it. The SDSP aux. status reg. (2) stores the attention flags. */ hc.sdspAttention= (~hc.sdspAttention) & 0xf; for (sdsp=0; sdsp hc.trigDelay)? procTime:hc.trigDelay; //Wait until the SDSP internal frame count dips below 25% : t0= TIMER_getCount(timer1); do { status= getDspStatus(sdsp, 0); dt= delta_t(t0); } while ( (hc.dspInfo[sdsp].nIdram > 8) && (dt < HCTRL_TIMEOUT) ); if (dt >= HCTRL_TIMEOUT) { //Issues on SDSP: sprintf(genStr, "%s%d%s", "SDSP #",sdsp, ": timed out while waiting for event backlog to clear.\n"); newError(&returnCode, EVENT_ERR, FATAL_ERR, "scanErrHandle", genStr, __FILE__, __LINE__); addDspInfo(ERR_BUFF, sdsp); return returnCode; } } //Clear the attention flag on the SDSP: x= getSlvReg(sdsp, COMMAND_REG_0); x|= (0xf<<16); setSlvReg(sdsp, COMMAND_REG_0, x); writeRegister(INTRPT_TO_SLV, 4, 0, (1<>4; delay(icnt2); /* Now wait for the events to arrive on the SDSPs (re-call the event-checking routine, this time requesting that it wait until the events have fully arrived. When this routine is called from the trigger loop, normally it does not bother waiting. This is done here to avoid disturbing the trigger loop for abnormal conditions. */ scanEventCheck(TRUE); //1st update the scan's statistics & counters with any events/errors: updateScanStatistics(); do { for (sdsp=0; sdsp>4; delay(icnt2); nErrs= scanEventCheck(TRUE); updateScanStatistics(); //Report the new events/errors. ++attempts; if (attempts >= MAX_RECOVER_ATTEMPTS) failed= TRUE; } while ((nErrs > 0) && (!failed)); if (failed) { sprintf(genStr, "%s%d%s", "Problems with electronics- could not correct " "errors after ", MAX_RECOVER_ATTEMPTS, " attempts. Exiting.\n"); newError(&returnCode, ELECTRONICS_ERROR, FATAL_ERR, "scanErrHandle", genStr, __FILE__, __LINE__); for (sdsp=0; sdsp 0x80) hc.trigLoopMax= 0x80; hc.evtWait= FALSE; genLoopInfo->timeStamp= TIMER_getCount(timer1); genLoopInfo->rep= hc.repetitions; genLoopInfo->origLoopMax= hc.trigLoopMax; genLoopInfo->origWait= hc.evtWait; for (sdsp=0; sdsp= hc.repetitions) hc.pulsing &= ~(1< don't care. if (hc.dspInfo[sdsp].seriesEvents[1]> 0x8000) newTrapSeries(); evt= hc.dspInfo[sdsp].nTrig; del= rep -evt; if (del <= hc.trigLoopMax) { hc.trigLoopMax= del; hc.evtWait= TRUE; } genLoopInfo->sdspLoop[sdsp].nTrig= hc.dspInfo[sdsp].nTrig; genLoopInfo->sdspLoop[sdsp].seriesEvts= hc.dspInfo[sdsp].seriesEvents[1]; genLoopInfo->sdspLoop[sdsp].nEvts= hc.dspInfo[sdsp].nEvents; genLoopInfo->sdspLoop[sdsp].nErr= hc.dspInfo[sdsp].nErrors; genLoopInfo->sdspLoop[sdsp].evtChk= evt; genLoopInfo->sdspLoop[sdsp].del= del; genLoopInfo->sdspLoop[sdsp].newLoopMax= hc.trigLoopMax; genLoopInfo->sdspLoop[sdsp].waitFlag= hc.evtWait; } genLoopInfo->loopMax= hc.trigLoopMax; genLoopInfo->waitFlag= hc.evtWait; genLoopInfo->trigField= hc.pulsing; genLoopInfo->timeStamp2= TIMER_getCount(timer1); if ((++genLoopInfo) >= ((GenLoopInfo *) 0x02c00000)) //wrap. genLoopInfo= (GenLoopInfo *) 0x02b00000; } /************************************************************************************ * histoCtrlInit * * synopsis: Performs various initializations and checks needed before the histogram * scan can begin. The routine reads the task parameters into a dedicated * global array, performs several checks to ensure the integrity of the input, * sets the ROD's running mode and sets a variety of variables which coordinate * the data-taking among different groups of modules. A separate initialization * routine (histoCtrlReady) is used to set up the SDSPs. * * author: Douglas Ferguson ************************************************************************************/ INT32 histoCtrlInit(TaskInput *tsi) { INT32 returnCode= SUCCESS, errorCode; UINT32 i, j, type, t0; UINT8 sdsp, twin, set, k, nPoints; MDAT32 delta; t0= TIMER_getCount(timer1); setTaskState(HISTOGRAM_CTRL_TASK, TASK_INIT); /* Zero out the control structures Note that these structures contain several variables which would naively be best left as local variables. However the DSP has some limitations on the number of local variables which can be set up before mysterious errors crop up (& before stack overflow too...) histoCtrl and scanTiming need a large number of variables; therefore it's safer to simply place most of them inside a global structure. */ setMem((UINT32 *) &hc, SIZEOF(MasterHistoCtrl), 0); setMem((UINT32 *) &scanStatus, SIZEOF(ScanStatus), 0); hc.scan= (ScanControl *) tsi; hc.status= (ScanStatus *) &scanStatus; hc.timing= (ScanTimingInfo *) &scanStatus.timing; hc.initTime = hc.time= t0; /* The trigger loop's max. time is set here; could imagine making this settable via the task's priority is some way. */ hc.taskTimeMax= 5000000; //.5 x 10^6 us //Get the task's control bits in the diagnostic register: getTaskCtrlBits(); hc.extSetup= hc.scan->rodSetup.extSetup; if (hc.extSetup & EXT_SETUP_RCF) { if (rodModeCfg[0].rodMode == CALIBRATION_MODE) hc.dataPath= rodModeCfg[0].sim; else hc.dataPath= DATA_PATH_NORMAL; } else { //Set up calibration mode: /* Set the ROD's running mode to calibration, preserving the simulation mode modifier if it is present; for other modifiers, the RCF must be set up externally. The old mode is stored. */ hc.dataPath= hc.scan->rodSetup.dataPath; if (hc.dataPath == DATA_PATH_NORMAL) i= CALIBRATION_MODE +INMEM_EVT_CAPTURE_MODE; else i= CALIBRATION_MODE +SIMULATION_MODE; i+= CALIBRATION_SLINK_OVERRIDE_MODE; rodMode(i, STORE_MODE, TRUE, 0x1000, 0, 1, TRUE); } writeRegister(EFB_CMND_0, 1, EFB_GROUP_COUNTER_EN_O, 1); //Enable EFB counters. //dpsf: place all in histoCtrlSlvSetup, load variables appropriately //SDSPs which will be histogramming (bitfield): hc.slvBits= hc.scan->dspDist.slvBits; //hc.timing->init.dt[0]= delta_t(hc.initTime); hc.time= TIMER_getCount(timer1); hc.cfgSet= hc.scan->general.cfgSet; if (hc.cfgSet >= N_MODULE_CONFIG_SETS) { sprintf(genStr, "%s%d%s","Invalid configuration set (max= ", (N_MODULE_CONFIG_SETS-1), ").\n"); newError(&returnCode, PRIM_PARAMETER_ERROR, FATAL_ERR, "histoCtrlInit", genStr, __FILE__, __LINE__); return returnCode; } hc.moduleCfg= moduleConfigSet[hc.cfgSet]; hc.port= hc.scan->serial.port; //If requested, reset modules using the PHYSICS config set: if (hc.scan->reset.moduleInit) { //type= (1<init.dt[1]= delta_t(hc.time); hc.timing->init.dt_cfg= cfgTiming.total; //hc.timing->init.dt_cfg_setup= cfgTiming.setup; hc.time= TIMER_getCount(timer1); //hc.timing->init.dt[2]= delta_t(hc.time); hc.time= TIMER_getCount(timer1); //Stage configuration mask is in basic register (for sendCfg): hc.stageCfg= CONFIG_MODULE_BASIC; //Determine which register contains the scan parameter: for (i=0; i<2; ++i) { hc.cfgReg[i]= hc.scan->general.scanParameter[i]; hc.sendCfg[i]= TRUE; hc.singleCfgVar[i]= FALSE; switch(hc.cfgReg[i]) { case SCAN_NONE: case ST_ELAPSED: hc.dataType[i]= CONFIG_NONE; hc.sendCfg[i]= FALSE; break; case ST_VTHR: case ST_VCAL: case ST_STROBE_DELAY: case ST_PREAMP: case ST_SHAPER: case ST_QTHR: case ST_QCAL: case ST_TTHR: case ST_TARGET: case ST_ROLE: hc.dataType[i]= CONFIG_MODULE_BASIC; break; case ST_TRIM: hc.dataType[i]= CONFIG_MODULE_TRIM; //dpsf: CONFIG_MODULE_SCAN_TRIM; break; case ST_MASK: case ST_NMASK: hc.dataType[i]= CONFIG_MODULE_BASIC; //dpsf: CONFIG_MODULE_MASK; break; case ST_BYPASS: case ST_TOKEN: hc.dataType[i]= CONFIG_MODULE_BASIC; hc.singleCfgVar[i]= TRUE; break; /* ROD trigger delay(s): */ case ST_TRIG_DELAY1: case ST_TRIG_DELAY2: hc.dataType[i]= CONFIG_ROD_TRIGGER; hc.sendCfg[i]= FALSE; break; /* BOC parameters: */ case ST_RX_DELAY: case ST_RX_DELAY0: case ST_RX_DELAY1: case ST_RX_THRESHOLD: case ST_RX_THRESHOLD0: case ST_RX_THRESHOLD1: case ST_TX_CURRENT: case ST_TX_MARKSPACE: case ST_TX_DELAY: case ST_TX_COARSE: case ST_TX_FINE: hc.dataType[i]= CONFIG_BOC; hc.sendCfg[i]= FALSE; hc.singleCfgVar[i]= TRUE; break; default: hc.dataType[i]= CONFIG_MODULE_ALL; break; } } for (i=0; i<2; ++i) { hc.dataPtr[i]= hc.scan->general.dataPtr[i]; hc.nBins[i]= hc.scan->general.nBins[i]; if (hc.nBins[i] > HISTOGRAM_BIN_MAX) { sprintf(genStr, "%s%d%s","Maximum number of bins is ", HISTOGRAM_BIN_MAX, ".\n"); newError(&returnCode, PRIM_PARAMETER_ERROR, FATAL_ERR, "histoCtrlInit", genStr, __FILE__, __LINE__); return returnCode; } for (j= 0; j< HISTOGRAM_BIN_MAX; ++j) {varRange[i][j]= 0; } } hc.repetitions= hc.scan->general.repetitions; for (i=0; i<2; ++i) { //dpsf: temp if (hc.cfgReg[i] != SCAN_NONE) { if (hc.scan->general.uniformPoints[i]) { nPoints= hc.scan->general.nBins[i] -1; if (nPoints <= 0) nPoints= 1; delta= (hc.scan->general.scanEnd[i] -hc.scan->general.scanStart[i])/nPoints; for (j= 0; j< hc.nBins[i]; ++j) { varRange[i][j]= hc.scan->general.scanStart[i] +j*delta; } } else { /* read in from pre-stored locations in memory */ //dpsf: need new var. distinguishing between dual ranges & 2D scan. //dpsf: scanDim= 1 or 2. #if 1 for (j= 0; j< hc.nBins[0]; ++j) { #else for (j= 0; j< hc.nBins[i]; ++j) { #endif varRange[i][j]= *(hc.dataPtr[i] +j); } } } //} //hc.timing->init.dt[3]= delta_t(hc.time); hc.time= TIMER_getCount(timer1); /* Set initial variable-loading settings for the initial pass through NEWBIN: */ hc.twoDScan= ((hc.cfgReg[1] != SCAN_NONE) && (hc.scan->general.nBins[1] > 0)); hc.stageAdvance= hc.binAdvance[1]= FALSE; if (hc.scan->general.maskMode == SCAN_STAGED) { hc.stageAdvance= TRUE; hc.status->currentMaskStage= 0; } hc.binAdvance[0]= TRUE; hc.status->currentBin[0]= hc.status->currentBin[1]= 0; if (hc.twoDScan) hc.binAdvance[1]= TRUE; //hc.timing->init.dt[4]= delta_t(hc.time); hc.time= TIMER_getCount(timer1); /* Modules are arranged into groups; each group has a (possibly) different SDSP destination and function (e.g. Some groups can generate interference). Group mappings to the serial ports and SDSPs must be unique (a group's events arrive on a single DSP, and command data is sent to it from a single serial port). */ hc.defGroups= hc.scan->dspDist.definedGroups; for (i=0; i<2; ++i) { hc.groupSPMap[i]= hc.scan->dspDist.groupSPMap[i] & hc.defGroups; hc.groupRangeMap[i]= hc.scan->dspDist.groupRangeMap[i] & hc.defGroups; } if ( ((hc.groupRangeMap[0] ^ hc.groupRangeMap[1]) != hc.defGroups) ||((hc.groupSPMap[0] ^ hc.groupSPMap[1]) != hc.defGroups) ) { sprintf(genStr, "%s", "Each group must map onto a unique " "range and serial port.\n"); newError(&returnCode, PARAM_ERROR, FATAL_ERR, "histoCtrlTask", genStr, __FILE__, __LINE__); return returnCode; } if ( ((hc.port == SP0) && (hc.groupSPMap[1])) ||((hc.port == SP1) && (hc.groupSPMap[0])) ) { newError(&returnCode, PARAM_ERROR, FATAL_ERR, "histoCtrlTask", "Illegal group serial port mapping.\n", __FILE__, __LINE__); return returnCode; } for (i=0; i<2; ++i) for (j=0; j<2; ++j) hc.dspPair[i][j]= 0xff; hc.nDspPairs= hc.scan->dspDist.nDspPairs; for (i=0; idspDist.nDspPairs; ++i) { for (j=0; j<2; ++j) hc.dspPair[i][j]= hc.scan->dspDist.dspPair[i][j] & 0x3; } for (j=sdsp=0; sdspdspDist.groupDSPMap[sdsp] & hc.defGroups; j+= (hc.groupDSPMap[sdsp] & hc.defGroups); } if (j != hc.defGroups) { sprintf(genStr, "%s","Each group must map onto a unique DSP.\n"); newError(&returnCode, PARAM_ERROR, FATAL_ERR, "histoCtrlTask", genStr, __FILE__, __LINE__); return returnCode; } /* Initialize the internal trigger sequences, and count the number of commands and triggers in them. Also initialize the internal ECR/BCR lists and null lists. */ for (i=j=k=0; k L1A delay, the trigger streams are implicitly assumed to be calculated from the structure. */ if ( (hc.scan->general.scanParameter[0] == ST_TRIG_DELAY1) ||(hc.scan->general.scanParameter[1] == ST_TRIG_DELAY1) ||(hc.scan->general.scanParameter[0] == ST_TRIG_DELAY2) ||(hc.scan->general.scanParameter[1] == ST_TRIG_DELAY2) ) hc.scan->serial.calcFromStruct= TRUE; if (hc.scan->serial.calcFromStruct) { hc.status->currentDelay= hc.scan->serial.calL1ADelay; buildScanTrigger(TRUE); /* Initialize the command lists */ } else { if ((hc.port == SP0) || (hc.port == SP_BOTH)) hc.triggerSequence[0]= hc.scan->serial.triggerSequence[0]; if ((hc.port == SP1) || (hc.port == SP_BOTH)) hc.triggerSequence[1]= hc.scan->serial.triggerSequence[1]; } for (i=j=k=0; k 0) && (hc.SPTriggers[1] > 0)) hc.triggerPairs= TRUE; //Build the L1-ID reset flag: hc.L1idReset= ( (hc.dataPath == DATA_PATH_INMEM) ||((hc.SPEcr[0]) || (hc.SPEcr[1])) ); /* Create maps from the bitfields: first fill in the groups' structures; then loop over the slave DSPs, using the contributing groups' information to calculate the ncessary masks & other DSP information. */ for (i=0; i<4; ++i) setLinkMasks(0, SP_BOTH, ((DATA_LINK)+(COMMAND_LINK)), INIT_MASK, i); for (i= 0; i < N_MODULE_GROUPS; ++i) { for (j= 0; j < 2; ++j) { if (hc.groupSPMap[j] & (1<<(i)) ) hc.groupInfo[i].serialPort= j; if (hc.groupRangeMap[j] & (1<<(i)) ) hc.groupInfo[i].rangeList= j; } /* Loop over modules in the configSet. If a module is present and in that module group, add it to the group's module map. Note that the extra "off-ROD" modules must have their data links turned off. */ for (k=0; kinit.dt[5]= delta_t(hc.time); hc.time= TIMER_getCount(timer1); for (sdsp= 0; sdsp < N_SDSP; ++sdsp) { hc.dspInfo[sdsp].dspNum= sdsp; /* The mask allows the trigger loop to make quick bitfield-based decisions about issuing triggers to SDSPs: */ hc.dspInfo[sdsp].mask= 0xff; //Default "inactive" mask. if (!(hc.slvBits & (1< 1) ||(hc.dspInfo[hc.dspPair[i][1]].nPorts > 1) ||(hc.dspInfo[hc.dspPair[i][0]].ports == hc.dspInfo[hc.dspPair[i][1]].ports) ||(hc.dspInfo[hc.dspPair[i][0]].ports != 1) ) { sprintf(genStr, "DSP pairing error.\n"); newError(&returnCode, PARAM_ERROR, FATAL_ERR, "histoCtrlTask", genStr, __FILE__, __LINE__); return returnCode; } } //hc.timing->init.dt[6]= delta_t(hc.time); hc.time= TIMER_getCount(timer1); //hc.timing->init.dt[7]= delta_t(hc.time); hc.time= TIMER_getCount(timer1); /* Pre-compute the mask-set deltas for each SDSP if the masks will be changing; note that we only care about the serial port command link masks and the dynamic mode bits (DATA_LINK). The link configuration (on or off) is left unchanged by these mask sets to increase switching speed. This is done in a separate SDSP loop to allow paired SDSPs to be linked together. */ if (GET_RBIT(DIAGNOSTIC_REG, DR_USE_MDSP_MASK_LUT)) { for (sdsp= 0; sdsp < N_SDSP; ++sdsp) { setLinkMasks(0, SP_BOTH, ((DATA_LINK) +(COMMAND_LINK)), COMPUTE_MASK_DELTAS, sdsp); } setLinkMasks(0, SP_BOTH, ((DATA_LINK) +(COMMAND_LINK)), COMPUTE_MASK_DELTAS, MASK_SET_INIT); } setLinkMasks(0, SP_BOTH, ((DATA_LINK) +(COMMAND_LINK)), SET_MASK, MASK_SET_INIT); hc.slvRep= hc.repetitions; hc.reTransmitCnt= 0; //hc.timing->init.dt[8]= delta_t(hc.time); hc.time= TIMER_getCount(timer1); /* Get pointers to & initialize the sp buffers */ hc.cmdBuffer[0]= &cmdBuffer[0]; hc.cmdBuffer[1]= &cmdBuffer[1]; initCmdBuffer(hc.port); /* Initialize the post-configuration command list structure. This is used later to re-enable data taking (the configuration commands will throw the ABCD chips into send-config mode), and issue a BC reset (to ensure that the modules & ROD are in synch). */ for (i=0; iinit.dt[9]= delta_t(hc.time); hc.time= TIMER_getCount(timer1); hc.timing->init.total = delta_t(hc.initTime); hc.time= TIMER_getCount(timer1); if (hc.manual) scanWait(SCAN_END_INIT, 0); //return returnCode; #if 1 //dpsf: temp. belongs in sdsp setup really. /* override the task manager's event filter on the slaves temporarily, and set the slaves' trap cmd-stat register to indicate that triggers will be pending */ for (sdsp= 0; sdsp< N_SDSP; ++sdsp) { if (!(hc.slvBits & (1<trigger.accepts; //Later we will add the range lists: hc_hsetup_i.xPtr[0]= hc_hsetup_i.xPtr[1]= (MDAT32 *) DEFAULT; } if (!(hc.extSetup & EXT_SETUP_HTASK)) { setMem((UINT32 *) &hc_htask_i, SIZEOF(hc_htask_i), 0); hc_htask_i.completionFlag= TRUE; hc_htask_i.priority= 1; hc_htask_i.taskType= HISTOGRAM_TASK; hc_htask_i.taskRevision= R_HISTOGRAM_TASK; hc_htask_i.taskStruct.histogramTaskIn.nEvents= COLLECT_FOREVER; hc_htask_i.taskStruct.histogramTaskIn.controlFlag= MASTER_HREG; } hc.setupState= HCSETUP_LISTMAKE; return WAITING_FOR_SLAVES; } /* Build the primitive list to be sent to the SDSPs. The list is re-built for each SDSP. The next SDSP will be handled after the list has been processed & checked for the current SDSP. */ else if (hc.setupState == HCSETUP_LISTMAKE) { /* get the first non-zero SDSP bit from the bitfield */ for (i= 0; i< N_SDSP; ++i) { if (!(slvBits & 1< HCTRL_TIMEOUT) { sprintf(genStr, "%s%d%s", "Timed out while waiting for SDSP #", sdsp, " to finish processing IDSP primitive list.\n"); newError(&returnCode, TIMEOUT_ERR, FATAL_ERR, "histoCtrlSdspSetup", genStr, __FILE__, __LINE__); hc.setupState= HCSETUP_INIT; return returnCode; } } else {hc.setupState= HCSETUP_LISTTEST; } return WAITING_FOR_SLAVES; } /* Check that the list completed without errors, and go on to the next SDSP, if necessary. */ else if (hc.setupState == HCSETUP_LISTTEST) { if ((lerr= getIntrDspErr()) || (lfatal= getIntrDspFatal())) { //SDSP problem? sprintf(genStr, "%s%d%s%d%s%d%s", "The inter-DSP list failed for SDSP #", sdsp, " (err, fatal err == ", lerr, " ", lfatal, ").\n"); newError(&returnCode, PRIMLIST_ERR, FATAL_ERR, "histoCtrlSdspSetup", genStr, __FILE__, __LINE__); hc.setupState= HCSETUP_INIT; return returnCode; } slvBits^= 1<nb.nExe++; hc.timing->nb.dt_task+= delta_t(hc.time); hc.time= TIMER_getCount(timer1); /* General setup: set the current command masks to the current run-time masks, and update all the MDSP registers & counters. Then set up all the necessary registers on each SDSP we are working with. The SDSPs regard each pass through NEWBIN as just that-- a new bin (albeit sometimes the bin # stays the same). */ setTaskState(HISTOGRAM_CTRL_TASK, HCTRL_NEWBIN); getTaskCtrlBits(); if (hc.binPause) scanWait(SCAN_NB_INIT, 0); /* set initial command and data mask states */ if (!GET_RBIT(DIAGNOSTIC_REG, DR_USE_MDSP_MASK_LUT)) writeRegisterDirect(FE_MASK_LUT_SELECT, 3, 0, MASK_SET_INIT); else { switchLinkMasks(((DATA_LINK)+(COMMAND_LINK)), MASK_SET_INIT); if ( (hc.cfgReg[0] == ST_BYPASS) || (hc.cfgReg[0] == ST_TOKEN) ||(hc.cfgReg[1] == ST_BYPASS) || (hc.cfgReg[1] == ST_TOKEN) ) { /* Pre-compute the mask-set deltas for each SDSP if the masks will be changing; note that we only care about the serial port command link masks and the dynamic mode bits (DATA_LINK). The link configuration (on or off) is left unchanged by these mask sets to increase switching speed. This is done in a separate SDSP loop to allow paired SDSPs to be linked together. */ for (i= 0; i < N_SDSP; ++i) { setLinkMasks(0, SP_BOTH, ((DATA_LINK) +(COMMAND_LINK)), COMPUTE_MASK_DELTAS, i); } setLinkMasks(0, SP_BOTH, ((DATA_LINK) +(COMMAND_LINK)), COMPUTE_MASK_DELTAS, MASK_SET_INIT); } } //Reset the EFB counters by toggling the cmd. reg. bit: writeRegister(EFB_CMND_0, 1, EFB_GROUP_COUNTER_EN_O, 0); writeRegister(EFB_CMND_0, 1, EFB_GROUP_COUNTER_EN_O, 1); hc.efbCnt= 0x00000000; hc.evtWait= TRUE; hc.trigLoopMax= 1; hc.trigDelay= 0; newTrapSeries(); //Give the SDSPs a new trap series. bin= hc.status->currentBin[0]; ASGN_RFLD(HSTATUS_REG_0, HSTAT0_BIN, HSTAT0_BIN_W, bin); //ASGN_RFLD(HSTATUS_REG_0, HSTAT0_CHIP, HSTAT0_CHIP_W, hc.status->currentChip); ASGN_RFLD(HSTATUS_REG_0, HSTAT0_STAGE, HSTAT0_STAGE_W, hc.status->currentMaskStage); WRITE_REG(HSTATUS_REG_1, 0); WRITE_REG(HSSTAT_REG_0, 0); WRITE_REG(HSSTAT_REG_1, 0); WRITE_REG(HSSTAT_REG_2, 0); WRITE_REG(HSSTAT_REG_3, 0); /* reset all the counters: */ hc.pulsing= hc.slvBits; for (slv= 0; slv< N_SDSP; ++slv) { if ((hc.scan->reset.binReset) && (hc.scan->reset.ECR)) { hc.dspInfo[slv].L1id[0]= hc.dspInfo[slv].L1id[1]= 0; } //hc.dspInfo[slv].nEvents[0]= hc.dspInfo[slv].nEvents[1]= 0; //hc.dspInfo[slv].nErrors[0]= hc.dspInfo[slv].nErrors[1]= 0; hc.dspInfo[slv].nTrig= hc.dspInfo[slv].nEvents= hc.dspInfo[slv].nErrors= 0; hc.dspInfo[slv].delErr= 0; hc.dspInfo[slv].updateCnt= hc.dspInfo[slv].sigmaEvtLen= 0; hc.dspInfo[slv].avgEvtLen= hc.dspInfo[slv].avgProcTime= 0; } #if 0 val= (hc.status->currentBin[0]<currentMaskStage<nb.dt_setup+= delta_t(hc.time); hc.time= TIMER_getCount(timer1); /* set the slaves histogram command registers. The waitExp state waits until they indicate they are ready to begin histogramming. */ for (slv= 0; slv< N_SDSP; ++slv) { if (!(hc.slvBits & (1<general.maskMode == SCAN_STAGED); hc.calLine= hc.status->currentMaskStage; for (slv= 0; slv< N_SDSP; ++slv) { if (!(hc.slvBits & (1<currentBin[0]<currentBin[0]<nb.dt_sdsp_setup+= delta_t(hc.time); hc.time= TIMER_getCount(timer1); #if 0 /* If advancing the current mask stage, calculate the new parameters, and then re-configure the masks on the modules. dpsf: for pixels & SCT, use pre-calculated global masks-- do not store the masks separately each time on each module-- time intensive. Instead, the current scan mask stage indicates the current mask, and it is broadcast to all modules, and then latched into the chips. If a given module needs special treatment: SCT: its mask is taken out of the broadcast and then each chips channel mask is set by bitwise ORing each channel's mask with the global mask. must decouple mask from basic struct sending in sendCfgSet. PXL: The FE enable on each module is looked at, if a given module has some FE not enabled, its mask is taken out of the global mask, the broadcast is done, with no mask setting/restoring in sendCfgSet & new settings : broadcast flag: loop disabled, will use the global structure's settings as reference, and add in the latch for each enabled chip only. */ if (hc.stageAdvance) { hc.timing->nb.loop[0].nExe++; //#ifndef SIM hc.timing->nb.loop[0].nExe++; if (hc.stagePause) scanWait(SCAN_STAGE_CFG, 0); for (i=0; icurrentMaskStage)); /* errorCode= setNextMaskStage(&hc.moduleCfg[i], hc.status->currentChip, hc.scan->general.moduleScanMode, hc.status->currentMaskStage); if not broadcasting */ }} //hc.timing->nb.loop[0].dt_calc[0]+= delta_t(hc.time); if (hc.stagePause) scanWait(SCAN_STAGE_SEND, 0); //Modify to allow sendCfg flag (set here) to handle stage setting while congfiguring //if it is doing so (if not configuring, the stage is set here): errorCode= sendConfigSet(hc.port, hc.mod8, ALL_CHIPS, //hc.status->currentChip, NORMAL_CONFIG_LOOP, //FALSE /*broadcast*/, TRUE, /* set & restore links */ hc.cfgSet, MODULE_GROUP_ALL, hc.stageCfg, TRUE /*activeOnly*/, FALSE /*enableDataTaking*/); //hc.timing->nb.loop[0].dt_calc[1]+= cfgTiming.setup; //hc.timing->nb.loop[0].dt_cfg+= cfgTiming.cfg; //hc.timing->nb.loop[0].total+= delta_t(hc.time); //#endif } #else for (i=0; icurrentChip, NORMAL_CONFIG_LOOP, //FALSE /*broadcast*/, TRUE, /* set & restore links */ hc.cfgSet, MODULE_GROUP_ALL, CONFIG_MODULE_BASIC, FALSE /*activeOnly*/, TRUE /*enableDataTaking*/); } #endif //#if !defined(SIM) /* load the variable into the configuration set (and set the calibration line if enabled). This is actually done only if it makes sense (time-wise) to do so, for varying things like trim-DACs the routine actually only loads a global structure. For varying the ROD trigger delay, the current delay in the scan control structure is updated instead: */ if (hc.manual) scanWait(SCAN_CFG_VARIABLE, 0); hc.time= TIMER_getCount(timer1); sendCfg= FALSE; for (i=0; i<2; ++i) { if (hc.binAdvance[i]) { if ( (hc.scan->general.scanParameter[i] == ST_TRIG_DELAY1) ||(hc.scan->general.scanParameter[1] == ST_TRIG_DELAY2) ) { hc.status->currentDelay= varRange[i][hc.status->currentBin[i]]; if (hc.scan->serial.calcFromStruct) buildScanTrigger(FALSE); else modifyTriggerDelay(hc.scan->general.scanParameter[i]); } else { sendCfg= TRUE; for (j=0; jcurrentChip, hc.cfgReg[i], varRange[k][hc.status->currentBin[i]]); #else //dpsf: temp. for (chip= 0; chip< N_CHIPS; ++chip) { /* If we are scanning across variables such as ST_BYPASS, TOKEN or a BOC variable, no need to loop over the chip variable. */ if ((chip>0) && (hc.singleCfgVar[i])) continue; errorCode= setChipVariable(&hc.moduleCfg[j], chip, hc.cfgReg[i], varRange[k][hc.status->currentBin[i]]); } #endif }} // Loop over modules (present & in group) } //hc.timing->nb.loop[1+i].dt_calc[0]+= delta_t(hc.time); }} // Loop over bin indices which advance. //#endif if (hc.manual) scanWait(SCAN_SEND_CFG, 0); /* later: if this RODs EXTERNAL MODULE histogram cmd reg flag has been set, then the ROD will pause between bins & signal the SBC that its ext modules need re-configuring by the controlling ROD(s?!!). All RODS with flag set will increment bins in lockstep, and an additional sendConfigSet call is made here. Histogram event triggering for these RODs is done by the SBC/TIM. If an error event occurs during histogramming, the ROD will notify the SBC which will send appropriate commands to the controlling ROD(s) (soft reset, etc.) */ if (sendCfg) { errorCode= sendConfigSet(hc.port, hc.mod8, ALL_CHIPS, //hc.status->currentChip, NORMAL_CONFIG_LOOP, //FALSE /*broadcast*/, TRUE, /* set & restore links */ hc.cfgSet, MODULE_GROUP_ALL, hc.dataType[0], FALSE /*activeOnly*/, TRUE /*enableDataTaking*/); } hc.timing->nb.dt_calc+= cfgTiming.setup; hc.timing->nb.dt_cfg+= cfgTiming.cfg; for (i=0; i<2; ++i) { if (hc.binAdvance[i]) { //hc.timing->nb.loop[1+i].dt_calc[1]+= cfgTiming.setup; //hc.timing->nb.loop[1+i].dt_cfg+= cfgTiming.cfg; //hc.timing->nb.loop[1+i].total+= delta_t(hc.time); }} hc.time= TIMER_getCount(timer1); if (hc.manual) scanWait(SCAN_NB_ECR_BCR, 0); if ( (hc.scan->reset.binReset) &&((hc.scan->reset.ECR) || (hc.scan->reset.BCR)) ){ resetModules(0, hc.scan->reset.ECR, hc.scan->reset.BCR, TRUE, TRUE); } hc.timing->nb.dt_resets+= delta_t(hc.time); hc.time= TIMER_getCount(timer1); hc.first= TRUE; /* Set the last trigger time for all SDSPs to the current time + i x the dwelling time per dsp: */ for (i=0; ipulse[bin].dsp[i].lastTrigger= // hc.time +i*(hc.timing->pulse[bin].dspDwell); ; //Add in total time taken in the routine: hc.timing->nb.total+= delta_t(t0); hc.time= TIMER_getCount(timer1); return returnCode; } #define WAITING_FOR_SLAVES 1 /************************************************************************************ * histoCtrlWaitExp * * synopsis: Waits until the slave DSPs indicate that they are expecting events. * Normally this state will exit immediately since the slaves' registers * were set in the beginning of state NEWBIN, and several micro-seconds have * elsapsed. However, to account for the possibility that the slaves have some * initializations to do before they are ready, and to allow any interleaved * primitives to execute, a pause for up to one second is allowed; the master DSP * will repeat this state until the time limit is reached, or the slaves are * expecting events. * * author: Douglas Ferguson ************************************************************************************/ INT32 histoCtrlWaitExp(void) { INT32 returnCode= WAITING_FOR_SLAVES, status; static UINT32 t0; UINT8 slv; if (hc.first) { hc.first= FALSE; setTaskState(HISTOGRAM_CTRL_TASK, HCTRL_WAITEXP); t0= TIMER_getCount(timer1); hc.timing->wexp.nExe++; hc.timing->wexp.dt_task+= delta_t(hc.time); hc.time= TIMER_getCount(timer1); } status= chkSlaves(hc.slvBits, &hc.expecting, SDSP_HSTATUS_REG_0, HSR0_SLV_EXP); if (status != SUCCESS) { addError(&returnCode, status, "histoCtrlWaitExp", "chkSlaves", __FILE__, __LINE__); if (FATAL(returnCode)) return returnCode; } if (hc.expecting == hc.slvBits) { hc.first= TRUE; returnCode= SUCCESS; /* reset the slaves' NEWBIN & NEWCAL bits */ for (slv= 0; slv< N_SDSP; ++slv) { if (!(hc.slvBits & (1<wexp.total+= delta_t(t0); hc.time= TIMER_getCount(timer1); } else if (delta_t(t0) > HCTRL_TIMEOUT) { if (GET_RBIT(DIAGNOSTIC_REG, DR_HISTO_3)) scanWait(SCAN_WAITEXP, 0); sprintf(genStr, "%s%s%s%s0x%04x, 0x%04x%s","A problem has developed on ", "(at least) one of the slaves or it is not under master control.\n", "Timed out while waiting for slave to indicate it was ready.\n", "Slave, expecting bitfields= ",hc.slvBits, hc.expecting,".\n"); newError(&returnCode, SLAVE_NOT_READY, FATAL_ERR, "histoCtrlWaitExp", genStr, __FILE__, __LINE__); } return returnCode; } /************************************************************************************ * histoCtrlWaiting * * synopsis: Waits until the slave DSPs indicate that they have completed * processing this bin. Normally this state will exit immediately since * the slaves have finished with their events. However, to account for the * possibility that the slaves have cleanup to do after the bin has ended, and * to allow any interleaved primitives to execute, a pause for up to ten seconds * is allowed; the master DSP will repeat this state until the time limit is * reached, or the slaves indicate that they are done. * * author: Douglas Ferguson ************************************************************************************/ INT32 histoCtrlWaiting(void) { INT32 returnCode= WAITING_FOR_SLAVES, status; static UINT32 t0; if (hc.first) { hc.first= FALSE; setTaskState(HISTOGRAM_CTRL_TASK, HCTRL_WAITING); t0= TIMER_getCount(timer1); hc.timing->wait.nExe++; hc.timing->wait.dt_task+= delta_t(hc.time); hc.time= TIMER_getCount(timer1); } status= chkSlaves(hc.slvBits, &hc.done, SDSP_HSTATUS_REG_0, HSR0_SLV_DONE); if (status != SUCCESS) { addError(&returnCode, status, "histoCtrlWaiting", "chkSlaves", __FILE__, __LINE__); if (FATAL(returnCode)) return returnCode; } if (hc.done == hc.slvBits) { hc.first= TRUE; returnCode= SUCCESS; hc.timing->wait.total+= delta_t(t0); hc.time= TIMER_getCount(timer1); } else if (delta_t(t0) > HCTRL_TIMEOUT) { sprintf(genStr, "%s%s%s%s0x%04x, 0x%04x%s","A problem has developed on ", "(at least) one of the slaves or it is not under master control.\n", "Timed out while waiting for slave to indicate it was done.\n" "Slave, done bitfields= ",hc.slvBits, hc.done,".\n"); newError(&returnCode, SLAVE_NOT_READY, FATAL_ERR, "histoCtrlWaiting", genStr, __FILE__, __LINE__); } return returnCode; } /************************************************************************************ * histoCtrlPrep * * synopsis: Prepares the MDSP to enter NEWBIN. On the MDSP (& SDSPs), the NEWBIN * state simply implies that a variable has changed-- the actual bin * number may or may not change. The routine increments the current mask stage or * bin number, and perhaps both. NEWBIN does all the actual mask setting on the * modules. Once all bins are completed, the routine flags the task to exit. * * author: Douglas Ferguson ************************************************************************************/ UINT8 histoCtrlPrep(void) { UINT8 state, i, j, done= FALSE; /* The necessary adjustments to the current mask stage, inner and outer loop variables, and chip are made here & tested to see if the scan has finished. If not done, NEWBIN will transfer the new settings (i.e. stage, etc.) to the modules. If mask staging is requested, masks can be staged either before or after the inner loop variable, depending on the boolean stageAdvanceFirst variable's setting. */ setTaskState(HISTOGRAM_CTRL_TASK, HCTRL_PREP); hc.timing->prep.nExe++; hc.timing->prep.dt_task+= delta_t(hc.time); hc.time= TIMER_getCount(timer1); hc.stageAdvance= hc.binAdvance[0]= hc.binAdvance[1]= FALSE; if (hc.scan->general.maskMode == SCAN_STAGED) { if (hc.scan->general.stageAdvanceFirst) { //Advance stage 1st hc.stageAdvance= TRUE; if (hc.status->currentMaskStage >= (hc.scan->general.maskStages -1)) hc.binAdvance[0]= TRUE; if ( (hc.binAdvance[0]) &&(hc.status->currentBin[0] >= (hc.scan->general.nBins[0] -1)) ) hc.binAdvance[1]= TRUE; } else { //Advance bin[0] 1st hc.binAdvance[0]= TRUE; if (hc.status->currentBin[0] >= (hc.scan->general.nBins[0] -1)) hc.stageAdvance= TRUE; if ( (hc.stageAdvance) &&(hc.status->currentMaskStage >= (hc.scan->general.maskStages -1)) ) hc.binAdvance[1]= TRUE; } } else { hc.binAdvance[0]= TRUE; if (hc.status->currentBin[0] >= (hc.scan->general.nBins[0] -1)) hc.binAdvance[1]= TRUE; } /* Get new settings */ if (hc.stageAdvance) { ++hc.status->currentMaskStage; if (hc.status->currentMaskStage >= hc.scan->general.maskStages) hc.status->currentMaskStage= 0; } for (i=0; i<2; ++i) { if (hc.binAdvance[i]) { ++hc.status->currentBin[i]; if (hc.status->currentBin[i] >= hc.scan->general.nBins[i]) { hc.status->currentBin[i]= 0; if (i == 1) done= TRUE; } } } if (!done) state= HCTRL_NEWBIN; else state= TASK_DONE; hc.timing->prep.total+= delta_t(hc.time); hc.time= TIMER_getCount(timer1); return state; } /************************************************************************************ * histoCtrlDone * * synopsis: Loads the output structure variables, and halts histogramming and * data-taking on the slaves if they were not externally set up. The ROD * is returned to the state in which it was when the task was initially entered * (link setup, FPGA registers, etc.) This routine halts the scan gracefully. * There are several ways in which this routine can be reached: * * 1) via sucessful completion of the task. * 2) a fatal run-time error. * 3) user abort of a scan. * * In case 1 & 2 the routine will actually be called twice: once when the * DONE state is entered, and once again when the task manager senses that * the task has requested termination and sets the opFlag to TASK_HALT. In * case 3, the latter call above is the only call made. In the initial call * the routine uses the error flag in the histogram control structure to * determine the overall error status of the task, and returns the ROD state * to the state it was in at the time the task was initialized. Any subsequent * calls (before the task has been re-initialized) will be treated as dummy * calls. * * author: Douglas Ferguson ************************************************************************************/ INT32 histoCtrlDone(void) { INT32 status; if (!hc.reinit) { hc.reinit= TRUE; hc.timing->done.dt_task+= delta_t(hc.time); hc.time= TIMER_getCount(timer1); /* Restore the original masks & running mode. */ setLinkMasks(0, SP_BOTH, ((DATA_LINK)+(COMMAND_LINK)), SET_MASK, MASK_SET_INIT); hc.timing->done.total+= delta_t(hc.time); hc.time= TIMER_getCount(timer1); return hc.error; } else { return SUCCESS; } } typedef struct { UINT32 issueTrig, trigLoopMax, trigSent, efbCnt, cnt, icnt1, icnt2, sdspMask, mask, irdy, ready; } xStruct; xStruct x; /************************************************************************************ * histoCtrlTask * * synopsis: Controls & monitors the filling of slave DSP histograms during a scan. * The task (state-machine) states which are infrequently called are * handled by subroutines (so they can be put in different memory segments if * desired); the pulsing state is the only state which is not done via a separate * routine as the additional delay to set up & call it (up to 2-3 micro-seconds) * is potentially undesirable. The smaller routine is also easier to fit in the * MDSP's fast internal memory. * * The routine is centered around the concept of module groups: sets of modules * which get the same trigger & behave in a similar fashion during a scan. Which * group a given module is in is determined by that module's (pre-loaded) control * structure (eg. ABCDModule). * * author: Douglas Ferguson ************************************************************************************/ INT32 histoCtrlTask(union TASK_STRUCTURES_IN *tsi, union TASK_STRUCTURES_OUT *tso, UINT32 opFlags) { INT32 returnCode= REPEAT_TASK, status, errorCnt; UINT32 t0, dt; static UINT8 state= TASK_INIT; register UINT32 sdsp, twin; #if defined(XS) register UINT32 issueTrig, trigLoopMax, trigSent, efbCnt, cnt, icnt1, icnt2, sdspMask, mask, irdy, ready; #endif /********************* data retrieval & routine reset *********************/ if (opFlags > 0x10) {return (returnCode= scanTaskOp(tso, opFlags, &state)); } /************************* routine states:PULSING *************************/ if (state == HCTRL_TRIGGERS) { t0= TIMER_getCount(timer1); /* The trigSent variable is a bitfield based upon the corresponding number of evts sent, with 8 bits / sdsp. It is compared inside the loop to the trigLoopMax variable. */ #if defined(XS) trigSent= 0x00000000; trigLoopMax= hc.trigLoopMax; //controls # triggers done this iteration. efbCnt= hc.efbCnt; //retrieve stored event count. issueTrig= hc.pulsing; //bitfield controlling trigger sending. #else x.trigSent= 0x00000000; x.trigLoopMax= hc.trigLoopMax; //controls # triggers done this iteration. x.efbCnt= hc.efbCnt; //retrieve stored event count. x.issueTrig= hc.pulsing; //bitfield controlling trigger sending. #endif #if defined(XS) while (issueTrig) { #else while (x.issueTrig) { #endif //Adjust trigger timing if needed: if (hc.trigDelay) delay(hc.trigDelay); //Cannot use pointer to register variable, so borrow dt: status= readRegister(EFB_EVT_CNT, 32, 0, &dt); #if defined(XS) cnt= dt; //Use extu intrinsic to guarantee single cycle for extract: icnt1= _extu(cnt, 28, 28); icnt2= _extu(efbCnt, 28, 28); ready= (icnt1 == icnt2); //sdsp 0 icnt1= _extu(cnt, 24, 28); icnt2= _extu(efbCnt, 24, 28); irdy= (icnt1 == icnt2); irdy<<= 1; ready|= irdy; //sdsp 1 icnt1= _extu(cnt, 20, 28); icnt2= _extu(efbCnt, 20, 28); irdy= (icnt1 == icnt2); irdy<<= 2; ready|= irdy; //sdsp 2 icnt1= _extu(cnt, 16, 28); icnt2= _extu(efbCnt, 16, 28); irdy= (icnt1 == icnt2); irdy<<= 3; ready|= irdy; //sdsp 3 #else x.cnt= dt; //Use extu intrinsic to guarantee single cycle for extract: x.icnt1= _extu(x.cnt, 28, 28); x.icnt2= _extu(x.efbCnt, 28, 28); x.ready= (x.icnt1 == x.icnt2); //sdsp 0 x.icnt1= _extu(x.cnt, 24, 28); x.icnt2= _extu(x.efbCnt, 24, 28); x.irdy= (x.icnt1 == x.icnt2); x.irdy<<= 1; x.ready|= x.irdy; //sdsp 1 x.icnt1= _extu(x.cnt, 20, 28); x.icnt2= _extu(x.efbCnt, 20, 28); x.irdy= (x.icnt1 == x.icnt2); x.irdy<<= 2; x.ready|= x.irdy; //sdsp 2 x.icnt1= _extu(x.cnt, 16, 28); x.icnt2= _extu(x.efbCnt, 16, 28); x.irdy= (x.icnt1 == x.icnt2); x.irdy<<= 3; x.ready|= x.irdy; //sdsp 3 #endif /* If any SDSP is indicating that it's not ready, break out of loop. This should only happen with a) an error or b) the SDSPs are using slower histogramming code & are filling up. Note that all the SDSPs are checked, even if some are not participating in the scan, since those SDSP could be set up externally to receive scan events as well. The condition is handled in the scanAttnHandle routine. */ status= readRegister(INTRPT_FROM_SLV, 4, 0, &hc.sdspAttention); if (hc.sdspAttention != 0xf) break; hc.trigTime= TIMER_getCount(timer1); #if defined(XS) ready &= issueTrig; #else x.ready &= x.issueTrig; #endif for (sdsp= 0; sdsp must handle wrapping): icnt1= sdsp<<2; icnt2= icnt1 +3; //borrow icnt1, icnt2 & cnt. //mask= 0xf< must handle wrapping): x.icnt1= sdsp<<2; x.icnt2= x.icnt1 +3; //borrow icnt1, icnt2 & cnt. //mask= 0xf< hc.taskTimeMax) x.issueTrig= FALSE; } //send triggers? #if defined(XS) hc.efbCnt= efbCnt; //Store new EFB counter. /* Increment trigger counter; this is done per SDSP to allow flexibility in deciding how to end the while loop above: */ for (sdsp= 0; sdsp>4; delay(icnt2); } #else if (hc.evtWait) { t0= TIMER_getCount(timer1); status= readRegister(EFB_BANDWIDTH_CNT, 16, 0, &dt); x.icnt1= dt; do { delay(20); //2 us delay. status= readRegister(EFB_BANDWIDTH_CNT, 16, 0, &dt); x.icnt2= dt; x.ready= (x.icnt2 == x.icnt1); x.icnt1= x.icnt2; } while ((!x.ready) && ((dt= delta_t(t0)) < HCTRL_TIMEOUT)); x.cnt= delta_t(hc.trigTime); x.icnt2= x.cnt>>4; delay(x.icnt2); } #endif //Now check the events & handle any errors: errorCnt= scanEventCheck(hc.evtWait); if (errorCnt) status= scanErrHandle(); if (status != SUCCESS) {state= TASK_DONE; hc.error= status; } /* Check the attention flag & handle if necessary. Note that the raw attention flag from the trigger loop is inverted: 0xf => all ok: */ if (hc.sdspAttention != 0xf) status= scanAttnHandle(); if (status != SUCCESS) {state= TASK_DONE; hc.error= status; } //Update statistics, and (potentially) extend the event loop's duration: updateScanStatistics(); scanExtrapolate(); if (!hc.pulsing) {/* yippie! */ hc.first= TRUE; state= HCTRL_WAITING; } } //state == trigger loop /*************************** other routine states *************************/ /* Other routine states are handled in a separate routine to conserve space in the on-chip program memory: */ else {returnCode= scanTaskStates(tsi, &state); } return returnCode; } /************************************************************************************ * scanTaskOp: Handles output for the histogram control task. * scanTaskStates: Handles all states other than the trigger loop for the * histogram control task ************************************************************************************/ INT32 scanTaskOp(union TASK_STRUCTURES_OUT *tso, UINT32 opFlags, UINT8 *state) { INT32 returnCode; tso->genTaskOut.dataPtr= hc.status; tso->genTaskOut.dataLength= SIZEOF(ScanStatus); if (opFlags & TASK_HALT_MASK) { newInformation(__FILE__, __LINE__, "Scan Control task halting.\n"); *state= TASK_INIT; returnCode= TASK_HALTED; } else if (opFlags & TASK_INIT_MASK) { newInformation(__FILE__, __LINE__, "Scan Control task re-initing.\n"); *state= TASK_INIT; returnCode= TASK_INITIALIZED; } else if (opFlags & TASK_QUERY_MASK) { newInformation(__FILE__, __LINE__, "Scan Control task: query data output.\n"); returnCode= TASK_QUERIED; } else returnCode= REPEAT_TASK; return returnCode; } /************************************************************************************/ INT32 scanTaskStates(union TASK_STRUCTURES_IN *tsi, UINT8 *state) { INT32 returnCode= REPEAT_TASK, status; /*************************** routine states:INIT **************************/ if (*state == TASK_INIT) { /* set up any static variables beyond state: */ status= histoCtrlInit(tsi); if (status != SUCCESS) {*state= TASK_DONE; hc.error= status; } else *state= HCTRL_SDSP_SETUP; } /*************************** routine states:SDSP_SETUP ********************/ if (*state == HCTRL_SDSP_SETUP) { status= histoCtrlSdspSetup(tsi); if (status != SUCCESS) {*state= TASK_DONE; hc.error= status; } else *state= HCTRL_NEWBIN; } /************************** routine states:NEWBIN *************************/ else if (*state == HCTRL_NEWBIN) { status= histoCtrlNewBin(); if (status != SUCCESS) {*state= TASK_DONE; hc.error= status; } else *state= HCTRL_WAITEXP; } /************************* routine states:WAITEXP *************************/ else if (*state == HCTRL_WAITEXP) { status= histoCtrlWaitExp(); if (status != SUCCESS) { if (FATAL(status)) { *state= TASK_DONE; hc.error= status; return returnCode; } else return returnCode; /* still waiting */ } /* The state is set here to avoid having to either set it or test to see if we've done so on each pass through the event loop: */ *state= HCTRL_TRIGGERS; setTaskState(HISTOGRAM_CTRL_TASK, *state); } /************************* routine states:WAITING *************************/ else if (*state == HCTRL_WAITING) { status= histoCtrlWaiting(); if (status != SUCCESS) { if (FATAL(status)) { *state= TASK_DONE; hc.error= status; return returnCode; } else return returnCode; /* still waiting */ } *state= HCTRL_PREP; } /*************************** routine states:PREP **************************/ else if (*state == HCTRL_PREP) { *state= histoCtrlPrep(); /* branch: DONE or NEWBIN */ return returnCode; } /*************************** routine states:DONE **************************/ else if (*state == TASK_DONE) { status= histoCtrlDone(); returnCode= status; } return returnCode; }