da4ml 0.5.1.post1__cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl

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