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