Overview | Releases | Download | Docs | Links | Help | RecentChanges

2DBOCscan

A 2DBOCscan scans through the RxDelay and RxThreshold at the same time, picking the best values for both at the same time. It is a "super-fast" scan.

The analysis of the scan is carried out in the DSP code on the ROD as follows:

bestDelay = (points[worstSlice] + 9) % 24; // handle wrapping

So the RxDelay is set 9ns from the falling edge

best[1] = ((points[first]+points[last])*2)/3; //

And so the RxThreshold is set 2/3 of the way up in the region of 50% occupancy (assumed to be clk/2).

These values are used to change the settings of the BOC and are printed to a text buffer found in the SctApiCrateServer?*.out file.

Here is an example:

http://www-pnp.physics.ox.ac.uk/~demirkoz/2DBOCscan1.png

Useful additions

It would be a good idea to read the set points, either from the text buffer, or from the BOC. These could then be stored in a test result for later examination. Could also then put a dot on the analysis plot. Currently, they are present in the archived configuration, if the settings remain to the end of run.

Location of the DSP code

The DSP code for the analysis can be found in

./Dsp/Common/Code/masterPrimFuncts.c
Here is some of it for handy reference:
INT32 bocScan(PrimData *primData) {
	INT32  returnCode= SUCCESS, errorCode;
	BocScanIn  *primInput = (BocScanIn *) primData->priBodyPtr;
	BocScanOut *primOutput = (BocScanOut *) primData->repBodyPtr;

 	// How many bits to capture
	UINT32 width = primInput->width;
	// Analysis on or off?
	UINT32 algorithm = primInput->algorithm;
    // Scan definition parameters
	UINT32 scanParameter[2];  /* Scan parameter specifier */
	UINT32 scanSize[2];       /* Number of points of each parameter */


	/* Loop vars */
	UINT32 link, x, y;
	UINT32 fmt, pr, cnt, old_cnt;
	UINT32 bin, nbins;

	UINT32 best[2];

	UINT32 outputLength;
	UINT16 *buffer = (UINT16*)(primOutput+1);
    UINT8  *points = (UINT8*)(primInput)+sizeof(BocScanIn);


	// Check requested algorithm is valid
	if(algorithm>1) {
		newInformation(__FILE__, __LINE__, "Unknown algorithm for BOC_SCAN");
	    // Set output count to 0
		primOutput->count = 0;
		primData->repBodyLength = 1;
		return returnCode;
	}


	// Check fifobuffer is big enough for input
	// accessFifo returns [3*2*width] bytes
	if(width > 0xFFFF){
		newInformation(__FILE__, __LINE__, "Requested width exceeds counter width");
		// Set output count to 0
		primOutput->count = 0;
		primData->repBodyLength = 1;
		return returnCode;
	}

	if(width&0x0001){
		newInformation(__FILE__,__LINE__,"Width decremented - even value required");
		width--;
	}

		// Copy scan configuration information and calculate scanpoints
	for(x=0; x<2; x++){
		scanParameter[x] = primInput->scanParameter[x]; 
		scanSize[x]      = primInput->scanSize[x];
	}

	// Scan configuration information is read directly from the input primitive
	// scanParameters[2]
	// scanSize[2]
	// scanPoints[]

	nbins=scanSize[0]*scanSize[1];

	// Allow RXDELAY only as outer loop parameter -
	// this takes longer to set than the other parameters
	if(scanParameter[1] == BOC_VAR_RXDELAY) {
		newInformation(__FILE__, __LINE__, "BOC_RXDELAY allowed only as outer loop variable");
	    // Set output count to 0
		primOutput->count = 0;
		primData->repBodyLength = 1;
		return returnCode;
	}
	
	if(nbins == 0){
		newInformation(__FILE__, __LINE__, "No points requested!!");
		// Set output count to 0
		primOutput->count = 0;
		primData->repBodyLength = 1;
		return returnCode;
	}


	// Single slice, returning overall counts for 96 modules, so 96 (16 bit) words
	outputLength = 96 * nbins;

	// How many words are available in the primitive reply buffer?
	cnt = primData->repBuffEnd - primData->repBodyPtr -2; //-2 => list trailer

	// Check primitive buffer is big enough for output
	// Output length is a word count, but MDSP_REP_BFR_SZ is in bytes
	if(outputLength/2 > cnt){
		sprintf(genStr, "repBodyPtr 0x%8x repBodyEnd 0x%8x freeWords 0x%8x outputLength 0x%8x", 
			primData->repBodyPtr, primData->repBuffEnd, cnt, outputLength);
		newInformation(__FILE__, __LINE__, genStr);
		newInformation(__FILE__, __LINE__, "Requested output length exceeds available space in primitive reply buffer");
		// Set output count to 0
		primOutput->count = 0;
		primData->repBodyLength = 1;
		return returnCode;
	}else{
		sprintf(genStr, "nbins %d outputLength 0x%8x", nbins, outputLength);
		newInformation(__FILE__, __LINE__, genStr);
	}
	setMem(buffer, outputLength, 0); // Clear buffer

    sprintf(genStr,"First and last outer points: %d, %d",points[0],points[scanSize[0]-1]);
    newInformation(__FILE__, __LINE__, "genStr");
    sprintf(genStr,"First two inner points: %d, %d",points[scanSize[0]],points[scanSize[0]+points[scanSize[1]-1]]);
    newInformation(__FILE__, __LINE__, "genStr");

	// Main Loop
    bin = 0;
	for(x=0; x<scanSize[0]; x++){
		errorCode = setBocVariableAll(scanParameter[0], points[x]);
		if (errorCode < 0) {
			addError(&returnCode, errorCode, "bocScan", "setBocVariable0", __FILE__, __LINE__);
			if (FATAL(returnCode)) { 
				primOutput->count = 0;
				primData->repBodyLength = 1;
				return returnCode;
			}
		}

		for(y=scanSize[0];y<(scanSize[0]+scanSize[1]);y++){
			errorCode = setBocVariableAll(scanParameter[1], points[y]);
			if (errorCode < 0) {
				addError(&returnCode, errorCode, "bocScan", "setBocVariable1", __FILE__, __LINE__);
				if (FATAL(returnCode)) { 
					primOutput->count = 0;
					primData->repBodyLength = 1;
					return returnCode;
				}
			}

			// Reset hardware counters
			for(fmt=0; fmt<FORMATTERS_PER_ROD; fmt++){
				writeRegisterDirect(FMT_COUNT_CTRL(fmt),32,0,0);
			}	

			// Set hardware counters
			for(fmt=0; fmt<FORMATTERS_PER_ROD; fmt++){
				writeRegisterDirect(FMT_GLOBAL_CNT(fmt),16,0,width); // works
			}

			// Start Counting
			for(fmt=0; fmt<FORMATTERS_PER_ROD; fmt++){
				writeRegisterDirect(FMT_COUNT_CTRL(fmt),32,0,1);
			}


			// Wait for counting to stop
			for(fmt=0; fmt<FORMATTERS_PER_ROD; fmt++){
				old_cnt = 0xffffffff;
				cnt = 0x0000ffff;
				while(cnt>0){
					readRegister(FMT_GLOBAL_CNT(fmt),16,16,&cnt);
					if(cnt==old_cnt){ // STALLED!
						newInformation(__FILE__, __LINE__, "STALLED");
  						// Set output count to 0
  						primOutput->count = 0;
 						primData->repBodyLength = 1;
  						return returnCode;
					}else{
						old_cnt = cnt;
					}
				}
			}

			// Read Counters
			link = 0;
			for(fmt=0; fmt<FORMATTERS_PER_ROD; fmt++){
				for(pr=0;pr<(LINKS_PER_FORMATTER/2); pr++){

					readRegister(FMT_PAIR_CNT(fmt,pr),16, 0,&cnt);
					buffer[( link   *nbins)+bin] = (UINT16) cnt;

					readRegister(FMT_PAIR_CNT(fmt,pr),16, 16,&cnt);
					buffer[((link+1)*nbins)+bin] = (UINT16) cnt;

					link+=2;
				}
			}

			bin++;
		} // end inner loop
	} // end outer loop

//	sprintf(genStr,"BOCScan of %d bins completed - honest!",bin);
//	newInformation(__FILE__,__LINE__,genStr);


	if(algorithm>0){

		UINT32 bestSlice=0xDADA;
		UINT32 bestAnySlice=0;
		UINT32 goodThisSlice=0;
		UINT32 worstSlice = 0;
		UINT32 worstAnySlice=0xDADA;
		UINT32 target = (width/2);
		UINT32 first, last;
		INT32 diff;
		UINT32 bestDiff;
		UINT32 bestDelay;

		if( (scanParameter[0]== BOC_VAR_RXDELAY) && (scanParameter[1]== BOC_VAR_RXTHRESHOLD) ){
			newInformation(__FILE__,__LINE__,"Analysis for BOC_RXDELAY / BOC_RXTHRESHOLD");

		

			for(link=0;link<96;link++){

				// First: find BOC_RXDELAY slice with smallest number of good clk/2 data points
				//        Set BOC_RXDELAY to this value plus 9 (to be away from trailing edge);


				bin=0;
				bestSlice=0;   // not actually used unless clk/2 data found 
				bestAnySlice=0;
				goodThisSlice=0;
				worstSlice=0;
				worstAnySlice=0xDADA;
				for(x=0; x<scanSize[0]; x++){ // delay
					goodThisSlice = 0;
					for(y=scanSize[0]; y<(scanSize[0]+scanSize[1]); y++){ // threshold
						if(buffer[( link   *nbins)+bin] == target){
							goodThisSlice++;
						}
						bin++;
					}
					if(goodThisSlice<worstAnySlice){
						worstAnySlice = goodThisSlice;

						worstSlice = x;
					}
					if(goodThisSlice>bestAnySlice){
						bestAnySlice = goodThisSlice;
					}
				}


				if(bestAnySlice >0){ // link did return some clk/2 data
					//bestSlice = worstSlice + 9; // assumes points[x] == x !!!
					bestDelay = (points[worstSlice] + 9) % 24; // handle wrapping

					// Now find the slice closest to (or equal to) this delay

					bestDiff=0xDADA;
					for(x=0;x<scanSize[0];x++){
						diff = (INT32)points[x] - (INT32)bestDelay;
						if(diff == 0){ // works if equal - what if not :-(
							bestSlice = x;
							break;
						}else if (diff<1){
						  diff = diff * -1;
						}
						if(diff < bestDiff){
							bestDiff = diff;
							bestSlice = x;
						}
					 }

					last = 0;
					first = 0xDADA;

					// Within the chosen BOC_RXDELAY slice, 
					// set BOC_RXTHRESHOLD to be 3/4 of the way between the lower and upper edges

					bin = bestSlice * scanSize[1]; // Start of this RXTHRESHOLD slice
					for(y=scanSize[0]; y<(scanSize[0]+scanSize[1]); y++){
						if(buffer[( link   *nbins)+bin] == target){
							if(y<first) first = y;
							if(y>last)  last = y;
						}
						bin++;
					}
					best[0] = bestDelay;
					best[1] = ((points[first]+points[last])*2)/3; // this is OK!

					sprintf(genStr,"link %d setting delay = 0d%02d threshold = 0d%03d\n",
						link,best[0],best[1]);
					newInformation(__FILE__,__LINE__,genStr);

					setBocVariable(link,scanParameter[0],best[0]);
					setBocVariable(link,scanParameter[1],best[1]);
				}

			} //end for(link)

		}else{
			newInformation(__FILE__,__LINE__,"No analysis available for requested scan");
		}


	}else{
		newInformation(__FILE__,__LINE__,"Algorithm <=0: analysis not requested");
	}

	// Finish off

	primOutput->count = outputLength/2;

	// Updating this is enough to get the reply sent
	primData->repBodyLength = (outputLength/2)+1;

	return returnCode;
}