TITLE "hmfire"; % accepts strip and adc sequence from hmaim and constructs cluster centroids % FUNCTION lpm_ff (data[LPM_WIDTH-1..0], clock, enable, sclr, sset, sload, aclr, aset, aload) WITH (LPM_WIDTH, LPM_AVALUE, LPM_SVALUE, LPM_FFTYPE) RETURNS (q[LPM_WIDTH-1..0]); FUNCTION lpm_counter (data[LPM_WIDTH-1..0], clock, clk_en, cnt_en, updown, aclr, aset, aconst, aload, sclr, sset, sconst, sload) WITH (LPM_WIDTH, LPM_DIRECTION, LPM_MODULUS, LPM_AVALUE, LPM_SVALUE, CARRY_CNT_EN, LABWIDE_SCLR) RETURNS (q[LPM_WIDTH-1..0], eq[15..0]); FUNCTION lpm_mux (data[LPM_SIZE-1..0][LPM_WIDTH-1..0], sel[LPM_WIDTHS-1..0], clock, aclr) WITH (LPM_WIDTH, LPM_SIZE, LPM_WIDTHS, LPM_PIPELINE) RETURNS (result[LPM_WIDTH-1..0]); FUNCTION lpm_add_sub (cin, dataa[LPM_WIDTH-1..0], datab[LPM_WIDTH-1..0], add_sub, clock, aclr) WITH (LPM_WIDTH, LPM_REPRESENTATION, LPM_DIRECTION, ONE_INPUT_IS_CONSTANT, LPM_PIPELINE, MAXIMIZE_SPEED) RETURNS (result[LPM_WIDTH-1..0], cout, overflow); SUBDESIGN hmfire ( clock :INPUT; % global clock % adc[6..0] :INPUT; % input adc value % strip[9..0] :INPUT; % input strip number % validin :INPUT; % input valid % enable :INPUT; % global pipeline enable % init :INPUT; % global pipeline clear % clusterchargecut[10..0] :INPUT; % threshold charge total for a valid cluster % clusterchargebig[10..0] :INPUT; % charge above which we flag LC % cramdata[5..0] :INPUT; % input cluster lookup table data % cramaddress[14..0] :OUTPUT; % output address to cluster lookup table% cramclock :OUTPUT; % output clock to cluster lookup table % hit[14..0] :OUTPUT; % output cluster centroid % validout :OUTPUT; % output valid % ) VARIABLE bvalid,cvalid,evalid,fvalid,mvalid,ovalid :lpm_ff WITH (LPM_WIDTH=1); badc,cadc,eadc :lpm_ff WITH (LPM_WIDTH=7); bstrip,cstrip,estrip,fstrip,mstrip :lpm_ff WITH (LPM_WIDTH=10); badjstrip :lpm_ff WITH (LPM_WIDTH=10); chargesummer : lpm_add_sub WITH (LPM_DIRECTION="ADD",LPM_REPRESENTATION="UNSIGNED",LPM_WIDTH=11); cclustercharge :lpm_ff WITH (LPM_WIDTH=11); cadjacent,eadjacent :lpm_ff WITH (LPM_WIDTH=1); cadjacentstripcount :lpm_counter WITH (LPM_WIDTH=3,LPM_MODULUS=6); egoodclustercharge,fgoodclustercharge,mgoodclustercharge :lpm_ff WITH (LPM_WIDTH=1); ebigcharge: lpm_ff WITH (LPM_WIDTH=1); eadjacentstripcount,fadjacentstripcount,madjacentstripcount :lpm_ff WITH (LPM_WIDTH=3); elongcluster,flongcluster,mlongcluster,olongcluster :lpm_ff WITH (LPM_WIDTH=1); fendofcluster,mendofcluster :lpm_ff WITH (LPM_WIDTH=1); clookup,elookup,flookup :lpm_ff WITH (LPM_WIDTH=5); shortlongmux :lpm_mux WITH (LPM_WIDTH=7, LPM_SIZE=2, LPM_WIDTHS=1); mlongoffset : lpm_ff WITH (LPM_WIDTH=3); mshortoffset :lpm_ff WITH (LPM_WIDTH=6); offsetadder :lpm_add_sub WITH (LPM_REPRESENTATION="UNSIGNED",LPM_WIDTH=14); ocentroid :lpm_ff WITH (LPM_WIDTH=14); BEGIN % stage b % % compute/latch "adjstrip": what adjacent strip number should be % badjstrip.clock = clock; badjstrip.enable = enable; badjstrip.data[] = strip[] + 1; badjstrip.sclr = !validin; badjstrip.aclr = init; % propagate (valid, strip, adc) % bvalid.clock = clock; bvalid.enable = enable; bvalid.data[] = validin; bvalid.aclr = init; bstrip.clock = clock; bstrip.enable = enable; bstrip.data[] = strip[]; bstrip.aclr = init; badc.clock = clock; badc.enable = enable; badc.data[] = adc[]; badc.sclr = !validin; badc.aclr = init; % stage c % % latch "adjacent" flag: is next strip is adjacent to current strip % cadjacent.clock = clock; cadjacent.enable = enable; cadjacent.data[] = (strip[] == badjstrip.q[]); cadjacent.sclr = !bvalid.q[]; cadjacent.aclr = init; % accumulate/latch "adjacentstripcount": running count of adjacent strips; % % adjacentstripcount is 0 for first strip and ((N-1) mod 6) for last strip % % in N-strip cluster % cadjacentstripcount.clock = clock; cadjacentstripcount.clk_en = enable; cadjacentstripcount.sclr = !cadjacent.q[]; cadjacentstripcount.aclr = init; % compute/latch "clustercharge": running sum of charges on adjacent strips % chargesummer.dataa[6..0] = badc.q[]; chargesummer.dataa[10..7] = GND; chargesummer.datab[] = % note special case for length mod 6 == 0 % cclustercharge.q[] & cadjacent.q[] & !cadjacentstripcount.eq[5]; cclustercharge.clock = clock; cclustercharge.enable = enable; cclustercharge.data[] = chargesummer.result[]; cclustercharge.sclr = !bvalid.q[]; cclustercharge.aclr = init; % propagate (valid, strip, adc) % cvalid.clock = clock; cvalid.enable = enable; cvalid.data[] = bvalid.q[]; cvalid.aclr = init; cstrip.clock = clock; cstrip.enable = enable; cstrip.data[] = bstrip.q[]; cstrip.aclr = init; cadc.clock = clock; cadc.enable = enable; cadc.data[] = badc.q[]; cadc.aclr = init; % stage e % % latch "goodclustercharge" flag: is cluster charge above threshold? % egoodclustercharge.clock = clock; egoodclustercharge.enable = enable; egoodclustercharge.data[] = (cclustercharge.q[] >= clusterchargecut[]); egoodclustercharge.sclr = !cvalid.q[]; egoodclustercharge.aclr = init; % latch "bigcharge" flag: is cluster charge unusually large? % ebigcharge.clock = clock; ebigcharge.enable = enable; ebigcharge.data[] = (cclustercharge.q[] > clusterchargebig[]); % latch "longcluster" flag: is cluster more than 3 strips long? % % note that we do not want longcluster to clear when % % adjacentstripcount wraps around to 0 % elongcluster.clock = clock; elongcluster.enable = enable; elongcluster.data[] = ((cadjacentstripcount.q[] > 2) # (elongcluster.q[])); elongcluster.sclr = !(cvalid.q[] & eadjacent.q[]); elongcluster.aclr = init; % propagate (valid, strip, adc, adjacent, adjacentstripcount) % evalid.clock = clock; evalid.enable = enable; evalid.data[] = cvalid.q[]; evalid.aclr = init; estrip.clock = clock; estrip.enable = enable; estrip.data[] = cstrip.q[]; estrip.aclr = init; eadc.clock = clock; eadc.enable = enable; eadc.data[] = cadc.q[]; eadc.aclr = init; eadjacent.clock = clock; eadjacent.enable = enable; eadjacent.data[] = cadjacent.q[]; eadjacent.aclr = init; eadjacentstripcount.clock = clock; eadjacentstripcount.enable = enable; eadjacentstripcount.data[] = cadjacentstripcount.q[]; eadjacentstripcount.sclr = !cvalid.q[]; eadjacentstripcount.aclr = init; % stage f % fendofcluster.clock = clock; fendofcluster.enable = enable; fendofcluster.data[] = (cadjacentstripcount.q[] == 0) # (!cvalid.q[]); fendofcluster.sclr = !evalid.q[]; fendofcluster.aclr = init; flongcluster.clock = clock; flongcluster.enable = enable; flongcluster.data[] = elongcluster.q[] # ebigcharge.q[]; flongcluster.aclr = init; fgoodclustercharge.clock = clock; fgoodclustercharge.enable = enable; fgoodclustercharge.data[] = egoodclustercharge.q[]; fgoodclustercharge.aclr = init; fadjacentstripcount.clock = clock; fadjacentstripcount.enable = enable; fadjacentstripcount.data[] = eadjacentstripcount.q[]; fadjacentstripcount.aclr = init; fstrip.clock = clock; fstrip.enable = enable; fstrip.data[] = estrip.q[]; fstrip.aclr = init; fvalid.clock = clock; fvalid.enable = enable; fvalid.data[] = evalid.q[]; fvalid.aclr = init; % cluster lookup % -- this is really part of stage C clookup.clock = clock; clookup.enable = enable; clookup.data[] = badc.q[6..2]; clookup.sclr = !cadjacent.q[]; clookup.aclr = init; -- this is really part of stage E elookup.clock = clock; elookup.enable = enable; elookup.data[] = cadc.q[6..2]; elookup.aclr = init; -- this is really part of stage F flookup.clock = clock; flookup.enable = enable; flookup.data[] = eadc.q[6..2]; flookup.sclr = !eadjacent.q[]; flookup.aclr = init; % stage m % mlongoffset.clock = clock; mlongoffset.enable = enable; mlongoffset.data[2..0] = fadjacentstripcount.q[]; mlongoffset.aclr = init; mshortoffset.clock = clock; mshortoffset.enable = enable; mshortoffset.data[5..0] = cramdata[5..0]; mshortoffset.aclr = init; mgoodclustercharge.clock = clock; mgoodclustercharge.enable = enable; mgoodclustercharge.data[] = fgoodclustercharge.q[]; mgoodclustercharge.aclr = init; madjacentstripcount.clock = clock; madjacentstripcount.enable = enable; madjacentstripcount.data[] = fadjacentstripcount.q[]; madjacentstripcount.aclr = init; mendofcluster.clock = clock; mendofcluster.enable = enable; mendofcluster.data[] = fendofcluster.q[]; mendofcluster.aclr = init; mlongcluster.clock = clock; mlongcluster.enable = enable; mlongcluster.data[] = flongcluster.q[]; mlongcluster.aclr = init; mstrip.clock = clock; mstrip.enable = enable; mstrip.data[] = fstrip.q[]; mstrip.aclr = init; mvalid.clock = clock; mvalid.enable = enable; mvalid.data[] = fvalid.q[]; mvalid.aclr = init; % stage o % shortlongmux.data[0][6] = mshortoffset.q[5]; shortlongmux.data[0][5] = GND; shortlongmux.data[0][4..0] = mshortoffset.q[4..0]; shortlongmux.data[1][6] = GND; shortlongmux.data[1][5..3] = mlongoffset.q[2..0]; shortlongmux.data[1][2..0] = GND; shortlongmux.sel[] = mlongcluster.q[]; offsetadder.add_sub = shortlongmux.result[6]; offsetadder.cin = !shortlongmux.result[6]; offsetadder.dataa[13..4] = mstrip.q[]; offsetadder.dataa[3..0] = B"1000"; offsetadder.datab[13..6] = GND; offsetadder.datab[5..0] = shortlongmux.result[5..0]; ocentroid.clock = clock; ocentroid.enable = enable & !((madjacentstripcount.q[] == 2) & (!mlongcluster.q[]) & (mendofcluster.q[]) ); ocentroid.data[] = offsetadder.result[]; ocentroid.aclr = init; olongcluster.clock = clock; olongcluster.enable = enable; olongcluster.data[] = mlongcluster.q[]; olongcluster.aclr = init; % always flag output invalid while enable is low % ovalid.clock = clock; ovalid.enable = VCC; ovalid.data[] = mvalid.q[] & mendofcluster.q[] & mgoodclustercharge.q[]; ovalid.sclr = !enable; ovalid.aclr = init; % outputs % cramaddress[14..10] = clookup.q[]; cramaddress[9..5] = elookup.q[]; cramaddress[4..0] = flookup.q[]; cramclock = clock; hit[14] = olongcluster.q[]; hit[13..0] = ocentroid.q[]; validout = ovalid.q[] & !init; END;