--
-- gb.tdf
-- data processor chip for SVT GhostBuster card
-- begun April 2001 by Bill Ashmanskas, 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";

--
-- 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]);

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]    : input;      -- 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
  dvxmag[9..0]    : node;
  acceptall       : node;
  rejectall       : node;
  acceptothers    : node;
  unique          : node;
  dvxcut[8..0]    : node;
  dobigdvxcut     : node;
  bigdvxcut[8..0] : node;
  dobigcrvcut     : node;
  dofilter        : node;
  docrvcut        : node;
  crvcut[7..0]    : node;
  csqcut[10..0]   : node;
  ntkcut[9..0]    : node;
  goodtrack       : node;
  beamfix         : lpm_ram_dp with (
	LPM_WIDTH=10, LPM_WIDTHAD=13,
	lpm_file="db.mif",
	lpm_outdata="unregistered",
	lpm_rdaddress_control="unregistered",
	lpm_wraddress_control="registered",
	lpm_indata="registered");
  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
  wcb[3..0]       : dffe;
  ddc[22..0]      : dffe;	-- extra stage
  bfc[9..0]       : dffe;
  d2cc[9..0]      : dffe;
  wcc[3..0]       : dffe;
  dvc             : dffe;	-- extra stage valid flag
  ddd[22..0]      : dffe;	-- extra stage
  adder : lpm_add_sub with (LPM_WIDTH=10);
  negdiff[9..0]   : node;
  diffd[9..0]     : dffe;
  wcd[3..0]       : dffe;
  bfd[9..0]       : dffe;
  dvd             : dffe;	-- extra stage valid flag
  dde[22..0]      : dffe;	-- extra stage
  ntrackse        : lpm_counter with (lpm_width=10);
  dve             : dffe;	-- extra stage valid flag
  lastxft[8..0]   : dffe;
  ddf[22..0]      : dffe;	-- extra stage
  ntracksf[9..0]  : dffe;
  dvf             : dffe;	-- extra stage valid flag
  ddg[22..0]      : dffe;	-- extra stage
  dvg             : dffe;	-- extra stage valid flag
  ddh[22..0]      : dffe;	-- extra stage
  dvh             : dffe;	-- extra stage valid flag
  ddi[22..0]      : dffe;	-- extra stage
  dvi             : dffe;	-- extra stage valid flag
  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;
  addrchk[31..0]  : dff;        -- test VME address bus
  ctrl[31..0]     : node;       -- alias for ctrlreg.q
  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);
  eplastvalid : dffe;
  enable : dff;
  prescale : lpm_counter with (lpm_width=16);
  buf0time : lpm_counter with (lpm_width=20);
  l1a0sync0 : dff;
  l1a0sync : dff;
  whichblock[5..0] : dff;

  -- 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;	--

  -- nodes holding results of VME address decoding
  vme_clr_ctrs    : node;	-- reset counters
  vme_ctrlwrite   : node;	-- write control registers
  vme_ctrl1write  : node;
  vme_beamwrite   : node;
  vme_framwrite   : node;
  vme_framread    : node;
  vme_whichblockwrite : node;
  vme_whichblockread : node;
  renanode        : node;	-- lcell for fiforena

begin
  -- handle control register
  ctrlreg[].d = data[];
  ctrlreg[].clk = vme_ctrlwrite;
  ctrl[] = ctrlreg[].q;

  ctrl1reg[].d = data[];
  ctrl1reg[].clk = vme_ctrl1write;

  whichblock[].d = data[5..0];
  whichblock[].clk = vme_whichblockwrite;

  -- register to check VME address bus
  addrchk[31..24].d = GND;
  addrchk[23..2].d = addr[23..2];
  addrchk[1..0].d = GND;
  addrchk[].clk = vmeas & vmewrite;

  -- 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;

  -- drive VME data lines from tri-state buffers
  data[] = datatri[];
  datatri[] = dataout[].out;

  -- some vme decoding
  vme_ctrlwrite = vmeas & vmewrite & addr[12..11]==id[] &
    (addr[23..14]==H"0") & (addr[10..2]==H"1");
  vme_clr_ctrs = vmeas & vmewrite & addr[12..11]==id[] &
    (addr[23..14]==H"0") & (addr[10..2]==H"2");
  vme_beamwrite = vmeas & vmewrite & addr[19..18]==id[] &
    (addr[23..20]==H"2");
  vme_framwrite = vmeas & vmewrite & addr[19..18]==id[] &
    (addr[23..20]==H"3");
  vme_framread = vmeas & !vmewrite & addr[19..18]==id[] &
    (addr[23..20]==H"3");
  vme_ctrl1write = vmeas & vmewrite & addr[12..11]==id[] &
    (addr[23..14]==H"0") & (addr[10..2]==H"3");
  vme_whichblockwrite = vmeas & vmewrite & addr[12..11]==id[] &
    (addr[23..14]==H"0") & (addr[10..2]==H"5");
  vme_whichblockread = vmeas & !vmewrite & addr[12..11]==id[] &
    (addr[23..14]==H"0") & (addr[10..2]==H"5");

  -- read data via vme
  if (vme_framread) then
    dataout[31..16] = GND;
    dataout[15..0].in = framdata[];
  end if;
  if (vme_whichblockread) then
    dataout[31..7] = GND;
    dataout[6] = framsts;
    dataout[5..0] = whichblock[].q;
  end if;
  if ((addr[23..14]==H"0") & (addr[10..2]==H"0")) then 
    dataout[].in = H"deadbeef";
  end if;
  if ((addr[23..14]==H"0") & (addr[10..2]==H"1")) then
    dataout[].in = ctrlreg[].q;
  end if;
  if ((addr[23..14]==H"0") & (addr[10..2]==H"2")) then
    dataout[31..0].in = H"fab40000";
  end if;
  if ((addr[23..14]==H"0") & (addr[10..2]==H"3")) then
    dataout[31..0].in = ctrl1reg[].q;
  end if;
  if ((addr[23..14]==H"0") & (addr[10..2]==H"4")) then
    dataout[].in = addrchk[].q;
  end if;

  -- ID prom
  if (addr[23..2]==H"40000") then
    dataout[].in = H"30000000";
  end if;
  if (addr[23..2]==H"40001") then
    dataout[].in = H"30000000";
  end if;
  if (addr[23..2]==H"40002") then
    dataout[].in = H"30000000";
  end if;
  if (addr[23..2]==H"40003") then
    dataout[31..28].in = H"3";
    dataout[27].in = GND;
    dataout[26..24].in = !dip[2..0];
    dataout[23..0].in = GND;
  end if;
  if (addr[23..2]==H"40004") then
    dataout[].in = H"20000000";
  end if;
  if (addr[23..2]==H"40005") then
    dataout[].in = H"30000000";
  end if;
  if (addr[23..2]==H"40006") then
    dataout[].in = H"37000000";
  end if;
  if (addr[23..2]==H"40007") then
    dataout[].in = H"33000000";
  end if;
  if (addr[23..2]==H"40008") then
    dataout[].in = H"20000000";
  end if;
  if (addr[23..2]==H"40009") then
    dataout[].in = H"43000000";
  end if;
  if (addr[23..2]==H"4000a") then
    dataout[].in = H"44000000";
  end if;
  if (addr[23..2]==H"4000b") then
    dataout[].in = H"46000000";
  end if;
  if (addr[23..2]==H"4000c") then
    dataout[].in = H"20000000";
  end if;
  if (addr[23..2]==H"4000d") then
    dataout[].in = H"53000000";
  end if;
  if (addr[23..2]==H"4000e") then
    dataout[].in = H"56000000";
  end if;
  if (addr[23..2]==H"4000f") then
    dataout[].in = H"54000000";
  end if;
  if (addr[23..2]==H"40010") then
    dataout[].in = H"20000000";
  end if;
  if (addr[23..2]==H"40011") then
    dataout[].in = H"47000000";
  end if;
  if (addr[23..2]==H"40012") then
    dataout[].in = H"68000000";
  end if;
  if (addr[23..2]==H"40013") then
    dataout[].in = H"6f000000";
  end if;
  if (addr[23..2]==H"40014") then
    dataout[].in = H"73000000";
  end if;
  if (addr[23..2]==H"40015") then
    dataout[].in = H"74000000";
  end if;
  if (addr[23..2]==H"40016") then
    dataout[].in = H"42000000";
  end if;
  if (addr[23..2]==H"40017") then
    dataout[].in = H"75000000";
  end if;
  if (addr[23..2]==H"40018") then
    dataout[].in = H"73000000";
  end if;
  if (addr[23..2]==H"40019") then
    dataout[].in = H"74000000";
  end if;
  if (addr[23..2]==H"4001a") then
    dataout[].in = H"65000000";
  end if;
  if (addr[23..2]==H"4001b") then
    dataout[].in = H"72000000";
  end if;
  if (addr[23..2]==H"4001c") then
    dataout[].in = H"20000000";
  end if;
  if (addr[23..2]==H"4001d") then
    dataout[].in = H"76000000";
  end if;
  if (addr[23..2]==H"4001e") then
    dataout[].in = H"30000000";
  end if;
  if (addr[23..2]==H"4001f") then
    dataout[].in = H"30000000";
  end if;

  dataout[].oe = 
    vmeas & !vmewrite & 
    (((addr[23..20]==0) & (addr[12..11]==id[])) # (vme_framread));

  -- beam correction
  beamfix.data[] = data[9..0];
  beamfix.wrclock = vmeds;
  beamfix.wren = vme_beamwrite;
  beamfix.wraddress[] = addr[14..2];
  -- beamfix.rdclock = clock;
  beamfix.rdaddress[] = ddc[15..3].q;

  -- 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 = dvi.q;
  dsinled = cdfl1a.q;

  -- input FIFO
  skipff0.d = VCC;
  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;

  eplastvalid.d = ffin[21].q;
  eplastvalid.ena = dvin.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 = dvin.q # eplastvalid.q;
  enable.clk = clock;

  debug[] = GND;

  -- output data

  dda[].d = ffin[].q;
  dda[].ena = VCC;
  dda[].clk = clock;
  dda[].clrn = _svtinit;
  dva.d = dvin.q & (ffin[].q!=H"3fffff");
  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;

  ddb[22..21].d = dda[22..21].q;
  ddb[19..0].d = dda[19..0].q;
  dvxcut[8..5] = GND;
  dvxcut[4..0] = ctrl[4..0];
  csqcut[10..8] = GND;
  csqcut[7..0] = ctrl[15..8];
  ntkcut[9..3] = GND;
  ntkcut[2..0] = ctrl[7..5];
  dobigdvxcut = ctrl[17];
  bigdvxcut[] = ctrl1reg[16..8].q;
  docrvcut = ctrl[18];
  crvcut[] = ctrl1reg[7..0].q;
  dofilter = ctrl[19];
  acceptothers = ctrl[29];
  rejectall = ctrl[28];
  acceptall = ctrl[27];
  unique = ctrl[26];
  if (wca.eq[4]) then
    ddb[20].d = 
      ((dvxcut[]==0) # (diffd[8..0].q>=dvxcut[])) &
      ((!dobigdvxcut) # (diffd[8..0].q<=bigdvxcut[])) &
      ((!docrvcut) # (ddd[17..10].q<=crvcut[]));
  else
    ddb[20].d = dda[20].q;
  end if;
  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;

  ddc[22..21].d = ddb[22..21].q;
  ddc[19..0].d = ddb[19..0].q;
  if (wca.eq[5]) then
    ddc[20].d = ddb[20].q &
      ((csqcut[]==0) # (dda[20..10].q<=csqcut[]));
  else
    ddc[20].d = ddb[20].q;
  end if;
  ddc[].ena = enable.q;
  ddc[].clk = clock;
  dvc.d = dvb.q;
  dvc.clrn = _svtinit;
  dvc.ena = enable.q;
  dvc.clk = clock;
  bfc[].d = -beamfix.q[];
  bfc[].ena = enable.q;
  bfc[].clk = clock;
  dvxmag[9] = GND;
  dvxmag[8..0] = ddb[8..0].q;
  if (ddb[9].q) then
    d2cc[].d = -dvxmag[];
  else
    d2cc[].d = dvxmag[];
  end if;
  d2cc[].ena = enable.q;
  d2cc[].clk = clock;
  wcc[].d = wcb[].q;
  wcc[].ena = enable.q;
  wcc[].clk = clock;

  if (ddc[22].q) then
    lastxft[].d = H"1FF";
  elsif (ddc[21].q) then
    lastxft[].d = ddc[8..0].q;
  else
    lastxft[].d = lastxft[].q;
  end if;
  lastxft[].ena = enable.q;
  lastxft[].clk = clock;
  lastxft[].prn = _svtinit;
  ddd[22..21].d = ddc[22..21].q;
  ddd[19..0].d = ddc[19..0].q;
  if (wca.eq[6]) then
    ddd[20].d = ddc[20].q &
      !(unique & (dda[8..0].q==lastxft[].q));
  else
    ddd[20].d = ddc[20].q;
  end if;
  ddd[].ena = enable.q;
  ddd[].clk = clock;
  dvd.d = dvc.q;
  dvd.clrn = _svtinit;
  dvd.ena = enable.q;
  dvd.clk = clock;
  bfd[].d = bfc[].q;
  bfd[].ena = enable.q;
  bfd[].clk = clock;
  adder.dataa[] = d2cc[].q;
  adder.datab[] = bfc[].q;
  negdiff[] = -adder.result[];
  if ((adder.result[9]) & (adder.result[8..0]!=0)) then
    diffd[9].d = VCC;
    diffd[8..0].d = negdiff[8..0];
  else
    diffd[9].d = GND;
    diffd[8..0].d = adder.result[8..0];
  end if;
  diffd[].ena = enable.q;
  diffd[].clk = clock;
  wcd[].d = wcc[].q;
  wcd[].ena = enable.q;
  wcd[].clk = clock;

  goodtrack = ddd[21].q & (wcd[].q==6) & ddf[20].q;
  ntrackse.cnt_en = goodtrack & enable.q;
  ntrackse.sclr = dde[22].q & enable.q;
  ntrackse.aclr = !_svtinit;
  ntrackse.clock = clock;
  if (wcd[].q==1) then
    dde[22..10].d = ddd[22..10].q;
    dde[9..0].d = diffd[].q;
  else
    dde[].d = ddd[].q;
  end if;
  dde[].ena = enable.q;
  dde[].clk = clock;
  dve.d = dvd.q;
  dve.clrn = _svtinit;
  dve.ena = enable.q;
  dve.clk = clock;

  ntracksf[].d = ntrackse.q[];
  ntracksf[].ena = enable.q;
  ntracksf[].clk = clock;
  ntracksf[].clrn = _svtinit;
  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;

  ddg[22..19].d = ddf[22..19].q;
  ddg[17..0].d = ddf[17..0].q;
  if (rejectall) then
    ddg[18].d = GND;
  elsif (acceptall) then
    ddg[18].d = VCC;
  elsif (ctrl[25]) then
    ddg[18].d = prescale.eq[0];
  elsif (ddf[22].q) then
    if (ddf[18].q) then
      ddg[18].d = (ntracksf[].q>=ntkcut[]);
    else
      ddg[18].d = acceptothers;
    end if;
  else
    ddg[18].d = ddf[18].q;
  end if;
  ddg[].ena = enable.q;
  ddg[].clk = clock;
  dvg.d = dvf.q;
  dvg.clrn = _svtinit;
  dvg.ena = enable.q;
  dvg.clk = clock;

  prescale.clock = clock;
  prescale.cnt_en = enable.q & ddg[22].q & dvg.q;
  prescale.aclr = !_svtinit;
  prescale.sclr = (prescale.q[]==ctrl[15..0]) & ctrl[16] & dvg.q;
  if (ctrl[30]) then
    ddh[22..20].d = ddg[22..20].q;
    ddh[19..0].d = buf0time.q[];
    dvh.d = dvg.q & ddg[22].q & !ddg[20].q & !ddg[19].q;
  else
    ddh[].d = ddg[].q;
    dvh.d = dvg.q;
  end if;
  ddh[].ena = enable.q;
  ddh[].clk = clock;
  dvh.clrn = _svtinit;
  dvh.ena = enable.q;
  dvh.clk = clock;

  ddi[].d = ddh[].q;
  ddi[].ena = enable.q;
  ddi[].clk = clock;
  dvi.d = dvh.q & enable.q;
  dvi.clrn = _svtinit;
  dvi.ena = VCC;
  dvi.clk = clock;

  ffout[].d = ddi[].q;
  ffout[].clk = clock;
  dout[] = ffout[].q;
  dvout.d = dvi.q; -- & enable.q;
  dvout.clk = !clock;
  _dsout = !lcell(dvout.q & clock);

  framaddr[20..15] = whichblock[].q;
  framaddr[14..0] = addr[16..2];
  framdata[] = fdtri[];
  fdtri[] = fdout[].out;
  fdout[].in = data[15..0];
  fdout[].oe = vme_framwrite;
  _framoe = !vme_framread;
  _framwe = !vme_framwrite;
  _framrp = VCC;
  _framwp = VCC;

  -- drive unimplemented outputs
  debugclk = clock;
  _svterror = VCC;
  _cdferror = VCC;
  runled = GND;
  errorled = GND;
end;
