Belle II Software development
FpgaUtility.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8#ifndef __EXTERNAL__
9#include "trg/cdc/FpgaUtility.h"
10#else
11#include "FpgaUtility.h"
12#endif
13
14#include <iostream>
15#include <fstream>
16#include <sstream>
17#include <bitset>
18#include <algorithm>
19#include <cmath>
20
21using std::cout;
22using std::endl;
23using std::vector;
24using std::map;
25using std::string;
26using std::stringstream;
27using std::bitset;
28using std::ifstream;
29using std::ofstream;
30using std::ceil;
31using std::floor;
32using std::fmod;
33using std::pow;
34using std::log;
35
36
37// Rounds value to an integer.
38double FpgaUtility::roundInt(double value)
39{
40 if (value > 0) {
41 value -= 0.5;
42 // If value is very near int, then let value be the int
43 if (value - floor(value) < 0.00001) value = floor(value);
44 if (floor(value + 1) - value < 0.00001) value = floor(value + 1);
45 // Round up
46 value = ceil(value);
47 } else {
48 value += 0.5;
49 // If value is very near int, then let value be the int
50 if (-value + ceil(value) < 0.00001) value = ceil(value);
51 if (-ceil(value - 1) + value < 0.00001) value = ceil(value - 1);
52 // Round down
53 value = floor(value);
54 }
55 return value;
56}
57
58// Radix changing functions
59// Change string to octal. Possible radix=[2,26].
60double FpgaUtility::arbToDouble(std::string in, int inRadix)
61{
62 if (inRadix < 2 || inRadix > 26) {
63 cout << "[Error] arbToDouble() => Radix is out of range [2,26]. Aborting." << endl;
64 return 0;
65 }
66 double result = 0;
67 for (unsigned int iChar = 0; iChar < in.size(); iChar++) {
68 if (in[iChar] == '-') continue;
69 result = result * inRadix;
70 if (in[iChar] >= '0' && in[iChar] <= '9') result += in[iChar] - 48;
71 else if (in[iChar] >= 'A' && in[iChar] <= 'Z') result += in[iChar] - 55;
72 else if (in[iChar] >= 'a' && in[iChar] <= 'z') result += in[iChar] - 87;
73 else {
74 cout << "[Error] arbToDouble() => Strange character detected. Aborting." << endl;
75 return 0;
76 }
77 } // end of string loop.
78 if (in[0] == '-') result *= -1;
79 return result;
80}
81// Change octal to string.
82string FpgaUtility::doubleToArb(double in, int outRadix, int numberOfDigits)
83{
84 string result;
85 int sign = 1;
86 if (in < 0) {
87 sign = -1;
88 in *= -1;
89 }
90 while (1) {
91 int rem = fmod(in, outRadix);
92 result.insert(result.begin(), char((rem >= 0 && rem <= 9) ? rem + 48 : rem + 55));
93 in = (in / outRadix) - (rem / outRadix);
94 if (in < outRadix) {
95 result.insert(result.begin(), char((in >= 0 && in <= 9) ? in + 48 : in + 55));
96 break;
97 }
98 }
99 // Padding for output.
100 if (int(result.size()) < numberOfDigits) {
101 int nBitsAdd = numberOfDigits - result.size();
102 for (int iZero = 0; iZero < nBitsAdd; iZero++) {
103 result.insert(0, "0");
104 }
105 } else if (numberOfDigits == -1) {
106 } else if (int(result.size()) > numberOfDigits) {
107 cout << "[Error] doubleToArb() => numberOfDigits too small. Aborting." << endl;
108 return 0;
109 }
110 if (sign == -1) result.insert(0, "-");
111 return result;
112}
113// Change number system between strings.
114string FpgaUtility::arbToArb(const std::string& in, int inRadix, int outRadix, int numberOfDigits)
115{
116 return doubleToArb(arbToDouble(in, inRadix), outRadix, numberOfDigits);
117}
118
119// Changes signed binary string to 2s complement binary string.
120string FpgaUtility::signedToTwosComplement(string in, int numberOfDigits)
121{
122 int sign = 1;
123 if (in[0] == '-') {
124 in.erase(0, 1);
125 sign = -1;
126 }
127 // Padding for output.
128 if (int(in.size()) < numberOfDigits) {
129 unsigned nBits = numberOfDigits - in.size();
130 for (unsigned iZero = 0; iZero < nBits; iZero++) {
131 in.insert(0, "0");
132 }
133 } else if (int(in.size()) >= numberOfDigits) {
134 cout << "[Error] signedToTwosComplement() => numberOfDigits too small. Aborting." << endl;
135 return "";
136 }
137 if (sign == 1) {
138 // For positive values.
139 } else {
140 // For negative values.
141 // Flip values.
142 for (unsigned int iChar = 0; iChar < in.size(); iChar++) {
143 if (in[iChar] == '1') in[iChar] = '0';
144 else if (in[iChar] == '0') in[iChar] = '1';
145 else cout << "[Error] signedToTwosComplement() => Strange character in string. Aborting." << endl;
146 }
147 //cout<<"Flip: "<<in<<endl;
148 // Add 1 to result.
149 for (int iDigit = in.size() - 1; iDigit >= 0; iDigit--) {
150 if (in[unsigned(iDigit)] == '0') {
151 in[unsigned(iDigit)] = '1';
152 break;
153 } else {
154 in[unsigned(iDigit)] = '0';
155 }
156 } // End of adding 1.
157 //cout<<"Adding: "<<in<<endl;
158 }
159 return in;
160}
161
162// Changes 2s complement binary string to signed binary string.
163std::string FpgaUtility::twosComplementToSigned(std::string in)
164{
165 // If value is positive.
166 if (in[0] == '0') {
167 } else {
168 // Subtract 1.
169 for (int iDigit = in.size() - 1; iDigit >= 0; iDigit--) {
170 if (in[unsigned(iDigit)] == '1') {
171 in[unsigned(iDigit)] = '0';
172 break;
173 } else {
174 in[unsigned(iDigit)] = '1';
175 }
176 } // End of subtract 1.
177 //cout<<"Subtract 1: "<<in<<endl;
178 // Flip values.
179 for (unsigned int iChar = 0; iChar < in.size(); iChar++) {
180 if (in[iChar] == '1') in[iChar] = '0';
181 else if (in[iChar] == '0') in[iChar] = '1';
182 else cout << "[Error] twosComplementToSigned() => Strange character in string. Aborting." << endl;
183 }
184 //cout<<"Flip: "<<in<<endl;;
185 // Remove padding '0's
186 for (int iDigit = 0; iDigit < int(in.size()); iDigit++) {
187 if (in[unsigned(iDigit)] == '0') {
188 if (in.size() == 1) break;
189 in.erase(iDigit, 1);
190 iDigit--;
191 } else {
192 break;
193 }
194 }
195 // Add minus sign.
196 in.insert(0, "-");
197 }
198 return in;
199}
200
201// Write values to a file.
202void FpgaUtility::writeSignals(std::string outFilePath, std::map<std::string, std::vector<signed long long> >& data)
203{
204 // Create file.
205 ofstream outFile;
206 outFile.open(outFilePath.c_str());
207 // Fill content of file.
208 for (auto it = data.begin(); it != data.end(); it++) {
209 outFile << (*it).first << " ";
210 for (unsigned iVector = 0; iVector < (*it).second.size(); iVector++) {
211 outFile << (*it).second[iVector] << " ";
212 }
213 outFile << endl;
214 }
215 // Close file.
216 outFile.close();
217}
218
219// COE file functions. [TODO] Should limit number of entries for write functions.
220void FpgaUtility::multipleWriteCoe(int lutInBitsize, std::map<std::string, std::vector<signed long long> >& data,
221 const std::string& fileDirectory)
222{
223 // Loop over all data.
224 for (auto it = data.begin(); it != data.end(); it++) {
225 FpgaUtility::writeCoe(fileDirectory + "/" + (*it).first + ".coe", lutInBitsize, (*it).second);
226 }
227}
228
229void FpgaUtility::writeCoe(std::string outFilePath, int lutInBitsize, std::vector<signed long long>& data)
230{
231
232 // Create file.
233 ofstream coeFile;
234 coeFile.open(outFilePath.c_str());
235 // Meta data for file.
236 coeFile << "memory_initialization_radix=10;" << endl;
237 coeFile << "memory_initialization_vector=" << endl;
238 unsigned nEntries = pow(2, lutInBitsize);
239 // Fill content of file.
240 unsigned nDataSize = data.size();
241 for (unsigned index = 0; index < (nEntries - 1); index++) {
242 if (index < nDataSize) coeFile << data[index] << "," << endl;
243 else coeFile << 0 << "," << endl;
244 }
245 if (nEntries <= nDataSize) coeFile << data[nEntries - 1] << ";" << endl;
246 else coeFile << 0 << ";" << endl;
247 // Close file.
248 coeFile.close();
249}
250
251void FpgaUtility::readCoe(std::string inFilePath, std::vector<signed long long>& data, bool twosComplement)
252{
253
254 ifstream coeFile;
255 coeFile.open(inFilePath.c_str());
256 if (coeFile.fail()) {
257 cout << "[Error] FpgaUtility::readCoe() => Can not open file: " << inFilePath << endl;
258 return;
259 } else {
260 // Read file
261 string t_line;
262 stringstream reformatCoeFile;
263 // Reformat file.
264 while (getline(coeFile, t_line)) {
265 // Remove all spaces
266 t_line.erase(remove_if(t_line.begin(), t_line.end(), ::isspace), t_line.end());
267 // Remove blank lines
268 if (t_line.size() == 0) continue;
269 // Remove all characters after ';'
270 size_t t_iFind = t_line.find(";");
271 if (t_iFind != string::npos) {
272 t_line.erase(t_iFind + 1, string::npos);
273 }
274 // Remove lines for comments
275 if (t_line == ";") continue;
276 // Combine lines until ';'
277 if (t_line.find(";") == string::npos) reformatCoeFile << t_line;
278 // Replace ';' with endl
279 else reformatCoeFile << t_line.substr(0, t_line.size() - 1) << endl;
280 }
281 // Process reformatted file.
282 //vector<string> keywords = {"memory_initialization_radix", "memory_initialization_vector"};
283 int t_radix = 0;
284 vector<string> t_rawData;
285 while (getline(reformatCoeFile, t_line)) {
286 //cout<<t_line<<endl;
287 // Find keywords
288 size_t t_iFind = t_line.find("=");
289 if (t_iFind != string::npos) {
290 // Find values for keywords
291 // Find radix
292 if (t_line.substr(0, t_iFind) == "memory_initialization_radix") {
293 //t_radix = t_line.substr(t_iFind+1, string::npos);
294 t_radix = atoi(t_line.substr(t_iFind + 1, string::npos).c_str());
295 } else if (t_line.substr(0, t_iFind) == "memory_initialization_vector") {
296 // Find data values
297 string t_dataLine = t_line.substr(t_iFind + 1, string::npos);
298 while (1) {
299 t_iFind = t_dataLine.find(",");
300 if (t_iFind != string::npos) {
301 t_rawData.push_back(t_dataLine.substr(0, t_iFind));
302 t_dataLine.erase(0, t_iFind + 1);
303 } else {
304 // last entry
305 t_rawData.push_back(t_dataLine);
306 break;
307 }
308 } // Finding data values loop
309 } else {
310 cout << "[Error] FpgaUtility::readCoe() => .coe format keyword is wrong. Aborting" << endl;
311 break;
312 } // End of finding values for keywords
313 } else {
314 cout << "[Error] FpgaUtility::readCoe() => .coe format is wrong. Needs keywords. Aborting" << endl;
315 break;
316 } // End of finding keywords
317 }
319 //for(auto it=t_rawData.begin(); it!=t_rawData.end(); it++){
320 // cout<<(*it)<<endl;
321 //}
322
323 // Clear data and set data size.
324 data.clear();
325 data.resize(t_rawData.size());
326
327 if (!twosComplement) {
328 for (int iData = 0; iData < int(t_rawData.size()); iData++) {
329 // Change string to float octal.
330 data[iData] = FpgaUtility::arbToDouble(t_rawData[iData], t_radix);
331 }
332 } else {
333 // Find number of bits in binary for data.
334 int nBits = t_rawData[0].size();
335 // Calculate max value.
336 int t_max = pow(t_radix, nBits) - 1;
337 // Calculate number of bits
338 nBits = floor(log(t_max) / log(2)) + 1;
339 for (int iData = 0; iData < int(t_rawData.size()); iData++) {
340 // Change to binary.
341 string t_binary = FpgaUtility::arbToArb(t_rawData[iData], t_radix, 2, nBits);
342 // Change to signed.
343 string t_signedBinary = FpgaUtility::twosComplementToSigned(t_binary);
344 // Change to float octal.
345 data[iData] = FpgaUtility::arbToDouble(t_signedBinary, 2);
346 }
347 } // End filling data.
349 //cout<<"LUT("<<inFilePath<<") data"<<endl;
350 //for(int iData=0; iData<int(data.size()); iData++){
351 // cout<<"["<<iData<<"] "<<data[iData]<<endl;
352 //}
353 }
354}
static std::string doubleToArb(double in, int outRadix, int numberOfDigits=-1)
Change octal to string.
Definition: FpgaUtility.cc:82
static void writeCoe(std::string outFilePath, int lutInBitsize, std::vector< signed long long > &data)
Writes a signal's values to a file in coe format.
Definition: FpgaUtility.cc:229
static double arbToDouble(std::string in, int inRadix)
Radix changing functions.
Definition: FpgaUtility.cc:60
static void writeSignals(std::string outFilePath, std::map< std::string, std::vector< signed long long > > &data)
COE file functions.
Definition: FpgaUtility.cc:202
static std::string arbToArb(const std::string &in, int inRadix, int outRadix, int numberOfDigits=-1)
Change string number to another string number depending on radix.
Definition: FpgaUtility.cc:114
static std::string twosComplementToSigned(std::string in)
Changes string two complements to string signed binary(-sign).
Definition: FpgaUtility.cc:163
static double roundInt(double value)
Round double value.
Definition: FpgaUtility.cc:38
static std::string signedToTwosComplement(std::string in, int numberOfDigits)
Changes string signed binary(-sign) to two complements.
Definition: FpgaUtility.cc:120
static void multipleWriteCoe(int lutInBitsize, std::map< std::string, std::vector< signed long long > > &data, const std::string &fileDirectory)
Writes multiple signal values to a file in coe format.
Definition: FpgaUtility.cc:220
static void readCoe(std::string inFilePath, std::vector< signed long long > &data, bool twoscomplement=0)
Reads a coe format file and stores the values in vector.
Definition: FpgaUtility.cc:251