Belle II Software  release-08-01-10
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 
21 using std::cout;
22 using std::endl;
23 using std::vector;
24 using std::map;
25 using std::string;
26 using std::stringstream;
27 using std::bitset;
28 using std::ifstream;
29 using std::ofstream;
30 using std::ceil;
31 using std::floor;
32 using std::fmod;
33 using std::pow;
34 using std::log;
35 
36 
37 // Rounds value to an integer.
38 double 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].
60 double 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.
82 string 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.
114 string 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.
120 string 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.
163 std::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.
202 void 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.
220 void 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 
229 void 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 
251 void 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