selective readout (prelim)

Ed Kearns (kearns@budoe.bu.edu)
Sun, 9 Oct 1994 02:18:17 -0400

Dear WFD folks, 10/9/94

This is a preliminary version of my documentation of the driver
for selective readout that we implemented in August. I'm releasing
this now for comments and to help Chris get started with LIP/TOHM
tests at Gran Sasso.

=========================================================================

To control selective readout of wfd channels, I have implemented
a software pattern register in the online DAQ (the mini-DAQ for now).
This consists of a global array:

wfd_spr : array[1..12] of integer;

which is filled by special CAMAC-list directives described below.
The first six elements of the array comprise the channel readout
pattern for the 6 MACRO supermodules. The remaining 6 elements
are designated to hold the number of tics to readout (determined
by the delay of the wfd stop manager).

The mapping between bits and channels is as follows:

channel-address
wfd_spr tank name end-0 end-1
bit 0 B01,B03,B05,B07 *$0n000000 $0n010000
bit 1 B02,B04,B06,B08 $0n020000 $0n030000
bit 2 B09,B11,B13,B15 *$0n040000 $0n050000
bit 3 B10,B12,B14,B16 $0n060000 $0n070000
bit 4 C01,C03,C05,C07 *$0n080000 $0n090000
bit 5 C02,C04,C06,C08 $0n0A0000 $0n0B0000
bit 6 C09,C11,C13,C15 *$0n0C0000 $0n0D0000
bit 7 C10,C12,C14,C16 $0n0E0000 $0n0F0000
bit 8 W01,W03,W05,W07 *$0n100000 $0n110000
bit 9 W02,W04,W06,--- $0n120000 $0n130000
bit 10 E01,E03,E05,E07 *$0n140000 $0n150000
bit 11 E02,E04,E06,--- $0n160000 $0n170000
bit 12 W08,W10,W12,W14 *$0n180000 $0n190000
bit 13 W09,W11,W13,--- $0n1A0000 $0n1B0000
bit 14 E08,E10,E12,E14 *$0n1C0000 $0n1D0000
bit 15 E09,E11,E13,--- $0n1E0000 $0n1F0000
bit 16 T01,T03,T05,T07 *$0n200000 $0n210000
bit 17 T02,T04,T06,T08 $0n220000 $0n230000
bit 18 T09,T11,T13,T15 *$0n240000 $0n250000
bit 19 T10,T12,T14,T16 $0n260000 $0n270000
bit 20 T17,---,---,--- *$0n280000 $0n290000
bit 21 N01,N03,N05,N07 *$0n2C0000 $0n2D0000
bit 22 N02,N04,N06,--- $0n2E0000 $0n2F0000

The 4-bits referred to as "n" in the address correspond to the
supermodule number (1-6). Therefore, every wfd channel in MACRO has a
unique hardware address. The address marked with "*" is the base address
for an entire card; these are set by dip switches on the wfd pcb.

Example: if wfd_spr[2] consists of $000301 then bit-0, bit-8 and bit-9
are set. When the wfd readout occurs, only the corresponding pairs of
channels will be readout.

The value in wfd_spr is manipulated from the CAMAC-list via the command:

WFD_SPR sm,id,subid

where "sm" is the supermodule number, "id" selects which type of trigger
is being used and "subid" selects a subrange or particular function. The
code for WFD_SPR is kept in USER_PROCEDURE.PAS.

For example, id=27 is assigned to the CIT latch. Currently, the CIT
latch writes 6 16-bit words into the data stream when the CAMAC-list
commands of equipment 27 are executed. These 16 bit words describe which
tanks have trigger (and activity) in the TOHM. The WFD_SPR code works by
looking back 32 bits into the data stream and using that bit pattern as
input. Depending on what bits are set in the input, the procedure sets
bits in the register. Therefore, the new CAMAC-lis operation for
equipment 27 on SM-1 will now look like this:

EQUIP 27
FQIGNORE 2,2,2,0,0,1
FQIGNORE 2,2,2,1,0,1
WFD_PATREG 1,27,1
FQIGNORE 2,2,2,2,0,1
FQIGNORE 2,2,2,3,0,1
WFD_PATREG 1,27,2
FQIGNORE 2,2,2,4,0,1
FQIGNORE 2,2,2,5,0,1
WFD_PATREG 1,27,3
T 2,2,2,0,9
...(SM-2)...
EOE

The first two FQIGNORE commands write 32 bits as follows: bits 31-24 are
activity for B16-B09, bits 23-16 are triggers for B16-B09, bits 15-8 are
activity for B08-B01 and bits 7-0 are triggers for B07-B01. Currently,
the algorithm coded in WFD_PATREG(1,27,1) looks at only the trigger bits
and only turns on the corresponding channels. If desirable, the
algorithm can be changed to readout more tanks on a trigger than this
minimum definition.

Example: if the bit pattern is 00000404, then tank 1B03 has triggered
(and as usual, also shows activity). 1B03 is plugged into the first wfd
channel of SM (fanned in with 1B01,1B05 and 1B07). So bit-0 of the
wfd_spr is set.

Each trigger in the detector has the opportunity to turn on more bits.
Later, the LIP trigger will be readout and if any additional triggers
are recorded, the wfd_spr will be updated. Similarly for the FMT/CSPAM
and perhaps eventually the ERP. By convention, the id of the WFD_PATREG
command that decodes a particular word is the same as the equipment
number.

An important special trigger-type is defined for id=0. This provides
direct manipulation of the register as follows:

WFD_PATREG sm=N,id=0,subid=0 write wfd_spr[N] into the data stream
WFD_PATREG sm=N,id=0,subid=1 count bits in wfd_spr[N], write result
WFD_PATREG sm=N,id=0,subid=2 OR function
WFD_PATREG sm=N,id=0,subid=2 AND function
WFD_PATREG sm=N,id=0,subid=2 CLEAR function
WFD_PATREG sm=N,id=0,subid=2 SET function

The CLEAR function sets all the bits to zero to initialize the register
for the next event. The OR function may be used to mask on particular
channels; the AND function may be used to mask off particular channels
and the SET function may be used to specify the readout pattern exactly.
These are most easily used in conjunction with WRITEHEX.

For example, let us consider the situation in October 1994 when we have
only 3 cards available in a test configuration. Only 1B09-1B16,
1C09-1C16 and 1W01-1W07 are cabled up. If we use the TOHM trigger to
drive the readout we will sometimes try to readout channels that are not
present. We can protect against this by ANDing with $3CC, which only
allows the appropriate channels to be set and masks off the rest. Put
the following in the CAMAC-list after all the triggers have had their
code executed but before the wfd readout occurs:

WRITEHEX $3CC
WFD_PATREG 1,0,2

There is also an essential initialization for the WFD_TEST readout
command. This initializes an array with the virtual and actual base
addresses of each channel. This is done in the INIT section of the
CAMAC-list. The VICbus mapping from actual to virtual is calculated.
The virtual address is used by the readout code; the actual address is
written into the data stream and serves as a channel-id for the wfd data
structure. The CAMAC-list command is WFD_MAP branch,crate,$base_addr,sm.
For example:

WFD_MAP 1,2,$1000000,1

This defines the mapping for all of channels listed above for SM-1.
The VICbus branch and crate correspond to the test setup of Oct 1994.

The following are snippets of code to which you may refer in order
to better understand the concepts described above.

------------------------------------------------------------------------
This is the code that decodes the CAMAC-list command line. It stores
information in the structure p^ which drives the readout. These lines
are from CAMACPROCEDURE.PAS
------------------------------------------------------------------------

WFD_PATREG:
begin
decode_i1i2i3(scratch_string,
tmpint,
p^.cam_add.full,
p^.data_to_write.full);
p^.l_mem_add := address(wfd_spr[tmpint]);
p^.mode_operation := 58;
previus:=p;
new(p);
previus^.next_elem:=p;
end;

WFD_TEST: begin
decode_i1i2(scratch_string,i1,i2);
p^.mode_operation:=56;
p^.spare:=i2*6 + i1;
previus:=p;
new(p);
previus^.next_elem:=p;

end;

------------------------------------------------------------------------
This is an important utility command which sets up the mapping of
pattern register bit to channel address. It initializes and array with
the actual and virtual address of each channel. The virtual address is
determined from the VICbus memory mapping. This is also in
CAMACPROCEDURE.PAS, but in the case statement for the CAMAC-list
commands which can be executed during init.
------------------------------------------------------------------------

WFD_MAP: begin
decode_vic_comm(scratch_string,vme_b,vme_c,vme_page,vme_add,
tmpint);

wfd_sm_base_addr := vme_page * %x100000 + vme_add;
for ichan := 0 to 23 do
begin
for iend := 0 to 1 do
begin
wfd_ch_base_addr := wfd_sm_base_addr +
(ichan*2+iend) * %x10000;
vme_page := wfd_ch_base_addr DIV %x100000;
vme_add := wfd_ch_base_addr MOD %x100000;
pr_vme_ex;
wfd_chan_addr[tmpint,ichan,iend].virtual :=
virtual_base_add::integer+vme_add::integer;
wfd_chan_addr[tmpint,ichan,iend].actual :=
wfd_ch_base_addr;
end;
end;
end;

------------------------------------------------------------------------
This is the top section of the wfd readout code (WFD_TEST), to show
how the bits of wfd_spr[N] are looped over to drive the readout.
This code fragment is from CADRIVER.PAS
------------------------------------------------------------------------

{ WFD Time Window Read *** TEST EDITION *** ----------------------------------}
{ *** This is test code for wfd selective readout *************************** }
{ *************************************************************************** }
{ This section of code reads wfd data words (2 x 32 bits) until a certain }
{ amount of time (in units of 5 ns at 200 MSPS) has elapsed. It begins by }
{ using the special wfd function that returns the address pointer that }
{ records the last memory location digitized when the STOP signal happens. }
{ The code then read "n" wfd data, from the adc bank and time bank. The code }
{ calculates the elapsed time by looking at the WFD timeword as it is stored. }
{ When the requested time has elapsed (passed in point^.spare), it calculates }
{ the length of the data and stores that at the beginning of the equipment, }
{ as well as in evt_word (used by the daq). This routine handles wrap-around }
{ reading of the wfd memory. }
{ ETK: 20-Aug-1994 }

56: begin
{ find bit set in wfd software pattern register }
indx := FIND_FIRST_BIT_SET(wfd_spr[point^.spare]::bit32);

while indx < 32 do
begin

for i := 0 to 1 do { loop over end-0 to end-1 }
begin

{ base address is indexed from array }
wfd_base_add::integer :=
wfd_chan_addr[point^.spare,indx,i].virtual;
....

------------------------------------------------------------------------
This is also from CADRIVER.PAS and shows some of the id=0 functions
as well as the call of the WFD_PATREG user procedure.
------------------------------------------------------------------------

{ WFD Pattern Register -------------------------------------------------------}
{ This is a software pattern register to control WFD readout. }
{ I have recruited the camac_list structure as follows: }
{ point^.l_mem_add = address of wfd software pattern register }
{ point^.cam_add.full = id of pattern unit (CIT,FMT,LIP etc) }
{ point^.data_to_write.full = sub-id of pattern unit }
{ ETK: 30-Sep-1994 }
58: begin
if (point^.cam_add.full = 0) and
(point^.data_to_write.full = 0) then
{ write wfd software pattern register into data stream }
begin
evt_word := evt_word + 1;
tmp_buf_p := address(evt_buffer[id]^[evt_word]);
tmp_buf_ptr::integer := tmp_buf_p::integer;
tmp_buf_ptr^ := point^.l_mem_add^;
evt_word := evt_word+1;
eqp_word := eqp_word+2;
end
else if (point^.cam_add.full = 0) and
(point^.data_to_write.full = 1) then
{ count bits in s.p.r. and write into data stream }
begin
bitson := 0;
indx := FIND_FIRST_BIT_SET(point^.l_mem_add^::bit32);
while indx < 32 do
begin
bitson := bitson + 1;
indx :=
FIND_FIRST_BIT_SET(point^.l_mem_add^::bit32,
indx+1);
end;
evt_word := evt_word + 1;
tmp_buf_p := address(evt_buffer[id]^[evt_word]);
tmp_buf_ptr::integer := tmp_buf_p::integer;
tmp_buf_ptr^ := bitson+bitson;
evt_word := evt_word+1;
eqp_word := eqp_word+2;
end
else
{ perform selected masking operation: }
begin
tmp_buf_p := address(evt_buffer[id]^[evt_word-1]);
tmp_buf_ptr::integer := tmp_buf_p::integer;
wfd_patreg(point^.l_mem_add,
point^.cam_add.full,
point^.data_to_write.full,
tmp_buf_ptr);
end;
end;

------------------------------------------------------------------------
This is an early version of WFD_PATREG showing just the id=0 functions
and the TOHM pattern recognition.
------------------------------------------------------------------------

procedure wfd_patreg(wfd_spr : ^integer;
id : integer;
subid : integer;
pat : ^integer);
type
bit32 = packed array [0..31] of boolean;
bit16 = packed array [0..15] of boolean;
var
indx : integer;
begin
case id of
0: case subid of
{ id = 0 is assigned to direct manipulation of the register }
0: begin
{ 0 is reserved for WRITE, which is handled elsewhere }
end;
1: begin
{ Count bits and write result to data stream }
{ This is handled elsewhere }
end;
2: begin
{ Mask specified bits (OR) }
indx := FIND_FIRST_BIT_SET(pat^::bit32);
while indx < 32 do
begin
wfd_spr^::bit32[indx] := true;
indx := FIND_FIRST_BIT_SET(pat^::bit32,indx+1);
end;
end;
3: begin
{ Mask specified bits off (AND) }
indx := FIND_FIRST_BIT_CLEAR(pat^::bit32);
while indx < 32 do
begin
wfd_spr^::bit32[indx] := false;
indx := FIND_FIRST_BIT_CLEAR(pat^::bit32,indx+1);
end;
end;
4: begin
{ Clear bits, ignoring word-1 passed from data buffer }
wfd_spr^ := 0;
end;
5: begin
{ Set bit pattern exactly }
wfd_spr^ := pat^;
end;
end;
27: case subid of
{ id = 27 is assigned to the CIT latch }
1: begin
{ subid = 1 handles the 1st pair of 16-bit patterns }
{ and it only checks the trigger bits (not activity) }
wfd_spr^::bit32[0] := wfd_spr^::bit32[0] or
pat^::bit32[0] or pat^::bit32[2] or
pat^::bit32[4] or pat^::bit32[6];
wfd_spr^::bit32[1] := wfd_spr^::bit32[1] or
pat^::bit32[1] or pat^::bit32[3] or
pat^::bit32[5] or pat^::bit32[7];
wfd_spr^::bit32[2] := wfd_spr^::bit32[2] or
pat^::bit32[16] or pat^::bit32[18] or
pat^::bit32[20] or pat^::bit32[22];
wfd_spr^::bit32[3] := wfd_spr^::bit32[3] or
pat^::bit32[17] or pat^::bit32[19] or
pat^::bit32[21] or pat^::bit32[23];
end;
2: begin
{ subid = 2 handles the 2nd pair of 16-bit patterns }
{ and it only checks the trigger bits (not activity) }
wfd_spr^::bit32[4] := wfd_spr^::bit32[4] or
pat^::bit32[0] or pat^::bit32[2] or
pat^::bit32[4] or pat^::bit32[6];
wfd_spr^::bit32[5] := wfd_spr^::bit32[5] or
pat^::bit32[1] or pat^::bit32[3] or
pat^::bit32[5] or pat^::bit32[7];
wfd_spr^::bit32[6] := wfd_spr^::bit32[6] or
pat^::bit32[16] or pat^::bit32[18] or
pat^::bit32[20] or pat^::bit32[22];
wfd_spr^::bit32[7] := wfd_spr^::bit32[7] or
pat^::bit32[17] or pat^::bit32[19] or
pat^::bit32[21] or pat^::bit32[23];
end;
3: begin
{ subid = 3 handles the 3rd pair of 16-bit patterns }
{ and it only checks the trigger bits (not activity) }
{ note that currently, bit-7 and bit-23 are unused }
wfd_spr^::bit32[8] := wfd_spr^::bit32[8] or
pat^::bit32[0] or pat^::bit32[2] or
pat^::bit32[4] or pat^::bit32[6];
wfd_spr^::bit32[9] := wfd_spr^::bit32[9] or
pat^::bit32[1] or pat^::bit32[3] or
pat^::bit32[5];
wfd_spr^::bit32[10] := wfd_spr^::bit32[10] or
pat^::bit32[16] or pat^::bit32[18] or
pat^::bit32[20] or pat^::bit32[22];
wfd_spr^::bit32[11] := wfd_spr^::bit32[11] or
pat^::bit32[17] or pat^::bit32[19] or
pat^::bit32[21];
end;
end;
end;
end;