MCA
Complete digital pulse-processing chain (fast trapezoidal trigger, slow trapezoidal energy shaper with pole-zero deconvolution, baseline restorer and energy sampler) delivered as a pre-generated netlist. It is the only one of the three MCA blocks that needs no HLS tool-chain at compile time: the RTL is shipped ready-made in three fixed sizes selected by the Shaping Size property.
Introduction
Principle of Operation
The MCA block is the classic Sci-Compiler pulse-height analysis chain. A single 16-bit ADC stream goes in, an energy word plus a data-valid strobe come out. Internally it is four stages on one clock, one sample per clock:
- Fast trapezoidal trigger — a short trapezoid (
TRIG_K,TRIG_M) whose derivative is compared againstTHRS; the peak of that derivative firesTRIGGER_OUT. - Slow trapezoidal shaper — a long trapezoid (
TRAP_K,TRAP_M) with integrated pole-zero deconvolution (DECONV_M) and an output gain (TRAP_GAIN). - Baseline restorer — a moving average of the shaper output over
$2^{\mathrm{BL_LEN}}$ samples, frozen for
BL_INIBsamples after every trigger. - Energy sampler — samples (shaper − baseline)
SAMPLE_POSsamples after the trigger and raisesENERGY_DV.
What makes this block different from its two siblings
The MCA family in this plugin has three members that do the same job with very different engineering trade-offs. All three are built from the same Vivado/Vitis HLS C sources, but only one of them runs HLS on your machine:
| MCA (this page) | MCA HLS | MCA Short Signal | |
|---|---|---|---|
| internal name | mcahp |
mcahp_test |
MCA_FAST |
| HLS tool-chain needed to compile | no | yes | no |
| RTL origin | pre-generated Vivado HLS 2017.4 netlist, shipped in the plugin | Vitis HLS run per project from psa_trigger.cpp |
pre-generated netlist (MCAFAST.vhd) |
| slow-shaper depth | 512 / 1024 / 2048 (one property) | 128 … 16384 | 512 fixed |
| trigger-shaper depth | 128, fixed | 128 … 16384 | 64 fixed |
| baseline depth | 2048, fixed | 128 … 16384 | 512 fixed |
| threshold width | 32 bit | 32 bit | 16 bit |
time stamping (TIMETAG / TIMESTAMP) |
no | yes | no |
| pile-up rejection | no | no | yes (PUR_MODE, PUR_INIB, PUR) |
trigger inhibit (TR_RESET) |
no | yes | no |
| delayed input monitor | no | DATA_OUT |
INPUT_SIGNAL |
| declared pipeline latency | 13 | 13 | 17 |
Pick this block when you want the standard chain and you do not want a Vitis HLS installation in the build path (it also makes remote/cloud builds and rebuilds on a plain Vivado install deterministic — the netlist is already in the plugin, so two builds of the same project give bit-identical logic).
Pick MCA HLS instead when you need shaping longer than 2048 samples, a trigger trapezoid longer than 128 samples, an independently sized baseline buffer, hardware time stamps, or the trigger-inhibit input.
Pick MCA Short Signal instead when the pulses are short, FPGA area is the constraint, or you need pile-up rejection.
Pin Description
'1'.
x"00000100".
x"0006".
|TRIG_M − TRIG_K|. Same 128-sample ceiling as TRIG_K.
Unconnected it is driven to x"0008".
x"0100" (256).
|TRAP_M − TRAP_K|; make it long enough to cover the charge-collection
spread of the detector. Must stay below Shaping Size.
Unconnected it is driven to x"010A" (266).
M = 256 / (exp(Ts/tau) − 1). 0 disables the deconvolution.
Unconnected it is driven to x"007C80".
0x010000 = ×1.0), 24 bit. Use it to map
the energy range onto the number of spectrum bins you want.
Unconnected it is driven to x"010000".
x"8" (256-sample average).
BL HOLD is high). Must be longer than
the whole trapezoid, otherwise pulse tails pollute the baseline and the
peak position moves with count rate. Unconnected it is driven to x"1000".
x"0108" (264).
e_G2_V). That stage’s
coefficient input has no pin on this symbol and is permanently 0, so the
effect of this pin alone is not determined from the sources. Leave it
unconnected; it then defaults to x"0000".
EXT_TRIGGER_SELECTOR.
GIN_SELECT_V port.
0 selects the internal trigger; the other codes combine it with
EXT_TRIGGER. The exact coding of values above 0 was not established from
the sources shipped with this block.
DATA_IN sample per rising edge.
SAMPLE_POS samples after the trigger, scaled by TRAP_GAIN. Latch it on
ENERGY DV.
ENERGY DV on the canvas). One clock high per
accepted event. Wire it to the DV of a Spectrum or List endpoint.
BL_INIB window after a
trigger). A permanently high BL HOLD means BL_INIB is too long for the
current rate and the baseline has stopped updating.
THRS. Scope
this pin to pick a threshold.
DECONV_M gives a flat top with no undershoot after it.
TRIGGER to place
SAMPLE_POS.
Properties
Set the maximum number of samples supported by the MCA. This will affect the trapezoidal shaper and the baseline restorer
Depth of the slow-shaper and energy-sampler delay memories, and therefore
the largest usable TRAP_K / TRAP_M.
| value | slow shaper / energy sampler | trigger shaper | baseline |
|---|---|---|---|
| 512 | 512 | 128 | 2048 |
| 1024 | 1024 | 128 | 2048 |
| 2048 | 2048 | 128 | 2048 |
Changing it swaps the whole pre-generated netlist (mcahp_512/1024/2048),
so it rebuilds the symbol and re-runs synthesis. Contrary to the property
tooltip it does not change the baseline restorer, which is 2048 words
in every variant, and it does not change the trigger trapezoid, which
is 128 words in every variant.
All MCA blocks in one project must use the same value — the netlist is
always written to pcores/mcahp.vhd.
Default: 2048
Default: 2048
Options: 512 1024 2048
⚙️ Detailed Operation
Where the RTL comes from
CompileHDL does not invoke any synthesis tool. It copies one of three
embedded VHDL files into the project’s pcores/ directory and instantiates the
matching top entity:
| Shaping Size | file written to pcores/mcahp.vhd |
entity instantiated |
|---|---|---|
| 512 | mcahp_512.vhd |
MCAHP_512 |
| 1024 | mcahp_1024.vhd |
MCAHP_1024 |
| 2048 | mcahp_2048.vhd |
MCAHP_2048 |
Each file is RTL emitted by Vivado HLS 2017.4. The generator report is
still embedded in the netlist as a CORE_GENERATION_INFO attribute; for the
2048 variant it reads:
MCAHP_2048,hls_ip_2017_4,{HLS_INPUT_TYPE=cxx, HLS_INPUT_FIXED=1,
HLS_INPUT_PART=xc7k160tfbg676-3, HLS_INPUT_CLOCK=12.500000,
HLS_INPUT_ARCH=pipeline, HLS_SYN_CLOCK=10.402286,
HLS_SYN_LAT=12, HLS_SYN_TPT=1,
HLS_SYN_MEM=9, HLS_SYN_DSP=6, HLS_SYN_FF=2343, HLS_SYN_LUT=2822}
So the core was closed at 12.5 ns (80 MHz) target, 10.4 ns achieved on a Kintex-7 −3, it is fully pipelined at one sample per clock, and it costs roughly 9 BRAM / 6 DSP / 2343 FF / 2822 LUT. Those figures are for the 2048 variant; the 512 and 1024 variants differ only in the depth of two RAMs (see below), so the DSP/FF/LUT cost is essentially the same and only the BRAM count shrinks.
What Shaping Size really changes
The delay memories inside the netlist were read directly from the three files. Only two of them scale:
| delay memory | 512 variant | 1024 variant | 2048 variant |
|---|---|---|---|
slow trapezoid (HLSDPP_trapezio) |
512 | 1024 | 2048 |
energy sampler (HLSDPP_energysamp…) |
512 | 1024 | 2048 |
baseline restorer (HLSDPP_baseline_ribs) |
2048 | 2048 | 2048 |
| fast trigger trapezoid — three RAMs | 128 | 128 | 128 |
input alignment delay (MCAHP_*_delay1…) |
256 | 256 | 256 |
This has three practical consequences that the property text does not mention:
TRAP_KandTRAP_Mmust stay below Shaping Size — they are used as read-pointer offsets into the two scaling RAMs, and an offset larger than the RAM depth aliases onto the wrong sample instead of raising an error.TRIG_KandTRIG_Mmust stay below 128 in every variant. Choosing Shaping Size = 2048 does not buy you a longer trigger trapezoid. If you need one, use MCA HLS.- The baseline ring buffer is always 2048 words, so
BL_LENis usable up to 11 ($2^{11} = 2048$) regardless of Shaping Size — even though the property description claims Shaping Size “will affect the trapezoidal shaper and the baseline restorer”. It does not affect the baseline restorer.
Trapezoidal filter and pole-zero
The slow shaper is the Jordanov–Knoll recursive trapezoid with the deconvolution term folded in:
$$ d^{k}[n] = x[n] - x[n-k] $$ $$ d^{k,m}[n] = d^{k}[n] - d^{k}[n-m] $$ $$ p[n] = p[n-1] + d^{k,m}[n] $$ $$ s[n] = s[n-1] + \bigl(256,p[n] + M,d^{k,m}[n]\bigr) $$
with $k$ = TRAP_K, $m$ = TRAP_M, $M$ = DECONV_M. The rise time of the
trapezoid is $\min(k,m)$ samples and the flat top is $|k-m|$ samples, so the
usual setting is TRAP_M = TRAP_K + flat-top (the default pair
0x0100 / 0x010A is a 256-sample rise with a 10-sample flat top).
DECONV_M is a fixed-point coefficient scaled by 256, which is why the
classic pole-zero formula carries that factor:
$$ M = \frac{256}{e^{T_s/\tau} - 1} $$
where $T_s$ is the sample period and $\tau$ the preamplifier decay constant.
Set DECONV_M to 0 to disable pole-zero cancellation.
TRAP_GAIN is a Q8.16 multiplier applied to the shaper output
(0x010000 = ×1.0).
Baseline restorer and energy sampling
The baseline is the moving average of the shaper output over $2^{\rm BL_LEN}$
samples. On every trigger the average is frozen and BASELINE_HOLD goes high
for BL_INIB samples, so BL_INIB must cover the whole pulse
(rise + flat top + fall) or the tail of the pulse will be averaged into the
baseline and the spectrum will drift with rate.
SAMPLE_POS is the distance, in samples, from the trigger to the point where
(shaper − baseline) is captured. It should land in the middle of the flat
top:
$$ \mathrm{SAMPLE_POS} \approx \mathrm{TRAP_K} + \frac{\mathrm{TRAP_M} - \mathrm{TRAP_K}}{2} $$
Configure / run
RUN_CFG is the master enable. With RUN_CFG = 0 the chain is held in its
configuration state: accumulators, delay lines and pointers are cleared and no
energy is produced. Bring all the parameter pins to their final values first,
then raise RUN_CFG. The HLS cores contain a pre-roll counter that discards
the first passes through the delay lines after RUN_CFG rises, so the first
valid energies appear only after the delay lines have filled — allow a few
thousand samples of dead time after every RUN_CFG 0→1 edge before trusting
the spectrum.
Software interface
This block declares no memory-mapped registers: CompileMMC and
CompileSDK are empty. Everything is controlled through pins. The usual
pattern is to drive the parameter pins from Register blocks (so the SciSDK
can write them) and to feed ENERGY / ENERGY_DV into a Spectrum,
List or Oscilloscope endpoint, which is where the SciSDK-visible
registers actually live.
Realistic wiring
ADC ─► DATA_IN ENERGY ───► Spectrum / List endpoint
POLARITY ENERGY DV ─┘
OFFSET TRIGGER ───► counter / coincidence logic
Reg ─► THRS TRIG_K TRIG_M BL HOLD ─► (diagnostics)
Reg ─► TRAP_K TRAP_M DECONV_M TRAP_GAIN
Reg ─► BL_LEN BL_INIB SAMPLE_POS
Reg ─► RUN(1) CFG(0) TRAP MON / TRAP-BL MON / BL MON ─► Oscilloscope
The five 32-bit monitor outputs (TRIGGER_DELTA_MON, TRIGGER_TRAP_MON,
TRAP_MON, TRAP_BL_MON, BL_MON) exist to be wired into an oscilloscope
endpoint while you tune the filter; they can all be left unconnected in
production.
Timing
| quantity | value |
|---|---|
| throughput | 1 sample per clock (HLS_SYN_TPT=1) |
| pipeline latency declared on the symbol | 13 clocks |
| pipeline latency in the HLS report inside the netlist | 12 clocks |
trigger → ENERGY_DV |
SAMPLE_POS samples (plus the pipeline latency) |
The symbol latency (13) is what the Sci-Compiler scheduler uses to align this block with parallel paths; the HLS report figure (12) is the core’s own measured latency. Use 13 when you have to compensate a parallel branch by hand.
Resources & Timing
-
Latency: 13 clocks declared on the symbol (the HLS report embedded in the netlist says 12); trigger to ENERGY DV is SAMPLE_POS samples on top of that
-
Throughput: 1 sample per clock (HLS_SYN_TPT = 1)
- Figures reported by Vivado HLS 2017.4 for the 2048 variant on
xc7k160tfbg676-3: 9 BRAM, 6 DSP, 2343 FF, 2822 LUT. - Timing was closed at a 12.5 ns target with a 10.4 ns estimate, i.e. the core is comfortable at 80 MHz and was not characterised above ~96 MHz.
- The 512 and 1024 variants differ only in the depth of two RAMs; expect the same DSP/FF/LUT cost and fewer BRAMs.
- No memory-mapped registers are generated (
CompileMMC/CompileSDKare empty) — the software interface is whatever endpoint you connectENERGYto.