LDMX Software
ap_fixed_base.h
1/*
2 * Copyright 2011-2019 Xilinx, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef __AP_FIXED_BASE_H__
18#define __AP_FIXED_BASE_H__
19
20#ifndef __AP_FIXED_H__
21#error "Only ap_fixed.h and ap_int.h can be included directly in user code."
22#endif
23
24// for ap_int_base and its reference types.
25#include <ap_int.h>
26#ifndef __SYNTHESIS__
27#if _AP_ENABLE_HALF_ == 1
28// for half type
29#include <hls_half.h>
30#endif
31// for std io
32#include <iostream>
33#endif
34
35#ifndef __cplusplus
36#error "C++ is required to include this header file"
37#else // __cplusplus
38
39// for warning on unsupported rounding mode in conversion to float/double.
40#if !defined(__SYNTHESIS__) && __cplusplus >= 201103L && \
41 (defined(__gnu_linux__) || defined(_WIN32))
42#define AP_FIXED_ENABLE_CPP_FENV 1
43#include <cfenv>
44#endif
45
46// ----------------------------------------------------------------------
47
48/* Major TODO
49 long double support: constructor, assign and other operators.
50 binary operators with ap_fixed_base and const char*.
51 return ap_fixed/ap_ufixed when result signedness is known.
52*/
53
54// Helper function in conversion to floating point types.
55
56#ifdef __SYNTHESIS__
57#define _AP_ctype_op_get_bit(var, index) _AP_ROOT_op_get_bit(var, index)
58#define _AP_ctype_op_set_bit(var, index, x) _AP_ROOT_op_set_bit(var, index, x)
59#define _AP_ctype_op_get_range(var, low, high) \
60 _AP_ROOT_op_get_range(var, low, high)
61#define _AP_ctype_op_set_range(var, low, high, x) \
62 _AP_ROOT_op_set_range(var, low, high, x)
63#else // ifdef __SYNTHESIS__
64template <typename _Tp1, typename _Tp2>
65inline bool _AP_ctype_op_get_bit(_Tp1& var, const _Tp2& index) {
66 return !!(var & (1ull << (index)));
67}
68template <typename _Tp1, typename _Tp2, typename _Tp3>
69inline _Tp1 _AP_ctype_op_set_bit(_Tp1& var, const _Tp2& index, const _Tp3& x) {
70 var |= (((x) ? 1ull : 0ull) << (index));
71 return var;
72}
73template <typename _Tp1, typename _Tp2, typename _Tp3>
74inline _Tp1 _AP_ctype_op_get_range(_Tp1& var, const _Tp2& low,
75 const _Tp3& high) {
76 _Tp1 r = var;
77 ap_ulong mask = -1ll;
78 mask >>= (sizeof(_Tp1) * 8 - ((high) - (low) + 1));
79 r >>= (low);
80 r &= mask;
81 return r;
82}
83template <typename _Tp1, typename _Tp2, typename _Tp3, typename _Tp4>
84inline _Tp1 _AP_ctype_op_set_range(_Tp1& var, const _Tp2& low, const _Tp3& high,
85 const _Tp4& x) {
86 ap_ulong mask = -1ll;
87 mask >>= (_AP_SIZE_ap_slong - ((high) - (low) + 1));
88 var &= ~(mask << (low));
89 var |= ((mask & x) << (low));
90 return var;
91}
92#endif // ifdef __SYNTHESIS__
93
94// trait for letting base class to return derived class.
95// Notice that derived class template is incomplete, and we cannot use
96// the member of the derived class.
97template <int _AP_W2, int _AP_I2, bool _AP_S2>
98struct _ap_fixed_factory;
99template <int _AP_W2, int _AP_I2>
100struct _ap_fixed_factory<_AP_W2, _AP_I2, true> {
101 typedef ap_fixed<_AP_W2, _AP_I2> type;
102};
103template <int _AP_W2, int _AP_I2>
104struct _ap_fixed_factory<_AP_W2, _AP_I2, false> {
105 typedef ap_ufixed<_AP_W2, _AP_I2> type;
106};
107
109
117// default for _AP_Q, _AP_O and _AP_N set in ap_decl.h
118template <int _AP_W, int _AP_I, bool _AP_S, ap_q_mode _AP_Q, ap_o_mode _AP_O,
119 int _AP_N>
120struct ap_fixed_base : _AP_ROOT_TYPE<_AP_W, _AP_S> {
121 public:
122 typedef _AP_ROOT_TYPE<_AP_W, _AP_S> Base;
123 static const int width = _AP_W;
124 static const int iwidth = _AP_I;
125 static const ap_q_mode qmode = _AP_Q;
126 static const ap_o_mode omode = _AP_O;
127
129 template <int _AP_W2, int _AP_I2, bool _AP_S2>
130 struct RType {
131 enum {
132 _AP_F = _AP_W - _AP_I,
133 F2 = _AP_W2 - _AP_I2,
134 mult_w = _AP_W + _AP_W2,
135 mult_i = _AP_I + _AP_I2,
136 mult_s = _AP_S || _AP_S2,
137 plus_w = AP_MAX(_AP_I + (_AP_S2 && !_AP_S), _AP_I2 + (_AP_S && !_AP_S2)) +
138 1 + AP_MAX(_AP_F, F2),
139 plus_i =
140 AP_MAX(_AP_I + (_AP_S2 && !_AP_S), _AP_I2 + (_AP_S && !_AP_S2)) + 1,
141 plus_s = _AP_S || _AP_S2,
142 minus_w =
143 AP_MAX(_AP_I + (_AP_S2 && !_AP_S), _AP_I2 + (_AP_S && !_AP_S2)) + 1 +
144 AP_MAX(_AP_F, F2),
145 minus_i =
146 AP_MAX(_AP_I + (_AP_S2 && !_AP_S), _AP_I2 + (_AP_S && !_AP_S2)) + 1,
147 minus_s = true,
148#ifndef __SC_COMPATIBLE__
149 div_w = _AP_S2 + _AP_W + AP_MAX(F2, 0),
150#else
151 div_w = _AP_S2 + _AP_W + AP_MAX(F2, 0) + AP_MAX(_AP_I2, 0),
152#endif
153 div_i = _AP_S2 + _AP_I + F2,
154 div_s = _AP_S || _AP_S2,
155 logic_w =
156 AP_MAX(_AP_I + (_AP_S2 && !_AP_S), _AP_I2 + (_AP_S && !_AP_S2)) +
157 AP_MAX(_AP_F, F2),
158 logic_i = AP_MAX(_AP_I + (_AP_S2 && !_AP_S), _AP_I2 + (_AP_S && !_AP_S2)),
159 logic_s = _AP_S || _AP_S2
160 };
161
164
169 typedef ap_fixed_base<div_w, div_i, div_s> div_base;
170 typedef ap_fixed_base<_AP_W, _AP_I, _AP_S> arg1_base;
171
172 typedef typename _ap_fixed_factory<mult_w, mult_i, mult_s>::type mult;
173 typedef typename _ap_fixed_factory<plus_w, plus_i, plus_s>::type plus;
174 typedef typename _ap_fixed_factory<minus_w, minus_i, minus_s>::type minus;
175 typedef typename _ap_fixed_factory<logic_w, logic_i, logic_s>::type logic;
176 typedef typename _ap_fixed_factory<div_w, div_i, div_s>::type div;
177 typedef typename _ap_fixed_factory<_AP_W, _AP_I, _AP_S>::type arg1;
178 };
179
180 private:
181#ifndef __SYNTHESIS__
182 // This cannot handle hex float format string.
183 void fromString(const std::string& val, unsigned char radix) {
184 _AP_ERROR(!(radix == 2 || radix == 8 || radix == 10 || radix == 16),
185 "ap_fixed_base::fromString(%s, %d)", val.c_str(), radix);
186
187 Base::V = 0;
188 int startPos = 0;
189 int endPos = val.length();
190 int decPos = val.find(".");
191 if (decPos == -1) decPos = endPos;
192
193 // handle sign
194 bool isNegative = false;
195 if (val[0] == '-') {
196 isNegative = true;
197 ++startPos;
198 } else if (val[0] == '+')
199 ++startPos;
200
201 // If there are no integer bits, e.g.:
202 // .0000XXXX, then keep at least one bit.
203 // If the width is greater than the number of integer bits, e.g.:
204 // XXXX.XXXX, then we keep the integer bits
205 // if the number of integer bits is greater than the width, e.g.:
206 // XXX000 then we keep the integer bits.
207 // Always keep one bit.
208 ap_fixed_base<AP_MAX(_AP_I, 4) + 4, AP_MAX(_AP_I, 4) + 4, false>
209 integer_bits = 0;
210
211 // Figure out if we can shift instead of multiply
212 unsigned shift = (radix == 16 ? 4 : radix == 8 ? 3 : radix == 2 ? 1 : 0);
213
214 // std::cout << "\n\n" << val << "\n";
215 // std::cout << startPos << " " << decPos << " " << endPos << "\n";
216
217 bool sticky_int = false;
218
219 // Traverse the integer digits from the MSD, multiplying by radix as we go.
220 for (int i = startPos; i < decPos; i++) {
221 // Get a digit
222 char cdigit = val[i];
223 if (cdigit == '\0') continue;
224 unsigned digit = ap_private_ops::decode_digit(cdigit, radix);
225
226 sticky_int |= integer_bits[AP_MAX(_AP_I, 4) + 4 - 1] |
227 integer_bits[AP_MAX(_AP_I, 4) + 4 - 2] |
228 integer_bits[AP_MAX(_AP_I, 4) + 4 - 3] |
229 integer_bits[AP_MAX(_AP_I, 4) + 4 - 4];
230 // Shift or multiply the value by the radix
231 if (shift)
232 integer_bits <<= shift;
233 else
234 integer_bits *= radix;
235
236 // Add in the digit we just interpreted
237 integer_bits += digit;
238 // std::cout << "idigit = " << digit << " " << integer_bits.to_string()
239 // << " " << sticky_int << "\n";
240 }
241 integer_bits[AP_MAX(_AP_I, 4) + 4 - 3] =
242 integer_bits[AP_MAX(_AP_I, 4) + 4 - 3] | sticky_int;
243
244 ap_fixed_base<AP_MAX(_AP_W - _AP_I, 0) + 4 + 4, 4, false> fractional_bits =
245 0;
246 bool sticky = false;
247
248 // Traverse the fractional digits from the LSD, dividing by radix as we go.
249 for (int i = endPos - 1; i >= decPos + 1; i--) {
250 // Get a digit
251 char cdigit = val[i];
252 if (cdigit == '\0') continue;
253 unsigned digit = ap_private_ops::decode_digit(cdigit, radix);
254 // Add in the digit we just interpreted
255 fractional_bits += digit;
256
257 sticky |= fractional_bits[0] | fractional_bits[1] | fractional_bits[2] |
258 fractional_bits[3];
259 // Shift or divide the value by the radix
260 if (shift)
261 fractional_bits >>= shift;
262 else
263 fractional_bits /= radix;
264
265 // std::cout << "fdigit = " << digit << " " << fractional_bits.to_string()
266 // << " " << sticky << "\n";
267 }
268
269 // std::cout << "Int =" << integer_bits.to_string() << " " <<
270 // fractional_bits.to_string() << "\n";
271
272 fractional_bits[0] = fractional_bits[0] | sticky;
273
274 if (isNegative)
275 *this = -(integer_bits + fractional_bits);
276 else
277 *this = integer_bits + fractional_bits;
278
279 // std::cout << "end = " << this->to_string(16) << "\n";
280 }
281
283 INLINE void report() {
284 if (!_AP_S && _AP_O == AP_WRAP_SM) {
285 fprintf(stderr, "ap_ufxied<...> cannot support AP_WRAP_SM.\n");
286 exit(1);
287 }
288 if (_AP_W > MAX_MODE(AP_INT_MAX_W) * 1024) {
289 fprintf(stderr,
290 "[E] ap_%sfixed<%d, ...>: Bitwidth exceeds the "
291 "default max value %d. Please use macro "
292 "AP_INT_MAX_W to set a larger max value.\n",
293 _AP_S ? "" : "u", _AP_W, MAX_MODE(AP_INT_MAX_W) * 1024);
294 exit(1);
295 }
296 }
297#else
298 INLINE void report() {}
299#endif // ifdef __SYNTHESIS__
300
302 // @{
303 INLINE void overflow_adjust(bool underflow, bool overflow, bool lD,
304 bool sign) {
305 if (!underflow && !overflow) return;
306 if (_AP_O == AP_WRAP) {
307 if (_AP_N == 0) return;
308 if (_AP_S) {
309 // signed AP_WRAP
310 // n_bits == 1
311 Base::V = _AP_ROOT_op_set_bit(Base::V, _AP_W - 1, sign);
312 if (_AP_N > 1) {
313 // n_bits > 1
315 if (sign) mask.V = 0;
316 Base::V =
317 _AP_ROOT_op_set_range(Base::V, _AP_W - _AP_N, _AP_W - 2, mask.V);
318 }
319 } else {
320 // unsigned AP_WRAP
322 Base::V =
323 _AP_ROOT_op_set_range(Base::V, _AP_W - _AP_N, _AP_W - 1, mask.V);
324 }
325 } else if (_AP_O == AP_SAT_ZERO) {
326 Base::V = 0;
327 } else if (_AP_O == AP_WRAP_SM && _AP_S) {
328 bool Ro = _AP_ROOT_op_get_bit(Base::V, _AP_W - 1);
329 if (_AP_N == 0) {
330 if (lD != Ro) {
331 Base::V = ~Base::V;
332 Base::V = _AP_ROOT_op_set_bit(Base::V, _AP_W - 1, lD);
333 }
334 } else {
335 if (_AP_N == 1 && sign != Ro) {
336 Base::V = ~Base::V;
337 } else if (_AP_N > 1) {
338 bool lNo = _AP_ROOT_op_get_bit(Base::V, _AP_W - _AP_N);
339 if (lNo == sign) Base::V = ~Base::V;
341 if (sign) mask.V = 0;
342 Base::V =
343 _AP_ROOT_op_set_range(Base::V, _AP_W - _AP_N, _AP_W - 2, mask.V);
344 }
345 Base::V = _AP_ROOT_op_set_bit(Base::V, _AP_W - 1, sign);
346 }
347 } else {
348 if (_AP_S) {
349 if (overflow) {
350 Base::V = 1;
351 Base::V <<= _AP_W - 1;
352 Base::V = ~Base::V;
353 } else if (underflow) {
354 Base::V = 1;
355 Base::V <<= _AP_W - 1;
356 if (_AP_O == AP_SAT_SYM) Base::V |= 1;
357 }
358 } else {
359 if (overflow)
360 Base::V = ~(ap_int_base<_AP_W, false>(0).V);
361 else if (underflow)
362 Base::V = 0;
363 }
364 }
365 }
366
367 INLINE bool quantization_adjust(bool qb, bool r, bool s) {
368 bool carry = (bool)_AP_ROOT_op_get_bit(Base::V, _AP_W - 1);
369 if (_AP_Q == AP_TRN) return false;
370 if (_AP_Q == AP_RND_ZERO)
371 qb &= s || r;
372 else if (_AP_Q == AP_RND_MIN_INF)
373 qb &= r;
374 else if (_AP_Q == AP_RND_INF)
375 qb &= !s || r;
376 else if (_AP_Q == AP_RND_CONV)
377 qb &= _AP_ROOT_op_get_bit(Base::V, 0) || r;
378 else if (_AP_Q == AP_TRN_ZERO)
379 qb = s && (qb || r);
380 Base::V += qb;
381 return carry && (!(bool)_AP_ROOT_op_get_bit(Base::V, _AP_W - 1));
382 }
383 // @}
384
385 public:
387 // @{
389 INLINE ap_fixed_base() {}
390
392 template <int _AP_W2, int _AP_I2, bool _AP_S2, ap_q_mode _AP_Q2,
393 ap_o_mode _AP_O2, int _AP_N2>
394 INLINE ap_fixed_base(
396 operator=(op);
397 report();
398 }
399
400 template <int _AP_W2, int _AP_I2, bool _AP_S2, ap_q_mode _AP_Q2,
401 ap_o_mode _AP_O2, int _AP_N2>
402 INLINE ap_fixed_base(const volatile ap_fixed_base<
403 _AP_W2, _AP_I2, _AP_S2, _AP_Q2, _AP_O2, _AP_N2>& op) {
404 operator=(op);
405 report();
406 }
407
408 template <int _AP_W2, bool _AP_S2>
411 tmp.V = op.V;
412 operator=(tmp);
413 report();
414 }
415
416 template <int _AP_W2, bool _AP_S2>
417 INLINE ap_fixed_base(const volatile ap_int_base<_AP_W2, _AP_S2>& op) {
419 tmp.V = op.V;
420 operator=(tmp);
421 report();
422 }
423
424#ifndef __SYNTHESIS__
425#ifndef NON_C99STRING
426 INLINE ap_fixed_base(const char* s, signed char rd = 0) {
427 unsigned char radix = rd;
428 std::string str =
429 ap_private_ops::parseString(s, radix); // will guess rd, default 10
430 _AP_ERROR(radix == 0,
431 "ap_fixed_base(const char* \"%s\", %d), str=%s, radix = %d", s,
432 rd, str.c_str(), radix); // TODO remove this check
433 fromString(str, radix);
434 }
435#else
436 INLINE ap_fixed_base(const char* s, signed char rd = 10) {
438 Base::V = t.V;
439 }
440#endif // ifndef NON_C99STRING
441#else // ifndef __SYNTHESIS__
442 // XXX _ssdm_string2bits only takes const string and const radix.
443 // It seems XFORM will do compile time processing of the string.
444 INLINE ap_fixed_base(const char* s) {
445 typeof(Base::V) t;
446 _ssdm_string2bits((void*)(&t), (const char*)(s), 10, _AP_I, _AP_S, _AP_Q,
447 _AP_O, _AP_N, _AP_C99);
448 Base::V = t;
449 }
450 INLINE ap_fixed_base(const char* s, signed char rd) {
451 typeof(Base::V) t;
452 _ssdm_string2bits((void*)(&t), (const char*)(s), rd, _AP_I, _AP_S, _AP_Q,
453 _AP_O, _AP_N, _AP_C99);
454 Base::V = t;
455 }
456#endif // ifndef __SYNTHESIS__ else
457
458 template <int _AP_W2, bool _AP_S2>
459 INLINE ap_fixed_base(const ap_bit_ref<_AP_W2, _AP_S2>& op) {
460 *this = ((bool)op);
461 report();
462 }
463
464 template <int _AP_W2, bool _AP_S2>
466 *this = (ap_int_base<_AP_W2, false>(op));
467 report();
468 }
469
470 template <int _AP_W2, typename _AP_T2, int _AP_W3, typename _AP_T3>
471 INLINE ap_fixed_base(
474 report();
475 }
476
477 template <int _AP_W2, int _AP_I2, bool _AP_S2, ap_q_mode _AP_Q2,
478 ap_o_mode _AP_O2, int _AP_N2>
479 INLINE ap_fixed_base(
481 *this = (bool(op));
482 report();
483 }
484
485 template <int _AP_W2, int _AP_I2, bool _AP_S2, ap_q_mode _AP_Q2,
486 ap_o_mode _AP_O2, int _AP_N2>
487 INLINE ap_fixed_base(
489 *this = (ap_int_base<_AP_W2, false>(op));
490 report();
491 }
492
493 // ctors from c types.
494 // make a temp ap_fixed_base first, and use ap_fixed_base.operator=
495#define CTOR_FROM_INT(C_TYPE, _AP_W2, _AP_S2) \
496 INLINE ap_fixed_base(const C_TYPE x) { \
497 ap_fixed_base<(_AP_W2), (_AP_W2), (_AP_S2)> tmp; \
498 tmp.V = x; \
499 *this = tmp; \
500 }
501
502 CTOR_FROM_INT(bool, 1, false)
503 CTOR_FROM_INT(char, 8, CHAR_IS_SIGNED)
504 CTOR_FROM_INT(signed char, 8, true)
505 CTOR_FROM_INT(unsigned char, 8, false)
506 CTOR_FROM_INT(short, _AP_SIZE_short, true)
507 CTOR_FROM_INT(unsigned short, _AP_SIZE_short, false)
508 CTOR_FROM_INT(int, _AP_SIZE_int, true)
509 CTOR_FROM_INT(unsigned int, _AP_SIZE_int, false)
510 CTOR_FROM_INT(long, _AP_SIZE_long, true)
511 CTOR_FROM_INT(unsigned long, _AP_SIZE_long, false)
512 CTOR_FROM_INT(ap_slong, _AP_SIZE_ap_slong, true)
513 CTOR_FROM_INT(ap_ulong, _AP_SIZE_ap_slong, false)
514#undef CTOR_FROM_INT
515 /*
516 * TODO:
517 *Theere used to be several funtions which were AP_WEAK.
518 *Now they're all INLINE expect ap_fixed_base(double d)
519 *Maybe we can use '#pragma HLS inline' instead of INLINE.
520 */
521 AP_WEAK ap_fixed_base(double d) {
523 ireg.V = doubleToRawBits(d);
524 bool isneg = _AP_ROOT_op_get_bit(ireg.V, 63);
525
528 exp_tmp.V =
529 _AP_ROOT_op_get_range(ireg.V, DOUBLE_MAN, DOUBLE_MAN + DOUBLE_EXP - 1);
530 exp = exp_tmp - DOUBLE_BIAS;
532 man.V = _AP_ROOT_op_get_range(ireg.V, 0, DOUBLE_MAN - 1);
533 // do not support NaN
534 _AP_WARNING(exp == APFX_IEEE_DOUBLE_E_MAX + 1 && man.V != 0,
535 "assign NaN to fixed point value");
536 man.V = _AP_ROOT_op_set_bit(man.V, DOUBLE_MAN, 1);
537 if (isneg) man = -man;
538 if ((ireg.V & 0x7fffffffffffffffLL) == 0) {
539 Base::V = 0;
540 } else {
541 int _AP_W2 = DOUBLE_MAN + 2, _AP_I2 = exp.V + 2, _AP_F = _AP_W - _AP_I,
542 F2 = _AP_W2 - _AP_I2;
543 bool _AP_S2 = true,
544 QUAN_INC = F2 > _AP_F &&
545 !(_AP_Q == AP_TRN || (_AP_Q == AP_TRN_ZERO && !_AP_S2));
546 bool carry = false;
547 // handle quantization
548 unsigned sh_amt = (F2 > _AP_F) ? F2 - _AP_F : _AP_F - F2;
549 if (F2 == _AP_F)
550 Base::V = man.V;
551 else if (F2 > _AP_F) {
552 if (sh_amt < DOUBLE_MAN + 2)
553 Base::V = man.V >> sh_amt;
554 else {
555 Base::V = isneg ? -1 : 0;
556 }
557 if ((_AP_Q != AP_TRN) && !((_AP_Q == AP_TRN_ZERO) && !_AP_S2)) {
558 bool qb = (F2 - _AP_F > _AP_W2)
559 ? isneg
560 : (bool)_AP_ROOT_op_get_bit(man.V, F2 - _AP_F - 1);
561 bool r = (F2 > _AP_F + 1)
562 ? _AP_ROOT_op_get_range(man.V, 0,
563 (F2 - _AP_F - 2 < _AP_W2)
564 ? (F2 - _AP_F - 2)
565 : (_AP_W2 - 1)) != 0
566 : false;
567 carry = quantization_adjust(qb, r, isneg);
568 }
569 } else { // no quantization
570 Base::V = man.V;
571 if (sh_amt < _AP_W)
572 Base::V = Base::V << sh_amt;
573 else
574 Base::V = 0;
575 }
576 // handle overflow/underflow
577 if ((_AP_O != AP_WRAP || _AP_N != 0) &&
578 ((!_AP_S && _AP_S2) ||
579 _AP_I - _AP_S <
580 _AP_I2 - _AP_S2 +
581 (QUAN_INC ||
582 (_AP_S2 && (_AP_O == AP_SAT_SYM))))) { // saturation
583 bool deleted_zeros = _AP_S2 ? true : !carry, deleted_ones = true;
584 bool neg_src = isneg;
585 bool lD = false;
586 int pos1 = F2 - _AP_F + _AP_W;
587 int pos2 = F2 - _AP_F + _AP_W + 1;
588 bool newsignbit = _AP_ROOT_op_get_bit(Base::V, _AP_W - 1);
589 if (pos1 < _AP_W2 && pos1 >= 0)
590 // lD = _AP_ROOT_op_get_bit(man.V, pos1);
591 lD = (man.V >> pos1) & 1;
592 if (pos1 < _AP_W2) {
593 bool Range1_all_ones = true;
594 bool Range1_all_zeros = true;
595 bool Range2_all_ones = true;
598
599 if (pos2 >= 0 && pos2 < _AP_W2) {
600 // Range2.V = _AP_ROOT_op_get_range(man.V,
601 // pos2, _AP_W2 - 1);
602 Range2.V = man.V;
603 Range2.V >>= pos2;
604 Range2_all_ones = Range2 == (all_ones >> pos2);
605 } else if (pos2 < 0)
606 Range2_all_ones = false;
607 if (pos1 >= 0 && pos2 < _AP_W2) {
608 Range1_all_ones = Range2_all_ones && lD;
609 Range1_all_zeros = !Range2.V && !lD;
610 } else if (pos2 == _AP_W2) {
611 Range1_all_ones = lD;
612 Range1_all_zeros = !lD;
613 } else if (pos1 < 0) {
614 Range1_all_zeros = !man.V;
615 Range1_all_ones = false;
616 }
617
618 deleted_zeros =
619 deleted_zeros && (carry ? Range1_all_ones : Range1_all_zeros);
620 deleted_ones =
621 carry ? Range2_all_ones && (pos1 < 0 || !lD) : Range1_all_ones;
622 neg_src = isneg && !(carry && Range1_all_ones);
623 } else
624 neg_src = isneg && newsignbit;
625 bool neg_trg = _AP_S && newsignbit;
626 bool overflow = (neg_trg || !deleted_zeros) && !isneg;
627 bool underflow = (!neg_trg || !deleted_ones) && neg_src;
628 if ((_AP_O == AP_SAT_SYM) && _AP_S2 && _AP_S)
629 underflow |= neg_src && (_AP_W > 1 ? _AP_ROOT_op_get_range(
630 Base::V, 0, _AP_W - 2) == 0
631 : true);
632 overflow_adjust(underflow, overflow, lD, neg_src);
633 }
634 }
635 report();
636 }
637
638 // TODO more optimized implementation.
639 INLINE ap_fixed_base(float d) { *this = ap_fixed_base(double(d)); }
640
641#if _AP_ENABLE_HALF_ == 1
642 // TODO more optimized implementation.
643 INLINE ap_fixed_base(half d) { *this = ap_fixed_base(double(d)); }
644#endif
645 // @}
646
649 /*
650 INLINE ap_fixed_base& operator=(
651 const ap_fixed_base<_AP_W, _AP_I, _AP_S, _AP_Q, _AP_O, _AP_N>& op) {
652 Base::V = op.V;
653 return *this;
654 }
655 */
656
657 template <int _AP_W2, int _AP_I2, bool _AP_S2, ap_q_mode _AP_Q2,
658 ap_o_mode _AP_O2, int _AP_N2>
659 INLINE ap_fixed_base& operator=(
661 const int _AP_F = _AP_W - _AP_I;
662 const int F2 = _AP_W2 - _AP_I2;
663 const int QUAN_INC =
664 F2 > _AP_F && !(_AP_Q == AP_TRN || (_AP_Q == AP_TRN_ZERO && !_AP_S2));
665
666 if (!op) Base::V = 0;
667 bool carry = false;
668 bool signbit = _AP_ROOT_op_get_bit(op.V, _AP_W2 - 1);
669 bool isneg = signbit && _AP_S2;
670 if (F2 == _AP_F)
671 Base::V = op.V;
672 else if (F2 > _AP_F) {
673 unsigned int sh_amt = F2 - _AP_F;
674 // moves bits right, handle quantization.
675 if (sh_amt < _AP_W2) {
676 Base::V = op.V >> sh_amt;
677 } else {
678 Base::V = isneg ? -1 : 0;
679 }
680 if (_AP_Q != AP_TRN && !(_AP_Q == AP_TRN_ZERO && !_AP_S2)) {
681 bool qbit = _AP_ROOT_op_get_bit(op.V, F2 - _AP_F - 1);
682 // bit after LSB.
683 bool qb = (F2 - _AP_F > _AP_W2) ? _AP_S2 && signbit : qbit;
684 enum {
685 hi = ((F2 - _AP_F - 2) < _AP_W2) ? (F2 - _AP_F - 2) : (_AP_W2 - 1)
686 };
687 // bits after qb.
688 bool r = (F2 > _AP_F + 1) ? (_AP_ROOT_op_get_range(op.V, 0, hi) != 0)
689 : false;
690 carry = quantization_adjust(qb, r, isneg);
691 }
692 } else {
693 unsigned sh_amt = _AP_F - F2;
694 // moves bits left, no quantization
695 if (sh_amt < _AP_W) {
696 if (_AP_W > _AP_W2) {
697 // extend and then shift, avoid losing bits.
698 Base::V = op.V;
699 Base::V <<= sh_amt;
700 } else {
701 // shift and truncate.
702 Base::V = op.V << sh_amt;
703 }
704 } else {
705 Base::V = 0;
706 }
707 }
708 // handle overflow/underflow
709 if ((_AP_O != AP_WRAP || _AP_N != 0) &&
710 ((!_AP_S && _AP_S2) ||
711 _AP_I - _AP_S <
712 _AP_I2 - _AP_S2 +
713 (QUAN_INC ||
714 (_AP_S2 && _AP_O == AP_SAT_SYM)))) { // saturation
715 bool deleted_zeros = _AP_S2 ? true : !carry;
716 bool deleted_ones = true;
717 bool neg_src = isneg;
718 bool newsignbit = _AP_ROOT_op_get_bit(Base::V, _AP_W - 1);
719 enum { pos1 = F2 - _AP_F + _AP_W, pos2 = F2 - _AP_F + _AP_W + 1 };
720 bool lD = (pos1 < _AP_W2 && pos1 >= 0) ? _AP_ROOT_op_get_bit(op.V, pos1)
721 : false;
722 if (pos1 < _AP_W2) {
723 bool Range1_all_ones = true;
724 bool Range1_all_zeros = true;
725 bool Range2_all_ones = true;
726 ap_int_base<_AP_W2, false> all_ones(-1);
727
728 if (pos2 < _AP_W2 && pos2 >= 0) {
730 Range2.V = _AP_ROOT_op_get_range(op.V, pos2, _AP_W2 - 1);
731 Range2_all_ones = Range2 == (all_ones >> pos2);
732 } else if (pos2 < 0) {
733 Range2_all_ones = false;
734 }
735
736 if (pos1 >= 0 && pos2 < _AP_W2) {
738 Range1.V = _AP_ROOT_op_get_range(op.V, pos1, _AP_W2 - 1);
739 Range1_all_ones = Range1 == (all_ones >> pos1);
740 Range1_all_zeros = !Range1.V;
741 } else if (pos2 == _AP_W2) {
742 Range1_all_ones = lD;
743 Range1_all_zeros = !lD;
744 } else if (pos1 < 0) {
745 Range1_all_zeros = !op.V;
746 Range1_all_ones = false;
747 }
748
749 deleted_zeros =
750 deleted_zeros && (carry ? Range1_all_ones : Range1_all_zeros);
751 deleted_ones =
752 carry ? Range2_all_ones && (pos1 < 0 || !lD) : Range1_all_ones;
753 neg_src = isneg && !(carry && Range1_all_ones);
754 } else
755 neg_src = isneg && newsignbit;
756 bool neg_trg = _AP_S && newsignbit;
757 bool overflow = (neg_trg || !deleted_zeros) && !isneg;
758 bool underflow = (!neg_trg || !deleted_ones) && neg_src;
759 if ((_AP_O == AP_SAT_SYM) && _AP_S2 && _AP_S)
760 underflow |= neg_src && (_AP_W > 1 ? _AP_ROOT_op_get_range(
761 Base::V, 0, _AP_W - 2) == 0
762 : true);
763
764 overflow_adjust(underflow, overflow, lD, neg_src);
765 }
766 return *this;
767 } // operator=
768
769 template <int _AP_W2, int _AP_I2, bool _AP_S2, ap_q_mode _AP_Q2,
770 ap_o_mode _AP_O2, int _AP_N2>
771 INLINE ap_fixed_base& operator=(
772 const volatile ap_fixed_base<_AP_W2, _AP_I2, _AP_S2, _AP_Q2, _AP_O2,
773 _AP_N2>& op) {
774 operator=(const_cast<const ap_fixed_base<_AP_W2, _AP_I2, _AP_S2, _AP_Q2,
775 _AP_O2, _AP_N2>&>(op));
776 return *this;
777 }
778
780 INLINE ap_fixed_base& setBits(ap_ulong bv) {
781 // TODO when ull is not be long enough...
782 Base::V = bv;
783 return *this;
784 }
785
787 static INLINE ap_fixed_base bitsToFixed(ap_ulong bv) {
788 // TODO fix when ull is not be long enough...
790#ifdef __SYNTHESIS__
791 t.V = bv;
792#else
793 t.V.set_bits(bv);
794#endif
795 return t;
796 }
797
798 // Explicit conversion functions to ap_int_base.
802 INLINE ap_int_base<AP_MAX(_AP_I, 1), _AP_S> to_ap_int_base(
803 bool Cnative = true) const {
804 ap_int_base<AP_MAX(_AP_I, 1), _AP_S> ret;
805 if (_AP_I == 0) {
806 ret.V = 0;
807 } else if (_AP_I > 0 && _AP_I <= _AP_W) {
808 ret.V = _AP_ROOT_op_get_range(Base::V, _AP_W - _AP_I, _AP_W - 1);
809 } else if (_AP_I > _AP_W) {
810 ret.V = _AP_ROOT_op_get_range(Base::V, 0, _AP_W - 1);
811 ret.V <<= (_AP_I - _AP_W);
812 }
813 /* Consider the following case
814 * float f = -7.5f;
815 * ap_fixed<8,4> t = f; // -8 0 0 0 . 0.5
816 * int i = t.to_int();
817 * the result should be -7 instead of -8.
818 * Therefore, after truncation, the value should be increated by 1.
819 * For (-1, 0), carry to MSB will happen, but result 0 is still correct.
820 */
821 if (Cnative && _AP_I < _AP_W) {
822 // Follow C native data type, conversion from double to int
823 if (_AP_S && _AP_ROOT_op_get_bit(Base::V, _AP_W - 1) && (_AP_I < _AP_W) &&
824 (_AP_ROOT_op_get_range(
825 Base::V, 0, _AP_I < 0 ? _AP_W - 1 : _AP_W - _AP_I - 1) != 0))
826 ++ret;
827 } else {
828 // Follow OSCI library, conversion from sc_fixed to sc_int
829 }
830 return ret;
831 };
832
833 public:
834 template <int _AP_W2, bool _AP_S2>
835 INLINE operator ap_int_base<_AP_W2, _AP_S2>() const {
836 return ap_int_base<_AP_W2, _AP_S2>(to_ap_int_base());
837 }
838
839 // Explicit conversion function to C built-in integral type.
840 INLINE char to_char() const { return to_ap_int_base().to_char(); }
841
842 INLINE int to_int() const { return to_ap_int_base().to_int(); }
843
844 INLINE unsigned to_uint() const { return to_ap_int_base().to_uint(); }
845
846 INLINE ap_slong to_int64() const { return to_ap_int_base().to_int64(); }
847
848 INLINE ap_ulong to_uint64() const { return to_ap_int_base().to_uint64(); }
849
851
852 INLINE double to_double() const {
853#if defined(AP_FIXED_ENABLE_CPP_FENV)
854 _AP_WARNING(std::fegetround() != FE_TONEAREST,
855 "Only FE_TONEAREST is supported");
856#endif
857 enum { BITS = DOUBLE_MAN + DOUBLE_EXP + 1 };
858 if (!Base::V) return 0.0f;
859 bool s = _AP_S && _AP_ROOT_op_get_bit(Base::V, _AP_W - 1);
861 if (s)
862 tmp.V = -Base::V; // may truncate one bit extra from neg in sim.
863 else
864 tmp.V = Base::V;
865 int l = tmp.countLeadingZeros();
866 int e = _AP_I - l - 1 + DOUBLE_BIAS;
867 int lsb_index = _AP_W - l - 1 - DOUBLE_MAN;
868 // more than 0.5?
869 bool a = (lsb_index >= 2)
870 ? (_AP_ROOT_op_get_range(tmp.V, 0, lsb_index - 2) != 0)
871 : 0;
872 // round to even
873 a |= (lsb_index >= 0) ? _AP_ROOT_op_get_bit(tmp.V, lsb_index) : 0;
874 // ull is at least 64-bit
875 ap_ulong m;
876 // may actually left shift, ensure buffer is wide enough.
877 if (_AP_W > BITS) {
878 m = (lsb_index >= 1) ? (ap_ulong)(tmp.V >> (lsb_index - 1))
879 : (ap_ulong)(tmp.V << (1 - lsb_index));
880 } else {
881 m = (ap_ulong)tmp.V;
882 m = (lsb_index >= 1) ? (m >> (lsb_index - 1)) : (m << (1 - lsb_index));
883 }
884 m += a;
885 m >>= 1;
886 // std::cout << '\n' << std::hex << m << '\n'; // TODO delete this
887 // carry to MSB, increase exponent
888 if (_AP_ctype_op_get_bit(m, DOUBLE_MAN + 1)) {
889 e += 1;
890 }
891 // set sign and exponent
892 m = _AP_ctype_op_set_bit(m, BITS - 1, s);
893 // std::cout << m << '\n'; // TODO delete this
894 m = _AP_ctype_op_set_range(m, DOUBLE_MAN, DOUBLE_MAN + DOUBLE_EXP - 1, e);
895 // std::cout << std::hex << m << std::dec << std::endl; // TODO delete this
896 // cast to fp
897 return rawBitsToDouble(m);
898 }
899
901
902 INLINE float to_float() const {
903#if defined(AP_FIXED_ENABLE_CPP_FENV)
904 _AP_WARNING(std::fegetround() != FE_TONEAREST,
905 "Only FE_TONEAREST is supported");
906#endif
907 enum { BITS = FLOAT_MAN + FLOAT_EXP + 1 };
908 if (!Base::V) return 0.0f;
909 bool s = _AP_S && _AP_ROOT_op_get_bit(Base::V, _AP_W - 1);
911 if (s)
912 tmp.V = -Base::V; // may truncate one bit extra from neg in sim.
913 else
914 tmp.V = Base::V;
915 int l = tmp.countLeadingZeros();
916 int e = _AP_I - l - 1 + FLOAT_BIAS;
917 int lsb_index = _AP_W - l - 1 - FLOAT_MAN;
918 // more than 0.5?
919 bool a = (lsb_index >= 2)
920 ? (_AP_ROOT_op_get_range(tmp.V, 0, lsb_index - 2) != 0)
921 : 0;
922 // round to even
923 a |= (lsb_index >= 0) ? _AP_ROOT_op_get_bit(tmp.V, lsb_index) : 0;
924 // ul is at least 32-bit
925 unsigned long m;
926 // may actually left shift, ensure buffer is wide enough.
927 if (_AP_W > BITS) {
928 m = (lsb_index >= 1) ? (unsigned long)(tmp.V >> (lsb_index - 1))
929 : (unsigned long)(tmp.V << (1 - lsb_index));
930 } else {
931 m = (unsigned long)tmp.V;
932 m = (lsb_index >= 1) ? (m >> (lsb_index - 1)) : (m << (1 - lsb_index));
933 }
934 m += a;
935 m >>= 1;
936 // carry to MSB, increase exponent
937 if (_AP_ctype_op_get_bit(m, FLOAT_MAN + 1)) {
938 e += 1;
939 }
940 // set sign and exponent
941 m = _AP_ctype_op_set_bit(m, BITS - 1, s);
942 m = _AP_ctype_op_set_range(m, FLOAT_MAN, FLOAT_MAN + FLOAT_EXP - 1, e);
943 // cast to fp
944 return rawBitsToFloat(m);
945 }
946
947#if _AP_ENABLE_HALF_ == 1
949
950 INLINE half to_half() const {
951#if defined(AP_FIXED_ENABLE_CPP_FENV)
952 _AP_WARNING(std::fegetround() != FE_TONEAREST,
953 "Only FE_TONEAREST is supported");
954#endif
955 enum {BITS = HALF_MAN + HALF_EXP + 1};
956 if (!Base::V) return 0.0f;
957 bool s = _AP_S && _AP_ROOT_op_get_bit(Base::V, _AP_W - 1);
959 if (s)
960 tmp.V = -Base::V; // may truncate one bit extra from neg in sim.
961 else
962 tmp.V = Base::V;
963 int l = tmp.countLeadingZeros();
964 int e = _AP_I - l - 1 + HALF_BIAS;
965 int lsb_index = _AP_W - l - 1 - HALF_MAN;
966 // more than 0.5?
967 bool a = (lsb_index >= 2)
968 ? (_AP_ROOT_op_get_range(tmp.V, 0, lsb_index - 2) != 0)
969 : 0;
970 // round to even
971 a |= (lsb_index >= 0) ? _AP_ROOT_op_get_bit(tmp.V, lsb_index) : 0;
972 // short is at least 16-bit
973 unsigned short m;
974 // may actually left shift, ensure buffer is wide enough.
975 if (_AP_W > BITS) {
976 m = (lsb_index >= 1) ? (unsigned short)(tmp.V >> (lsb_index - 1))
977 : (unsigned short)(tmp.V << (1 - lsb_index));
978 } else {
979 m = (unsigned short)tmp.V;
980 m = (lsb_index >= 1) ? (m >> (lsb_index - 1)) : (m << (1 - lsb_index));
981 }
982 m += a;
983 m >>= 1;
984 // carry to MSB, increase exponent
985 if (_AP_ctype_op_get_bit(m, HALF_MAN + 1)) {
986 e += 1;
987 }
988 // set sign and exponent
989 m = _AP_ctype_op_set_bit(m, BITS - 1, s);
990 m = _AP_ctype_op_set_range(m, HALF_MAN, HALF_MAN + HALF_EXP - 1, e);
991 // cast to fp
992 return rawBitsToHalf(m);
993 }
994#endif
995
996 // FIXME inherited from old code, this may loose precision!
997 INLINE operator long double() const { return (long double)to_double(); }
998
999 INLINE operator double() const { return to_double(); }
1000
1001 INLINE operator float() const { return to_float(); }
1002
1003#if _AP_ENABLE_HALF_ == 1
1004 INLINE operator half() const { return to_half(); }
1005#endif
1006
1007 INLINE operator bool() const { return (bool)Base::V != 0; }
1008
1009 INLINE operator char() const { return (char)to_int(); }
1010
1011 INLINE operator signed char() const { return (signed char)to_int(); }
1012
1013 INLINE operator unsigned char() const { return (unsigned char)to_uint(); }
1014
1015 INLINE operator short() const { return (short)to_int(); }
1016
1017 INLINE operator unsigned short() const { return (unsigned short)to_uint(); }
1018
1019 INLINE operator int() const { return to_int(); }
1020
1021 INLINE operator unsigned int() const { return to_uint(); }
1022
1023// FIXME don't assume data width...
1024#ifdef __x86_64__
1025 INLINE operator long() const { return (long)to_int64(); }
1026
1027 INLINE operator unsigned long() const { return (unsigned long)to_uint64(); }
1028#else
1029 INLINE operator long() const { return (long)to_int(); }
1030
1031 INLINE operator unsigned long() const { return (unsigned long)to_uint(); }
1032#endif // ifdef __x86_64__ else
1033
1034 INLINE operator ap_ulong() const { return to_uint64(); }
1035
1036 INLINE operator ap_slong() const { return to_int64(); }
1037
1038 INLINE int length() const { return _AP_W; };
1039
1040 // bits_to_int64 deleted.
1041#ifndef __SYNTHESIS__
1042 // Used in autowrap, when _AP_W < 64.
1043 INLINE ap_ulong bits_to_uint64() const { return (Base::V).to_uint64(); }
1044#endif
1045
1046 // Count the number of zeros from the most significant bit
1047 // to the first one bit. Note this is only for ap_fixed_base whose
1048 // _AP_W <= 64, otherwise will incur assertion.
1049 INLINE int countLeadingZeros() {
1050#ifdef __SYNTHESIS__
1051 // TODO: used llvm.ctlz intrinsic ?
1052 if (_AP_W <= 32) {
1053 ap_int_base<32, false> t(-1ULL);
1054 t.range(_AP_W - 1, 0) = this->range(0, _AP_W - 1);
1055 return __builtin_ctz(t.V);
1056 } else if (_AP_W <= 64) {
1057 ap_int_base<64, false> t(-1ULL);
1058 t.range(_AP_W - 1, 0) = this->range(0, _AP_W - 1);
1059 return __builtin_ctzll(t.V);
1060 } else {
1061 enum {__N = (_AP_W + 63) / 64};
1062 int NZeros = 0;
1063 int i = 0;
1064 bool hitNonZero = false;
1065 for (i = 0; i < __N - 1; ++i) {
1067 t.range(0, 63) = this->range(_AP_W - i * 64 - 64, _AP_W - i * 64 - 1);
1068 NZeros += hitNonZero ? 0 : __builtin_clzll(t.V);
1069 hitNonZero |= (t != 0);
1070 }
1071 if (!hitNonZero) {
1072 ap_int_base<64, false> t(-1ULL);
1073 t.range(63 - (_AP_W - 1) % 64, 63) = this->range(0, (_AP_W - 1) % 64);
1074 NZeros += __builtin_clzll(t.V);
1075 }
1076 return NZeros;
1077 }
1078#else
1079 return Base::V.countLeadingZeros();
1080#endif
1081 }
1082
1083 // Arithmetic : Binary
1084 // -------------------------------------------------------------------------
1085 template <int _AP_W2, int _AP_I2, bool _AP_S2, ap_q_mode _AP_Q2,
1086 ap_o_mode _AP_O2, int _AP_N2>
1087 INLINE typename RType<_AP_W2, _AP_I2, _AP_S2>::mult operator*(
1089 const {
1090 typename RType<_AP_W2, _AP_I2, _AP_S2>::mult_base r, t;
1091 r.V = Base::V;
1092 t.V = op2.V;
1093 r.V *= op2.V;
1094 return r;
1095 }
1096
1097 // multiply function deleted.
1098
1099 template <int _AP_W2, int _AP_I2, bool _AP_S2, ap_q_mode _AP_Q2,
1100 ap_o_mode _AP_O2, int _AP_N2>
1101 INLINE typename RType<_AP_W2, _AP_I2, _AP_S2>::div operator/(
1103 const {
1104 typename RType<_AP_W2, _AP_I2, _AP_S2>::div_base r;
1105#ifndef __SYNTHESIS__
1106 enum {F2 = _AP_W2 - _AP_I2,
1107 _W1 = AP_MAX(_AP_W + AP_MAX(F2, 0) + ((_AP_S2 && !_AP_S) ? 1 : 0),
1108 _AP_W2 + ((_AP_S && !_AP_S2) ? 1 : 0))};
1109 ap_int_base<_W1, _AP_S || _AP_S2> dividend, divisior;
1112 tmp1.V = Base::V;
1113 tmp1.V <<= AP_MAX(F2, 0);
1114 tmp2.V = op2.V;
1115 dividend = tmp1;
1116 divisior = tmp2;
1117 r.V = ((_AP_S || _AP_S2) ? dividend.V.sdiv(divisior.V)
1118 : dividend.V.udiv(divisior.V));
1119#else
1120#ifndef __SC_COMPATIBLE__
1121 ap_fixed_base<_AP_W + AP_MAX(_AP_W2 - _AP_I2, 0), _AP_I, _AP_S> t(*this);
1122#else
1123 ap_fixed_base<_AP_W + AP_MAX(_AP_W2 - _AP_I2, 0) + AP_MAX(_AP_I2, 0), _AP_I,
1124 _AP_S>
1125 t(*this);
1126#endif
1127 r.V = t.V / op2.V;
1128#endif
1129 /*
1130 enum {
1131 F2 = _AP_W2 - _AP_I2,
1132 shl = AP_MAX(F2, 0) + AP_MAX(_AP_I2, 0),
1133 #ifndef __SC_COMPATIBLE__
1134 shr = AP_MAX(_AP_I2, 0),
1135 #else
1136 shr = 0,
1137 #endif
1138 W3 = _AP_S2 + _AP_W + shl,
1139 S3 = _AP_S || _AP_S2,
1140 };
1141 ap_int_base<W3, S3> dividend, t;
1142 dividend.V = Base::V;
1143 // multiply both by (1 << F2), and than do integer division.
1144 dividend.V <<= (int) shl;
1145 #ifdef __SYNTHESIS__
1146 // .V's have right signedness, and will have right extending.
1147 t.V = dividend.V / op2.V;
1148 #else
1149 // XXX op2 may be wider than dividend, and sdiv and udiv takes the same
1150 with
1151 // as left hand operand, so data might be truncated by mistake if not
1152 // handled here.
1153 t.V = S3 ? dividend.V.sdiv(op2.V) : dividend.V.udiv(op2.V);
1154 #endif
1155 r.V = t.V >> (int) shr;
1156 */
1157 return r;
1158 }
1159
1160#define OP_BIN_AF(Sym, Rty) \
1161 template <int _AP_W2, int _AP_I2, bool _AP_S2, ap_q_mode _AP_Q2, \
1162 ap_o_mode _AP_O2, int _AP_N2> \
1163 INLINE typename RType<_AP_W2, _AP_I2, _AP_S2>::Rty operator Sym( \
1164 const ap_fixed_base<_AP_W2, _AP_I2, _AP_S2, _AP_Q2, _AP_O2, _AP_N2>& \
1165 op2) const { \
1166 typename RType<_AP_W2, _AP_I2, _AP_S2>::Rty##_base ret, lhs(*this), \
1167 rhs(op2); \
1168 ret.V = lhs.V Sym rhs.V; \
1169 return ret; \
1170 }
1171
1172 OP_BIN_AF(+, plus)
1173 OP_BIN_AF(-, minus)
1174 OP_BIN_AF(&, logic)
1175 OP_BIN_AF(|, logic)
1176 OP_BIN_AF(^, logic)
1177
1178// Arithmetic : assign
1179// -------------------------------------------------------------------------
1180#define OP_ASSIGN_AF(Sym) \
1181 template <int _AP_W2, int _AP_I2, bool _AP_S2, ap_q_mode _AP_Q2, \
1182 ap_o_mode _AP_O2, int _AP_N2> \
1183 INLINE ap_fixed_base& operator Sym##=( \
1184 const ap_fixed_base<_AP_W2, _AP_I2, _AP_S2, _AP_Q2, _AP_O2, _AP_N2>& \
1185 op2) { \
1186 *this = operator Sym(op2); \
1187 return *this; \
1188 }
1189
1190 OP_ASSIGN_AF(*)
1191 OP_ASSIGN_AF(/)
1192 OP_ASSIGN_AF(+)
1193 OP_ASSIGN_AF(-)
1194 OP_ASSIGN_AF(&)
1195 OP_ASSIGN_AF(|)
1196 OP_ASSIGN_AF(^)
1197
1198 // Prefix and postfix increment and decrement.
1199 // -------------------------------------------------------------------------
1200
1202 INLINE ap_fixed_base& operator++() {
1204 return *this;
1205 }
1206
1208 INLINE ap_fixed_base& operator--() {
1210 return *this;
1211 }
1212
1214 INLINE const ap_fixed_base operator++(int) {
1215 ap_fixed_base r(*this);
1216 operator++();
1217 return r;
1218 }
1219
1221 INLINE const ap_fixed_base operator--(int) {
1222 ap_fixed_base r(*this);
1223 operator--();
1224 return r;
1225 }
1226
1227 // Unary arithmetic.
1228 // -------------------------------------------------------------------------
1229 INLINE ap_fixed_base operator+() { return *this; }
1230
1231 INLINE ap_fixed_base<_AP_W + 1, _AP_I + 1, true> operator-() const {
1233 r.V = -r.V;
1234 return r;
1235 }
1236
1239 r.V = -r.V;
1240 return r;
1241 }
1242
1243 // Not (!)
1244 // -------------------------------------------------------------------------
1245 INLINE bool operator!() const { return Base::V == 0; }
1246
1247 // Bitwise complement
1248 // -------------------------------------------------------------------------
1249 // XXX different from Mentor's ac_fixed.
1250 INLINE ap_fixed_base<_AP_W, _AP_I, _AP_S> operator~() const {
1252 r.V = ~Base::V;
1253 return r;
1254 }
1255
1256 // Shift
1257 // -------------------------------------------------------------------------
1258 // left shift is the same as moving point right, i.e. increate I.
1259 template <int _AP_SHIFT>
1262 r.V = Base::V;
1263 return r;
1264 }
1265
1266 template <int _AP_SHIFT>
1267 INLINE ap_fixed_base<_AP_W, _AP_I - _AP_SHIFT, _AP_S> rshift() const {
1268 ap_fixed_base<_AP_W, _AP_I - _AP_SHIFT, _AP_S> r;
1269 r.V = Base::V;
1270 return r;
1271 }
1272
1273 // Because the return type is the type of the the first operand, shift assign
1274 // operators do not carry out any quantization or overflow
1275 // While systemc, shift assigns for sc_fixed/sc_ufixed will result in
1276 // quantization or overflow (depending on the mode of the first operand)
1277 INLINE ap_fixed_base operator<<(unsigned int sh) const {
1278 ap_fixed_base r;
1279 r.V = Base::V << sh;
1280// TODO check shift overflow?
1281#ifdef __SC_COMPATIBLE__
1282 if (sh == 0) return r;
1283 if (_AP_O != AP_WRAP || _AP_N != 0) {
1284 bool neg_src = _AP_S && _AP_ROOT_op_get_bit(Base::V, _AP_W - 1);
1285 bool allones, allzeros;
1287 if (sh <= _AP_W) {
1289 range1.V = _AP_ROOT_op_get_range(
1290 const_cast<ap_fixed_base*>(this)->Base::V, _AP_W - sh, _AP_W - 1);
1291 allones = range1 == (ones >> (_AP_W - sh));
1292 allzeros = range1 == 0;
1293 } else {
1294 allones = false;
1295 allzeros = Base::V == 0;
1296 }
1297 bool overflow = !allzeros && !neg_src;
1298 bool underflow = !allones && neg_src;
1299 if ((_AP_O == AP_SAT_SYM) && _AP_S)
1300 underflow |=
1301 neg_src &&
1302 (_AP_W > 1 ? _AP_ROOT_op_get_range(r.V, 0, _AP_W - 2) == 0 : true);
1303 bool lD = false;
1304 if (sh < _AP_W) lD = _AP_ROOT_op_get_bit(Base::V, _AP_W - sh - 1);
1305 r.overflow_adjust(underflow, overflow, lD, neg_src);
1306 }
1307#endif
1308 return r;
1309 }
1310
1311 INLINE ap_fixed_base operator>>(unsigned int sh) const {
1312 ap_fixed_base r;
1313 r.V = Base::V >> sh;
1314// TODO check shift overflow?
1315#ifdef __SC_COMPATIBLE__
1316 if (sh == 0) return r;
1317 if (_AP_Q != AP_TRN) {
1318 bool qb = false;
1319 if (sh <= _AP_W) qb = _AP_ROOT_op_get_bit(Base::V, sh - 1);
1320 bool rb = false;
1321 if (sh > 1 && sh <= _AP_W)
1322 rb = _AP_ROOT_op_get_range(const_cast<ap_fixed_base*>(this)->Base::V, 0,
1323 sh - 2) != 0;
1324 else if (sh > _AP_W)
1325 rb = Base::V != 0;
1326 r.quantization_adjust(qb, rb,
1327 _AP_S && _AP_ROOT_op_get_bit(Base::V, _AP_W - 1));
1328 }
1329#endif
1330 return r;
1331 }
1332
1333 // left and right shift for int
1334 INLINE ap_fixed_base operator<<(int sh) const {
1335 ap_fixed_base r;
1336 bool isNeg = sh < 0;
1337 unsigned int ush = isNeg ? -sh : sh;
1338 if (isNeg) {
1339 return operator>>(ush);
1340 } else {
1341 return operator<<(ush);
1342 }
1343 }
1344
1345 INLINE ap_fixed_base operator>>(int sh) const {
1346 bool isNeg = sh < 0;
1347 unsigned int ush = isNeg ? -sh : sh;
1348 if (isNeg) {
1349 return operator<<(ush);
1350 } else {
1351 return operator>>(ush);
1352 }
1353 }
1354
1355 // left and right shift for ap_int.
1356 template <int _AP_W2>
1357 INLINE ap_fixed_base operator<<(const ap_int_base<_AP_W2, true>& op2) const {
1358 // TODO the code seems not optimal. ap_fixed<8,8> << ap_int<2> needs only a
1359 // small mux, but integer need a big one!
1360 int sh = op2.to_int();
1361 return operator<<(sh);
1362 }
1363
1364 template <int _AP_W2>
1365 INLINE ap_fixed_base operator>>(const ap_int_base<_AP_W2, true>& op2) const {
1366 int sh = op2.to_int();
1367 return operator>>(sh);
1368 }
1369
1370 // left and right shift for ap_uint.
1371 template <int _AP_W2>
1372 INLINE ap_fixed_base operator<<(const ap_int_base<_AP_W2, false>& op2) const {
1373 unsigned int sh = op2.to_uint();
1374 return operator<<(sh);
1375 }
1376
1377 template <int _AP_W2>
1378 INLINE ap_fixed_base operator>>(const ap_int_base<_AP_W2, false>& op2) const {
1379 unsigned int sh = op2.to_uint();
1380 return operator>>(sh);
1381 }
1382
1383 // left and right shift for ap_fixed
1384 template <int _AP_W2, int _AP_I2, bool _AP_S2, ap_q_mode _AP_Q2,
1385 ap_o_mode _AP_O2, int _AP_N2>
1386 INLINE ap_fixed_base operator<<(
1388 op2) {
1389 return operator<<(op2.to_ap_int_base());
1390 }
1391
1392 template <int _AP_W2, int _AP_I2, bool _AP_S2, ap_q_mode _AP_Q2,
1393 ap_o_mode _AP_O2, int _AP_N2>
1394 INLINE ap_fixed_base operator>>(
1396 op2) {
1397 return operator>>(op2.to_ap_int_base());
1398 }
1399
1400 // Shift assign.
1401 // -------------------------------------------------------------------------
1402
1403 // left shift assign.
1404 INLINE ap_fixed_base& operator<<=(const int sh) {
1405 *this = operator<<(sh);
1406 return *this;
1407 }
1408
1409 INLINE ap_fixed_base& operator<<=(const unsigned int sh) {
1410 *this = operator<<(sh);
1411 return *this;
1412 }
1413
1414 template <int _AP_W2, bool _AP_S2>
1415 INLINE ap_fixed_base& operator<<=(const ap_int_base<_AP_W2, _AP_S2>& sh) {
1416 *this = operator<<(sh.to_int());
1417 return *this;
1418 }
1419
1420 template <int _AP_W2, int _AP_I2, bool _AP_S2, ap_q_mode _AP_Q2,
1421 ap_o_mode _AP_O2, int _AP_N2>
1422 INLINE ap_fixed_base& operator<<=(
1424 *this = operator<<(sh.to_int());
1425 return *this;
1426 }
1427
1428 // right shift assign.
1429 INLINE ap_fixed_base& operator>>=(const int sh) {
1430 *this = operator>>(sh);
1431 return *this;
1432 }
1433
1434 INLINE ap_fixed_base& operator>>=(const unsigned int sh) {
1435 *this = operator>>(sh);
1436 return *this;
1437 }
1438
1439 template <int _AP_W2, bool _AP_S2>
1440 INLINE ap_fixed_base& operator>>=(const ap_int_base<_AP_W2, _AP_S2>& sh) {
1441 *this = operator>>(sh.to_int());
1442 return *this;
1443 }
1444
1445 template <int _AP_W2, int _AP_I2, bool _AP_S2, ap_q_mode _AP_Q2,
1446 ap_o_mode _AP_O2, int _AP_N2>
1447 INLINE ap_fixed_base& operator>>=(
1449 *this = operator>>(sh.to_int());
1450 return *this;
1451 }
1452
1453// Comparisons.
1454// -------------------------------------------------------------------------
1455#define OP_CMP_AF(Sym) \
1456 template <int _AP_W2, int _AP_I2, bool _AP_S2, ap_q_mode _AP_Q2, \
1457 ap_o_mode _AP_O2, int _AP_N2> \
1458 INLINE bool operator Sym(const ap_fixed_base<_AP_W2, _AP_I2, _AP_S2, _AP_Q2, \
1459 _AP_O2, _AP_N2>& op2) const { \
1460 enum { _AP_F = _AP_W - _AP_I, F2 = _AP_W2 - _AP_I2 }; \
1461 if (_AP_F == F2) \
1462 return Base::V Sym op2.V; \
1463 else if (_AP_F > F2) \
1464 return Base::V Sym ap_fixed_base<AP_MAX(_AP_W2 + _AP_F - F2, 1), _AP_I2, \
1465 _AP_S2, _AP_Q2, _AP_O2, _AP_N2>(op2) \
1466 .V; \
1467 else \
1468 return ap_fixed_base<AP_MAX(_AP_W + F2 - _AP_F + 1, 1), _AP_I + 1, \
1469 _AP_S, _AP_Q, _AP_O, _AP_N>(*this) \
1470 .V Sym op2.V; \
1471 return false; \
1472 }
1473
1474 OP_CMP_AF(>)
1475 OP_CMP_AF(<)
1476 OP_CMP_AF(>=)
1477 OP_CMP_AF(<=)
1478 OP_CMP_AF(==)
1479 OP_CMP_AF(!=)
1480// FIXME: Move compare with double out of struct ap_fixed_base defination
1481// and combine it with compare operator(double, ap_fixed_base)
1482#define DOUBLE_CMP_AF(Sym) \
1483 INLINE bool operator Sym(double d) const { return to_double() Sym d; }
1484
1485 DOUBLE_CMP_AF(>)
1486 DOUBLE_CMP_AF(<)
1487 DOUBLE_CMP_AF(>=)
1488 DOUBLE_CMP_AF(<=)
1489 DOUBLE_CMP_AF(==)
1490 DOUBLE_CMP_AF(!=)
1491
1492 // Bit and Slice Select
1493 INLINE af_bit_ref<_AP_W, _AP_I, _AP_S, _AP_Q, _AP_O, _AP_N> operator[](
1494 unsigned index) {
1495 _AP_WARNING(index >= _AP_W, "Attempting to read bit beyond MSB");
1497 }
1498
1499 template <int _AP_W2, bool _AP_S2>
1501 const ap_int_base<_AP_W2, _AP_S2>& index) {
1502 _AP_WARNING(index < 0, "Attempting to read bit with negative index");
1503 _AP_WARNING(index >= _AP_W, "Attempting to read bit beyond MSB");
1505 index.to_int());
1506 }
1507
1508 INLINE bool operator[](unsigned index) const {
1509 _AP_WARNING(index >= _AP_W, "Attempting to read bit beyond MSB");
1510 return _AP_ROOT_op_get_bit(const_cast<ap_fixed_base*>(this)->V, index);
1511 }
1512
1514 unsigned index) {
1515 _AP_WARNING(index >= _AP_W, "Attempting to read bit beyond MSB");
1517 }
1518
1519 template <int _AP_W2, bool _AP_S2>
1521 const ap_int_base<_AP_W2, _AP_S2>& index) {
1522 _AP_WARNING(index < 0, "Attempting to read bit with negative index");
1523 _AP_WARNING(index >= _AP_W, "Attempting to read bit beyond MSB");
1525 index.to_int());
1526 }
1527
1528 INLINE bool bit(unsigned index) const {
1529 _AP_WARNING(index >= _AP_W, "Attempting to read bit beyond MSB");
1530 return _AP_ROOT_op_get_bit(const_cast<ap_fixed_base*>(this)->V, index);
1531 }
1532
1533 template <int _AP_W2>
1535 const ap_int_base<_AP_W2, true>& index) {
1536 _AP_WARNING(index < _AP_I - _AP_W,
1537 "Attempting to read bit with negative index");
1538 _AP_WARNING(index >= _AP_I, "Attempting to read bit beyond MSB");
1540 this, index.to_int() + _AP_W - _AP_I);
1541 }
1542
1543 INLINE bool get_bit(int index) const {
1544 _AP_WARNING(index >= _AP_I, "Attempting to read bit beyond MSB");
1545 _AP_WARNING(index < _AP_I - _AP_W, "Attempting to read bit beyond MSB");
1546 return _AP_ROOT_op_get_bit(const_cast<ap_fixed_base*>(this)->V,
1547 index + _AP_W - _AP_I);
1548 }
1549#if 0
1551 int index) {
1552 _AP_WARNING(index < _AP_I - _AP_W,
1553 "Attempting to read bit with negative index");
1554 _AP_WARNING(index >= _AP_I, "Attempting to read bit beyond MSB");
1556 this, index + _AP_W - _AP_I);
1557 }
1558#endif
1559
1560 template <int _AP_W2>
1561 INLINE bool get_bit(const ap_int_base<_AP_W2, true>& index) const {
1562 _AP_WARNING(index >= _AP_I, "Attempting to read bit beyond MSB");
1563 _AP_WARNING(index < _AP_I - _AP_W, "Attempting to read bit beyond MSB");
1564 return _AP_ROOT_op_get_bit(const_cast<ap_fixed_base*>(this)->V,
1565 index.to_int() + _AP_W - _AP_I);
1566 }
1567
1569 int Lo) {
1570 _AP_WARNING((Hi >= _AP_W) || (Lo >= _AP_W), "Out of bounds in range()");
1572 }
1573
1574 // This is a must to strip constness to produce reference type.
1576 int Hi, int Lo) const {
1577 _AP_WARNING((Hi >= _AP_W) || (Lo >= _AP_W), "Out of bounds in range()");
1579 const_cast<ap_fixed_base*>(this), Hi, Lo);
1580 }
1581
1582 template <int _AP_W2, bool _AP_S2, int _AP_W3, bool _AP_S3>
1584 const ap_int_base<_AP_W2, _AP_S2>& HiIdx,
1585 const ap_int_base<_AP_W3, _AP_S3>& LoIdx) {
1586 int Hi = HiIdx.to_int();
1587 int Lo = LoIdx.to_int();
1588 return this->range(Hi, Lo);
1589 }
1590
1591 template <int _AP_W2, bool _AP_S2, int _AP_W3, bool _AP_S3>
1593 const ap_int_base<_AP_W2, _AP_S2>& HiIdx,
1594 const ap_int_base<_AP_W3, _AP_S3>& LoIdx) const {
1595 int Hi = HiIdx.to_int();
1596 int Lo = LoIdx.to_int();
1597 return this->range(Hi, Lo);
1598 }
1599
1601 return this->range(_AP_W - 1, 0);
1602 }
1603
1605 return this->range(_AP_W - 1, 0);
1606 }
1607
1609 int Hi, int Lo) {
1610 return this->range(Hi, Lo);
1611 }
1612
1614 int Hi, int Lo) const {
1615 return this->range(Hi, Lo);
1616 }
1617
1618 template <int _AP_W2, bool _AP_S2, int _AP_W3, bool _AP_S3>
1620 const ap_int_base<_AP_W2, _AP_S2>& HiIdx,
1621 const ap_int_base<_AP_W3, _AP_S3>& LoIdx) {
1622 int Hi = HiIdx.to_int();
1623 int Lo = LoIdx.to_int();
1624 return this->range(Hi, Lo);
1625 }
1626
1627 template <int _AP_W2, bool _AP_S2, int _AP_W3, bool _AP_S3>
1629 const ap_int_base<_AP_W2, _AP_S2>& HiIdx,
1630 const ap_int_base<_AP_W3, _AP_S3>& LoIdx) const {
1631 int Hi = HiIdx.to_int();
1632 int Lo = LoIdx.to_int();
1633 return this->range(Hi, Lo);
1634 }
1635
1636 INLINE bool is_zero() const { return Base::V == 0; }
1637
1638 INLINE bool is_neg() const {
1639 if (_AP_S && _AP_ROOT_op_get_bit(Base::V, _AP_W - 1)) return true;
1640 return false;
1641 }
1642
1643 INLINE int wl() const { return _AP_W; }
1644
1645 INLINE int iwl() const { return _AP_I; }
1646
1647 INLINE ap_q_mode q_mode() const { return _AP_Q; }
1648
1649 INLINE ap_o_mode o_mode() const { return _AP_O; }
1650
1651 INLINE int n_bits() const { return _AP_N; }
1652
1653 // print a string representation of this number in the given radix.
1654 // Radix support is 2, 8, 10, or 16.
1655 // The result will include a prefix indicating the radix, except for decimal,
1656 // where no prefix is needed. The default is to output a signed
1657 // representation of signed numbers, or an unsigned representation of
1658 // unsigned numbers. For non-decimal formats, this can be changed by the
1659 // 'sign' argument.
1660#ifndef __SYNTHESIS__
1661 std::string to_string(unsigned char radix = 2, bool sign = _AP_S) const {
1662 // XXX in autosim/autowrap.tcl "(${name}).to_string(2).c_str()" is used to
1663 // initialize sc_lv, which seems incapable of handling format "-0b".
1664 if (radix == 2) sign = false;
1665
1666 std::string str;
1667 str.clear();
1668 char step = 0;
1669 bool isNeg = sign && (Base::V < 0);
1670
1671 // Extend to take care of the -MAX case.
1673 if (isNeg) {
1674 tmp = -tmp;
1675 str += '-';
1676 }
1677 std::string prefix;
1678 switch (radix) {
1679 case 2:
1680 prefix = "0b";
1681 step = 1;
1682 break;
1683 case 8:
1684 prefix = "0o";
1685 step = 3;
1686 break;
1687 case 16:
1688 prefix = "0x";
1689 step = 4;
1690 break;
1691 default:
1692 break;
1693 }
1694
1695 if (_AP_I > 0) {
1696 // Note we drop the quantization and rounding flags here. The
1697 // integer part is always in range, and the fractional part we
1698 // want to drop. Also, the number is always positive, because
1699 // of the absolute value above.
1700 ap_int_base<AP_MAX(_AP_I + 1, 1), false> int_part;
1701 // [1] [ I ] d [ W - I ]
1702 // | | |
1703 // | W-I 0
1704 // W
1705 int_part.V = _AP_ROOT_op_get_range(tmp.V, _AP_W - _AP_I, _AP_W);
1706 str += int_part.to_string(radix, false);
1707 } else {
1708 str += prefix;
1709 str += '0';
1710 }
1711
1712 ap_fixed_base<AP_MAX(_AP_W - _AP_I, 1), 0, false> frac_part = tmp;
1713
1714 if (radix == 10) {
1715 if (frac_part != 0) {
1716 str += ".";
1717 while (frac_part != 0) {
1718 char digit = (frac_part * radix).to_char();
1719 str += static_cast<char>(digit + '0');
1720 frac_part *= radix;
1721 }
1722 }
1723 } else {
1724 if (frac_part != 0) {
1725 str += ".";
1726 for (signed i = _AP_W - _AP_I - 1; i >= 0; i -= step) {
1727 char digit = frac_part.range(i, AP_MAX(0, i - step + 1)).to_char();
1728 // If we have a partial bit pattern at the end, then we need
1729 // to put it in the high-order bits of 'digit'.
1730 int offset = AP_MIN(0, i - step + 1);
1731 digit <<= -offset;
1732 str += digit < 10 ? static_cast<char>(digit + '0')
1733 : static_cast<char>(digit - 10 + 'a');
1734 }
1735 if (radix == 16)
1736 str += "p0"; // C99 Hex constants are required to have an exponent.
1737 }
1738 }
1739 return str;
1740 }
1741#else
1742 // XXX HLS will delete this in synthesis
1743 INLINE char* to_string(unsigned char radix = 2, bool sign = _AP_S) const {
1744 return 0;
1745 }
1746#endif
1747}; // struct ap_fixed_base.
1748
1749template <int _AP_W, int _AP_I, bool _AP_S, ap_q_mode _AP_Q, ap_o_mode _AP_O,
1750 int _AP_N>
1751INLINE void b_not(
1754 ret.V = ~op.V;
1755}
1756
1757template <int _AP_W, int _AP_I, bool _AP_S, ap_q_mode _AP_Q, ap_o_mode _AP_O,
1758 int _AP_N>
1759INLINE void b_and(
1763 ret.V = op1.V & op2.V;
1764}
1765
1766template <int _AP_W, int _AP_I, bool _AP_S, ap_q_mode _AP_Q, ap_o_mode _AP_O,
1767 int _AP_N>
1768INLINE void b_or(
1772 ret.V = op1.V | op2.V;
1773}
1774
1775template <int _AP_W, int _AP_I, bool _AP_S, ap_q_mode _AP_Q, ap_o_mode _AP_O,
1776 int _AP_N>
1777INLINE void b_xor(
1781 ret.V = op1.V ^ op2.V;
1782}
1783
1784template <int _AP_W, int _AP_I, bool _AP_S, ap_q_mode _AP_Q, ap_o_mode _AP_O,
1785 int _AP_N, int _AP_W2, int _AP_I2, bool _AP_S2, ap_q_mode _AP_Q2,
1786 ap_o_mode _AP_O2, int _AP_N2>
1787INLINE void neg(
1790 ap_fixed_base<_AP_W2 + !_AP_S2, _AP_I2 + !_AP_S2, true, _AP_Q2, _AP_O2,
1791 _AP_N2>
1792 t;
1793 t.V = -op.V;
1794 ret = t;
1795}
1796
1797template <int _AP_W, int _AP_I, bool _AP_S, ap_q_mode _AP_Q, ap_o_mode _AP_O,
1798 int _AP_N, int _AP_W2, int _AP_I2, bool _AP_S2, ap_q_mode _AP_Q2,
1799 ap_o_mode _AP_O2, int _AP_N2>
1800INLINE void lshift(
1803 int i) {
1804 enum {
1805 F2 = _AP_W2 - _AP_I2,
1806 _AP_I3 = AP_MAX(_AP_I, _AP_I2),
1807 _AP_W3 = _AP_I3 + F2,
1808 };
1809 // wide buffer
1811 t.V = op.V;
1812 t.V <<= i; // FIXME overflow?
1813 // handle quantization and overflow
1814 ret = t;
1815}
1816
1817template <int _AP_W, int _AP_I, bool _AP_S, ap_q_mode _AP_Q, ap_o_mode _AP_O,
1818 int _AP_N, int _AP_W2, int _AP_I2, bool _AP_S2, ap_q_mode _AP_Q2,
1819 ap_o_mode _AP_O2, int _AP_N2>
1820INLINE void rshift(
1823 int i) {
1824 enum {
1825 F = _AP_W - _AP_I,
1826 F2 = _AP_W2 - _AP_I2,
1827 F3 = AP_MAX(F, F2),
1828 _AP_W3 = _AP_I2 + F3,
1829 sh = F - F2,
1830 };
1831 // wide buffer
1833 t.V = op.V;
1834 if (sh >= 0) t.V <<= (int)sh;
1835 t.V >>= i;
1836 // handle quantization and overflow
1837 ret = t;
1838}
1839
1845//
1846
1847#ifndef __SYNTHESIS__
1848INLINE std::string scientificFormat(std::string& input) {
1849 if (input.length() == 0) return input;
1850
1851 size_t decPosition = input.find('.');
1852 if (decPosition == std::string::npos) decPosition = input.length();
1853
1854 size_t firstNonZeroPos = 0;
1855 for (; input[firstNonZeroPos] > '9' || input[firstNonZeroPos] < '1';
1856 firstNonZeroPos++)
1857 ;
1858
1859 int exp;
1860 if (firstNonZeroPos > decPosition)
1861 exp = decPosition - firstNonZeroPos;
1862 else
1863 exp = decPosition - firstNonZeroPos - 1;
1864 std::string expString = "";
1865 if (exp == 0)
1866 ;
1867 else if (exp < 0) {
1868 expString += "e-";
1869 exp = -exp;
1870 } else
1871 expString += "e+";
1872
1873 if (exp < 10 && exp > 0) {
1874 expString += '0';
1875 expString += (char)('0' + exp);
1876 } else if (exp != 0) {
1877 std::string tmp;
1878
1879 std::ostringstream oss;
1880 oss << exp;
1881
1882 tmp = oss.str();
1883 expString += tmp;
1884 }
1885
1886 int lastNonZeroPos = (int)(input.length() - 1);
1887 for (; lastNonZeroPos >= 0; --lastNonZeroPos)
1888 if (input[lastNonZeroPos] <= '9' && input[lastNonZeroPos] > '0') break;
1889
1890 std::string ans = "";
1891 ans += input[firstNonZeroPos];
1892 if (firstNonZeroPos != (size_t)lastNonZeroPos) {
1893 ans += '.';
1894 for (int i = firstNonZeroPos + 1; i <= lastNonZeroPos; i++)
1895 if (input[i] != '.') ans += input[i];
1896 }
1897
1898 ans += expString;
1899 return ans;
1900}
1901
1902INLINE std::string reduceToPrecision(std::string& input, int precision) {
1903 bool isZero = true;
1904 size_t inputLen = input.length();
1905 for (size_t i = 0; i < inputLen && isZero; i++)
1906 if (input[i] != '.' && input[i] != '0') isZero = false;
1907 if (isZero) return "0";
1908
1909 // Find the first valid number, skip '-'
1910 int FirstNonZeroPos = 0;
1911 int LastNonZeroPos = (int)inputLen - 1;
1912 int truncBitPosition = 0;
1913 size_t decPosition = input.find('.');
1914 for (; input[FirstNonZeroPos] < '1' || input[FirstNonZeroPos] > '9';
1915 FirstNonZeroPos++)
1916 ;
1917
1918 for (; input[LastNonZeroPos] < '1' || input[LastNonZeroPos] > '9';
1919 LastNonZeroPos--)
1920 ;
1921
1922 if (decPosition == std::string::npos) decPosition = inputLen;
1923 // Count the valid number, to decide whether we need to truncate
1924 if ((int)decPosition > LastNonZeroPos) {
1925 if (LastNonZeroPos - FirstNonZeroPos + 1 <= precision) return input;
1926 truncBitPosition = FirstNonZeroPos + precision;
1927 } else if ((int)decPosition < FirstNonZeroPos) { // This is pure decimal
1928 if (LastNonZeroPos - FirstNonZeroPos + 1 <= precision) {
1929 if (FirstNonZeroPos - decPosition - 1 < 4) {
1930 return input;
1931 } else {
1932 if (input[0] == '-') {
1933 std::string tmp = input.substr(1, inputLen - 1);
1934 return std::string("-") + scientificFormat(tmp);
1935 } else
1936 return scientificFormat(input);
1937 }
1938 }
1939 truncBitPosition = FirstNonZeroPos + precision;
1940 } else {
1941 if (LastNonZeroPos - FirstNonZeroPos <= precision) return input;
1942 truncBitPosition = FirstNonZeroPos + precision + 1;
1943 }
1944
1945 // duplicate the input string, we want to add "0" before the valid numbers
1946 // This is easy for quantization, since we may change 9999 to 10000
1947 std::string ans = "";
1948 std::string dupInput = "0";
1949 if (input[0] == '-') {
1950 ans += '-';
1951 dupInput += input.substr(1, inputLen - 1);
1952 } else {
1953 dupInput += input.substr(0, inputLen);
1954 ++truncBitPosition;
1955 }
1956
1957 // Add 'carry' after truncation, if necessary
1958 bool carry = dupInput[truncBitPosition] > '4';
1959 for (int i = truncBitPosition - 1; i >= 0 && carry; i--) {
1960 if (dupInput[i] == '.') continue;
1961 if (dupInput[i] == '9')
1962 dupInput[i] = '0';
1963 else {
1964 ++dupInput[i];
1965 carry = false;
1966 }
1967 }
1968
1969 // bits outside precision range should be set to 0
1970 if (dupInput[0] == '1')
1971 FirstNonZeroPos = 0;
1972 else {
1973 FirstNonZeroPos = 0;
1974 while (dupInput[FirstNonZeroPos] < '1' || dupInput[FirstNonZeroPos] > '9')
1975 ++FirstNonZeroPos;
1976 }
1977
1978 unsigned it = FirstNonZeroPos;
1979 int NValidNumber = 0;
1980 while (it < dupInput.length()) {
1981 if (dupInput[it] == '.') {
1982 ++it;
1983 continue;
1984 }
1985 ++NValidNumber;
1986 if (NValidNumber > precision) dupInput[it] = '0';
1987 ++it;
1988 }
1989
1990 // Here we wanted to adjust the truncate position and the value
1991 decPosition = dupInput.find('.');
1992 if (decPosition == std::string::npos) // When this is integer
1993 truncBitPosition = (int)dupInput.length();
1994 else
1995 for (truncBitPosition = (int)(dupInput.length() - 1); truncBitPosition >= 0;
1996 --truncBitPosition) {
1997 if (dupInput[truncBitPosition] == '.') break;
1998 if (dupInput[truncBitPosition] != '0') {
1999 truncBitPosition++;
2000 break;
2001 }
2002 }
2003
2004 if (dupInput[0] == '1')
2005 dupInput = dupInput.substr(0, truncBitPosition);
2006 else
2007 dupInput = dupInput.substr(1, truncBitPosition - 1);
2008
2009 decPosition = dupInput.find('.');
2010 if (decPosition != std::string::npos) {
2011 size_t it = 0;
2012 for (it = decPosition + 1; dupInput[it] == '0'; it++)
2013 ;
2014 if (it - decPosition - 1 < 4) {
2015 ans += dupInput;
2016 return ans;
2017 } else {
2018 ans += scientificFormat(dupInput);
2019 return ans;
2020 }
2021 } else if ((int)(dupInput.length()) <= precision) {
2022 ans += dupInput;
2023 return ans;
2024 }
2025
2026 ans += scientificFormat(dupInput);
2027 return ans;
2028}
2029
2030template <int _AP_W, int _AP_I, bool _AP_S, ap_q_mode _AP_Q, ap_o_mode _AP_O,
2031 int _AP_N>
2032INLINE void print(
2034 if (_AP_I > 0) {
2036 p1.V = x.V >> (_AP_W - _AP_I);
2037 print(p1.V); // print overlaod for .V should exit
2038 } else {
2039 printf("0");
2040 }
2041 printf(".");
2042 if (_AP_I < _AP_W) {
2043 ap_int_base<_AP_W - _AP_I, false> p2;
2044 p2.V = _AP_ROOT_op_get_range(x.V, 0, _AP_W - _AP_I);
2045 print(p2.V, false); // print overlaod for .V should exit
2046 }
2047}
2048#endif // ifndef __SYNTHESIS__
2049
2050// XXX the following two functions have to exist in synthesis,
2051// as some old HLS Video Library code uses the ostream overload,
2052// although HLS will later delete I/O function call.
2053
2055//-----------------------------------------------------------------------------
2056// XXX apcc cannot handle global std::ios_base::Init() brought in by <iostream>
2057#ifndef AP_AUTOCC
2058#ifndef __SYNTHESIS__
2059template <int _AP_W, int _AP_I, bool _AP_S, ap_q_mode _AP_Q, ap_o_mode _AP_O,
2060 int _AP_N>
2061INLINE std::ostream& operator<<(
2062 std::ostream& out,
2064 // TODO support std::ios_base::fmtflags
2065 unsigned width = out.width();
2066 unsigned precision = out.precision();
2067 char fill = out.fill();
2068 std::string str = x.to_string(10, _AP_S);
2069 str = reduceToPrecision(str, precision);
2070 if (width > str.length()) {
2071 for (unsigned i = 0; i < width - str.length(); ++i) out << fill;
2072 }
2073 out << str;
2074 return out;
2075}
2076#endif // ifndef __SYNTHESIS__
2077
2079// -----------------------------------------------------------------------------
2080#ifndef __SYNTHESIS__
2081template <int _AP_W, int _AP_I, bool _AP_S, ap_q_mode _AP_Q, ap_o_mode _AP_O,
2082 int _AP_N>
2083INLINE std::istream& operator>>(
2084 std::istream& in,
2086 double d;
2087 in >> d;
2089 return in;
2090}
2091#endif
2092#endif // ifndef AP_AUTOCC
2093
2095// -----------------------------------------------------------------------------
2096#define AF_BIN_OP_WITH_INT_SF(BIN_OP, C_TYPE, _AP_W2, _AP_S2, RTYPE) \
2097 template <int _AP_W, int _AP_I, bool _AP_S, ap_q_mode _AP_Q, \
2098 ap_o_mode _AP_O, int _AP_N> \
2099 INLINE typename ap_fixed_base<_AP_W, _AP_I, _AP_S>::template RType< \
2100 _AP_W2, _AP_W2, _AP_S2>::RTYPE \
2101 operator BIN_OP( \
2102 const ap_fixed_base<_AP_W, _AP_I, _AP_S, _AP_Q, _AP_O, _AP_N>& op, \
2103 C_TYPE i_op) { \
2104 return op.operator BIN_OP(ap_int_base<_AP_W2, _AP_S2>(i_op)); \
2105 }
2106
2107#define AF_BIN_OP_WITH_INT(BIN_OP, C_TYPE, _AP_W2, _AP_S2, RTYPE) \
2108 template <int _AP_W, int _AP_I, bool _AP_S, ap_q_mode _AP_Q, \
2109 ap_o_mode _AP_O, int _AP_N> \
2110 INLINE typename ap_fixed_base<_AP_W, _AP_I, _AP_S>::template RType< \
2111 _AP_W2, _AP_W2, _AP_S2>::RTYPE \
2112 operator BIN_OP( \
2113 const ap_fixed_base<_AP_W, _AP_I, _AP_S, _AP_Q, _AP_O, _AP_N>& op, \
2114 C_TYPE i_op) { \
2115 return op.operator BIN_OP(ap_fixed_base<_AP_W2, _AP_W2, _AP_S2>(i_op)); \
2116 } \
2117 template <int _AP_W, int _AP_I, bool _AP_S, ap_q_mode _AP_Q, \
2118 ap_o_mode _AP_O, int _AP_N> \
2119 INLINE typename ap_fixed_base<_AP_W, _AP_I, _AP_S>::template RType< \
2120 _AP_W2, _AP_W2, _AP_S2>::RTYPE \
2121 operator BIN_OP( \
2122 C_TYPE i_op, \
2123 const ap_fixed_base<_AP_W, _AP_I, _AP_S, _AP_Q, _AP_O, _AP_N>& op) { \
2124 return ap_fixed_base<_AP_W2, _AP_W2, _AP_S2>(i_op).operator BIN_OP(op); \
2125 }
2126
2127#define AF_REL_OP_WITH_INT(REL_OP, C_TYPE, _AP_W2, _AP_S2) \
2128 template <int _AP_W, int _AP_I, bool _AP_S, ap_q_mode _AP_Q, \
2129 ap_o_mode _AP_O, int _AP_N> \
2130 INLINE bool operator REL_OP( \
2131 const ap_fixed_base<_AP_W, _AP_I, _AP_S, _AP_Q, _AP_O, _AP_N>& op, \
2132 C_TYPE i_op) { \
2133 return op.operator REL_OP(ap_fixed_base<_AP_W2, _AP_W2, _AP_S2>(i_op)); \
2134 } \
2135 template <int _AP_W, int _AP_I, bool _AP_S, ap_q_mode _AP_Q, \
2136 ap_o_mode _AP_O, int _AP_N> \
2137 INLINE bool operator REL_OP( \
2138 C_TYPE i_op, \
2139 const ap_fixed_base<_AP_W, _AP_I, _AP_S, _AP_Q, _AP_O, _AP_N>& op) { \
2140 return ap_fixed_base<_AP_W2, _AP_W2, _AP_S2>(i_op).operator REL_OP(op); \
2141 }
2142
2143#define AF_ASSIGN_OP_WITH_INT(ASSIGN_OP, C_TYPE, _AP_W2, _AP_S2) \
2144 template <int _AP_W, int _AP_I, bool _AP_S, ap_q_mode _AP_Q, \
2145 ap_o_mode _AP_O, int _AP_N> \
2146 INLINE ap_fixed_base<_AP_W, _AP_I, _AP_S, _AP_Q, _AP_O, _AP_N>& \
2147 operator ASSIGN_OP( \
2148 ap_fixed_base<_AP_W, _AP_I, _AP_S, _AP_Q, _AP_O, _AP_N>& op, \
2149 C_TYPE i_op) { \
2150 return op.operator ASSIGN_OP(ap_fixed_base<_AP_W2, _AP_W2, _AP_S2>(i_op)); \
2151 }
2152
2153#define AF_ASSIGN_OP_WITH_INT_SF(ASSIGN_OP, C_TYPE, _AP_W2, _AP_S2) \
2154 template <int _AP_W, int _AP_I, bool _AP_S, ap_q_mode _AP_Q, \
2155 ap_o_mode _AP_O, int _AP_N> \
2156 INLINE ap_fixed_base<_AP_W, _AP_I, _AP_S, _AP_Q, _AP_O, _AP_N>& \
2157 operator ASSIGN_OP( \
2158 ap_fixed_base<_AP_W, _AP_I, _AP_S, _AP_Q, _AP_O, _AP_N>& op, \
2159 C_TYPE i_op) { \
2160 return op.operator ASSIGN_OP(ap_int_base<_AP_W2, _AP_S2>(i_op)); \
2161 }
2162
2163#define ALL_AF_OP_WITH_INT(C_TYPE, BITS, SIGN) \
2164 AF_BIN_OP_WITH_INT(+, C_TYPE, (BITS), (SIGN), plus) \
2165 AF_BIN_OP_WITH_INT(-, C_TYPE, (BITS), (SIGN), minus) \
2166 AF_BIN_OP_WITH_INT(*, C_TYPE, (BITS), (SIGN), mult) \
2167 AF_BIN_OP_WITH_INT(/, C_TYPE, (BITS), (SIGN), div) \
2168 AF_BIN_OP_WITH_INT(&, C_TYPE, (BITS), (SIGN), logic) \
2169 AF_BIN_OP_WITH_INT(|, C_TYPE, (BITS), (SIGN), logic) \
2170 AF_BIN_OP_WITH_INT(^, C_TYPE, (BITS), (SIGN), logic) \
2171 AF_BIN_OP_WITH_INT_SF(>>, C_TYPE, (BITS), (SIGN), lhs) \
2172 AF_BIN_OP_WITH_INT_SF(<<, C_TYPE, (BITS), (SIGN), lhs) \
2173 \
2174 AF_ASSIGN_OP_WITH_INT(+=, C_TYPE, (BITS), (SIGN)) \
2175 AF_ASSIGN_OP_WITH_INT(-=, C_TYPE, (BITS), (SIGN)) \
2176 AF_ASSIGN_OP_WITH_INT(*=, C_TYPE, (BITS), (SIGN)) \
2177 AF_ASSIGN_OP_WITH_INT(/=, C_TYPE, (BITS), (SIGN)) \
2178 AF_ASSIGN_OP_WITH_INT(&=, C_TYPE, (BITS), (SIGN)) \
2179 AF_ASSIGN_OP_WITH_INT(|=, C_TYPE, (BITS), (SIGN)) \
2180 AF_ASSIGN_OP_WITH_INT(^=, C_TYPE, (BITS), (SIGN)) \
2181 AF_ASSIGN_OP_WITH_INT_SF(>>=, C_TYPE, (BITS), (SIGN)) \
2182 AF_ASSIGN_OP_WITH_INT_SF(<<=, C_TYPE, (BITS), (SIGN)) \
2183 \
2184 AF_REL_OP_WITH_INT(>, C_TYPE, (BITS), (SIGN)) \
2185 AF_REL_OP_WITH_INT(<, C_TYPE, (BITS), (SIGN)) \
2186 AF_REL_OP_WITH_INT(>=, C_TYPE, (BITS), (SIGN)) \
2187 AF_REL_OP_WITH_INT(<=, C_TYPE, (BITS), (SIGN)) \
2188 AF_REL_OP_WITH_INT(==, C_TYPE, (BITS), (SIGN)) \
2189 AF_REL_OP_WITH_INT(!=, C_TYPE, (BITS), (SIGN))
2190
2191ALL_AF_OP_WITH_INT(bool, 1, false)
2192ALL_AF_OP_WITH_INT(char, 8, CHAR_IS_SIGNED)
2193ALL_AF_OP_WITH_INT(signed char, 8, true)
2194ALL_AF_OP_WITH_INT(unsigned char, 8, false)
2195ALL_AF_OP_WITH_INT(short, _AP_SIZE_short, true)
2196ALL_AF_OP_WITH_INT(unsigned short, _AP_SIZE_short, false)
2197ALL_AF_OP_WITH_INT(int, _AP_SIZE_int, true)
2198ALL_AF_OP_WITH_INT(unsigned int, _AP_SIZE_int, false)
2199ALL_AF_OP_WITH_INT(long, _AP_SIZE_long, true)
2200ALL_AF_OP_WITH_INT(unsigned long, _AP_SIZE_long, false)
2201ALL_AF_OP_WITH_INT(ap_slong, _AP_SIZE_ap_slong, true)
2202ALL_AF_OP_WITH_INT(ap_ulong, _AP_SIZE_ap_slong, false)
2203
2204#undef ALL_AF_OP_WITH_INT
2205#undef AF_BIN_OP_WITH_INT
2206#undef AF_BIN_OP_WITH_INT_SF
2207#undef AF_ASSIGN_OP_WITH_INT
2208#undef AF_ASSIGN_OP_WITH_INT_SF
2209#undef AF_REL_OP_WITH_INT
2210
2211/*
2212 * **********************************************************************
2213 * TODO
2214 * There is no operator defined with float/double/long double, so that
2215 * code like
2216 * ap_fixed<8,4> a = 1.5f;
2217 * a += 0.5f;
2218 * will fail in compilation.
2219 * Operator with warning about conversion might be wanted.
2220 * **********************************************************************
2221 */
2222
2223#define AF_BIN_OP_WITH_AP_INT(BIN_OP, RTYPE) \
2224 template <int _AP_W, int _AP_I, bool _AP_S, ap_q_mode _AP_Q, \
2225 ap_o_mode _AP_O, int _AP_N, int _AP_W2, bool _AP_S2> \
2226 INLINE typename ap_fixed_base<_AP_W2, _AP_W2, _AP_S2>::template RType< \
2227 _AP_W, _AP_I, _AP_S>::RTYPE \
2228 operator BIN_OP( \
2229 const ap_int_base<_AP_W2, _AP_S2>& i_op, \
2230 const ap_fixed_base<_AP_W, _AP_I, _AP_S, _AP_Q, _AP_O, _AP_N>& op) { \
2231 return ap_fixed_base<_AP_W2, _AP_W2, _AP_S2>(i_op).operator BIN_OP(op); \
2232 } \
2233 \
2234 template <int _AP_W, int _AP_I, bool _AP_S, ap_q_mode _AP_Q, \
2235 ap_o_mode _AP_O, int _AP_N, int _AP_W2, bool _AP_S2> \
2236 INLINE typename ap_fixed_base<_AP_W, _AP_I, _AP_S>::template RType< \
2237 _AP_W2, _AP_W2, _AP_S2>::RTYPE \
2238 operator BIN_OP( \
2239 const ap_fixed_base<_AP_W, _AP_I, _AP_S, _AP_Q, _AP_O, _AP_N>& op, \
2240 const ap_int_base<_AP_W2, _AP_S2>& i_op) { \
2241 return op.operator BIN_OP(ap_fixed_base<_AP_W2, _AP_W2, _AP_S2>(i_op)); \
2242 }
2243
2244#define AF_REL_OP_WITH_AP_INT(REL_OP) \
2245 template <int _AP_W, int _AP_I, bool _AP_S, ap_q_mode _AP_Q, \
2246 ap_o_mode _AP_O, int _AP_N, int _AP_W2, bool _AP_S2> \
2247 INLINE bool operator REL_OP( \
2248 const ap_fixed_base<_AP_W, _AP_I, _AP_S, _AP_Q, _AP_O, _AP_N>& op, \
2249 const ap_int_base<_AP_W2, _AP_S2>& i_op) { \
2250 return op.operator REL_OP(ap_fixed_base<_AP_W2, _AP_W2, _AP_S2>(i_op)); \
2251 } \
2252 \
2253 template <int _AP_W, int _AP_I, bool _AP_S, ap_q_mode _AP_Q, \
2254 ap_o_mode _AP_O, int _AP_N, int _AP_W2, bool _AP_S2> \
2255 INLINE bool operator REL_OP( \
2256 const ap_int_base<_AP_W2, _AP_S2>& i_op, \
2257 const ap_fixed_base<_AP_W, _AP_I, _AP_S, _AP_Q, _AP_O, _AP_N>& op) { \
2258 return ap_fixed_base<_AP_W2, _AP_W2, _AP_S2>(i_op).operator REL_OP(op); \
2259 }
2260
2261#define AF_ASSIGN_OP_WITH_AP_INT(ASSIGN_OP) \
2262 template <int _AP_W, int _AP_I, bool _AP_S, ap_q_mode _AP_Q, \
2263 ap_o_mode _AP_O, int _AP_N, int _AP_W2, bool _AP_S2> \
2264 INLINE ap_fixed_base<_AP_W, _AP_I, _AP_S, _AP_Q, _AP_O, _AP_N>& \
2265 operator ASSIGN_OP( \
2266 ap_fixed_base<_AP_W, _AP_I, _AP_S, _AP_Q, _AP_O, _AP_N>& op, \
2267 const ap_int_base<_AP_W2, _AP_S2>& i_op) { \
2268 return op.operator ASSIGN_OP(ap_fixed_base<_AP_W2, _AP_W2, _AP_S2>(i_op)); \
2269 } \
2270 \
2271 template <int _AP_W, int _AP_I, bool _AP_S, ap_q_mode _AP_Q, \
2272 ap_o_mode _AP_O, int _AP_N, int _AP_W2, bool _AP_S2> \
2273 INLINE ap_int_base<_AP_W2, _AP_S2>& operator ASSIGN_OP( \
2274 ap_int_base<_AP_W2, _AP_S2>& i_op, \
2275 const ap_fixed_base<_AP_W, _AP_I, _AP_S, _AP_Q, _AP_O, _AP_N>& op) { \
2276 return i_op.operator ASSIGN_OP(op.to_ap_int_base()); \
2277 }
2278
2279AF_BIN_OP_WITH_AP_INT(+, plus)
2280AF_BIN_OP_WITH_AP_INT(-, minus)
2281AF_BIN_OP_WITH_AP_INT(*, mult)
2282AF_BIN_OP_WITH_AP_INT(/, div)
2283AF_BIN_OP_WITH_AP_INT(&, logic)
2284AF_BIN_OP_WITH_AP_INT(|, logic)
2285AF_BIN_OP_WITH_AP_INT(^, logic)
2286
2287#undef AF_BIN_OP_WITH_AP_INT
2288
2289AF_ASSIGN_OP_WITH_AP_INT(+=)
2290AF_ASSIGN_OP_WITH_AP_INT(-=)
2291AF_ASSIGN_OP_WITH_AP_INT(*=)
2292AF_ASSIGN_OP_WITH_AP_INT(/=)
2293AF_ASSIGN_OP_WITH_AP_INT(&=)
2294AF_ASSIGN_OP_WITH_AP_INT(|=)
2295AF_ASSIGN_OP_WITH_AP_INT(^=)
2296
2297#undef AF_ASSIGN_OP_WITH_AP_INT
2298
2299AF_REL_OP_WITH_AP_INT(==)
2300AF_REL_OP_WITH_AP_INT(!=)
2301AF_REL_OP_WITH_AP_INT(>)
2302AF_REL_OP_WITH_AP_INT(>=)
2303AF_REL_OP_WITH_AP_INT(<)
2304AF_REL_OP_WITH_AP_INT(<=)
2305
2306#undef AF_REL_OP_WITH_AP_INT
2307
2308// Relational Operators with double
2309template <int _AP_W, int _AP_I, bool _AP_S, ap_q_mode _AP_Q, ap_o_mode _AP_O,
2310 int _AP_N>
2311INLINE bool operator==(
2312 double op1,
2314 return op2.operator==(op1);
2315}
2316
2317template <int _AP_W, int _AP_I, bool _AP_S, ap_q_mode _AP_Q, ap_o_mode _AP_O,
2318 int _AP_N>
2319INLINE bool operator!=(
2320 double op1,
2322 return op2.operator!=(op1);
2323}
2324
2325template <int _AP_W, int _AP_I, bool _AP_S, ap_q_mode _AP_Q, ap_o_mode _AP_O,
2326 int _AP_N>
2327INLINE bool operator>(
2328 double op1,
2330 return op2.operator<(op1);
2331}
2332
2333template <int _AP_W, int _AP_I, bool _AP_S, ap_q_mode _AP_Q, ap_o_mode _AP_O,
2334 int _AP_N>
2335INLINE bool operator>=(
2336 double op1,
2338 return op2.operator<=(op1);
2339}
2340
2341template <int _AP_W, int _AP_I, bool _AP_S, ap_q_mode _AP_Q, ap_o_mode _AP_O,
2342 int _AP_N>
2343INLINE bool operator<(
2344 double op1,
2346 return op2.operator>(op1);
2347}
2348
2349template <int _AP_W, int _AP_I, bool _AP_S, ap_q_mode _AP_Q, ap_o_mode _AP_O,
2350 int _AP_N>
2351INLINE bool operator<=(
2352 double op1,
2354 return op2.operator>=(op1);
2355}
2356
2357#endif // ifndef __cplusplus else
2358
2359#endif // ifndef __AP_FIXED_BASE_H__ else
2360
2361// -*- cpp -*-
conditions objects which are tables indexed by raw detector id values
Signed Arbitrary Precision Fixed-Point Type.
Definition ap_fixed.h:29