Line data Source code
1 : /**
2 : * @file TPGenerator.hpp
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 :
9 : #include "tpglibs/TPGenerator.hpp"
10 :
11 : namespace tpglibs {
12 :
13 : void
14 3 : TPGenerator::configure(const std::vector<std::pair<std::string, nlohmann::json>>& configs,
15 : const std::vector<std::pair<dunedaq::trgdataformats::channel_t, int16_t>> channel_plane_numbers,
16 : const float sample_tick_difference)
17 : {
18 3 : if (m_configured) {
19 0 : reset();
20 : }
21 :
22 3 : m_num_pipelines = channel_plane_numbers.size() / m_num_channels_per_pipeline;
23 3 : m_sample_tick_difference = sample_tick_difference;
24 :
25 15 : for (int p = 0; p < m_num_pipelines; p++) {
26 12 : AVXPipeline new_pipe = AVXPipeline();
27 12 : auto begin_channel_plane = channel_plane_numbers.begin() + p * m_num_channels_per_pipeline;
28 12 : auto end_channel_plane = begin_channel_plane + m_num_channels_per_pipeline;
29 12 : new_pipe.configure(
30 : configs,
31 24 : std::vector<std::pair<dunedaq::trgdataformats::channel_t, int16_t>>(begin_channel_plane, end_channel_plane));
32 12 : new_pipe.set_sot_minima(m_sot_minima);
33 12 : m_tpg_pipelines.push_back(new_pipe);
34 12 : }
35 :
36 3 : m_configured = true;
37 3 : }
38 :
39 : std::vector<std::pair<std::shared_ptr<AbstractProcessor<__m256i>>, int>>
40 0 : TPGenerator::get_all_processor_references_with_pipeline_index()
41 : {
42 0 : std::vector<std::pair<std::shared_ptr<AbstractProcessor<__m256i>>, int>> processor_references;
43 :
44 0 : for (int pipeline_id = 0; pipeline_id < m_num_pipelines; ++pipeline_id) {
45 0 : for (auto& processor : m_tpg_pipelines[pipeline_id].get_all_processor_references()) {
46 0 : processor_references.push_back(std::make_pair(processor, pipeline_id));
47 0 : }
48 : }
49 0 : return processor_references;
50 0 : }
51 :
52 : void
53 2 : TPGenerator::reset()
54 : {
55 2 : m_num_pipelines = 0;
56 2 : m_tpg_pipelines.clear();
57 2 : m_sample_tick_difference = 0;
58 2 : m_sot_minima = { 1, 1, 1 };
59 2 : m_configured = false;
60 2 : }
61 :
62 : void
63 0 : TPGenerator::set_sot_minima(const std::vector<uint16_t>& sot_minima)
64 : {
65 0 : m_sot_minima = sot_minima;
66 0 : }
67 :
68 : __m256i
69 768 : TPGenerator::expand_frame(const __m256i& regi)
70 : {
71 : // Refer to the diagram and documentation on frame expansion for details.
72 :
73 : // Prepare even (2,4,6,8), odd (1,3,5,7) rows in 64-bit sense.
74 768 : __m256i odd = _mm256_permutevar8x32_epi32(regi, _mm256_setr_epi32(1, 0, 1, 2, 3, 4, 5, 6));
75 :
76 : // Shift into place.
77 768 : __m256i even = _mm256_sllv_epi64(regi, _mm256_setr_epi64x(6, 14, 22, 30));
78 768 : odd = _mm256_srlv_epi64(odd, _mm256_setr_epi64x(30, 22, 14, 6));
79 :
80 : // Everything is center aligned in 32-bit. Mask and right-align the right side.
81 768 : __m256i both = _mm256_blend_epi32(even, odd, 0b01010101);
82 768 : __m256i right = _mm256_and_si256(_mm256_set1_epi32(0xFFFFu), both);
83 768 : __m256i left = _mm256_and_si256(_mm256_set1_epi32(0x3FFF0000u), both);
84 :
85 768 : right = _mm256_srli_epi32(right, 2);
86 768 : return _mm256_or_si256(left, right);
87 : }
88 :
89 : __m256i
90 0 : TPGenerator::old_expand_frame(const __m256i& regi)
91 : {
92 : // Refer to the diagram and documentation on frame expansion for details.
93 :
94 : // Rearrange original with row 3 doubled.
95 0 : __m256i idx = _mm256_set_epi32(6, 5, 4, 3, 3, 2, 1, 0);
96 0 : __m256i shuf1 = _mm256_permutevar8x32_epi32(regi, idx);
97 :
98 : // Left shift each row.
99 0 : __m256i count = _mm256_set_epi32(12, 8, 4, 0, 14, 10, 6, 2);
100 0 : __m256i high_half = _mm256_sllv_epi32(shuf1, count);
101 0 : high_half = _mm256_and_si256(high_half, _mm256_set1_epi32(0x3FFF0000u)); // Mask out the low half.
102 :
103 : // Left shift for low half later.
104 0 : count = _mm256_set_epi32(10, 6, 2, 0, 12, 8, 4, 0);
105 0 : __m256i shift2 = _mm256_sllv_epi32(shuf1, count);
106 :
107 : // Rearrange original and doubled rows 2 and 0.
108 0 : idx = _mm256_set_epi32(5, 4, 3, 2, 2, 1, 0, 0);
109 0 : __m256i shuf2 = _mm256_permutevar8x32_epi32(regi, idx);
110 :
111 : // Right shift each row.
112 0 : count = _mm256_set_epi32(22, 26, 30, 0, 20, 24, 28, 0);
113 0 : __m256i shift3 = _mm256_srlv_epi32(shuf2, count);
114 :
115 : // "Complete" the low half. Still more.
116 0 : __m256i low_half = _mm256_or_si256(shift2, shift3);
117 0 : low_half = _mm256_and_si256(low_half, _mm256_set1_epi32(0x3FFFu)); // Mask out the high half.
118 :
119 : // Combine halves and clear space for an odd entry.
120 0 : __m256i both = _mm256_or_si256(low_half, high_half);
121 0 : both = _mm256_andnot_si256(_mm256_set_epi32(0, 0, 0, 0xFFFFu, 0, 0, 0, 0), both);
122 :
123 : // There is a specific 16-bit entry that needs special handling.
124 : // Align it.
125 0 : __m256i shift4 = _mm256_srli_epi32(regi, 18);
126 : // Mask it.
127 0 : shift4 = _mm256_and_si256(_mm256_set_epi32(0, 0x3FFFu, 0, 0, 0, 0, 0, 0), shift4);
128 :
129 : // Permute into the right spot
130 0 : idx = _mm256_set_epi32(0, 0, 0, 6, 0, 0, 0, 0);
131 0 : __m256i shuf3 = _mm256_permutevar8x32_epi32(shift4, idx);
132 :
133 : // Add it in.
134 0 : both = _mm256_or_si256(both, shuf3);
135 0 : return both;
136 : }
137 :
138 : } // namespace tpglibs
|