/************************************************************************************ * histogram.c * * synopsis: Contains routines responsible for creating and organizing histograms, * and generating histograms from incoming trapped events. * * in this file: initHistos, histoSetup, setHistoModuleBase, histoEvent_c * * Douglas Ferguson, UW Madison (510) 486-5230 dpferguson@lbl.gov ************************************************************************************/ #include #include #include #include #include "resources.h" #include "comRegDfns.h" #include "serialStreams.h" #include "histogram.h" #pragma CODE_SECTION(initHistos, "xcode"); #pragma CODE_SECTION(histoSetup, "xcode"); #pragma CODE_SECTION(setHistoModuleBase, "icode"); #pragma CODE_SECTION(histoEvent_c, "icode"); #pragma CODE_SECTION(histoEvent_c_chipocc, "icode"); extern char genStr[]; extern far ModuleMaskData moduleMaskData[N_TOTMODULES]; extern far UINT32 maskDataFlag; #pragma DATA_SECTION(histoCtrl, "idata"); #pragma DATA_SECTION(binCtr, "xpdata"); #pragma DATA_SECTION(varRange, "xpdata"); HistoCtrl histoCtrl; BinCtr binCtr; FLOAT32 varRange[2][HISTOGRAM_BIN_MAX]; UINT32 chipOcc[16]; /************************************************************************************ * initHistos * synopsis: initializes the histogram control structure. ************************************************************************************/ INT32 initHistos() { INT32 returnCode= SUCCESS; setMem((UINT32 *) &histoCtrl, SIZEOF(HistoCtrl), 0); setMem((UINT32 *) &binCtr, SIZEOF(binCtr), 0); return returnCode; } /************************************************************************************ * histoSetup * * synopsis: Sets up and initializes histograms and histogramming variables. * * parameters: * * base: The base of the histograms in memory. * nBins: The number of bins in each histogram. * binSize: The size of each occupancy bin (16 or 32 bits). * routineType: The type of routine to use: assembly language or c. * * opt[0]: True if chip-occupancy histograms are desired. * opt[1]: The link data format (condensed or expanded). * opt[2]: Verbose mode flag (c code only). * opt[3]: Unused. * * validModules[2]: Bitfield indicating which modules will actually have * histogram space reserved for them. * moduleRangeMap[2][2]: Bitfields indicating which modules use which range * map (see below). * *xPtr[2]: Pointer to the range data (bins' central values); there * are 2 possible ranges, and a given module (group) can use * either one. Range data is stored after the primitive's input structure in * the primitive list if its pointer is set to the DEFAULT value (0xffffffff). * There must be one entry per bin in this table. Used for histogram fitting. * dataType[2]: The type of data represented by the x axis (bins) of the * histograms; the two types correspond to the two possible * maps. * * author: Douglas Ferguson ************************************************************************************/ INT32 histoSetup(UINT32 *base, UINT32 nBins, UINT32 binSize, UINT32 routineType, UINT32 dataType[2], UINT32 opt[4], UINT32 validModules[2], UINT32 moduleRangeMap[2][2], MDAT32 *xPtr[2]) { INT32 returnCode= SUCCESS, errorCode; UINT32 *ptr, ptrInc, setSize; UINT8 i, j, mod, bin, set; /* Parameter & other error checking */ if (!maskDataFlag) { newError(&returnCode, LINKMASK_ERR, FATAL_ERR, "histogramSetup", "The module data link masks must be loaded first via moduleMask.\n", __FILE__, __LINE__); } if (nBins > HISTOGRAM_BIN_MAX) { sprintf(genStr, "%s%d%s%d%s","Maximum number of bins is ", HISTOGRAM_BIN_MAX, " ([0,",(HISTOGRAM_BIN_MAX-1),"]).\n"); newError(&returnCode, PRIM_PARAMETER_ERROR, FATAL_ERR, "histoSetup", genStr, __FILE__, __LINE__); } if (returnCode != SUCCESS) return returnCode; /***** setup *****/ errorCode= initHistos(); if (base == (UINT32 *) DEFAULT) histoCtrl.base= (UINT32 *) HISTOGRAM_DEFAULT_BASE; else histoCtrl.base= base; histoCtrl.nBins= nBins; histoCtrl.binSize= binSize; histoCtrl.routineType= routineType; histoCtrl.doChipOcc= opt[0]; histoCtrl.dataFormat= opt[1]; histoCtrl.verbose= opt[2]; if (GET_RBIT(DIAGNOSTIC_REG, DR_HTYPE_REGSET)) { histoCtrl.doChipOcc= GET_RBIT(DIAGNOSTIC_REG, DR_HISTO_CHIPOCC); histoCtrl.routineType= GET_RBIT(DIAGNOSTIC_REG, DR_HISTO_ASM); } if (histoCtrl.routineType == HISTO_ROUTINE_ASM) { if (histoCtrl.verbose) {histoVerboseAsmWarnM(); } if (histoCtrl.dataFormat == HISTOGRAM_FULL) {histoFormatAsmFatalM(); } if (histoCtrl.binSize != HISTOGRAM_32BIT) {histoBinSizeAsmFatalM(); } sprintf(genStr, "Using assembly language histogram function"); if (histoCtrl.doChipOcc) histoCtrl.histoFxn= histoEvent_asm_chipocc; else histoCtrl.histoFxn= histoEvent_asm; } else if (histoCtrl.routineType == HISTO_ROUTINE_C) { sprintf(genStr, "Using c histogram function"); if (histoCtrl.doChipOcc) histoCtrl.histoFxn= histoEvent_c_chipocc; else histoCtrl.histoFxn= histoEvent_c; } if (histoCtrl.doChipOcc) strcat(genStr, " with chip occupancy counters"); strcat(genStr, ".\n"); newInformation(__FILE__, __LINE__, genStr); for (i=0; i<2; ++i) { histoCtrl.validModules[i]= validModules[i]; histoCtrl.xPtr[i]= xPtr[i]; /* dpsf: later read in lists */ histoCtrl.dataType[i]= dataType[i]; histoCtrl.moduleRangeMap[i][0]= moduleRangeMap[i][0]; histoCtrl.moduleRangeMap[i][1]= moduleRangeMap[i][1]; } histoCtrl.calLine= 0; if ( ((UINT32) histoCtrl.base < HISTOGRAM_DEFAULT_BASE) ||((UINT32) histoCtrl.base > (SDRAM1_BASE+SDRAM1_SZ)) ) { sprintf(genStr, "%s%s%d","Histograms must be in SDRAM, above the reserved ", "memory (preferred base: ", HISTOGRAM_DEFAULT_BASE,").\n"); newError(&returnCode, PRIM_PARAMETER_ERROR, FATAL_ERR, "histogramSetup", genStr, __FILE__, __LINE__); return returnCode; } histoCtrl.binCtr= (BinCtr *) &binCtr; /* The look-up table base pointer points to the base of the current bin's lookup table which gives the corresponding module's histogram address base for a given link. It could be simply referred to since the array is in the histogram control structure anyway, but setting a pointer to in allows the LUT base to be easily modified to point to another LUT if desired */ histoCtrl.lutBase= (UINT32 *) &histoCtrl.moduleBase[1][0]; for (i= 0; i < 2; ++i) { for (j= 0; j< histoCtrl.nBins; ++j) { varRange[i][j]= *(histoCtrl.xPtr[i] +j); } } /* scan the validModule fields to find the # of enabled modules for this slave DSP */ histoCtrl.nValidModules= 0; for (mod=0; mod=32) && (validModules[1] & (1<<(mod-32)))) ) { /* enabled */ ++histoCtrl.nValidModules; } } /* build deltaChan, chip, module & bin. All offsets are computed in terms of the offsets to the current pointer (either 16 or 32 bit): */ histoCtrl.emptyLength= 16; histoCtrl.hashScheme= 4; histoCtrl.deltaChan= 1; histoCtrl.deltaChip= N_STRIPS*histoCtrl.deltaChan; /* Note that by letting SCT chips vary between 0 & 15 as seen below some gaps are left in the histogram space. However, this allows for faster histogramming since the needed offsets do not require any computation using the chip number (0-5, then 8-12) */ histoCtrl.deltaModule= 16*histoCtrl.deltaChip; histoCtrl.deltaBin= histoCtrl.nValidModules*histoCtrl.deltaModule; histoCtrl.deltaSet= histoCtrl.deltaBin*histoCtrl.nBins; /* + one extra (1 bin) module to collect any hits from "stray" (invalid, or without any histogramming space reserved) modules, if not all modules are valid. Placed at the end of valid data; this block is always unformatted. */ histoCtrl.invalidData= histoCtrl.base +histoCtrl.deltaSet*histoCtrl.binSize/32; histoCtrl.deltaSet+= histoCtrl.deltaModule; /* check to make sure that the histograms fit in memory. The factor of 2 accounts for the fact that these are 16 bit bins (size is in bytes). If 32 bit bins are desired, the factor is increased to four. If the full rather than condensed data format is used, the size triples. */ histoCtrl.size= 2*histoCtrl.deltaSet; if (histoCtrl.binSize == HISTOGRAM_32BIT) histoCtrl.size*= 2; if (histoCtrl.dataFormat == HISTOGRAM_FULL) histoCtrl.size*= 3; if ( ((UINT32) histoCtrl.base) + histoCtrl.size > (SDRAM1_BASE +SDRAM1_SZ)) { newError(&returnCode, MEMORY_EXCEEDED, FATAL_ERR, "histoSetup", "The requested histograms do not fit in memory.\n", __FILE__, __LINE__); return returnCode; } /* Now set up module memory maps; here we set up the initialization pointers- these must be modified to construct the working set ([1]) before collecting events in each bin by calling the routine below again */ setHistoModuleBase(TRUE /* init */, 0); //Now zero-out and mark the histograms (unless simulating, which causes //painful delays: #if ((!defined(SIM)) && (!defined(TI_EVM))) setMem(histoCtrl.base, histoCtrl.size/4, 0); setSize= histoCtrl.size/(4*3); /* slice histograms: place a module and bin marker in the unused space at the end of each module */ if (histoCtrl.binSize == HISTOGRAM_32BIT) ptrInc= histoCtrl.deltaModule; else if (histoCtrl.binSize == HISTOGRAM_16BIT) ptrInc= histoCtrl.deltaModule/2; for (set= 0; set=32) && (validModules[1] & (1<<(mod-32)))) ) { ptr+= ptrInc; ptr-= 10; *ptr++= 0xffffffff; *ptr++= 0; sprintf((char *) ptr, "End of bin %02d Module %02d ", bin, mod); ptr+= 7; *ptr++= 0xffffffff; }} /* loop over all valid modules */ } /* loop over bins */ } /* loop over sets (previous/current/next BCX for full format) */ #endif histoCtrl.histogramsAreSetup= TRUE; return returnCode; } /************************************************************************************ * setHistoModuleBase: Initializes & sets the moduleBase[][] field in the * histogram control structure to point to the base of * memory for that module. This routine must be run at the start of every * new bin, before accumulating hit data. The moduleBase pointers take into * account the way the formatters convert module numbers (base 12; so * module 23= links 0x3a, 3b). The link number is divided by two (shifted right * by one) to get the module's pointer index. ************************************************************************************/ void setHistoModuleBase(UINT8 init, UINT8 bin) { UINT8 mod, i, idx, nMod; UINT32 *ptr, dBase; if (init) { ptr= histoCtrl.base; for (idx=0; idx<128; ++idx) histoCtrl.moduleBase[0][idx]= histoCtrl.invalidData; for (nMod= mod= 0; mod=32) && (histoCtrl.validModules[1] & (1<<(mod-32)))) ) { //Get the valid links for this module & assign the pointers. for (i=0; i<2; ++i) { idx= moduleMaskData[mod].fmtLink[i]; if ((idx > 0x7b) || ((idx & 0xf) > 0xb)) continue; /* The right shift divides by 32 */ histoCtrl.moduleBase[0][idx]= ptr +((nMod*histoCtrl.deltaModule*histoCtrl.binSize)>>5); } ++nMod; //increment the valid-module counter } } } /* Use the histogramming delta-bin offset to create a set of working module bases for this bin. */ else { /* dBase equals the pointer offset needed to reach the current histogram base, given the absolute base (for each module). */ dBase= (bin*histoCtrl.deltaBin*histoCtrl.binSize)>>5; for (idx=0; idx<128; ++idx) { if (histoCtrl.moduleBase[0][idx] == histoCtrl.invalidData) { histoCtrl.moduleBase[1][idx]= histoCtrl.moduleBase[0][idx]; } else { histoCtrl.moduleBase[1][idx]= histoCtrl.moduleBase[0][idx] +dBase; } } } } /************************************************************************************ * histogramming routines: * * synopsis: Given a pointer to an event's data structure, histoEvt uses the * histogram structures set up by the histogram manager to add its * contents to the histograms in memory. Error checking has already been done * (by the router & given to the DSP in a trailer word), so it is not necessary * to scan the links for errors. Since so many masks are used that the code * gets awkward, for brevity and clarity they have been replaced by the (fixed) * bitmasks. The various masks and their explanations are included here for * reference; see also the documentation in the ROD Operations Manual: Chapter 4, * and the ADCD3T ASIC Chip Specification. * * author: Douglas Ferguson ************************************************************************************/ void histoEvent_c(struct EventData *data) { UINT16 *dataPtr, *startPtr, *endPtr, maskStore, mask, cc; UINT32 *hModBase, *hPtr, wData; UINT8 i, hw= 1, nDataFrames, lMod, dataFramesDone= 0, frame, module, ncle, cl, test1, test2, dataWarn= 0; ncle= (histoCtrl.calLineEnable)? 0:16; cl= histoCtrl.calLine; test1= test2= ncle; //pre-load the static part of line testing. hModBase= histoCtrl.invalidData; //protect against bad data. 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+= 20; /* 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 */ /* condensed links store 1 or 2 hit in adjacent channels inside half-words. If the same address repeats, the cluster extends to 3, 4 or more hits. */ if ((mask=(*dataPtr & 0xfff0)) != maskStore) { maskStore= mask; /* repeat= 0; */ cc= _extu(wData, 17, 21); } else { cc+= 2; } /* If calibration line looping is not enabled, then the tests are already true (all channels enabled); otherwise check to see if the channels match the calibration line */ if (!test1) { mask= cc & 3; if (mask++ == cl) test1++; //re-use mask mask &= 3; if (mask == cl) test2++; } if ((*dataPtr & 0x0001) == 0) test2= 0; hPtr= hModBase +cc; if (test1) ++(*hPtr); if (test2) ++(*(hPtr+1)); test1= test2= ncle; //reset the line tests. } /* Test to see if the data represents a link header. The router gives headers as either 0x21LL (condensed format) or 0x20LL (expanded format), where the LL indicates the link data for the lookup table. The LSB of the 0x21/20 is shifted away for the comparision. */ else if (_extu(wData, 16, 25) == 0x10) { maskStore= 0; module= (*dataPtr & 0x7f); /* Get the module's histogram base from the LUT, and warn if the link is invalid (and thus the histograms do not have space reserved for this module). */ hModBase= histoCtrl.moduleBase[1][module]; if (hModBase == histoCtrl.invalidData) { dataWarn|= 2; } /* If an expanded format link is found, exit with a warning. (Histograms here are not set up to deal with this). */ if ((*dataPtr & 0x0100) == 0) { dataWarn|= 1; return; } } //Link header processing. } //Loop over data words in frame. frame= getNextFrame(data, frame, TRAP_FXN_HISTOGRAM); ++dataFramesDone; } if (dataWarn) { /* Warn user about link formatting. */ histoCtrl.dataWarn= dataWarn; ASGN_RFLD(HSTAT_REG_0, HSR0_SLV_WARN, HSR0_SLV_WARN_W, dataWarn); } } /************************************************************************************/ void histoEvent_c_chipocc(struct EventData *data) { UINT16 *dataPtr, *startPtr, *endPtr, maskStore, mask, cc; UINT32 *hModBase, *hPtr, wData; UINT8 i, hw= 1, nDataFrames, lMod, dataFramesDone= 0, frame, module, chip, ncle, cl, test1, test2, dataWarn= 0; ncle= (histoCtrl.calLineEnable)? 0:16; cl= histoCtrl.calLine; test1= test2= ncle; //pre-load the static part of line testing. hModBase= histoCtrl.invalidData; //protect against bad data. /* Zero the chip occupancy counters: */ for (chip= 0; chip < 16; ++chip) chipOcc[chip]= 0; 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+= 20; /* 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 */ /* condensed links store 1 or 2 hit in adjacent channels inside half-words. If the same address repeats, the cluster extends to 3, 4 or more hits. */ if ((mask=(*dataPtr & 0xfff0)) != maskStore) { maskStore= mask; /* repeat= 0; */ chip= _extu(wData, 17, 28); cc= _extu(wData, 17, 21); } else { cc+= 2; } /* If calibration line looping is not enabled, then the tests are already true (all channels enabled); otherwise check to see if the channels match the calibration line */ if (!test1) { mask= cc & 3; if (mask++ == cl) test1++; //re-use mask mask &= 3; if (mask == cl) test2++; } if ((*dataPtr & 0x0001) == 0) test2= 0; hPtr= hModBase +cc; if (test1) {++(*hPtr); ++chipOcc[chip]; } if (test2) {++(*(hPtr+1)); ++chipOcc[chip]; } test1= test2= ncle; //reset the line tests. } /* Test to see if the data represents a link header. The router gives headers as either 0x21LL (condensed format) or 0x20LL (expanded format), where the LL indicates the link data for the lookup table. The LSB of the 0x21/20 is shifted away for the comparision. */ else if (_extu(wData, 16, 25) == 0x10) { maskStore= 0; module= (*dataPtr & 0x7f); /* Upon encountering every new link header, if the module is different (in which case the base in memory will change), store the previously accumulated chip occupancy counters into memory. Afterward, clear them for the next module's data, which follows. The chip occupancy histograms are stored in the two unused areas above the channel occupancy histograms (corresponding to chips 6-7 & 14-15, which do not exist). Chip occupancies for chips 0-5 are stored in the area for chips 6-7, and occupancies for chips 8-13 are stored in the area for chips 14-15. */ for (chip= 0; chip < 14; ++chip) { if (chipOcc[chip] == 0) continue; if (chip < 8) hPtr= hModBase +6*N_STRIPS +N_CHIPOCC_BINS*chip; else hPtr= hModBase +14*N_STRIPS +N_CHIPOCC_BINS*(chip-8); cc= --chipOcc[chip]; cc>>= 2; //=> occ 1-4= bin 0, 5-8= bin 1 ... ++(*(hPtr +cc)); chipOcc[chip]= 0; //reset the counter. } /* Get the module's histogram base from the LUT, and warn if the link is invalid (and thus the histograms do not have space reserved for this module). */ hModBase= histoCtrl.moduleBase[1][module]; if (hModBase == histoCtrl.invalidData) { dataWarn|= 2; } /* If an expanded format link is found, exit with a warning. (Histograms here are not set up to deal with this). */ if ((*dataPtr & 0x0100) == 0) { dataWarn|= 1; return; } } //Link header processing. } //Loop over data words in frame. frame= getNextFrame(data, frame, TRAP_FXN_HISTOGRAM); ++dataFramesDone; } /* Store the data from the last encountered link header (with data): */ for (chip= 0; chip < 14; ++chip) { if (chipOcc[chip] == 0) continue; if (chip < 8) hPtr= hModBase +6*N_STRIPS +N_CHIPOCC_BINS*chip; else hPtr= hModBase +14*N_STRIPS +N_CHIPOCC_BINS*(chip-8); cc= --chipOcc[chip]; cc>>= 2; //=> occ 1-4= bin 0, 5-8= bin 1 ... ++(*(hPtr +cc)); } if (dataWarn) { /* Warn user about link formatting. */ histoCtrl.dataWarn= dataWarn; ASGN_RFLD(HSTAT_REG_0, HSR0_SLV_WARN, HSR0_SLV_WARN_W, dataWarn); } } #if 0 //dpsf dbg UINT32 memReserve(void) { if (histoCtrl.nBins == 0) return 0; else if (histoCtrl.nBins == 1) return 1; else if (histoCtrl.nBins == 2) return 2; else if (histoCtrl.nBins == 3) return 3; else if (histoCtrl.nBins == 4) return 4; else if (histoCtrl.nBins == 5) return 5; else if (histoCtrl.nBins == 6) return 6; else if (histoCtrl.nBins == 7) return 7; else if (histoCtrl.nBins == 8) return 8; else if (histoCtrl.nBins == 9) return 9; else if (histoCtrl.nBins == 10) return 10; else if (histoCtrl.nBins == 11) return 11; else if (histoCtrl.nBins == 12) return 12; else if (histoCtrl.nBins == 13) return 13; else if (histoCtrl.nBins == 14) return 14; else if (histoCtrl.nBins == 15) return 15; else if (histoCtrl.nBins == 16) return 16; else if (histoCtrl.nBins == 17) return 17; else if (histoCtrl.nBins == 18) return 18; else if (histoCtrl.nBins == 19) return 19; return 100; } #endif