TITLE "HITMAN"; include "lpm_counter.inc"; include "lpm_mux.inc"; include "lpm_ff.inc"; FUNCTION hmready(channel[7..0],adc[7..0],clock,dav,grterror,disable,init,timeout, chipid[7..0][4..0],toomanyclust,nchipexpect[3..0]) RETURNS (endeventword[14..0],endevent,endeventstate,outdata[17..0], validout,idlestate,headerstate,runningstate); FUNCTION hmaim(strip[9..0],adc[7..0],clock,validin,init, vmepedramin[6..0],pedramaddress[9..0],pedramclock,pedramwrite, vmethresholdin[6..0],thresholdaddress[2..0],thresholdclock, thresholdwrite) RETURNS (vmepedramout[6..0],vmethresholdout[6..0], stripout[9..0],adcout[6..0],validout,enableout); FUNCTION hmfire(clock,adc[6..0],strip[9..0],validin,enable,init, clusterchargecut[10..0], clusterchargebig[10..0], cramdata[5..0]) RETURNS (cramaddress[14..0],cramclock,hit[14..0], validout); FUNCTION hmvmedecode(streamid[3..0],address[24..0],vmewrite, hf_freeze,hf_init,hf_load,hf_test,hf_as) RETURNS (vmefifowrite, vmecramread, vmecramwrite, vmecramaddrhighbit, vmepedramread, vmepedramwrite, vmespyread, vmespywrite, ppspyread, ppspywrite, vmespycounterread, vmespycounterreset, vmechipidread[7..0], vmechipidwrite[7..0], vmethresholdread, vmethresholdwrite, vmechargecutread, vmechargecutwrite, vmechargebigread, vmechargebigwrite, vmemaxnclustread, vmemaxnclustwrite, vmenchipexpectread, vmenchipexpectwrite); FUNCTION vmechipidbus(vmedata[5..0],vmeclock, vmechipidread[7..0],vmechipidwrite[7..0]) RETURNS (vmedataout[15..0],chipid[7..0][4..0]); SUBDESIGN hitman ( % inputs from DAD chip % dadchannel[7..0] :INPUT; dadadc[7..0] :INPUT; dadclock :INPUT; dav :INPUT; grterror :INPUT; % inputs from control chip, including vme bus % streamid[3..0] :INPUT; hf_freeze :INPUT; hf_init :INPUT; hf_load :INPUT; hf_test :INPUT; hf_spare :INPUT; vme_as :INPUT; vmespare :INPUT; testclock :INPUT; vmeclock :INPUT; vmewrite :INPUT; vmeaddress[24..0] :INPUT; vmedata[17..0] :BIDIR; hm_spare :OUTPUT; % ISPY interface % spyadc[7..0] :BIDIR; spychannel[7..0] :BIDIR; spyspare[1..0] :BIDIR; spyaddress[15..0] :OUTPUT; spyoe :OUTPUT; spycs :OUTPUT; spywrite :OUTPUT; spyclock :OUTPUT; % CRAM interface % cramdata[7..0] :BIDIR; cramaddress[16..0] :OUTPUT; cramoe :OUTPUT; cramcs :OUTPUT; cramwrite :OUTPUT; % HITLIST interface % fifodata[17..0] :OUTPUT; fifoclock :OUTPUT; fifowrite :OUTPUT; fifo_reset :OUTPUT; ) VARIABLE ready :hmready; aim :hmaim; fire :hmfire; vmechipid :vmechipidbus; % local nodes for DAD inputs % dadchannelnode[7..0] :NODE; dadadcnode[7..0] :NODE; davnode :NODE; grterrornode :NODE; % registers for dad inputs % dadff[17..0] :DFFE; davgg,davhh :DFFE; fireenable : NODE; % internal input nodes for pp % ppchannel[7..0], ppadc[7..0], ppspare[1..0], theclock, ppclock, qqclock :NODE; % is svxdecode state machine in an "idle" state? % idlestate : NODE; % node for this stream's test mode % hf_test_node : NODE; % is svxdecode state machine in the "header" state? % headerstate : NODE; runningstate : node; % internal nodes for PEDRAM % pedramdata[6..0], pedramaddress[9..0], pedramclock, pedramwrite :NODE; % internal nodes for adc threshold ram % threshold[6..0], thresholdaddress[2..0], thresholdclock, thresholdwrite :NODE; % multiplexes hits with end-of event word % eehitmux :lpm_mux WITH (LPM_WIDTH=15, LPM_SIZE=2, LPM_WIDTHS=1); % multiplexes vme data with ENGINE hits % vmehitmux :lpm_mux WITH (LPM_WIDTH=19, LPM_SIZE=2, LPM_WIDTHS=1); % multiplexes vme data with fire data for cram access % vmefiremux :lpm_mux WITH (LPM_WIDTH=17, LPM_SIZE=2, LPM_WIDTHS=1); % counter for addressing ISPY % spycounter :lpm_counter WITH (LPM_WIDTH=16, LPM_DIRECTION="UP", LPM_MODULUS=2^16); spyoverflow : DFFE; % count number of clusters written per event % clustcounter :lpm_counter WITH (LPM_WIDTH=8, LPM_DIRECTION="DOWN", LPM_MODULUS=2^8); % cluster overflow error signal % tmc : NODE; % register to hold max # clusters/stream to output % maxnclust :lpm_ff with (lpm_width=8); % register to hold "stream disable" flag % streamdisable : lpm_ff with (lpm_width=1); % register to hold # axial chip IDs to expect % nchipexpect : lpm_ff with (lpm_width=4); % Register to latch data-vs-endevent flag % readyeeff :lpm_ff with (lpm_width=1); % charge cut register % chargecut :lpm_ff WITH (LPM_WIDTH=11); chargebig : lpm_ff WITH (LPM_WIDTH=11); % decode vme address % vmedecoder :hmvmedecode; % bus switches % vmenchipexpectwrite, vmenchipexpectread, vmemaxnclustwrite, vmemaxnclustread, vmespycounterreset, vmefifowrite,vmecramread,vmecramwrite,vmecramaddrhighbit, vmepedramread,vmepedramwrite,vmespyread,vmespywrite,ppspyread, ppspywrite,vmespycounterread,vmechipidread[7..0], vmechipidwrite[7..0],vmethresholdread,vmethresholdwrite, vmechargecutread,vmechargecutwrite, vmechargebigread, vmechargebigwrite:NODE; % tri state buses % spyadcvmetri[7..0] :TRI; spychannelvmetri[7..0] :TRI; spysparevmetri[1..0] : TRI; vmespyadctri[7..0] :TRI; vmespychanneltri[7..0] :TRI; vmespysparetri[1..0] : TRI; ppspyadctri[7..0] :TRI; ppspychanneltri[7..0] :TRI; ppspysparetri[1..0] : TRI; spycountervmetri[17..0] :TRI; pedramvmetri[17..0] :TRI; cramvmetri[17..0] :TRI; vmecramtri[7..0]:TRI; thresholdvmetri[17..0]:TRI; chargecutvmetri[17..0]:TRI; chargebigvmetri[17..0]:TRI; maxnclustvmetri[17..0] :TRI; nchipexpectvmetri[17..0] : TRI; % tri state nodes for BIDIR pins % spyadctri[7..0],spychanneltri[7..0],spysparetri[1..0], cramdatatri[7..0], vmedatatri[17..0] :TRI_STATE_NODE; % register to hold cram address % cramaddrff: lpm_ff WITH (LPM_WIDTH=17); % override freeze when in ispy test mode % freezeff1, freezeff2 : DFF; freezeff3 : DFF; -- this is nonsense just to perturb compilation do_freeze : NODE; % synchronize hf_init signal to data clock % hf_init_node : NODE; hf_init_ff1, hf_init_ff2 : DFF; -- register for FIFO output fifodataff[17..0] : DFF; fifowriteff : DFF; -- timeout mechanism timeout : lpm_counter with (lpm_width=11); BEGIN -- synchronize hf_init signal hf_init_ff1.d = hf_init; hf_init_ff1.clk = ppclock; hf_init_ff2.d = hf_init_ff1.q; hf_init_ff2.clk = ppclock; hf_init_node = hf_init_ff2.q # (hf_load & hf_init); -- synchronize hf_freeze signal freezeff1.d = hf_freeze; freezeff1.clk = ppclock; freezeff2.d = freezeff1.q; freezeff2.clk = ppclock; freezeff3.d = freezeff2.q; freezeff3.clk = !ppclock; do_freeze = freezeff3.q; -- latch DAD inputs dadff[17].d = dav; dadff[16].d = grterror; dadff[15..8].d = dadchannel[]; dadff[7..0].d = dadadc[]; dadff[].clk = dadclock; davgg.d = dadff[17].q; davgg.clk = dadclock; davhh.d = davgg.q; davhh.clk = dadclock; dadchannelnode[] = dadff[15..8].q; dadadcnode[] = dadff[7..0].q; davnode = dadff[17].q; grterrornode = dadff[16].q; %BIDIR pin connections % vmedata[] = vmedatatri[]; spychannel[] = spychanneltri[]; spyadc[] = spyadctri[]; spyspare[] = spysparetri[]; cramdata[] = cramdatatri[]; % preprocessor inputs % ready.clock = ppclock; ready.channel[] = ppchannel[]; ready.adc[] = ppadc[]; ready.dav = ppspare[1]; ready.grterror = ppspare[0]; ready.init = hf_init_node; ready.disable = hf_load; ready.chipid[][] = vmechipid.chipid[][]; ready.toomanyclust = tmc; ready.nchipexpect[] = nchipexpect.q[]; aim.vmepedramin[] = pedramdata[]; aim.pedramaddress[] = pedramaddress[]; aim.pedramclock = pedramclock; aim.pedramwrite = pedramwrite; aim.vmethresholdin[] = threshold[]; aim.thresholdaddress[] = thresholdaddress[]; aim.thresholdclock = thresholdclock; aim.thresholdwrite = thresholdwrite; aim.strip[] = ready.outdata[17..8]; aim.adc[] = ready.outdata[7..0]; aim.clock = ppclock; aim.validin = ready.validout; aim.init = hf_init_node; vmechipid.vmedata[] = vmedata[5..0]; vmechipid.vmechipidwrite[] = vmechipidwrite[]; vmechipid.vmechipidread[] = vmechipidread[]; vmechipid.vmeclock = vmeclock; vmedatatri[15..0] = vmechipid.vmedataout[]; -- multiplex spy data with dad data IF (ppspyread) THEN ppadc[] = spyadc[]; ppchannel[] = spychannel[]; ppspare[] = spyspare[1..0] & !(spycounter.q[15..2]==0); ELSE ppadc[] = dadadcnode[]; ppchannel[] = dadchannelnode[]; ppspare[0] = grterrornode; ppspare[1] = davnode; END IF; IF (!hf_load & !hf_test_node) THEN theclock = dadclock; ELSIF (hf_load) THEN theclock = vme_as; ELSIF (hf_test_node) THEN theclock = testclock; END IF; ppclock = global(theclock); qqclock = ppclock $ ppspyread; % ISPY interface % % multiplex vme and pp for ISPY clock and address % spycounter.clock = qqclock; spycounter.cnt_en = (!idlestate & !do_freeze) # (ppspyread & (ppspare[]!=1)); spycounter.aclr = vmespycounterreset; spycounter.sclr = ppspyread & (ppspare[]==1) & ppchannel[7]; spyoverflow.clk = qqclock; spyoverflow.d = spyoverflow.q # spycounter.cout; spyoverflow.clrn = !vmespycounterreset; IF (hf_load # do_freeze) THEN spyaddress[15..0] = vmeaddress[15..0]; spyclock = (vmespyread # vmespywrite) & vmeclock; spycs = !vmespyread & !vmespywrite; ELSE spyaddress[15..0] = spycounter.q[15..0]; spyclock = !qqclock; spycs = idlestate & !ppspyread; END IF; spywrite = !(vmespywrite # ppspywrite); spyoe = !(ppspyread # vmespyread); spyadcvmetri[].in = spyadc[]; spyadcvmetri[].oe = vmespyread; vmedatatri[7..0] = spyadcvmetri[].out; spychannelvmetri[].in = spychannel[]; spychannelvmetri[].oe = vmespyread; vmedatatri[15..8] = spychannelvmetri[].out; spysparevmetri[].in = spyspare[]; spysparevmetri[].oe = vmespyread; vmedatatri[17..16] = spysparevmetri[].out; vmespyadctri[].in = vmedata[7..0]; vmespyadctri[].oe = vmespywrite; spyadctri[] = vmespyadctri[].out; vmespychanneltri[].in = vmedata[15..8]; vmespychanneltri[].oe = vmespywrite; spychanneltri[] = vmespychanneltri[].out; vmespysparetri[].in = vmedata[17..16]; vmespysparetri[].oe = vmespywrite; spysparetri[] = vmespysparetri[].out; ppspyadctri[].in = dadadcnode[7..0]; ppspyadctri[].oe = ppspywrite; spyadctri[] = ppspyadctri[].out; ppspychanneltri[].in = dadchannelnode[7..0]; ppspychanneltri[].oe = ppspywrite; spychanneltri[] = ppspychanneltri[].out; ppspysparetri[0].in = grterrornode; ppspysparetri[1].in = davnode; ppspysparetri[].oe = ppspywrite; spysparetri[] = ppspysparetri[].out; spycountervmetri[15..0].in = spycounter.q[]; spycountervmetri[16].in = spyoverflow.q; spycountervmetri[17].in = do_freeze; spycountervmetri[].oe = vmespycounterread; vmedatatri[17..0] = spycountervmetri[17..0].out; -- hmaim pedram interface IF (hf_load) THEN pedramaddress[] = vmeaddress[9..0]; pedramclock = vmeclock & (vmepedramread # vmepedramwrite); ELSE pedramaddress[] = ready.outdata[17..8]; pedramclock = ppclock; END IF; pedramwrite = vmepedramwrite; pedramdata[] = vmedata[6..0]; pedramvmetri[6..0].in = aim.vmepedramout[6..0]; pedramvmetri[17..7].in = GND; pedramvmetri[].oe = vmepedramread; vmedatatri[17..0] = pedramvmetri[17..0].out; -- hmaim adc threshold interface IF (hf_load) THEN thresholdclock = vmeclock & (vmethresholdread # vmethresholdwrite); thresholdaddress[] = vmeaddress[2..0]; ELSE thresholdclock = ppclock; thresholdaddress[] = ready.outdata[17..15]; END IF; thresholdwrite = vmethresholdwrite; threshold[] = vmedata[6..0]; thresholdvmetri[6..0].in = aim.vmethresholdout[6..0]; thresholdvmetri[17..7].in = GND; thresholdvmetri[].oe = vmethresholdread; vmedatatri[17..0] = thresholdvmetri[17..0].out; -- write to charge cut register over VME chargecut.clock = vmeclock & vmechargecutwrite; chargecut.data[] = vmedata[10..0]; -- read charge cut register over VME chargecutvmetri[10..0].in = chargecut.q[]; chargecutvmetri[17..11].in = GND; chargecutvmetri[].oe = vmechargecutread; vmedatatri[17..0] = chargecutvmetri[17..0].out; -- write to "big charge" register over VME chargebig.clock = vmeclock & vmechargebigwrite; chargebig.data[] = vmedata[10..0]; -- read "big charge" register over VME chargebigvmetri[10..0].in = chargebig.q[]; chargebigvmetri[17..11].in = GND; chargebigvmetri[].oe = vmechargebigread; vmedatatri[17..0] = chargebigvmetri[17..0].out; % cluster fire inputs % fire.clock = ppclock; fireenable = ready.endeventstate # aim.enableout; fire.enable = fireenable; fire.adc[] = aim.adcout[]; fire.strip[] = aim.stripout[]; fire.validin = aim.validout; fire.init = hf_init_node; fire.clusterchargecut[] = chargecut.q[]; fire.clusterchargebig[] = chargebig.q[]; fire.cramdata[] = cramdata[5..0]; % CRAM interface with vme and fire % vmefiremux.data[0][14..0] = fire.cramaddress[14..0]; vmefiremux.data[0][16..15] = GND; vmefiremux.data[1][15..0] = vmeaddress[15..0]; vmefiremux.data[1][16] = vmecramaddrhighbit; vmefiremux.sel[] = hf_load; cramaddrff.data[] = vmefiremux.result[16..0]; cramaddress[16..0] = cramaddrff.q[]; cramaddrff.clock = ppclock; cramaddrff.enable = fireenable # hf_load; cramoe = hf_load & !vmecramread; cramwrite = !(vmecramwrite&vmeclock); cramcs = hf_load & !vmecramread & !vmecramwrite; cramvmetri[7..0].in = cramdata[7..0]; cramvmetri[17..8].in = GND; cramvmetri[].oe = vmecramread; vmedatatri[17..0] = cramvmetri[17..0].out; vmecramtri[].in = vmedata[7..0]; vmecramtri[].oe = vmecramwrite; cramdatatri[] = vmecramtri[].out; % multiplex end-of-event word (from pp) with hits (from fire) to produce final output to HITLISTs % readyeeff.data[0] = ready.endevent # (streamdisable.q[0] & !hf_load); readyeeff.clock = ppclock; readyeeff.aclr = hf_init_node; eehitmux.data[0][14..0] = fire.hit[]; eehitmux.data[1][14..0] = ready.endeventword[]; eehitmux.sel[] = readyeeff.q[0]; -- FIFO interface -- multiplex vme hits with HITMAN hits vmehitmux.data[0][14..0] = eehitmux.result[]; vmehitmux.data[0][15] = readyeeff.q[0]; vmehitmux.data[0][16] = tmc; vmehitmux.data[0][17] = GND; vmehitmux.data[0][18] = !ppclock; vmehitmux.data[1][17..0] = vmedata[17..0]; vmehitmux.data[1][18] = vmeclock & vmefifowrite; vmehitmux.sel[] = hf_load; fifodataff[17..0].d = vmehitmux.result[17..0]; fifoclock = vmehitmux.result[18]; fifowriteff.d = !(((vmefifowrite))# ((!hf_load)& ((fire.validout&!tmc)# readyeeff.q[0]))); fifo_reset = !hf_init_node; fifodataff[].clk = ppclock; fifowriteff.clk = ppclock; fifodata[17..0] = fifodataff[17..0].q; fifowrite = fifowriteff.q; -- spare pins hm_spare = runningstate; timeout.sclr = headerstate; timeout.clock = ppclock; ready.timeout = timeout.q[10]; -- nchipexpect: number of expected chip IDs -- includes option to load typical values via broadcast IF (vmedata[5]) THEN IF (streamid[]==0) THEN nchipexpect.data[] = 1; END IF; IF (streamid[]==1) THEN nchipexpect.data[] = 2; END IF; IF (streamid[]==2) THEN nchipexpect.data[] = 4; END IF; IF (streamid[]==3) THEN nchipexpect.data[] = 5; END IF; IF (streamid[]==4) THEN nchipexpect.data[] = 6; END IF; IF (streamid[]==5) THEN nchipexpect.data[] = 1; END IF; IF (streamid[]==6) THEN nchipexpect.data[] = 2; END IF; IF (streamid[]==7) THEN nchipexpect.data[] = 4; END IF; IF (streamid[]==8) THEN nchipexpect.data[] = 5; END IF; IF (streamid[]==9) THEN nchipexpect.data[] = 6; END IF; ELSE nchipexpect.data[] = vmedata[3..0]; END IF; nchipexpect.clock = vmeclock; nchipexpect.enable = vmenchipexpectwrite; nchipexpectvmetri[3..0].in = nchipexpect.q[3..0]; nchipexpectvmetri[17..4].in = GND; nchipexpectvmetri[].oe = vmenchipexpectread; vmedatatri[17..0] = nchipexpectvmetri[17..0].out; -- maxnclust: implement maximum number of output clusters maxnclust.data[7..0] = vmedata[7..0]; maxnclust.clock = vmeclock; maxnclust.enable = vmemaxnclustwrite; maxnclustvmetri[7..0].in = maxnclust.q[7..0]; maxnclustvmetri[15..8].in = clustcounter.q[7..0]; maxnclustvmetri[16].in = tmc; maxnclustvmetri[17].in = streamdisable.q[0]; maxnclustvmetri[].oe = vmemaxnclustread; vmedatatri[17..0] = maxnclustvmetri[17..0].out; clustcounter.clock = ppclock; clustcounter.cnt_en = !hf_load & fire.validout & !tmc; clustcounter.aload = headerstate # hf_init_node; clustcounter.data[] = maxnclust.q[]; tmc = clustcounter.eq[0] & (maxnclust.q[]!=0); streamdisable.data[0] = vmedata[8]; streamdisable.clock = vmeclock; streamdisable.enable = vmemaxnclustwrite; hf_test_node = hf_test; -- idle state (disables spy writing) idlestate = !dadff[17].q & !davgg.q; -- & !davhh.q; -- header state (resets too-many-clusters counter) headerstate = ready.headerstate; runningstate = ready.runningstate; -- vme decoder vmedecoder.streamid[] = streamid[]; vmedecoder.address[] = vmeaddress[]; vmedecoder.vmewrite = vmewrite; vmedecoder.hf_freeze = do_freeze; vmedecoder.hf_load = hf_load; vmedecoder.hf_init = hf_init_node; vmedecoder.hf_test = hf_test_node; vmedecoder.hf_as = vme_as; vmefifowrite = vmedecoder.vmefifowrite; vmecramread = vmedecoder.vmecramread; vmecramwrite = vmedecoder.vmecramwrite; vmecramaddrhighbit = vmedecoder.vmecramaddrhighbit; vmepedramread = vmedecoder.vmepedramread; vmepedramwrite = vmedecoder.vmepedramwrite; vmespyread = vmedecoder.vmespyread; vmespywrite = vmedecoder.vmespywrite; ppspyread = vmedecoder.ppspyread; ppspywrite = vmedecoder.ppspywrite; vmespycounterread = vmedecoder.vmespycounterread; vmechipidread[] = vmedecoder.vmechipidread[]; vmechipidwrite[] = vmedecoder.vmechipidwrite[]; vmethresholdread = vmedecoder.vmethresholdread; vmethresholdwrite = vmedecoder.vmethresholdwrite; vmechargecutread = vmedecoder.vmechargecutread; vmechargecutwrite = vmedecoder.vmechargecutwrite; vmechargebigread = vmedecoder.vmechargebigread; vmechargebigwrite = vmedecoder.vmechargebigwrite; vmemaxnclustwrite = vmedecoder.vmemaxnclustwrite; vmemaxnclustread = vmedecoder.vmemaxnclustread; vmenchipexpectwrite = vmedecoder.vmenchipexpectwrite; vmenchipexpectread = vmedecoder.vmenchipexpectread; vmespycounterreset = vmedecoder.vmespycounterreset; END;