--
-- gb.tdf
-- data processor chip for SVT GhostBuster card
-- begun April 2001 by Bill Ashmanskas, U. Chicago / CDF
-- modified Jun-Sep 2002 by Taka Maruyama, U. Chicago / CDF
--

title "delete duplicate tracks; perform various utility functions";

include "lpm_counter.inc";
include "altclklock.inc";
include "lpm_ram_dp.inc";
include "lpm_fifo_dc.inc";
include "lpm_add_sub.inc";
include "lpm_mult.inc";
include "lpm_compare.inc";

--
-- Upon L1A with corresponding buffer number, records data
-- for later VME readout
--
function buffer (
  indata[23..0], clock, trigger, reset, raddr[8..0], rclk)
returns (idle, data[23..0]);

--
-- Decodes low address bits into ID PROM contents
--
function idprom (
  addr[4..0], dip[2..0])
returns (data[7..0]);

subdesign gb
(
  -- input data from FIFO; associated control signals
  din[22..0]      : input;	-- FIFO data
  _fifoef[1..0]   : input;	-- empty* flags (2 FIFOs)
  _fifofull       : input;	-- full* flag (1st FIFO)
  _fifoaf         : input;	-- almost-full* flag (1st FIFO)
  fiforclk        : output;	-- read clock (2 FIFOs)
  _fiforena       : output;	-- read enable* (2 FIFOs)
  _fiforeset      : output;	-- reset* (2 FIFOs)
  inphold         : output;	-- flow control to upstream board
  _inpds          : input;	-- upstream data strobe* (useful?)

  -- output data to downstream board; control signals
  dout[22..0]     : output;	-- cable data
  _dsout          : output;	-- data strobe*
  outphold        : input;	-- flow control from downstream board

  -- flash RAM, perhaps to store lookup tables
  framaddr[20..0] : output;	-- address bus
  framdata[15..0] : bidir;	-- data bus
  _framoe         : output;	-- output enable*
  _framwe         : output;	-- write ena* (rising edge latches A/D)
  _framrp         : output;	-- reset*
  _framwp         : output;	-- write prot* (pulldown for safety?)
  framsts         : input;	-- status (ready/busy*) (needs pullup)

  -- VME I/O
  addr[23..2]     : input;      -- address (minus GA, unused 26-24,1-0)
  data[31..0]     : bidir;      -- data lines
  vmewrite        : input;      -- qualifies address value (r vs w)
  vmeas           : input;      -- derived signal for latching address
  vmeds           : input;      -- derived signal for latching data

  -- CDF J2 custom backplane signals: see CDF 2388 for specification
  cdfclk          : input;      -- 132 ns clock
  _cdfbc          : input;      -- bunch crossing
  _cdfb0          : input;      -- bunch zero marker
  _cdfl1a         : input;      -- level 1 accept
  _cdfl1r         : input;      -- level 1 reject
  _cdfl2b0        : input;      -- level 2 buffer number (bit 0)
  _cdfl2b1        : input;      -- level 2 buffer number (bit 1)
  _cdfhalt        : input;      -- 
  _cdfrecover     : input;      -- 
  _cdfl2a         : input;      -- level 2 accept

  -- SVT-specific J2 control signals
  _svtinit        : input;	-- clear FIFOs, etc.
  _svtfreeze      : input;	-- freeze spy buffers (N/A?)
  _svtspare       : input;	-- reserved input

  -- these should be O/C outputs, so that any chip can drive them
  _svterror       : output;     -- assert the SVT_ERROR* signal
  _cdferror       : output;     -- assert the CDF_ERROR* signal

  -- VME access to *next* chip's JTAG connector
  vmejtagtck      : input;	-- TCK (should be tri-stated)
  vmejtagtdo      : input;	-- TDO
  vmejtagtms      : input;	-- TMS (should be tri-stated)
  vmejtagtdi      : input;	-- TDI (should be tri-stated)

  -- various and sundry I/O
  clock           : input;	-- on-board 30 MHz oscillator
  id[1..0]        : input;      -- which channel am I (of 3 on board)?
  dip[2..0]       : input;      -- board ID DIP switch
  debug[15..0]    : output;     -- to logic analyzer
  debugclk        : output;     -- clock to logic analyzer
  sysclk          : input;      -- VME system clock (possibly useful)
  spare[29..0]    : bidir;      -- bussed spare lines
  ctrlspare[2..0] : input;      -- spare global control lines (??)
  l2data[33..0]   : input;
  -- LEDs
  dsinled         : output;	-- input data strobe
  holdinled       : output;	-- input hold
  dsoutled        : output;	-- output data strobe
  holdoutled      : output;	-- output hold
  runled          : output;	-- run-mode LED
  errorled        : output;	-- error LED (O/C output?)
)

variable
  ffin[22..0]     : dff;	-- latch inputs
  dvin            : dff;	-- input valid flag

  dda[22..0]      : dffe;	-- extra stage
  dva             : dffe;	-- extra stage valid flag
  wca : lpm_counter with (lpm_width=4);

  ddb[22..0]      : dffe;	-- extra stage
  dvb             : dffe;	-- extra stage valid flag
  parityb         : dffe;	-- check parity of input data
  perrorb         : dffe;	-- report input parity error
  wcb[3..0]       : dffe;       -- word count in stage B
  xftnumb[8..0]   : dffe;	-- latch track's XFT ID
  phib[12..0]     : dffe;	-- latch track's TF phi
  bpreg[120..0]   : dffe;       -- beam position as a func. of z(0-5)  
  bpb[19..0]      : dffe;       -- beam position for current track 
  ntfstatb[11..0] : dffe;       -- tf_status for current track
  ncsqb[10..0]    : dffe;       -- csq for current track

  ddc[22..0]      : dffe;	-- extra stage
  bfc[9..0]       : dffe;  
  wcc[3..0]       : dffe;       -- word count in stage C
  dvc             : dffe;	-- extra stage valid flag
  addcsqc : lpm_add_sub with (LPM_WIDTH=10);  
  newcsqc[10..0]  : dffe;

  ddd[22..0]      : dffe;	-- extra stage
  wcd[3..0]       : dffe;       -- word count in stage D
  bfd[9..0]       : dffe;
  dvd             : dffe;	-- extra stage valid flag

  dde[22..0]      : dffe;	-- extra stage
  wce[3..0]       : dffe;       -- word count for Stage E
  dve             : dffe;	-- extra stage valid flag
  cosphie[7..0]   : dffe;       -- abs(cos(phi)) from chip#1
  sinphie[7..0]   : dffe;       -- abs(sin(phi)) from chip#2

  ddf[22..0]      : dffe;	-- extra stage
  wcf[3..0]       : dffe;       -- word count in stage F
  dvf             : dffe;	-- extra stage valid flag
  phifixf[10..0]  : dffe;       -- phi correction in stage F 

  ddg[22..0]      : dffe;	-- extra stage
  wcg[3..0]       : dffe;       -- word count in Stage G
  dvg             : dffe;	-- extra stage valid flag
  comwedge : lpm_compare with (lpm_width=4);  -- for wedge comparison
  phifixg[12..0]  : dffe;       -- final correction value for track phi
  sincor          : dffe;       -- sign flag for phicorr
  multier : lpm_mult with (
    lpm_widtha=8, lpm_widthb=9, lpm_widthp=17 );
  multier2 : lpm_mult with (
    lpm_widtha=8, lpm_widthb=9, lpm_widthp=17 );
  ycosg[17..0]    : dffe;       -- y(z) * cos(phi) 
  xsing[17..0]    : dffe;       -- x(z) * sin(phi) 

  ddh[22..0]      : dffe;	-- extra stage
  wch[3..0]       : dffe;       -- word count in stage H
  abscomp : lpm_compare with (lpm_width=18);
  sinaddh         : dffe;       -- add_sub for final d correction
  ipcorr : lpm_add_sub with (LPM_WIDTH=18);
  ipsub[17..0]    : dffe;
  rounder: lpm_add_sub with (LPM_WIDTH=10);
  times7 : lpm_mult with (
    lpm_widtha=9, lpm_widthb=3, lpm_widthp=12, 
    input_b_is_constant="yes");
  sparsetimes7 : lpm_mult with (
    lpm_widtha=9, lpm_widthb=3, lpm_widthp=12, 
    input_b_is_constant="yes");
  sparseaddr[10..0] : dff;
  ipcorr2 : lpm_add_sub with (LPM_WIDTH=10);
  wcfillh[10..0] : node;

  csqaddri[10..0] : node;
  dvh             : dffe;	-- extra stage valid flag
  ddi[22..0]      : dffe;	-- extra stage
  wci[3..0]       : dffe;
  xftnumi[8..0]   : dffe;
  baseaddri[10..0] : dffe;
  addri[10..0]    : dffe;
  eei[22..0]      : dffe;
  dvi             : dffe;	-- extra stage valid flag

  oldexistsj      : node;
  oldcsqj[10..0]  : node;
  newcsqj[10..0]  : node;
  ddj[22..0]      : dffe;
  wcj[3..0]       : dffe;
  phicorr : lpm_add_sub with (LPM_WIDTH=13);
  xftnumj[8..0]   : dffe;
  dvj             : dffe;
  abscompj : lpm_compare with (lpm_width=10);

  keeperk         : dffe;
  addrj[10..0]    : dffe;
  oldexistsk      : dffe;
  oldcsqk[10..0]  : dffe;
  newcsqk[10..0]  : dffe;
  ddk[22..0]      : dffe;
  ddkdum[22..0]   : dffe;
  dvk             : dffe;
  xftnumk[8..0]   : dffe;
  wck[3..0]       : dffe;
  addrk[10..0]    : dffe;

  ddl[22..0]      : dffe;
  dvl             : dffe;
  ddm[22..0]      : dff;
  dvm             : dff;
  ddn[22..0]      : dff;
  dvn             : dff;
  parityn         : dffe;

  ffout[22..0]    : dff;	-- latch outputs
  dvout           : dff;	-- output valid flag
  _dataready      : dff;	-- data are available to read
  skipff          : dff;
  skipff0         : dff;
  ctrlreg[31..0]  : dff;	-- misc control registers
  ctrl1reg[31..0] : dff;
  ctrl[63..0]     : node;       -- alias for ctrlreg.q
  addrchk[31..0]  : dff;        -- test VME address bus
  cdfl1a          : dff;	-- latch/invert backplane sigs
  cdfl2b0         : dff;
  cdfl2b1         : dff;
  cdfb0           : dff;
  cdfrec          : dff;
  cdfcc           : lpm_counter	-- count CDF_CLKs between B0
	with (LPM_WIDTH=8);
  cdfcc1          : lpm_counter	-- count CDF_CLKs since marker
	with (LPM_WIDTH=8, LPM_MODULUS=159);
  l1afifo         : lpm_fifo_dc	--
	with (LPM_WIDTH=10,LPM_NUMWORDS=7,LPM_WIDTHU=3);
  svtfifo         : lpm_fifo_dc
        -- with (LPM_WIDTH=23,LPM_NUMWORDS=32,LPM_WIDTHU=5);
        with (LPM_WIDTH=23,LPM_NUMWORDS=256,LPM_WIDTHU=8);
  xftsparse       : lpm_fifo_dc	--
	with (LPM_WIDTH=9,LPM_NUMWORDS=288,LPM_WIDTHU=9);
  gotsparse : dff;
  gotdata : dff;
  eplastvalid : dffe;
  enable : dff;
  buf0time : lpm_counter with (lpm_width=20);
  l1a0sync0 : dff;
  l1a0sync : dff;
  whichblock[5..0] : dff;
  renanode : node;

  -- synchronize, invert hold signal from downstream board
  _outputhold0    : dff;
  _outputhold     : dff;

  -- tri-state buffers for VME and FRAM data lines
  datatri[31..0]  : tri_state_node;
  dataout[31..0]  : tri;        -- vme readout gets muxed here
  fdtri[15..0]    : tri_state_node;
  fdout[15..0]    : tri;	--
  sdtri[29..0]    : tri_state_node;
  sdout[29..0]    : tri;	--

  -- nodes holding results of VME address decoding
  locaddr[19..0]  : node;
  vme_chipsel     : node;
  vme_deadbeef    : node;
  vme_reset       : node;
  vme_ctrlwrite   : node;
  vme_ctrlread    : node;
  vme_ctrl1write  : node;
  vme_ctrl1read   : node;
  vme_addrcheckread : node;
  vme_framwrite   : node;
  vme_framread    : node;
  vme_whichblockwrite : node;
  vme_whichblockread : node;
  vme_besttrackread : node;
  vme_beamwrite   : node;
  vme_beamread    : node;
  vme_buf0z0beamread : node;	
  vme_buf0z1beamread : node;	
  vme_buf0z2beamread : node;	
  vme_buf0z3beamread : node;	
  vme_buf0z4beamread : node;	
  vme_buf0z5beamread : node;	
  vme_buf1z0beamread : node;	
  vme_buf1z1beamread : node;	
  vme_buf1z2beamread : node;	
  vme_buf1z3beamread : node;	
  vme_buf1z4beamread : node;	
  vme_buf1z5beamread : node;	
  vme_buf2z0beamread : node;	
  vme_buf2z1beamread : node;	
  vme_buf2z2beamread : node;	
  vme_buf2z3beamread : node;	
  vme_buf2z4beamread : node;	
  vme_buf2z5beamread : node;	
  vme_buf3z0beamread : node;	
  vme_buf3z1beamread : node;	
  vme_buf3z2beamread : node;	
  vme_buf3z3beamread : node;	
  vme_buf3z4beamread : node;	
  vme_buf3z5beamread : node;	
  vme_csqcwrite      : node;
  vme_csqcread       : node;
  myidprom        : idprom;

  -- for double buffering method
  regbeam0[120..0] : dffe;
  beamvalidflag    : dffe;
  buf0beam[120..0] : dffe;
  buf1beam[120..0] : dffe;
  buf2beam[120..0] : dffe;
  buf3beam[120..0] : dffe;

  -- misc
  dsinstretch : lpm_counter with (lpm_width=2);
  fsm : machine with states (
    start, zero, waitevent, procevent, flushpipe,
    dumpfifo, dumpfifo00, dumpfifo0, dumpfifo1, dumpfifo2, 
    dumpfifo3, dumpfifo4, dumpfifo5, dumpfifo6, holddump,
    doneevent);
  besttrack : lpm_ram_dp with (
    lpm_width=23, lpm_widthad=11,
    lpm_outdata="unregistered",
    lpm_rdaddress_control="unregistered",
    lpm_wraddress_control="registered",
    lpm_indata="registered");
  besttrack2 : lpm_ram_dp with (
    lpm_width=11, lpm_widthad=11,
    lpm_outdata="unregistered",
    lpm_rdaddress_control="unregistered",
    lpm_wraddress_control="registered",
    lpm_indata="registered");
  fsmcount : lpm_counter with (lpm_width=12);
  csqcorr    : lpm_ram_dp with (
    LPM_WIDTH=6, LPM_WIDTHAD=8,
    lpm_file="csqcorr.mif",
    lpm_outdata="unregistered",
    lpm_rdaddress_control="unregistered",
    lpm_wraddress_control="registered",
    lpm_indata="registered");
  
begin
  -- finite state machines
  fsm.clk = clock;
  fsm.reset = !_svtinit;
  case fsm is
    when start =>
      fsmcount.sclr = VCC;
      besttrack.rdaddress[] = locaddr[10..0];
      fsm = zero;
    when zero =>
      -- completely erase "best track" RAM on Halt/Recover/Run
      -- this takes 68 usec, so we can't do it every event
      besttrack.wraddress[] = fsmcount.q[10..0];
      besttrack.data[] = GND;
      besttrack.wren = VCC;
      besttrack2.wraddress[] = fsmcount.q[10..0];
      besttrack2.data[] = GND;
      besttrack2.wren = VCC;
      if fsmcount.q[]==2047 then
        fsm = waitevent;
      end if;
      -- this is a hack for fast partial erase during CAD simulation
      if (fsmcount.q[]==31) & ctrl[62] then
        fsm = waitevent;
      end if;
    when waitevent =>
      -- while idly waiting for data, make "best track" RAM available
      -- for VME read, so that we can verify that it is indeed in the
      -- zeroed state before each new event is processed
      if !svtfifo.rdempty then
        fsm = procevent;
      end if;
      besttrack.rdaddress[] = locaddr[10..0];
    when procevent =>
      -- process data until end-event bit is seen on input
      if gotdata.q & svtfifo.q[22] then
        fsmcount.sclr = VCC;
        fsm = flushpipe;
      else
        svtfifo.rdreq = !svtfifo.rdempty;
        gotdata.d = !svtfifo.rdempty;
      end if;
      -- we write incoming track word to 7*xftnum + wordnum
      besttrack.wraddress[] = addrk[].q;  -- 7*xftnum + wordnum
      besttrack2.wraddress[] = addrk[].q;  -- 7*xftnum + wordnum
      -- if it is better than any track that may already be there
      besttrack.wren = dvk.q & !ddk[22].q & keeperk.q;
      besttrack.data[21..0] = ddk[21..0].q;
      besttrack.data[22] = VCC;
      besttrack2.wren = dvk.q & !ddkdum[22].q & keeperk.q;
      besttrack2.data[] = ddkdum[20..10].q;
      -- need to read chisq value for previous best SVT track that
      -- has the same XFT track number for the incoming SVT track
      besttrack.rdaddress[] = csqaddri[];
      besttrack2.rdaddress[] = csqaddri[];

    when flushpipe =>
      -- at end of event, first wait 20 clock cycles (excessive?)
      -- for input pipeline to drain (660 nsec is a lot!)
      besttrack.wraddress[] = addrk[].q;  -- 7*xftnum + wordnum
      besttrack.wren = dvk.q & !ddk[22].q & keeperk.q;
      besttrack.data[21..0] = ddk[21..0].q;
      besttrack.data[22] = VCC;
      besttrack2.wraddress[] = addrk[].q;  -- 7*xftnum + wordnum
      besttrack2.wren = dvk.q & !ddkdum[22].q & keeperk.q;
      besttrack2.data[] = ddkdum[20..10].q;
      if fsmcount.q[]==20 then
        fsmcount.sclr = VCC;
        if ctrl[61] then
          fsm = waitevent;
        else
          fsm = dumpfifo;
        end if;
      end if;
      besttrack.rdaddress[] = csqaddri[];
      besttrack2.rdaddress[] = csqaddri[];
    when dumpfifo =>
      -- At end of event, we loop through list of XFT tracks, and
      -- write out the best SVT track for each XFT track.  Notice
      -- that we have filled a FIFO with the XFT id number of each
      -- unique XFT track that comes in on the SVT track list.  We
      -- then loop through the good tracks by reading the XFT IDs
      -- from that FIFO.
      if xftsparse.rdempty then
        -- if no more words in FIFO, we're done
        fsm = doneevent;
      else
        -- read next track ID from FIFO
        xftsparse.rdreq = VCC;
        fsm = dumpfifo00;
      end if;
    when dumpfifo00 =>
      -- this is a debug option to insert XFT ID into data stream
      ddm[21].d = VCC;
      ddm[19..16].d = H"f";
      ddm[8..0].d = xftsparse.q[];
      dvm.d = ctrl[63];
      sparseaddr[].d = sparsetimes7.result[10..0];
      fsm = dumpfifo0;
    when dumpfifo0 =>
      -- send track word 0 to output; rewrite zeros to RAM
      besttrack.wraddress[] = sparseaddr[].q;
      besttrack.data[] = GND;
      besttrack.wren = VCC;
      besttrack2.wraddress[] = sparseaddr[].q;
      besttrack2.data[] = GND;
      besttrack2.wren = VCC;
      besttrack.rdaddress[] = sparseaddr[].q;
      ddm[21..0].d = besttrack.q[21..0];
      dvm.d = VCC;
      sparseaddr[].d = sparseaddr[].q+1;
      fsm = dumpfifo1;
    when dumpfifo1 =>
      -- send track word 1 to output; rewrite zeros to RAM
      besttrack.wraddress[] = sparseaddr[].q;
      besttrack.data[] = GND;
      besttrack.wren = VCC;
      besttrack2.wraddress[] = sparseaddr[].q;
      besttrack2.data[] = GND;
      besttrack2.wren = VCC;
      besttrack.rdaddress[] = sparseaddr[].q;
      ddm[21..0].d = besttrack.q[21..0];
      dvm.d = VCC;
      sparseaddr[].d = sparseaddr[].q+1;
      fsm = dumpfifo2;
    when dumpfifo2 =>
      -- send track word 2 to output; rewrite zeros to RAM
      besttrack.wraddress[] = sparseaddr[].q;
      besttrack.data[] = GND;
      besttrack.wren = VCC;
      besttrack2.wraddress[] = sparseaddr[].q;
      besttrack2.data[] = GND;
      besttrack2.wren = VCC;
      besttrack.rdaddress[] = sparseaddr[].q;
      ddm[21..0].d = besttrack.q[21..0];
      dvm.d = VCC;
      sparseaddr[].d = sparseaddr[].q+1;
      fsm = dumpfifo3;
    when dumpfifo3 =>
      -- send track word 3 to output; rewrite zeros to RAM
      besttrack.wraddress[] = sparseaddr[].q;
      besttrack.data[] = GND;
      besttrack.wren = VCC;
      besttrack2.wraddress[] = sparseaddr[].q;
      besttrack2.data[] = GND;
      besttrack2.wren = VCC;
      besttrack.rdaddress[] = sparseaddr[].q;
      ddm[21..0].d = besttrack.q[21..0];
      dvm.d = VCC;
      sparseaddr[].d = sparseaddr[].q+1;
      fsm = dumpfifo4;
    when dumpfifo4 =>
      -- send track word 4 to output; rewrite zeros to RAM
      besttrack.wraddress[] = sparseaddr[].q;
      besttrack.data[] = GND;
      besttrack.wren = VCC;
      besttrack2.wraddress[] = sparseaddr[].q;
      besttrack2.data[] = GND;
      besttrack2.wren = VCC;
      besttrack.rdaddress[] = sparseaddr[].q;
      ddm[21..0].d = besttrack.q[21..0];
      dvm.d = VCC;
      sparseaddr[].d = sparseaddr[].q+1;
      fsm = dumpfifo5;
    when dumpfifo5 =>
      -- send track word 5 to output; rewrite zeros to RAM
      besttrack.wraddress[] = sparseaddr[].q;
      besttrack.data[] = GND;
      besttrack.wren = VCC;
      besttrack2.wraddress[] = sparseaddr[].q;
      besttrack2.data[] = GND;
      besttrack2.wren = VCC;
      besttrack.rdaddress[] = sparseaddr[].q;
      ddm[21..0].d = besttrack.q[21..0];
      dvm.d = VCC;
      sparseaddr[].d = sparseaddr[].q+1;
      fsm = dumpfifo6;
    when dumpfifo6 =>
      -- send track word 6 to output; rewrite zeros to RAM
      besttrack.wraddress[] = sparseaddr[].q;
      besttrack.data[] = GND;
      besttrack.wren = VCC;
      besttrack2.wraddress[] = sparseaddr[].q;
      besttrack2.data[] = GND;
      besttrack2.wren = VCC;
      besttrack.rdaddress[] = sparseaddr[].q;
      ddm[21..0].d = besttrack.q[21..0];
      dvm.d = VCC;
      if _outputhold.q then
        fsm = dumpfifo;
      else
	fsm = holddump;
      end if;
    when holddump =>
      if (_outputhold.q) # ctrl[58] then
        fsm = dumpfifo;
      end if;
    when doneevent =>
      ddm[].d = eei[].q;
      dvm.d = VCC;
      fsm = waitevent;
  end case;

  -- send beam position as a func. of z via VME
  if ((addr[4..2]==0)) then
    regbeam0[19..0].d = data[19..0];
    regbeam0[119..20].d = regbeam0[119..20].q;
    regbeam0[120].d = data[20];
  elsif ((addr[4..2]==1)) then
    regbeam0[19..0].d = regbeam0[19..0].q;
    regbeam0[39..20].d = data[19..0];
    regbeam0[120..40].d = regbeam0[120..40].q;
  elsif ((addr[4..2]==2)) then
    regbeam0[39..0].d = regbeam0[39..0].q;
    regbeam0[59..40].d = data[19..0];
    regbeam0[120..60].d = regbeam0[120..60].q;
  elsif ((addr[4..2]==3)) then
    regbeam0[59..0].d = regbeam0[59..0].q;
    regbeam0[79..60].d = data[19..0];
    regbeam0[120..80].d = regbeam0[120..80].q;
  elsif ((addr[4..2]==4)) then
    regbeam0[79..0].d = regbeam0[79..0].q;
    regbeam0[99..80].d = data[19..0];
    regbeam0[120..100].d = regbeam0[120..100].q;
  elsif ((addr[4..2]==5)) then
    regbeam0[99..0].d = regbeam0[99..0].q;
    regbeam0[119..100].d = data[19..0];
    regbeam0[120].d = regbeam0[120].q;
  end if;
  if (addr[4..2]==6) then
    regbeam0[].d = regbeam0[].q;
  end if;
  if (fsm==waitevent) & (beamvalidflag.q) then
    bpreg[].d = regbeam0[].q;
  end if;
  if (addr[4..2]==6) & (!beamvalidflag.q) then
    beamvalidflag.d = VCC;
  -- if mailman raise the valid flag, beam info. should be stored 
  -- in register.
  -- immidiately after storing position, we turned off the flag.
  elsif (fsm==waitevent) & (beamvalidflag.q) then
    --bpreg[].d = regbeam0[].q;
    beamvalidflag.d = GND;
  end if;
  beamvalidflag.clk = (clock # vmeds);
  beamvalidflag.ena = ((beamvalidflag.q) & (fsm==waitevent)) #
                      (vme_beamwrite & (!beamvalidflag.q)); 
  regbeam0[].clk = vmeds;
  regbeam0[].ena = vme_beamwrite & (!beamvalidflag.q);
  bpreg[].clk = clock;
  bpreg[].ena = (beamvalidflag.q) & (fsm==waitevent);

  -- To buffer store (See CDF note 2388 to understand L2buffer)
  if(eei[20..19].q ==0) then
    buf0beam[].d = bpreg[].q;
  elsif(eei[20..19].q ==1) then
    buf1beam[].d = bpreg[].q;
  elsif(eei[20..19].q ==2) then
    buf2beam[].d = bpreg[].q;
  elsif(eei[20..19].q ==3) then
    buf3beam[].d = bpreg[].q;
  end if;
  buf0beam[].ena = (eei[20..19].q == 0) & (fsm == doneevent); 
  buf0beam[].clk = clock;
  buf1beam[].ena = (eei[20..19].q == 1) & (fsm == doneevent); 
  buf1beam[].clk = clock;
  buf2beam[].ena = (eei[20..19].q == 2) & (fsm == doneevent); 
  buf2beam[].clk = clock;
  buf3beam[].ena = (eei[20..19].q == 3) & (fsm == doneevent); 
  buf3beam[].clk = clock;

  fsmcount.clock = clock;
  besttrack.wrclock = clock;
  besttrack2.wrclock = clock;
  gotsparse.clk = clock;
  sparsetimes7.dataa[] = xftsparse.q[];
  sparsetimes7.datab[] = 7;
  sparseaddr[].clk = clock;

  -- VME decoding
  locaddr[] = addr[21..2];
  vme_chipsel = vmeas &
    ((addr[23..22]==id[]) # (vmewrite & addr[23] & addr[22]));
  vme_deadbeef = vme_chipsel & !vmewrite & (locaddr[]==0);
  vme_reset = vme_chipsel & vmewrite & (locaddr[]==0);
  vme_ctrlwrite = vme_chipsel & vmewrite & (locaddr[]==1);
  vme_ctrlread = vme_chipsel & !vmewrite & (locaddr[]==1);
  vme_ctrl1write = vme_chipsel & vmewrite & (locaddr[]==2);
  vme_ctrl1read = vme_chipsel & !vmewrite & (locaddr[]==2);
  vme_whichblockwrite = vme_chipsel & vmewrite & (locaddr[]==3);
  vme_whichblockread = vme_chipsel & !vmewrite & (locaddr[]==3);
  vme_addrcheckread = vme_chipsel & !vmewrite & (locaddr[]==4);
  vme_framwrite = vme_chipsel & vmewrite & (locaddr[19..15]==H"1f");
  vme_framread = vme_chipsel & !vmewrite & (locaddr[19..15]==H"1f");
  vme_besttrackread = vme_chipsel & !vmewrite & (locaddr[19..11]==H"1");
  -- this is newly defined 
  vme_beamwrite = vme_chipsel & vmewrite & locaddr[19..15]==H"1a";
  vme_beamread = vme_chipsel & !vmewrite & locaddr[19..15]==H"1a";
  vme_csqcwrite = vme_chipsel & vmewrite & locaddr[19..15]==H"1b";
  vme_csqcread = vme_chipsel & !vmewrite & locaddr[19..15]==H"1b";
  -- read the beam for a given level2 buffer number
  vme_buf0z0beamread = vme_chipsel & !vmewrite & locaddr[]==H"80";
  vme_buf0z1beamread = vme_chipsel & !vmewrite & locaddr[]==H"81";
  vme_buf0z2beamread = vme_chipsel & !vmewrite & locaddr[]==H"82";
  vme_buf0z3beamread = vme_chipsel & !vmewrite & locaddr[]==H"83";
  vme_buf0z4beamread = vme_chipsel & !vmewrite & locaddr[]==H"84";
  vme_buf0z5beamread = vme_chipsel & !vmewrite & locaddr[]==H"85";
  vme_buf1z0beamread = vme_chipsel & !vmewrite & locaddr[]==H"90";
  vme_buf1z1beamread = vme_chipsel & !vmewrite & locaddr[]==H"91";
  vme_buf1z2beamread = vme_chipsel & !vmewrite & locaddr[]==H"92";
  vme_buf1z3beamread = vme_chipsel & !vmewrite & locaddr[]==H"93";
  vme_buf1z4beamread = vme_chipsel & !vmewrite & locaddr[]==H"94";
  vme_buf1z5beamread = vme_chipsel & !vmewrite & locaddr[]==H"95";
  vme_buf2z0beamread = vme_chipsel & !vmewrite & locaddr[]==H"a0";
  vme_buf2z1beamread = vme_chipsel & !vmewrite & locaddr[]==H"a1";
  vme_buf2z2beamread = vme_chipsel & !vmewrite & locaddr[]==H"a2";
  vme_buf2z3beamread = vme_chipsel & !vmewrite & locaddr[]==H"a3";
  vme_buf2z4beamread = vme_chipsel & !vmewrite & locaddr[]==H"a4";
  vme_buf2z5beamread = vme_chipsel & !vmewrite & locaddr[]==H"a5";
  vme_buf3z0beamread = vme_chipsel & !vmewrite & locaddr[]==H"b0";
  vme_buf3z1beamread = vme_chipsel & !vmewrite & locaddr[]==H"b1";
  vme_buf3z2beamread = vme_chipsel & !vmewrite & locaddr[]==H"b2";
  vme_buf3z3beamread = vme_chipsel & !vmewrite & locaddr[]==H"b3";
  vme_buf3z4beamread = vme_chipsel & !vmewrite & locaddr[]==H"b4";
  vme_buf3z5beamread = vme_chipsel & !vmewrite & locaddr[]==H"b5";

  -- drive VME data lines from tri-state buffers
  data[] = datatri[];
  datatri[] = dataout[].out;
  dataout[].oe = vme_chipsel & !vmewrite;

  -- read data via vme
  if vme_deadbeef then
    dataout[].in = H"deadbeef";
  end if;
  if vme_ctrlread then
    dataout[].in = ctrlreg[].q;
  end if;
  if vme_ctrl1read then
    dataout[].in = ctrl1reg[].q;
  end if;
  if vme_whichblockread then
    dataout[6].in = framsts;
    dataout[5..0].in = whichblock[].q;
  end if;
  if vme_framread then
    dataout[15..0].in = framdata[];
  end if;
  if vme_addrcheckread then
    dataout[].in = addrchk[].q;
  end if;
  if vme_besttrackread then
    dataout[10..0].in = besttrack.q[10..0];
  end if;
  if vme_csqcread then
    dataout[5..0].in = csqcorr.q[5..0];
  end if;

  -- for beam position reading out (to buffer) 
  if vme_buf0z0beamread then
    dataout[19..0].in = buf0beam[19..0].q;
    dataout[20].in = buf0beam[120].q;
  end if;
  if vme_buf0z1beamread then
    dataout[19..0].in = buf0beam[39..20].q;
    dataout[20].in = buf0beam[120].q;
  end if;
  if vme_buf0z2beamread then
    dataout[19..0].in = buf0beam[59..40].q;
    dataout[20].in = buf0beam[120].q;
  end if;
  if vme_buf0z3beamread then
    dataout[19..0].in = buf0beam[79..60].q;
    dataout[20].in = buf0beam[120].q;
  end if;
  if vme_buf0z4beamread then
    dataout[19..0].in = buf0beam[99..80].q;
    dataout[20].in = buf0beam[120].q;
  end if;
  if vme_buf0z5beamread then
    dataout[19..0].in = buf0beam[119..100].q;
    dataout[20].in = buf0beam[120].q;
  end if;

  if vme_buf1z0beamread then
    dataout[19..0].in = buf1beam[19..0].q;
    dataout[20].in = buf1beam[120].q;
  end if;
  if vme_buf1z1beamread then
    dataout[19..0].in = buf1beam[39..20].q;
    dataout[20].in = buf1beam[120].q;
  end if;
  if vme_buf1z2beamread then
    dataout[19..0].in = buf1beam[59..40].q;
    dataout[20].in = buf1beam[120].q;
  end if;
  if vme_buf1z3beamread then
    dataout[19..0].in = buf1beam[79..60].q;
    dataout[20].in = buf1beam[120].q;
  end if;
  if vme_buf1z4beamread then
    dataout[19..0].in = buf1beam[99..80].q;
    dataout[20].in = buf1beam[120].q;
  end if;
  if vme_buf1z5beamread then
    dataout[19..0].in = buf1beam[119..100].q;
    dataout[20].in = buf1beam[120].q;
  end if;

  if vme_buf2z0beamread then
    dataout[19..0].in = buf2beam[19..0].q;
    dataout[20].in = buf2beam[120].q;
  end if;
  if vme_buf2z1beamread then
    dataout[19..0].in = buf2beam[39..20].q;
    dataout[20].in = buf2beam[120].q;
  end if;
  if vme_buf2z2beamread then
    dataout[19..0].in = buf2beam[59..40].q;
    dataout[20].in = buf2beam[120].q;
  end if;
  if vme_buf2z3beamread then
    dataout[19..0].in = buf2beam[79..60].q;
    dataout[20].in = buf2beam[120].q;
  end if;
  if vme_buf2z4beamread then
    dataout[19..0].in = buf2beam[99..80].q;
    dataout[20].in = buf2beam[120].q;
  end if;
  if vme_buf2z5beamread then
    dataout[19..0].in = buf2beam[119..100].q;
    dataout[20].in = buf2beam[120].q;
  end if;

  if vme_buf3z0beamread then
    dataout[19..0].in = buf3beam[19..0].q;
    dataout[20].in = buf3beam[120].q;
  end if;
  if vme_buf3z1beamread then
    dataout[19..0].in = buf3beam[39..20].q;
    dataout[20].in = buf3beam[120].q;
  end if;
  if vme_buf3z2beamread then
    dataout[19..0].in = buf3beam[59..40].q;
    dataout[20].in = buf3beam[120].q;
  end if;
  if vme_buf3z3beamread then
    dataout[19..0].in = buf3beam[79..60].q;
    dataout[20].in = buf3beam[120].q;
  end if;
  if vme_buf3z4beamread then
    dataout[19..0].in = buf3beam[99..80].q;
    dataout[20].in = buf3beam[120].q;
  end if;
  if vme_buf3z5beamread then
    dataout[19..0].in = buf3beam[119..100].q;
    dataout[20].in = buf3beam[120].q;
  end if;

  -- ID prom
  myidprom.addr[] = locaddr[4..0];
  myidprom.dip[] = dip[];
  if (locaddr[] # H"1f")==H"4001f" then
    dataout[31..24].in = myidprom.data[];
  end if;

  -- handle control registers
  ctrlreg[].d = data[];
  ctrlreg[].clk = vme_ctrlwrite;
  ctrl[31..0] = ctrlreg[].q;
  ctrl1reg[].d = data[];
  ctrl1reg[].clk = vme_ctrl1write;
  ctrl[63..32] = ctrl1reg[].q;

  -- register to check VME address bus
  addrchk[31..30].d = GND;
  addrchk[29..28].d = id[];
  addrchk[27..24].d = GND;
  addrchk[23..2].d = addr[23..2];
  addrchk[1..0].d = GND;
  addrchk[].clk = vmeas & vmewrite;

  -- FRAM address banking
  whichblock[].d = data[5..0];
  whichblock[].clk = vme_whichblockwrite;

  -- latch backplane trigger signals; write L1A into FIFO
  cdfl1a.d = !_cdfl1a;			-- get active-high L1A
  cdfl1a.clk = cdfclk;			-- and latch to clock
  cdfrec.d = !_cdfrecover;		-- CDF_RECOVER
  cdfrec.clk = cdfclk;
  cdfl2b0.d = !_cdfl2b0;		-- L2B0
  cdfl2b0.clk = cdfclk;			--
  cdfl2b1.d = !_cdfl2b1;		-- L2B1
  cdfl2b1.clk = cdfclk;			--
  cdfb0.d = !_cdfb0;			-- B0 marker
  cdfb0.clk = cdfclk;			--
  cdfcc.clock = cdfclk;			-- clocks-since-B0 counter
  cdfcc.sclr = cdfb0.q;			--
  cdfcc1.clock = cdfclk;		-- clocks-since-Bn (set n via VME)
  cdfcc1.sclr = (cdfcc.q[]==ctrl[31..24]);
  l1afifo.data[7..0] = cdfcc1.q[];	-- bunch counter number
  l1afifo.data[8] = cdfl2b0.q;	        -- L2 buffer number
  l1afifo.data[9] = cdfl2b1.q;	        --
  l1afifo.wrreq = cdfl1a.q;		-- write every L1A
  l1afifo.wrclock = cdfclk;		--
  l1afifo.aclr = !_svtinit;
  l1afifo.rdreq = GND;
  l1afifo.rdclock = clock;		--

  l1a0sync0.d = cdfl1a.q & !cdfl2b0.q & !cdfl2b1.q;
  l1a0sync0.clk = clock;
  l1a0sync.d = l1a0sync0.q;
  l1a0sync.clk = clock;
  buf0time.aclr = !_svtinit;
  buf0time.sclr = l1a0sync.q;
  buf0time.clock = clock;

  -- hold logic and I/O LEDs
  _outputhold0.d = !outphold;
  _outputhold0.clk = clock;
  _outputhold.d = _outputhold0.q;
  _outputhold.clk = clock;
  inphold = !_fifoaf;
  holdinled = !_fifoaf;
  holdoutled = !_outputhold.q;
  dsoutled = dvj.q;
  dsinled = !dsinstretch.eq[3];
  dsinstretch.cnt_en = !dsinstretch.eq[3];
  dsinstretch.aclr = !_inpds;
  dsinstretch.clock = clock;

  -- input FIFO
  skipff0.d = !svtfifo.wrusedw[7];  -- was 4 2002/07/15
  skipff0.clk = clock;
  skipff0.clrn = _svtinit;
  skipff.d = skipff0.q;
  skipff.clk = !clock;
  fiforclk = clock;
  renanode = lcell(!(_fifoef1 & _fifoef0 & skipff.q));
  _dataready.d = renanode;
  _dataready.clk = clock;
  _fiforena = renanode;
  _fiforeset = _svtinit;
  ffin[].d = din[];
  ffin[].clk = clock;
  dvin.d = !_dataready.q;
  dvin.clk = clock;

  svtfifo.data[] = ffin[].q;
  svtfifo.wrreq = dvin.q;
  svtfifo.wrclock = clock;
  svtfifo.aclr = !_svtinit;
  svtfifo.rdclock = clock;
  gotdata.clk = clock;
  gotdata.clrn = _svtinit;

  eplastvalid.d = svtfifo.q[21];
  eplastvalid.ena = gotdata.q;
  eplastvalid.clrn = _svtinit;
  eplastvalid.clk = clock;

  -- enable the pipeline if we read a valid word
  -- or clock it anyway if the last valid word was
  -- an end-of-packet word
  enable.d = gotdata.q # eplastvalid.q;
  enable.clk = clock;

  -- output data

  -- latch input data from FIFO; count word number within track;
  -- we can probably remove stage A, as long as we handle word count
  dda[].d = svtfifo.q[];
  dda[].ena = VCC;
  dda[].clk = clock;
  dda[].clrn = _svtinit;
  dva.d = gotdata.q;
  dva.clrn = _svtinit;
  dva.ena = VCC;
  dva.clk = clock;
  wca.aclr = !_svtinit;
  wca.sclr = (!dva.q # dda[21].q) & enable.q;
  wca.cnt_en = enable.q;
  wca.clock = clock;

  -- stage B; latch XFT number and TF phi value.
  --          send phi to spareline, read/write beam center.
  -- input parity calcuration 
  parityb.d =
    (parityb.q $ dda[21].q $ dda[20].q $
    dda[19].q $ dda[18].q $ dda[17].q $ dda[16].q $
    dda[15].q $ dda[14].q $ dda[13].q $ dda[12].q $
    dda[11].q $ dda[10].q $ dda[9].q $ dda[8].q $
    dda[7].q $ dda[6].q $ dda[5].q $ dda[4].q $
    dda[3].q $ dda[2].q $ dda[1].q $ dda[0].q) & (!dda[22].q);
  parityb.clrn = _svtinit;
  parityb.ena = dva.q;
  parityb.clk = clock;
  perrorb.d = parityb.q $ dda[8].q;
  perrorb.ena = dva.q & dda[22].q;
  perrorb.clk = clock;
  ddb[22..0].d = dda[22..0].q;
  ddb[].ena = enable.q;
  ddb[].clk = clock;
  dvb.d = dva.q;
  dvb.clrn = _svtinit;
  dvb.ena = enable.q;
  dvb.clk = clock;
  wcb[].d = wca.q[];
  wcb[].ena = enable.q;
  wcb[].clk = clock;
  -- latch xft number  
  xftnumb[].d = dda[8..0].q;
  xftnumb[].ena = (wca.q[]==6) & dva.q & enable.q;
  xftnumb[].clk = clock;
  -- latch TF phi value
  phib[].d = dda[12..0].q;
  phib[].ena = (wca.q[]==0) & dva.q & enable.q;
  phib[].clk = clock;
  -- send phi information to spare line (chip0)
  spare[] = sdtri[];
  sdtri[] = sdout[].out;
  sdout[12..0].in = phib[].q;
  sdout[29..13].in = GND;
  sdout[12..0].oe = dva.q & enable.q;
  sdout[29..13].oe = GND;
  -- get tf_status for this track
  ntfstatb[].d = dda[20..9].q;
  ntfstatb[].ena = (wca.q[]==6) & dva.q & enable.q;
  ntfstatb[].clk = clock;
  -- get chisq for this track
  ncsqb[].d = dda[20..10].q;
  ncsqb[].ena = (wca.q[]==5) & dva.q & enable.q;
  ncsqb[].clk = clock;

  -- Stage C: 
  if( (wcb[].q==6) & enable.q ) then   
    csqcorr.rdaddress[3..0] = ntfstatb[3..0].q;
    if(!ncsqb[10].q & !ncsqb[9].q & !ncsqb[8].q & !ncsqb[7].q &
      !ncsqb[6].q & !ncsqb[5].q & !ncsqb[4].q ) then
      csqcorr.rdaddress[7..4] = ncsqb[3..0].q;
    else 
      csqcorr.rdaddress[7..4] = VCC;  
    end if;
    addcsqc.dataa[5..0] = csqcorr.q[];
    addcsqc.dataa[9..6] = GND;
    addcsqc.datab[9..0] = ncsqb[9..0].q;
    newcsqc[10].d = ncsqb[10].q;
    newcsqc[9..0].d = addcsqc.result[];
    --if (ntfstatb[11].q) then
    --  newcsqc[].d = VCC;
    --end if;
  end if;
  newcsqc[].ena = ( (wcb[].q==6) & enable.q );
  newcsqc[].clk = clock;
  ddc[].d = ddb[].q;
  ddc[].ena = enable.q;
  ddc[].clk = clock;
  dvc.d = dvb.q;
  dvc.clrn = _svtinit;
  dvc.ena = enable.q;
  dvc.clk = clock;
  wcc[].d = wcb[].q;
  wcc[].ena = enable.q;
  wcc[].clk = clock;
  -- get beam position from dffe
  if ddb[15..13].q==0 then
    bpb[].d = bpreg[19..0].q;
  elsif ddb[15..13].q==1 then
    bpb[].d = bpreg[39..20].q; 
  elsif ddb[15..13].q==2 then
    bpb[].d = bpreg[59..40].q; 
  elsif ddb[15..13].q==3 then
    bpb[].d = bpreg[79..60].q; 
  elsif ddb[15..13].q==4 then
    bpb[].d = bpreg[99..80].q; 
  elsif ddb[15..13].q==5 then
    bpb[].d = bpreg[119..100].q; 
  end if;
  bpb[].ena = (wcb[].q==0) & dvb.q;  
  bpb[].clk = clock;  


  -- Stage D;
  ddd[].d = ddc[].q;
  ddd[].ena = enable.q;
  ddd[].clk = clock;
  dvd.d = dvc.q;
  dvd.clrn = _svtinit;
  dvd.ena = enable.q;
  dvd.clk = clock;
  wcd[].d = wcc[].q;
  wcd[].ena = enable.q;
  wcd[].clk = clock;

  -- Stage E;
  dde[].d = ddd[].q;
  dde[].ena = enable.q;
  dde[].clk = clock;
  dve.d = dvd.q;
  dve.clrn = _svtinit;
  dve.ena = enable.q;
  dve.clk = clock;
  wce[].d = wcd[].q;
  wce[].ena = enable.q;
  wce[].clk = clock;

  -- Stage F; latch correction value of Phi from FRAM.
  ddf[].d = dde[].q;
  ddf[].ena = enable.q;
  ddf[].clk = clock;
  dvf.d = dve.q;
  dvf.clrn = _svtinit;
  dvf.ena = enable.q;
  dvf.clk = clock;
  wcf[].d = wce[].q;
  wcf[].ena = enable.q;
  wcf[].clk = clock;
  -- latch chip#0 FRAM value (expected wedge# and expected correcion number) 
  phifixf[].d = framdata[10..0];
  phifixf[].ena = enable.q & (wce[].q==0);
  phifixf[].clk = clock;

  -- Stage G; determine correction value of phi and (ycos xsin).
  -- To correct phi value using wedge and correction value.
  if (wcf[].q==2) & enable.q then
    comwedge.dataa[] = phifixf[8..5].q;
    comwedge.datab[] = ddf[20..17].q;
    if !comwedge.aeb then
       sincor.d = phifixf[4].q;   -- sincor is correcion sign (VCC=+, GND=-)
       phifixg[3].d = VCC;        -- stored data is (- is VCC, + is GND)
       phifixg[2..0].d = GND;     -- so this means flipped.
    else
       if phifixf[4] then
          sincor.d = GND;
       else
          sincor.d = VCC;
       end if;
       phifixg[3..0].d = phifixf[3..0].q;
    end if;
    phifixg[12..4].d = GND;       --  this is for add_sub
  end if;
  sincor.ena = enable.q & (wcf[].q==2);
  sincor.clk = clock;
  phifixg[].ena = enable.q & (wcf[].q==2);
  phifixg[].clk = clock;
  -- for beam subtraction (calc. y(z)*cos, x(z)*sin)
  multier.dataa[] = cosphie[].q;
  multier.datab[] = bpb[8..0].q;
  ycosg[17].d = GND;
  ycosg[16..0].d = multier.result[];
  ycosg[].ena = enable.q;
  ycosg[].clk = clock;
  multier2.dataa[] = sinphie[].q;
  multier2.datab[] = bpb[18..10].q;
  xsing[17].d = GND;
  xsing[16..0].d = multier2.result[];
  xsing[].ena = enable.q;
  xsing[].clk = clock;

  ddg[].d = ddf[].q;
  ddg[].ena = enable.q;
  ddg[].clk = clock;
  dvg.d = dvf.q;
  dvg.clrn = _svtinit;
  dvg.ena = enable.q;
  dvg.clk = clock;
  wcg[].d = wcf[].q;
  wcg[].ena = enable.q;
  wcg[].clk = clock;

  -- Stage H; calcurate {xsin(phi) - ysin(phi)}
  -- xsin(phi) - ysin(phi) w/ correct sign. (there may be more smart way) 
  abscomp.dataa[] = xsing[].q;
  abscomp.datab[] = ycosg[].q;
  --     cos sign          sin sign           y sign        x sign
  if( (phifixf[9].q==0 & phifixf[10].q==0 & bpb[9].q==0 & bpb[19].q==0) # 
      (phifixf[9].q==1 & phifixf[10].q==0 & bpb[9].q==1 & bpb[19].q==0) # 
      (phifixf[9].q==0 & phifixf[10].q==1 & bpb[9].q==0 & bpb[19].q==1) # 
      (phifixf[9].q==1 & phifixf[10].q==1 & bpb[9].q==1 & bpb[19].q==1) ) then
    ipcorr.add_sub = GND;    
    if (abscomp.ageb) then
      ipcorr.dataa[] = xsing[].q;
      ipcorr.datab[] = ycosg[].q;
      sinaddh.d = GND;
    else  
      ipcorr.dataa[] = ycosg[].q;
      ipcorr.datab[] = xsing[].q;
      sinaddh.d = VCC;
    end if;
  elsif( (phifixf[9].q==1 & phifixf[10].q==1 & bpb[9].q==0 & bpb[19].q==0) # 
         (phifixf[9].q==0 & phifixf[10].q==1 & bpb[9].q==1 & bpb[19].q==0) # 
         (phifixf[9].q==1 & phifixf[10].q==0 & bpb[9].q==0 & bpb[19].q==1) # 
       (phifixf[9].q==0 & phifixf[10].q==0 & bpb[9].q==1 & bpb[19].q==1)) then
    ipcorr.add_sub = GND;    
    if (abscomp.ageb) then
      ipcorr.dataa[] = xsing[].q;
      ipcorr.datab[] = ycosg[].q;
      sinaddh.d = VCC;
    else  
      ipcorr.dataa[] = ycosg[].q;
      ipcorr.datab[] = xsing[].q;
      sinaddh.d = GND;
    end if;
  elsif( (phifixf[9].q==1 & phifixf[10].q==0 & bpb[9].q==0 & bpb[19].q==0) # 
         (phifixf[9].q==0 & phifixf[10].q==0 & bpb[9].q==1 & bpb[19].q==0) # 
         (phifixf[9].q==1 & phifixf[10].q==1 & bpb[9].q==0 & bpb[19].q==1) # 
       (phifixf[9].q==0 & phifixf[10].q==1 & bpb[9].q==1 & bpb[19].q==1)) then
    ipcorr.dataa[] = xsing[].q;
    ipcorr.datab[] = ycosg[].q;
    ipcorr.add_sub = VCC;    
    sinaddh.d = GND;
  else 
    ipcorr.dataa[] = xsing[].q;
    ipcorr.datab[] = ycosg[].q;
    ipcorr.add_sub = VCC;
    sinaddh.d = VCC;
  end if;
  if (!ipcorr.result[7]) then
    ipsub[].d = ipcorr.result[17..0];  
  else
    ipsub[7..0].d = GND;
    rounder.dataa[] = ipcorr.result[17..8];
    rounder.datab[0] = VCC;
    rounder.datab[9..1] = GND;	 
    ipsub[17..8].d = rounder.result[];
  end if;
  ipsub[].ena = enable.q & wcg[].q==1;
  ipsub[].clk = clock;
  sinaddh.ena = enable.q & wcg[].q==1;
  sinaddh.clk = clock;
        
  ddh[].d = ddg[].q;
  dvh.d = dvg.q;
  ddh[].ena = enable.q;
  ddh[].clk = clock;
  dvh.clrn = _svtinit;
  dvh.ena = enable.q;
  dvh.clk = clock;
  wch[].d = wcg[].q;
  wch[].ena = enable.q;
  wch[].clk = clock;
  wcfillh[10..3] = GND;
  wcfillh[2..0] = wch[2..0].q;

  -- Stage I; Ghost removal, and put corrected phi and ip 
  -- here is where the ghost removal begins
  ddi[].d = ddh[].q;
  ddi[].ena = enable.q;
  ddi[].clk = clock;
  eei[].d = ddh[].q;
  eei[].ena = enable.q & dvh.q & ddh[22].q;
  eei[].clk = clock;
  dvi.d = dvh.q;
  dvi.clrn = _svtinit;
  dvi.ena = enable.q;
  dvi.clk = clock;
  xftnumi[].d = xftnumb[].q;
  xftnumi[].clk = clock;
  xftnumi[].ena = enable.q;
  times7.dataa[] = xftnumb[].q;
  times7.datab[] = 7;
  baseaddri[].d = times7.result[10..0];
  baseaddri[].clk = clock;
  baseaddri[].ena = enable.q & dvh.q;
  addri[].d = times7.result[10..0] + wcfillh[];
  addri[].clk = clock;
  addri[].ena = enable.q;
  csqaddri[] = times7.result[10..0]+5;
  wci[].d = wch[].q;
  wci[].ena = enable.q;
  wci[].clk = clock;

  -- this is for ghost removal
  ddj[22..13].d = ddi[22..13].q;
  -- this is phi correction part
  if (wci[].q==0) & !ddi[22].q & !ctrl[59] then
    phicorr.dataa[] = ddi[12..0].q;
    phicorr.datab[] = phifixg[].q;
    phicorr.add_sub = sincor.q;
    ddj[12..0].d = phicorr.result[];
  -- this is ip correction part 
  elsif (wci[].q==1) & !ddi[22].q then
    ddj[12..10].d = ddi[12..10].q;
    abscompj.dataa[9] = GND;
    abscompj.dataa[8..0] = ddi[8..0].q;
    abscompj.datab[9..0] = ipsub[17..8].q;
    -- if sign of original ip and (-ycos+xsin) are same 
    if ( (sinaddh.q & ddi[9].q) # (!sinaddh.q & !ddi[9].q) ) then
      ipcorr2.dataa[9] = GND;
      ipcorr2.dataa[8..0] = ddi[8..0].q;
      ipcorr2.datab[9..0] = ipsub[17..8].q;
      ipcorr2.add_sub = VCC;
      if ((sinaddh.q & ddi[9].q)) then
	ddj[9].d = VCC;
      else
        ddj[9].d = GND;
      end if;	
    -- if sign of original ip and (-ycos+xsin) are opposite 
    else 
      if abscompj.agb then
        ipcorr2.dataa[9] = GND;
        ipcorr2.dataa[8..0] = ddi[8..0].q;
        ipcorr2.datab[9..0] = ipsub[17..8].q; 
        if sinaddh.q then
	  ddj[9].d = GND;
        else
	  ddj[9].d = VCC;
        end if;
      elsif abscompj.aeb then
        ddj[9].d = GND;
        ipcorr2.dataa[9..0] = GND;
        ipcorr2.datab[9..0] = GND;
      else 
        ipcorr2.dataa[9..0] = ipsub[17..8].q;
        ipcorr2.datab[9] = GND;
        ipcorr2.datab[8..0] = ddi[8..0].q;
        if sinaddh.q then
	  ddj[9].d = VCC;
        else
	  ddj[9].d = GND;
        end if;
      end if;
      ipcorr2.add_sub = GND;
    end if;
    ddj[8..0].d = ipcorr2.result[8..0];
  else
    ddj[12..0].d = ddi[12..0].q;
  end if;

  ddj[].clk = clock;
  ddj[].ena = enable.q;
  dvj.d = dvi.q;
  dvj.clk = clock;
  dvj.ena = enable.q;
  dvj.clrn = _svtinit;
  addrj[].d = addri[].q;
  addrj[].clk = clock;
  addrj[].ena = enable.q;
  wcj[].d = wci[].q;
  wcj[].ena = enable.q;
  wcj[].clk = clock;
  oldexistsj = besttrack.q[22];
  --oldcsqj[] = besttrack.q[20..10];
  oldcsqj[] = besttrack2.q[];
  newcsqj[] = newcsqc[].q;
  debug[11..0] = ntfstatb[11..0].q; 
  debug[15..12] = GND;
  --newcsqj[] = dde[20..10].q;
  xftnumj[].d = xftnumi[].q;
  xftnumj[].ena = enable.q;
  xftnumj[].clk = clock;

  -- Stage K;
  -- this stage decides whether to keep incoming track
  if (wcj[].q==5) then
    ddkdum[20..10].d = newcsqc[].q;
    ddkdum[22..21].d = ddj[22..21].q;
    ddkdum[9..0].d = ddj[9..0].q;
  else 
    ddkdum[].d = ddj[].q;
  end if;  
  ddkdum[].clk = clock;
  ddkdum[].ena = enable.q;
  ddk[].d = ddj[].q;
  ddk[].clk = clock;
  ddk[].ena = enable.q;
  dvk.d = dvj.q;
  dvk.clk = clock;
  dvk.ena = enable.q;
  dvk.clrn = _svtinit;
  addrk[].d = addrj[].q;
  addrk[].clk = clock;
  addrk[].ena = enable.q;
  keeperk.d = (newcsqj[] < oldcsqj[]) # !oldexistsj;
  keeperk.clk = clock;
  keeperk.ena = enable.q & (wcj[].q==0);
  oldcsqk[].d = oldcsqj[];
  oldcsqk[].clk = clock;
  oldcsqk[].ena = enable.q;
  oldexistsk.d = oldexistsj;
  oldexistsk.clk = clock;
  oldexistsk.ena = enable.q;
  newcsqk[].d = newcsqj[];
  newcsqk[].clk = clock;
  newcsqk[].ena = enable.q;
  xftnumk[].d = xftnumj[].q;
  xftnumk[].ena = enable.q;
  xftnumk[].clk = clock;
  wck[].d = wcj[].q;
  wck[].ena = enable.q;
  wck[].clk = clock;

  -- this is where we write unique XFT track IDs to the FIFO
  xftsparse.data[] = xftnumk[].q;
  xftsparse.wrreq = 
    !oldexistsk.q & !ddk[21].q & (wck[].q==0) & dvk.q & enable.q;
  xftsparse.wrclock = clock;
  xftsparse.aclr = !_svtinit;
  xftsparse.rdclock = clock;

  -- Stage L;
  ddl[].d = ddk[].q;
  ddl[].clk = clock;
  ddl[].ena = enable.q;
  dvl.d = dvk.q;
  dvl.clk = clock;
  dvl.ena = enable.q;
  dvl.clrn = _svtinit;

  -- stage M is where the output is inserted into the pipeline
  if (fsm==procevent) # (fsm==flushpipe) then
    ddm[].d = ddl[].q;
    dvm.d = dvl.q & enable.q & ctrl[60];
  end if;
  dvm.clrn = _svtinit;
  ddm[].clk = clock;
  dvm.clk = clock;

  parityn.d =
    (parityn.q $ ddm[21].q $ ddm[20].q $
    ddm[19].q $ ddm[18].q $ ddm[17].q $ ddm[16].q $
    ddm[15].q $ ddm[14].q $ ddm[13].q $ ddm[12].q $
    ddm[11].q $ ddm[10].q $ ddm[9].q $ ddm[8].q $
    ddm[7].q $ ddm[6].q $ ddm[5].q $ ddm[4].q $
    ddm[3].q $ ddm[2].q $ ddm[1].q $ ddm[0].q) & (!ddm[22].q);
  parityn.clrn = _svtinit;
  parityn.ena = dvm.q;
  parityn.clk = clock;
  ddn[22..10].d = ddm[22..10].q;
  if ddm[22].q then
    ddn[9].d = ddm[9].q # perrorb.q;
    ddn[8].d = parityn.q;
  else
    ddn[9].d = ddm[9].q;
    ddn[8].d = ddm[8].q;
  end if;
  ddn[7..0].d = ddm[7..0].q;
  ddn[].clk = clock;
  dvn.d = dvm.q;
  dvn.clrn = _svtinit;
  dvn.clk = clock;

  ffout[].d = ddn[].q;
  ffout[].clk = clock;
  dout[] = ffout[].q;
  dvout.d = dvn.q;
  dvout.clk = !clock;
  _dsout = !lcell(dvout.q & clock);

  -- Flash RAM
  if (fsm==procevent) # (fsm==flushpipe) then
    framaddr[20..13] = GND;
    framaddr[12..0] = phib[].q;
    -- recieve cos/sin information from spare line
    cosphie[7..0].d = spare[20..13];
    sinphie[7..0].d = spare[28..21];
    cosphie[].ena = enable.q;
    cosphie[].clk = clock;
    sinphie[].ena = enable.q;
    sinphie[].clk = clock;
  else
    framaddr[20..15] = whichblock[].q;
    framaddr[14..0] = locaddr[14..0];
    --beampos.rdaddress[] = addr[4..2];  
    -- chisq correction value via VME 
    csqcorr.wraddress[] = addr[9..2];
    csqcorr.rdaddress[] = addr[9..2];  
  end if;
  framdata[] = fdtri[];
  fdtri[] = fdout[].out;
  fdout[].in = data[15..0];
  fdout[].oe = vme_framwrite;
  _framoe = vme_framwrite;  -- output-enable whenever not writing
  _framwe = !vme_framwrite;
  _framrp = !(vme_whichblockwrite & data[31]);
  _framwp = VCC;
  csqcorr.data[] = data[5..0];
  csqcorr.wrclock = vmeds;
  csqcorr.wren = vme_csqcwrite;

  -- drive unimplemented outputs
  debugclk = clock;
  _svterror = VCC;
  _cdferror = VCC;
  runled = GND;
  errorled = GND;
end;
