Histogramming Firmware - Rev 1 HTR Boards (2002)

There are 2 different versions of this firmware.  The link provided is a zip file that contains the firmware for the Xilinx and Altera FPGAs on the HTR, with additional Xilinx implementations for boards SN10 and SN12, as these boards have had to have several signals rerouted. Each fiber input to the HTR contains information from 3 different QIEs, and each QIE has 4 different capacitors.  This makes a total of 12 different inputs which need to be histogrammed on a given fiber.  There are 8 fibers, giving a total of 96 histograms needed.  The Xilinx XCV1000E has only 96 different block RAMs, and 32 are used (in the 8-channel implemetation) just for the asynchronous FIFOs and the VME spy FIFOs.  Memory for the histogramming is implemented in distributed RAM due to insufficient block RAMs.  Actually, there are enough block RAMs for the 4-channel implementation, however we simply used the same verilog files for both 4- and 8-channel projects.
 

Implementation

Each distinct QIE/CAPID on any given fiber appears once every 4 clock cycles due to the rotation cap id's.  This gives us 4 clock ticks in which to perform the histogram filling.  For each QIE/CAPID pair, 32 16-bit words of distributed RAM are allocated.  When the particular capid appears, the mantissa is used as a lookup into distributed RAM for the frequency of that particular value appearing.  The number retrieved is incremented and restored in the same memory location.  This is implemented with a state machine that does its job in 4 clock ticks, ready for the next appearance of the particular QIE/CAPID.  Each QIE/CAPID distributed RAM (the histogram) is distinct from all others in the firmware implementation.

Powerup:  At powerup, or on a hard reset (VME write of 0x1 to LocalBus CSR, address 0x10 on the LocalBus), histogramming is disabled, and transmission to the DCC is disabled.

LEDs:  The top bank of 2 LEDs is the same heartbeat signal as always from the Altera.  The lower bank of 4 LEDs, from the Xilinx, has the same meaning as in the regular firmware:

Xilinx firmware version:  The 4-channel firmware has version 0x25 (0x23 before the LEMO_L1A feature was added), the 8-channel firmware has version 0x26 (0x24 before the LEMO_L1A feature was added).  Firmware versions are determined via a VME read from the LocalBus address 0x24 (FPGAversionN in the documentation).

VME configuration needed to implement histogram:  There are  only 2 things you have to do in order to get histograms to be filled and written to the DCC:

Mantissa and Exponent:  If the exponent is identically 0, the value of the mantissa is used for the histogram.  If the exponent is nonzero, the last bin in the histogram (bin 31) will be increment regardless of the mantissa value.

4- vs. 8-Channel Firmware:  Since there is only enough RAM to hold 48 histograms (4 fibers x 3 QIE x 4 CAPID), the firmware will alternate between FILL+SEND histograms from fiber inputs 1-4 and fibers 5-8.  This translates into a "live time" of 50% (transmission to the DCC is neglected since it is only a few % of the filling time).
 
 

Readout

Readout is either via VME, or the DCC:

Readout via DCC:  At powerup, or on a hard reset (VME write of 0x1 to LocalBus CSR, address 0x10 on the LocalBus), histogramming is disabled.   To start histogramming, issue the proper VME commands as described above - VME_Start and VME_Stop controls the entire histogramming and transmission to the DCC.  Once you start it, the DCC will begin to see data after approximatley 7 ms.  The histograms will be filled as soon as the VME Start signal is asserted inside the Xilinx chip.  The sequence of events are as follows:

Synchronization with source position:  In order to try to synchronize the source posistion with the histogram, the following has funcctionality has been added:


DCC Data Format:  The data sent to the DCC will have exactly the same format as the data sent using the regular firmware, namely a 6-word header followed by data followed by a 2-word trailer, with each word having 16-bits.  The format of each is:

Software example

Since we did not have a working S-Link transmitter card (LSC) at Maryland, we tested the HTR->DCC link by reading data out of the DCC through VME.  We used Eric Hazen's htr_test program to reset the HTR, set the module number, and issue the VME_Start.  Then we used Eric's "shell" with the DCC_capture.vme script to read out the DCC and dump the data into a file.  The file, a byte stream, is then read in and decoded, with histograms dumped to disk formatted.  The program we used to decode the data is included below.  It will keep reading blocks ("events") as long as you don't bail.
 
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

/* this file takes the output from the shell that eric wrote, which
dumps a histogram file to disk, and then (this program that is)
prints the histogram for you so it's easy to see what was sent
*/

int main(int argc, char* argv[]) {

  ////////////////////////////////////
  ///make initial declarations here...
  ////////////////////////////////////

  int i,j,k,m,n,p, word;

  if (argc<2) {
    printf("you must specify an input file to use this");
    return 0;
  }

  FILE* f=fopen(argv[1],"r");
  if (f==NULL) {
    printf("Cannot open '%s'.\n",argv[1]);
    return 1;
  }
//
// read file.  format is  6 words of header, data, 2 words of trailer
//
  unsigned short buff[1544]; // 1544 is enough
  int ret;
  int ibr = 0;
  while (ibr == 0) {
    ret = fread(buff, 2, 1544, f);
//
    char tch[80];
    int header1 = buff[0];
    int header2 = buff[1];
    int header3 = buff[2];
    int header4 = buff[3];
    int header5 = buff[4];
    int header6 = buff[5];
/*  printf("Header word    Value\n");
    printf("      1        0x%4.4X\n",header1);
    printf("      2        0x%4.4X\n",header2);
    printf("      3        0x%4.4X\n",header3);
    printf("      4        0x%4.4X\n",header4);
    printf("      5        0x%4.4X\n",header5);
    printf("      6        0x%4.4X\n",header6);
    printf("Trailer word   Value\n"); */
    int wcnt = header3;
    int trailer1 = buff[wcnt-2];
    int trailer2 = buff[wcnt-1];
/*  printf("      1        0x%4.4X\n",trailer1);
    printf("      2        0x%4.4X\n",trailer2);
*/
    //
    // event number:
    //
    int ev1 = header1;
    int ev2 = header2;
    int evn = ev1 + 256*ev2;
    printf("Event number %d ",evn,ev1,ev2);
    //
    // heater card number
    //
    int hcn = header5 & 0xFF;
    printf("HTR card number %d\n",hcn);
    //
    // word count:
    //
    printf("Word count %d ",wcnt);
    //
    // number of histograms: (word count - 8 for H+T, divided by 32 bins/hist
    //
    int nhists = (wcnt - 8)/32;
    //
    // number of fibers: 12 histos per fiber always
    //
    int nfibers = nhists/12;
    printf("Number of fibers = %d and number of histos = %d\n",nfibers, nhists);
    //
    // trigger type
    //
    int ttype = header6;
    ttype = header6 >> 12;   // shift down 12 bits
    printf("Trigger type %X - should be 5 for histogramming\n",ttype);
    //
    // mode, nfiber check, and mux bit
    //
    int mode =  header4 & 0xFF;
    if (mode == 2) printf("    Histogram mode confirmed\n");
    else printf("     Mode not right!  We decode 0x%X\n",mode);
    int nfibs = header4 >> 8;  // shift right 8 bits
    nfibs = nfibs & 0x3F;
    printf("Fibers from header word 4 = %d\n",nfibs+1);
    int muxbit = header4 >> 14;  // shift down 14 bits
    muxbit = muxbit & 1;
    printf("Muxbit this histogram set to %d\n",muxbit);
    //
    // latched event number
    //
    int lev1 = header5 >> 8;   // shift down 8 bits
    int lev2 = header6 & 0xFFF; // mask off upper 4 bits
    int evnl = lev2 + (lev1 << 12);  // shift lev1 up 12
    printf("Latched event number = %d\n",evnl);
    //
    // trailer:
    //
    printf("Trailer word 1 = %d (should be %d)\n",trailer1,wcnt/2);
    int trailer_evn = trailer2 >> 8;   // shift down 8 bits
    printf("Trailer evn[7:0] = %d (should be %d)\n",trailer_evn,ev1);
    n = 6;
    //
    // histograms are packed:  32 bins at a time
    // packing is:  fiber1:qie1:capid0:bins0-31 and then capid1:bins0-31 ad nasuem
    //
    ibr = 0;
    for (i=0; i<nfibers; i++) {
      printf("\n     Histograms from fiber %d\n",i);
      if (ibr == 1) break;
      for (j=0; j<3; j++) {
        if (ibr == 1) break;
        printf("     QIE number %d\n",j);
        unsigned short qiebins[4][32];
        p = 0;
        for (k=0; k<4; k++) {
          for (m=0; m<32; m++) {
            qiebins[k][m] = buff[n++];
          }
        }
        //
        // printout in columns for convenience
        //
        printf(" Bin    CAPID0 CAPID1 CAPID2 CAPID3\n");
        for (m=0; m<32; m++) {
          printf("%3d   %6d %6d %6d %6d\n",m,
                qiebins[0][m],qiebins[1][m],qiebins[2][m],qiebins[3][m]);
        }
        printf(" HIT <n> for next QIE or anything else to exit: ");
        int ret = scanf("%s",tch);
        if ( ret == 0) ibr = 1;
        if (tch[0] == 'n' || tch[0] == 'N') ibr = 0;
        else ibr = 1;
      }
    }
  }
  fclose(f);
}
 




Last modified 7/28/02 Drew Baden