Line data Source code
1 : /**
2 : * @file emu_confgen.cxx Generates files tad can be loaded by flx-config
3 : *
4 : * This is part of the DUNE DAQ , copyright 2020.
5 : * Licensing/copyright details are in the COPYING file that you should have
6 : * received with this code.
7 : */
8 : #include "logging/Logging.hpp"
9 :
10 : #include <cstdint>
11 : #include <cstdlib>
12 : #include <fstream>
13 : #include <iostream>
14 : #include <sstream>
15 : #include <string>
16 : #include <vector>
17 :
18 : // IDLE=K28.5, SOP=K28.1, EOP=K28.6, SOB=K28.2, EOB=K28.3
19 : const constexpr uint64_t FM_KCHAR_IDLE = (((uint64_t)1 << 32) | 0xBC); // NOLINT
20 : const constexpr uint64_t FM_KCHAR_SOP = (((uint64_t)1 << 32) | 0x3C); // NOLINT
21 : const constexpr uint64_t FM_KCHAR_EOP = (((uint64_t)1 << 32) | 0xDC); // NOLINT
22 : const constexpr uint64_t FM_KCHAR_SOB = (((uint64_t)1 << 32) | 0x5C); // NOLINT
23 : const constexpr uint64_t FM_KCHAR_EOB = (((uint64_t)1 << 32) | 0x7C); // NOLINT
24 :
25 : // CRC constants
26 : const constexpr uint64_t CRC_WIDTH = 20; // NOLINT
27 : const constexpr uint64_t CRC_MASK = ((1 << CRC_WIDTH) - 1); // NOLINT
28 : const constexpr uint64_t CRC_POLYNOM_1 = 0xC1ACF; // NOLINT
29 : const constexpr uint64_t CRC_POLYNOM_2 = 0x8359F; // NOLINT
30 : const constexpr uint64_t CRC_INITVAL = 0xFFFFF; // NOLINT
31 :
32 : // Chunk constants
33 : const constexpr uint64_t CHUNKHDR_SIZE = 8; // NOLINT
34 :
35 : // EMU constant
36 : const constexpr size_t EMU_SIZE = 8192; // NOLINT
37 :
38 : uint64_t // NOLINT
39 0 : crc20(uint64_t* data, uint64_t length, bool crc_new) // NOLINT
40 : {
41 : // Initialize
42 0 : uint64_t crc = CRC_INITVAL; // NOLINT
43 0 : uint64_t polynomial; // NOLINT
44 0 : if (crc_new) {
45 : polynomial = CRC_POLYNOM_2;
46 : } else {
47 0 : polynomial = CRC_POLYNOM_1;
48 : }
49 :
50 0 : unsigned int i, k; // NOLINT
51 0 : for (k = 0; k < CRC_WIDTH; ++k) {
52 0 : if ((crc & 1)) {
53 0 : crc = (crc >> 1) ^ ((1 << (CRC_WIDTH - 1)) | (polynomial >> 1));
54 : } else {
55 0 : crc = (crc >> 1);
56 : }
57 : }
58 :
59 : // Calculate CRC
60 0 : for (i = 0; i < length; i++) {
61 0 : for (k = 1; k <= 32; k++) {
62 0 : if (crc & (1 << (CRC_WIDTH - 1))) {
63 0 : crc = ((crc << 1) | ((data[i] >> (32 - k)) & 1)) ^ polynomial;
64 : } else {
65 0 : crc = ((crc << 1) | ((data[i] >> (32 - k)) & 1));
66 : }
67 : }
68 0 : crc &= CRC_MASK;
69 : }
70 :
71 : // One more loop
72 0 : for (k = 0; k < CRC_WIDTH; k++) {
73 0 : if (crc & (1 << (CRC_WIDTH - 1))) {
74 0 : crc = (crc << 1) ^ polynomial;
75 : } else {
76 0 : crc = (crc << 1);
77 : }
78 : }
79 0 : crc &= CRC_MASK;
80 :
81 0 : return crc;
82 : }
83 :
84 : bool
85 0 : generateFm(uint64_t* emudata, // NOLINT
86 : uint64_t emusize, // NOLINT
87 : uint32_t req_chunksize, // NOLINT
88 : uint32_t pattern_id, // NOLINT
89 : uint32_t idle_chars, // NOLINT
90 : bool random_sz,
91 : bool crc_new,
92 : bool use_streamid,
93 : bool add_busy,
94 : bool omit_one_soc,
95 : bool omit_one_eoc,
96 : bool add_crc_err)
97 : {
98 : // Initialize emudata to all zeroes
99 0 : unsigned i; // NOLINT
100 0 : for (i = 0; i < emusize; ++i) {
101 0 : emudata[i] = 0;
102 : }
103 :
104 : // Determine the number of chunks that will fit
105 : // (chunk size includes 8-byte header): 2 IDLEs, SOP, chunk, EOP
106 0 : uint32_t max_chunkcnt = (emusize - 2) / (1 + req_chunksize / 4 + 1 + idle_chars); // NOLINT
107 0 : uint32_t index = 0; // NOLINT
108 0 : bool success = true;
109 : // g_chunk_count = max_chunkcnt;
110 :
111 : // Start with some IDLE symbols
112 0 : emudata[index++] = FM_KCHAR_IDLE; // NOLINT(runtime/increment_decrement)
113 0 : emudata[index++] = FM_KCHAR_IDLE; // NOLINT(runtime/increment_decrement)
114 :
115 : // Multiple chunks
116 0 : uint32_t next_index, chunkcntr = 0, chunksz, chunk_datasz; // NOLINT
117 0 : while (index < emusize && chunkcntr < max_chunkcnt) {
118 0 : if (random_sz && req_chunksize > 8) { // Size not less than 8
119 : // Determine a random (data) size to use for the next chunk
120 : // (here: size between req_chunksize/2 and req_chunksize,
121 : // but rounded up to a multiple of 4 bytes)
122 0 : uint32_t sz = (req_chunksize + 1) / 2; // NOLINT
123 0 : double r = static_cast<double>(rand()) / RAND_MAX; // NOLINT
124 0 : double d = 0.5 * static_cast<double>(1 - (req_chunksize & 1));
125 0 : chunksz = ((sz + static_cast<uint32_t>(static_cast<double>(sz) * r + d) + 3) / 4) * 4; // NOLINT
126 :
127 : } else {
128 : chunksz = req_chunksize;
129 : }
130 :
131 : // Check if the next chunk will fit
132 : // (chunksz includes header)
133 0 : next_index = index + (1 + chunksz / 4 + 1);
134 0 : if (next_index >= emusize) {
135 : // It won't fit, so forget it: from here onwards fill with IDLEs
136 0 : for (; index < emusize; ++index) {
137 0 : emudata[index] = FM_KCHAR_IDLE;
138 : }
139 : // Should exit the while-loop on the basis of the chunk counter
140 : // so we consider this an error...
141 0 : success = false;
142 0 : continue; // Jump to start of while-loop
143 : }
144 :
145 : // SOP
146 0 : emudata[index++] = FM_KCHAR_SOP; // NOLINT
147 0 : if (omit_one_soc && chunkcntr == 2) {
148 0 : --index; // For testing
149 : }
150 :
151 : // Add chunk header
152 0 : chunk_datasz = chunksz - CHUNKHDR_SIZE;
153 0 : if (use_streamid) {
154 0 : emudata[index++] = ((chunkcntr & 0xFF) | // Chunk counter = StreamID // NOLINT
155 0 : (chunk_datasz & 0xF00) | ((chunk_datasz & 0x0FF) << 16) | ((chunkcntr & 0xFF) << 24));
156 : } else {
157 0 : emudata[index++] = // NOLINT
158 0 : (0xAA | (chunk_datasz & 0xF00) | ((chunk_datasz & 0x0FF) << 16) | ((chunkcntr & 0xFF) << 24));
159 : }
160 :
161 0 : emudata[index++] = 0x10AABB00; // ewidth=0x10=16 bits // NOLINT
162 :
163 : // Add chunk data according to 'pattern_id'
164 0 : if (pattern_id == 1) {
165 0 : for (i = 0; i < chunk_datasz / 4; ++i) {
166 0 : emudata[index++] = 0xAA55AA55; // NOLINT
167 : }
168 0 : } else if (pattern_id == 2) {
169 0 : for (i = 0; i < chunk_datasz / 4; ++i) {
170 0 : emudata[index++] = 0xFFFFFFFF; // NOLINT
171 : }
172 0 : } else if (pattern_id == 3) {
173 0 : for (i = 0; i < chunk_datasz / 4; ++i) {
174 0 : emudata[index++] = 0x00000000; // NOLINT
175 : }
176 : } else {
177 : unsigned int cntr = 0; // NOLINT
178 0 : for (i = 0; i < chunk_datasz / 4; ++i, cntr += 4) {
179 0 : emudata[index++] = // NOLINT
180 0 : ((((cntr + 3) & 0xFF) << 24) | (((cntr + 2) & 0xFF) << 16) | (((cntr + 1) & 0xFF) << 8) |
181 0 : (((cntr + 0) & 0xFF) << 0));
182 : }
183 : }
184 :
185 : // EOP (+ 20-bits CRC)
186 0 : uint64_t crc = crc20(&emudata[index - chunksz / 4], chunksz / 4, crc_new); // NOLINT
187 :
188 0 : if (add_crc_err && chunkcntr == 3) {
189 0 : ++crc; // For testing
190 : }
191 :
192 0 : emudata[index++] = FM_KCHAR_EOP | (crc << 8); // NOLINT
193 :
194 0 : if (omit_one_eoc && chunkcntr == 2) {
195 0 : --index; // For testing
196 : }
197 :
198 0 : if (add_busy && chunkcntr == 0) {
199 0 : emudata[index++] = FM_KCHAR_SOB; // NOLINT
200 : }
201 :
202 : // A configurable number of comma symbols in between chunks
203 0 : for (i = 0; i < idle_chars; ++i) {
204 0 : emudata[index++] = FM_KCHAR_IDLE; // NOLINT
205 : }
206 :
207 0 : if (add_busy && chunkcntr == 0) {
208 0 : emudata[index++] = FM_KCHAR_EOB; // NOLINT
209 : }
210 :
211 0 : ++chunkcntr;
212 : }
213 :
214 : // Fill any remaining uninitialised array locations with IDLE symbols
215 0 : for (; index < emusize; ++index) {
216 0 : emudata[index] = FM_KCHAR_IDLE;
217 : }
218 :
219 : // We expect to have generated max_chunkcnt chunks!
220 0 : if (chunkcntr < max_chunkcnt) {
221 0 : success = false;
222 : }
223 :
224 0 : return success;
225 : } // NOLINT(readability/fn_size)
226 :
227 : int
228 0 : main(int argc, char* argv[])
229 : {
230 :
231 : // "-h", "--help", "--filename", "--emuSize", "--chunkSize", "--idles", "--pattern"
232 :
233 0 : const std::vector<std::string> cmdArgs = { argv,
234 0 : argv + argc }; // store arguments, options and flags from the command line
235 :
236 : // set default values
237 0 : uint32_t emusize = 8192; // NOLINT
238 0 : uint32_t req_chunksize = 464; // NOLINT
239 0 : uint32_t pattern_id = 0; // NOLINT
240 0 : uint32_t idle_chars = 1; // NOLINT
241 0 : bool random_sz = false;
242 0 : bool crc_new = true;
243 0 : bool use_streamid = false;
244 0 : bool add_busy = false;
245 0 : bool omit_one_soc = false;
246 0 : bool omit_one_eoc = false;
247 0 : bool add_crc_err = false;
248 0 : std::string filename = "emuconfigreg";
249 :
250 : // parse command line information
251 0 : for (unsigned j = 0; j < cmdArgs.size(); j++) { // NOLINT
252 0 : std::string arg = cmdArgs[j];
253 0 : if (arg == "-h" || arg == "--help") {
254 0 : std::ostringstream oss;
255 0 : oss
256 : << "\nThis app is used to create basic emulator configurations for the FELIX to use with flx-config. Usage: \n"
257 : << " -h/--help : display help messege \n"
258 : << " --filename : output configuration filename \n"
259 : //<< " --emuSize : total number of lines of data \n"
260 : << " --chunkSize : chunk sie of each block of data \n"
261 : << " --idles : number of idle charachters between chunks \n"
262 : << " --pattern : type of data to write \n"
263 : << " 0 is incrimental \n"
264 : << " 1 sets all to 0xAA55AA55 \n"
265 : << " 2 sets all to 0xFFFFFFFF \n"
266 0 : << " 3 sets all to 0x00000000";
267 0 : TLOG() << oss.str();
268 0 : exit(0);
269 0 : } else if (arg == "--filename") {
270 : // get input file name, then print it
271 0 : if (j >= cmdArgs.size() - 1) // check if the arguement is at the end of the line without an input
272 : {
273 0 : TLOG() << "No file name was specified";
274 0 : break;
275 : }
276 0 : filename = cmdArgs[j + 1];
277 :
278 : //} else if (arg == "--emuSize") {
279 : // if (j >= cmdArgs.size() - 1) {
280 : // TLOG() << "No value was specified \n";
281 : // break;
282 : // }
283 : // emusize = std::stoi(cmdArgs[j + 1]);
284 :
285 0 : } else if (arg == "--chunkSize") {
286 0 : if (j >= cmdArgs.size() - 1) {
287 0 : TLOG() << "No value was specified";
288 0 : break;
289 : }
290 0 : req_chunksize = std::stoi(cmdArgs[j + 1]);
291 :
292 0 : } else if (arg == "--idles") {
293 0 : if (j >= cmdArgs.size() - 1) {
294 0 : TLOG() << "No value was specified";
295 0 : break;
296 : }
297 0 : idle_chars = std::stoi(cmdArgs[j + 1]);
298 :
299 0 : } else if (arg == "--pattern") {
300 0 : if (j >= cmdArgs.size() - 1) {
301 0 : TLOG() << "No value was specified";
302 0 : break;
303 : }
304 0 : pattern_id = std::stoi(cmdArgs[j + 1]);
305 : }
306 0 : }
307 : // TLOG() << "number of lines : " << emusize;
308 0 : TLOG() << "chunk size : " << req_chunksize;
309 0 : TLOG() << "idle characters : " << idle_chars;
310 0 : TLOG() << "pattern type : " << pattern_id;
311 :
312 0 : filename += "_" + std::to_string(req_chunksize) + "_" + std::to_string(idle_chars) + "_" + std::to_string(pattern_id);
313 0 : TLOG() << "output file : " << filename;
314 :
315 0 : uint64_t emudata[EMU_SIZE]; // NOLINT
316 0 : std::ofstream output;
317 0 : output.open(filename);
318 :
319 0 : generateFm(emudata,
320 : emusize,
321 : req_chunksize,
322 : pattern_id,
323 : idle_chars,
324 : random_sz,
325 : crc_new,
326 : use_streamid,
327 : add_busy,
328 : omit_one_soc,
329 : omit_one_eoc,
330 : add_crc_err);
331 :
332 0 : for (unsigned i = 0; i < emusize; i++) { // NOLINT
333 0 : output << "FE_EMU_CONFIG_WRADDR=0x" << std::hex << i << std::endl;
334 0 : output << "FE_EMU_CONFIG_WRDATA=0x" << std::hex << emudata[i] << std::endl;
335 0 : output << "FE_EMU_CONFIG_WE=1" << std::endl;
336 0 : output << "FE_EMU_CONFIG_WE=0" << std::endl;
337 : }
338 :
339 0 : output.close();
340 :
341 0 : TLOG() << "Config file written.";
342 :
343 0 : } // NOLINT(readability/fn_size)
|