bmv2
Designing your own switch target with bmv2
data.h
1 /* Copyright 2013-present Barefoot Networks, Inc.
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 /*
17  * Antonin Bas (antonin@barefootnetworks.com)
18  *
19  */
20 
22 
23 #ifndef BM_BM_SIM_DATA_H_
24 #define BM_BM_SIM_DATA_H_
25 
26 #include <iosfwd>
27 #include <string>
28 #include <type_traits>
29 #include <utility>
30 #include <vector>
31 
32 #include <cstring>
33 #include <cassert>
34 
35 #include "bignum.h"
36 #include "bytecontainer.h"
37 
38 namespace bm {
39 
40 using bignum::Bignum;
41 
59 class Data {
60  public:
61  Data() {}
62 
64  template<typename T,
65  typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
66  explicit Data(T i)
67  : value(i) {}
68 
70  Data(const char *bytes, int nbytes) {
71  bignum::import_bytes(&value, bytes, nbytes);
72  }
73 
74  virtual ~Data() { }
75 
76  static char char2digit(char c) {
77  if (c >= '0' && c <= '9')
78  return (c - '0');
79  if (c >= 'A' && c <= 'F')
80  return (c - 'A' + 10);
81  if (c >= 'a' && c <= 'f')
82  return (c - 'a' + 10);
83  assert(0);
84  return 0;
85  }
86 
91  explicit Data(const std::string &hexstring) {
92  set(hexstring);
93  }
94 
95  virtual void export_bytes() {}
96 
99  int sign() const { return value.sign(); }
100 
101  // TODO(Antonin): need to figure out what to do with signed values
103  template<typename T,
104  typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
105  void set(T i) {
106  value = i;
107  export_bytes();
108  }
109 
111  template<typename T,
112  typename std::enable_if<std::is_enum<T>::value, int>::type = 0>
113  void set(T i) {
114  value = static_cast<int>(i);
115  export_bytes();
116  }
117 
119  void set(const char *bytes, int nbytes) {
120  bignum::import_bytes(&value, bytes, nbytes);
121  export_bytes();
122  }
123 
125  void set(const Data &data) {
126  value = data.value;
127  export_bytes();
128  }
129 
130  void set(Data &&data) {
131  value = std::move(data.value);
132  export_bytes();
133  }
134 
135  void set(const ByteContainer &bc) {
136  bignum::import_bytes(&value, bc.data(), bc.size());
137  export_bytes();
138  }
139 
142  void
143 #if __GNUC__ == 5 && __GNUC_MINOR__ <= 2
144  // With g++-5.2, and when compiling with -O2, I sometimes get a segfault in
145  // this function (after calling mpz_import). I do not see anything wrong with
146  // this code and g++-4.8/9, as well as g++5.3, do not have this issue. I was
147  // not able to reproduce this bug with a simpler code sample (one without the
148  // bignum) and the assembly is too difficult for me to look at, so I am just
149  // going to blame it on the compiler and move on...
150  __attribute__((optimize("O0")))
151 #endif
152  set(const std::string &hexstring) {
153  std::vector<char> bytes;
154  size_t idx = 0;
155  bool neg = false;
156 
157  if (hexstring[idx] == '-') {
158  neg = true;
159  ++idx;
160  }
161  if (hexstring[idx] == '0' && hexstring[idx + 1] == 'x') {
162  idx += 2;
163  }
164  size_t size = hexstring.size();
165  assert((size - idx) > 0);
166 
167  if ((size - idx) % 2 != 0) {
168  char c = char2digit(hexstring[idx++]);
169  bytes.push_back(c);
170  }
171 
172  for (; idx < size; ) {
173  char c = char2digit(hexstring[idx++]) << 4;
174  c += char2digit(hexstring[idx++]);
175  bytes.push_back(c);
176  }
177 
178  bignum::import_bytes(&value, bytes.data(), bytes.size());
179  if (neg) value = -value;
180  export_bytes(); // not very efficient for fields, we import then export...
181  }
182 
184  template<typename T,
185  typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
186  T get() const {
187  assert(arith);
188  return value.convert_to<typename std::remove_const<T>::type>();
189  }
190 
192  unsigned int get_uint() const {
193  assert(arith);
194  return value.convert_to<unsigned int>();
195  }
196 
198  uint64_t get_uint64() const {
199  assert(arith);
200  return value.convert_to<uint64_t>();
201  }
202 
204  int get_int() const {
205  assert(arith);
206  return value.convert_to<int>();
207  }
208 
211  std::string get_string() const {
212  assert(arith);
213  const size_t export_size = bignum::export_size_in_bytes(value);
214  std::string s(export_size, '\x00');
215  // this is not technically correct, but works for all compilers
216  bignum::export_bytes(&s[0], export_size, value);
217  return s;
218  }
219 
220  std::string get_string_repr() const {
221  assert(arith);
222  return value.convert_to<std::string>();
223  }
224 
225  bool get_arith() const { return arith; }
226 
227  // TODO(antonin): overload operators for those ?
228 
230  void add(const Data &src1, const Data &src2) {
231  assert(src1.arith && src2.arith);
232  value = src1.value + src2.value;
233  export_bytes();
234  }
235 
237  void sub(const Data &src1, const Data &src2) {
238  assert(src1.arith && src2.arith);
239  value = src1.value - src2.value;
240  export_bytes();
241  }
242 
245  void mod(const Data &src1, const Data &src2) {
246  assert(src1.arith && src2.arith);
247  assert(src1.value >= 0 && src2.value > 0);
248  value = src1.value % src2.value;
249  export_bytes();
250  }
251 
254  void divide(const Data &src1, const Data &src2) {
255  assert(src1.arith && src2.arith);
256  assert(src1.value >= 0 && src2.value > 0);
257  value = src1.value / src2.value;
258  export_bytes();
259  }
260 
262  void multiply(const Data &src1, const Data &src2) {
263  assert(src1.arith && src2.arith);
264  value = src1.value * src2.value;
265  export_bytes();
266  }
267 
269  void shift_left(const Data &src1, const Data &src2) {
270  assert(src1.arith && src2.arith);
271  assert(src2.value >= 0);
272  value = src1.value << (src2.get_uint());
273  export_bytes();
274  }
275 
277  void shift_right(const Data &src1, const Data &src2) {
278  assert(src1.arith && src2.arith);
279  assert(src2.value >= 0);
280  value = src1.value >> (src2.get_uint());
281  export_bytes();
282  }
283 
285  void shift_left(const Data &src1, unsigned int src2) {
286  assert(src1.arith);
287  value = src1.value << src2;
288  export_bytes();
289  }
290 
292  void shift_right(const Data &src1, unsigned int src2) {
293  assert(src1.arith);
294  value = src1.value >> src2;
295  export_bytes();
296  }
297 
299  void bit_and(const Data &src1, const Data &src2) {
300  assert(src1.arith && src2.arith);
301  value = src1.value & src2.value;
302  export_bytes();
303  }
304 
306  void bit_or(const Data &src1, const Data &src2) {
307  assert(src1.arith && src2.arith);
308  value = src1.value | src2.value;
309  export_bytes();
310  }
311 
313  void bit_xor(const Data &src1, const Data &src2) {
314  assert(src1.arith && src2.arith);
315  value = src1.value ^ src2.value;
316  export_bytes();
317  }
318 
320  void bit_neg(const Data &src) {
321  assert(src.arith);
322  value = ~src.value;
323  export_bytes();
324  }
325 
328  void two_comp_mod(const Data &src, const Data &width) {
329  static const Bignum one(1);
330  unsigned int uwidth = width.get_uint();
331  Bignum mask = (one << uwidth) - 1;
332  Bignum max = (one << (uwidth - 1)) - 1;
333  Bignum min = -(one << (uwidth - 1));
334  if (src.value < min || src.value > max) {
335  value = src.value & mask;
336  if (value > max)
337  value -= (one << uwidth);
338  } else {
339  value = src.value;
340  }
341  export_bytes();
342  }
343 
347  void usat_cast(const Data &src, const Data &width) {
348  static const Bignum one(1);
349  unsigned int uwidth = width.get_uint();
350  Bignum max = (one << uwidth) - 1;
351  if (src.value > max)
352  value = max;
353  else if (src.value < 0)
354  value = 0;
355  else
356  value = src.value;
357  export_bytes();
358  }
359 
363  void sat_cast(const Data &src, const Data &width) {
364  static const Bignum one(1);
365  unsigned int uwidth = width.get_uint();
366  Bignum max = (one << (uwidth - 1)) - 1;
367  Bignum min = -(one << (uwidth - 1));
368  if (src.value > max)
369  value = max;
370  else if (src.value < min)
371  value = min;
372  else
373  value = src.value;
374  export_bytes();
375  }
376 
378  template<typename T,
379  typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
380  bool test_eq(T i) const {
381  return (value == i);
382  }
383 
385  friend bool operator==(const Data &lhs, const Data &rhs) {
386  assert(lhs.arith && rhs.arith);
387  return lhs.value == rhs.value;
388  }
389 
391  friend bool operator!=(const Data &lhs, const Data &rhs) {
392  assert(lhs.arith && rhs.arith);
393  return !(lhs == rhs);
394  }
395 
397  friend bool operator>(const Data &lhs, const Data &rhs) {
398  assert(lhs.arith && rhs.arith);
399  return lhs.value > rhs.value;
400  }
401 
403  friend bool operator>=(const Data &lhs, const Data &rhs) {
404  assert(lhs.arith && rhs.arith);
405  return lhs.value >= rhs.value;
406  }
407 
409  friend bool operator<(const Data &lhs, const Data &rhs) {
410  assert(lhs.arith && rhs.arith);
411  return lhs.value < rhs.value;
412  }
413 
415  friend bool operator<=(const Data &lhs, const Data &rhs) {
416  assert(lhs.arith && rhs.arith);
417  return lhs.value <= rhs.value;
418  }
419 
421  friend std::ostream& operator<<(std::ostream &out, const Data &d) {
422  assert(d.arith);
423  out << d.value;
424  return out;
425  }
426 
427  // Copy constructor
429  Data(const Data &other)
430  : arith(other.arith) {
431  if (other.arith) value = other.value;
432  }
433 
434  // Copy assignment operator
436  Data &operator=(const Data &other) {
437  Data tmp(other); // re-use copy-constructor
438  *this = std::move(tmp); // re-use move-assignment
439  return *this;
440  }
441 
443  Data(Data &&other) = default;
444 
446  Data &operator=(Data &&other) = default;
447 
448  protected:
449  Bignum value{0};
450  bool arith{true};
451 };
452 
453 } // namespace bm
454 
455 #endif // BM_BM_SIM_DATA_H_
bytecontainer.h
bm::ByteContainer::size
size_type size() const noexcept
Returns the number of bytes in the container.
Definition: bytecontainer.h:117