bmv2
Designing your own switch target with bmv2
Loading...
Searching...
No Matches
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
38namespace bm {
39
40using bignum::Bignum;
41
59class 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_