Line data Source code
1 : /**
2 : * @file AVXPipeline.cpp
3 : *
4 : * @copyright This is part of the DUNE DAQ Software Suite, copyright 2020.
5 : * Licensing/copyright details are in the COPYING file that you should have
6 : * received with this code.
7 : */
8 : #include "tpglibs/AVXPipeline.hpp"
9 :
10 : namespace tpglibs {
11 :
12 : __m256i
13 780 : AVXPipeline::save_state(const __m256i& processed_signal)
14 : {
15 780 : __m256i active = _mm256_cmpgt_epi16(processed_signal, _mm256_setzero_si256());
16 780 : __m256i inactive = _mm256_cmpeq_epi16(processed_signal, _mm256_setzero_si256());
17 780 : __m256i was_inactive = _mm256_cmpeq_epi16(m_samples_over_threshold, _mm256_setzero_si256());
18 :
19 : // If it was *not* inactive and is now inactive, then it must be a new TP.
20 780 : __m256i new_tps = _mm256_andnot_si256(was_inactive, inactive);
21 :
22 : // Get the potentially saturated integral and overflown integral.
23 780 : __m256i adc_integral_sat = _mm256_adds_epu16(m_adc_integral_lo, processed_signal);
24 780 : m_adc_integral_lo = _mm256_add_epi16(m_adc_integral_lo, processed_signal);
25 :
26 : // If it is saturated, then increment the hi. The overflown integral already "reset".
27 780 : __m256i is_saturated = _mm256_cmpeq_epi16(adc_integral_sat, m_max_value_register);
28 : // If lo and sat are the same, then it is *not* saturated and happened to exactly sum to 0xFFFF.
29 780 : __m256i exact = _mm256_cmpeq_epi16(m_adc_integral_lo, adc_integral_sat);
30 : // So, (!exact) & is_saturated == [truly saturated].
31 780 : is_saturated = _mm256_andnot_si256(exact, is_saturated);
32 :
33 780 : __m256i to_add = _mm256_and_si256(m_ones_register, is_saturated);
34 780 : m_adc_integral_hi = _mm256_adds_epu16(m_adc_integral_hi, to_add);
35 :
36 780 : __m256i above_peak = _mm256_cmpgt_epi16(processed_signal, m_adc_peak);
37 :
38 780 : m_adc_peak = _mm256_max_epi16(m_adc_peak, processed_signal);
39 780 : m_samples_to_peak = _mm256_blendv_epi8(m_samples_to_peak, m_samples_over_threshold, above_peak);
40 :
41 780 : __m256i time_add = _mm256_blendv_epi8(_mm256_setzero_si256(), m_ones_register, active);
42 780 : m_samples_over_threshold = _mm256_adds_epi16(m_samples_over_threshold, time_add);
43 :
44 780 : return new_tps;
45 : }
46 :
47 : bool
48 780 : AVXPipeline::check_for_tps(const __m256i& tp_mask)
49 : {
50 : // tp_mask & 0xFFFF = 0 -> tp_mask == 0.
51 : // True => tp_mask is all zeros and has no TPs.
52 : // Negate!
53 780 : return !_mm256_testz_si256(tp_mask, _mm256_set1_epi16(-1));
54 : }
55 :
56 : std::vector<dunedaq::trgdataformats::TriggerPrimitive>
57 147 : AVXPipeline::generate_tps(const __m256i& tp_mask)
58 : {
59 : // Mask everything that's relevant.
60 147 : __m256i samples_over_threshold = _mm256_blendv_epi8(_mm256_setzero_si256(), m_samples_over_threshold, tp_mask);
61 147 : __m256i adc_integral_lo = _mm256_blendv_epi8(_mm256_setzero_si256(), m_adc_integral_lo, tp_mask);
62 147 : __m256i adc_integral_hi = _mm256_blendv_epi8(_mm256_setzero_si256(), m_adc_integral_hi, tp_mask);
63 147 : __m256i adc_peak = _mm256_blendv_epi8(_mm256_setzero_si256(), m_adc_peak, tp_mask);
64 147 : __m256i samples_to_peak = _mm256_blendv_epi8(_mm256_setzero_si256(), m_samples_to_peak, tp_mask);
65 :
66 : // Convert to uint16_t.
67 147 : uint16_t tp_sot[16], tp_integral_lo[16], tp_integral_hi[16], tp_adc_peak[16], tp_samples_to_peak[16];
68 147 : _mm256_storeu_si256(reinterpret_cast<__m256i*>(tp_sot), samples_over_threshold);
69 147 : _mm256_storeu_si256(reinterpret_cast<__m256i*>(tp_integral_lo), adc_integral_lo);
70 147 : _mm256_storeu_si256(reinterpret_cast<__m256i*>(tp_integral_hi), adc_integral_hi);
71 147 : _mm256_storeu_si256(reinterpret_cast<__m256i*>(tp_adc_peak), adc_peak);
72 147 : _mm256_storeu_si256(reinterpret_cast<__m256i*>(tp_samples_to_peak), samples_to_peak);
73 :
74 147 : std::vector<dunedaq::trgdataformats::TriggerPrimitive> tps;
75 2499 : for (int i = 0; i < 16; i++) {
76 2352 : if (tp_sot[i] < m_sot_minima[m_plane_numbers[i]])
77 368 : continue; // Don't track short TPs.
78 1984 : dunedaq::trgdataformats::TriggerPrimitive tp;
79 1984 : tp.adc_integral = uint32_t(tp_integral_lo[i]) + (uint32_t(tp_integral_hi[i]) << 16);
80 1984 : tp.adc_peak = tp_adc_peak[i];
81 1984 : tp.channel = m_channels[i];
82 1984 : tp.samples_to_peak = tp_samples_to_peak[i];
83 1984 : tp.samples_over_threshold = tp_sot[i];
84 :
85 : // time_start is handled at the next level up, since it is aware of the true and relative times.
86 1984 : tps.push_back(tp);
87 : }
88 :
89 : // Reset the channels that generated tps.
90 147 : m_samples_over_threshold = _mm256_blendv_epi8(m_samples_over_threshold, _mm256_setzero_si256(), tp_mask);
91 147 : m_adc_integral_lo = _mm256_blendv_epi8(m_adc_integral_lo, _mm256_setzero_si256(), tp_mask);
92 147 : m_adc_integral_hi = _mm256_blendv_epi8(m_adc_integral_hi, _mm256_setzero_si256(), tp_mask);
93 147 : m_adc_peak = _mm256_blendv_epi8(m_adc_peak, _mm256_setzero_si256(), tp_mask);
94 147 : m_samples_to_peak = _mm256_blendv_epi8(m_samples_to_peak, _mm256_setzero_si256(), tp_mask);
95 :
96 : // Finalize.
97 147 : return tps;
98 0 : }
99 :
100 : } // namespace tpglibs
|