MatchLib
nvhls_int.h
1 /*
2  * Copyright (c) 2016-2020, NVIDIA CORPORATION. All rights reserved.
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 /*
18  * When indicated below in comments, some compute functions in this file have
19  * been derived from code in the Algorithmic C Datatypes v3.7.1 distributed
20  * with the following license:
21  */
22 /**************************************************************************
23  * *
24  * Algorithmic C (tm) Datatypes *
25  * *
26  * Software Version: 3.7 *
27  * *
28  * Release Date : Sat Jun 25 13:27:03 PDT 2016 *
29  * Release Type : Production Release *
30  * Release Build : 3.7.1 *
31  * *
32  * Copyright 2004-2016, Mentor Graphics Corporation, *
33  * *
34  * All Rights Reserved. *
35  *
36  **************************************************************************
37  * Licensed under the Apache License, Version 2.0 (the "License"); *
38  * you may not use this file except in compliance with the License. *
39  * You may obtain a copy of the License at *
40  * *
41  * http://www.apache.org/licenses/LICENSE-2.0 *
42  * *
43  * Unless required by applicable law or agreed to in writing, software *
44  * distributed under the License is distributed on an "AS IS" BASIS, *
45  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or *
46  * implied. *
47  * See the License for the specific language governing permissions and *
48  * limitations under the License. *
49  **************************************************************************
50  * *
51  * The most recent version of this package is available at github. *
52  * *
53  *************************************************************************/
54 
55 #ifndef NVHLS_INT_H
56 #define NVHLS_INT_H
57 
58 #include <systemc.h>
59 #include <nvhls_marshaller.h>
60 #ifdef HLS_CATAPULT
61 #include <ac_sc.h>
62 #include <ac_int.h>
63 #endif
64 
65 namespace nvhls {
66 
67 /**************************************************************************
68  * Begin *
69  * Algorithmic C (tm) Datatypes *
70  *************************************************************************/
71 
72 // Helper structs for statically computing log2 like functions (nbits,
73 // log2_floor, log2_ceil) using recursive templates
74 
75 template <unsigned char N>
76 struct s_N {
77  template <unsigned X>
78  struct s_X {
79  enum {
80  X2 = X >> N,
81  N_div_2 = N >> 1,
82  nbits = X ? (X2 ? N + (int)s_N<N_div_2>::template s_X<X2>::nbits
84  : 0
85  };
86  };
87 };
88 template <>
89 struct s_N<0> {
90  template <unsigned X>
91  struct s_X {
92  enum { nbits = !!X };
93  };
94 };
95 
96 // compiler time constant for log2 like functions
117 template <unsigned X>
118 struct nbits {
119  enum { val = s_N<16>::s_X<X>::nbits };
120 };
141 template <unsigned X>
142 struct log2_floor {
143  enum { val = nbits<X>::val - 1 };
144 };
145 
151 template <>
152 struct log2_floor<0> {};
173 template <unsigned X>
174 struct log2_ceil {
175  enum { lf = log2_floor<X>::val, val = (X == (1 << lf) ? lf : lf + 1) };
176 };
177 
183 template <>
184 struct log2_ceil<0> {};
185 
186 
207 template <int n_val>
208 struct next_pow2 {
209  enum {
210  val =
211  n_val <= 1
212  ? 1
213  : n_val <= 2
214  ? 2
215  : n_val <= 4
216  ? 4
217  : n_val <= 8
218  ? 8
219  : n_val <= 16
220  ? 16
221  : n_val <= 32
222  ? 32
223  : n_val <= 64
224  ? 64
225  : n_val <= 128
226  ? 128
227  : n_val <= 256
228  ? 256
229  : n_val <= 512
230  ? 512
231  : n_val <=
232  1024
233  ? 1024
234  : n_val <=
235  2048
236  ? 2048
237  : n_val <=
238  4096
239  ? 4096
240  : n_val <=
241  8192
242  ? 8192
243  : n_val <=
244  16384
245  ? 16384
246  : n_val <=
247  32768
248  ? 32768
249  : n_val <=
250  65536
251  ? 65536
252  : 1048576
253  };
254 };
255 
256 /**************************************************************************
257  * End *
258  * Algorithmic C (tm) Datatypes *
259  *************************************************************************/
260 
284 template <unsigned X>
285 struct index_width {
286  enum { val = (X==1)? 1 : log2_ceil<X>::val };
287 };
288 
289 // Definition of vendor agnostic data types. We can add more data types to
290 // nvhls_t struct and move it to a separate file if needed
328 #ifdef HLS_CATAPULT
329 template <unsigned int N>
330 struct nvhls_t {
331  typedef ac_int<N, true> nvint_t;
332  typedef ac_int<N, false> nvuint_t;
333 };
334 #else
335 template <unsigned int N, bool B = (N <= 64)>
336 struct nvhls_t;
337 
338 template <unsigned int N>
340  typedef sc_int<N> nvint_t;
341  typedef sc_uint<N> nvuint_t;
342 };
343 
344 template <unsigned int N>
346  typedef sc_bigint<N> nvint_t;
347  typedef sc_biguint<N> nvuint_t;
348 };
349 #endif
350 
386 template <typename type1, typename type2>
387 type1 set_slc(type1 X, type2 Y, const unsigned int i) {
388  type1 X_temp = X;
389 #ifdef HLS_CATAPULT
390  X_temp.set_slc(i, Y);
391  return X_temp;
392 #else
393  const unsigned int W2 = Wrapped<type2>::width;
394  X_temp.range(i + W2 - 1, i) = Y;
395  return X_temp;
396 #endif
397 }
398 
433 template <unsigned int W, typename type>
434 #ifdef HLS_STRATUS
435 sc_biguint<W> get_slc(type X, const unsigned int i){
436 #else
437 typename nvhls_t<W>::nvuint_t get_slc(type X, const unsigned int i) {
438 #endif
439  // Assuming i>=0,
440  type X_temp = X;
441 typename nvhls_t<W>::nvuint_t Z;
442 #ifdef HLS_CATAPULT
443 Z = X_temp.template slc<W>(i);
444 return Z;
445 #else
446  Z = X_temp.range(i + W - 1, i);
447  return Z;
448 #endif
449 }
450 
486 template <typename type>
487 type get_slc(type X, const unsigned int i, const unsigned int j) {
488  // Assuming i>=0,j>=0, i>=j
489  type X_temp = X;
490  type Z;
491 #ifdef HLS_CATAPULT
492  const unsigned int W = type::width;
493  Z = (X_temp >> j) & ((((ac_int<W + 1>)1) << (i - j + 1)) - 1);
494 #else
495  Z = X_temp.range(i, j);
496 #endif
497  return Z;
498 }
499 
500 // Leading zero detector function
501 // template <typename type1, typename type2>
502 // type2 lzd_impl(type1 X) {
503 // type1 X_temp = X;
504 // type2 Z;
505 // const unsigned int W1 = Wrapped<type1>::width;
506 // const bool is_signed = Wrapped<type1>::is_signed;
507 // int i;
508 // if (is_signed) {
509 // for (i = W1 - 2; i >= 0; i--) {
510 // if (X_temp[i] != 0) break;
511 // }
512 // Z = W1 - 2 - i;
513 // } else {
514 // for (i = W1 - 1; i >= 0; i--) {
515 // if (X_temp[i] != 0) break;
516 // }
517 // Z = W1 - 1 - i;
518 // }
519 // return Z;
520 //}
521 
522 /**************************************************************************
523  * Begin *
524  * Algorithmic C (tm) Datatypes *
525  *************************************************************************/
526 // Based on MG implementation
560 template <unsigned int W1, typename type1, typename type2>
561 inline type2 leading_ones(type1 X) {
562  const unsigned int W2 = log2_ceil<W1>::val;
563  enum { P2 = next_pow2<(W1 + 1) / 2>::val };
564 
565  typename nvhls_t<W1>::nvuint_t X_temp = X;
566  enum { Wu = (W1 > P2) ? (W1 - P2) : 1 };
567  typename nvhls_t<Wu>::nvuint_t upper = get_slc<Wu>(X_temp, P2);
568  typename nvhls_t<P2>::nvuint_t lower = get_slc<P2>(X_temp, 0);
569  typename nvhls_t<W2>::nvuint_t idx = 0;
570 
571  enum { logWu = (log2_ceil<Wu>::val > 0) ? log2_ceil<Wu>::val : 1 };
572  enum { logP2 = (log2_ceil<P2>::val > 0) ? log2_ceil<P2>::val : 1 };
573  typename nvhls_t<logWu>::nvuint_t idxu = 0;
574  typename nvhls_t<P2>::nvuint_t idxl = 0;
575  if (upper != 0) {
576  idxu = leading_ones<Wu, typename nvhls_t<Wu>::nvuint_t,
577  typename nvhls_t<logWu>::nvuint_t>(upper);
578  idx = idxu | P2;
579  } else {
580  idxl = leading_ones<P2, typename nvhls_t<P2>::nvuint_t,
581  typename nvhls_t<logP2>::nvuint_t>(lower);
582  idx = idxl;
583  }
584  return idx;
585 }
586 /**************************************************************************
587  * End *
588  * Algorithmic C (tm) Datatypes *
589  *************************************************************************/
590 
591 template <>
592 inline nvhls_t<1>::nvuint_t leading_ones<
593  1, nvhls_t<1>::nvuint_t, nvhls_t<1>::nvuint_t>(nvhls_t<1>::nvuint_t X) {
594  return 0;
595 }
596 
626 template <typename type1>
627 unsigned int lzd(type1 X) {
628  unsigned int l;
629 #ifdef HLS_CATAPULT
630  if (X!=0) {
631  l = X.leading_sign();
632  } else {
633  l = Wrapped<type1>::width -1;
634  }
635  return l;
636 #else
637 #if defined(DPOPT)
638  HLS_DPOPT_REGION(DPOPT_DEFAULT, "leading_ones", "leading_ones");
639  HLS_CONSTRAIN_REGION(0, 1);
640 #endif
641  const unsigned int W1 = Wrapped<type1>::width;
642  const unsigned int W2 = log2_ceil<W1>::val;
643  typedef typename nvhls_t<W2>::nvuint_t type2;
644  const bool is_signed = Wrapped<type1>::is_signed;
645  l = leading_ones<W1, type1, type2>(X);
646  if (is_signed)
647  l = W1 - 2 - l;
648  else
649  l = W1 - 1 - l;
650  return l;
651 #endif
652 }
653 
681 template <typename type>
682 type get_min_val() {
683  const unsigned int W = Wrapped<type>::width;
684  const bool is_signed = Wrapped<type>::is_signed;
685  type out;
686  if (is_signed)
687  out = (-((((type)(1)) << (W - 1)) - 1));
688  else
689  out = 0;
690  return out;
691 }
692 
721 template <typename type>
722 type left_shift(type X, int shift) {
723 #ifdef HLS_CATAPULT
724  return (X << shift);
725 #else
726  const unsigned int W = Wrapped<type>::width;
727  const bool is_signed = Wrapped<type>::is_signed;
728  type mag, out;
729  if (is_signed) {
730  mag = X.range(W - 2, 0);
731  // Catapult reports an error for the following line
732  // mag = (shift > 0) ? static_cast<type>(mag << shift) :
733  // static_cast<type>(mag >> (-shift));
734  if (shift > 0)
735  mag <<= shift;
736  else
737  mag >>= (-shift);
738  out = mag;
739  out[W - 1] = X[W - 1];
740  } else {
741  mag = X;
742  // mag = (shift > 0) ? (mag << shift) : (mag >> (-shift));
743  if (shift > 0)
744  mag <<= shift;
745  else
746  mag >>= (-shift);
747  out = mag;
748  }
749  return out;
750 #endif
751 }
781 template <typename type>
782 type right_shift(type X, int shift) {
783 #ifdef HLS_CATAPULT
784  return (X >> shift);
785 #else
786  const unsigned int W = Wrapped<type>::width;
787  const bool is_signed = Wrapped<type>::is_signed;
788  type mag, out;
789  if (is_signed) {
790  mag = X.range(W - 2, 0);
791  // mag = (shift > 0) ? static_cast<type>(mag >> shift) :
792  // static_cast<type>(mag << (-shift));
793  if (shift > 0)
794  mag >>= shift;
795  else
796  mag <<= (-shift);
797  out = mag;
798  out[W - 1] = X[W - 1];
799  } else {
800  mag = X;
801  // mag = (shift > 0) ? static_cast<type>(mag << shift) :
802  // static_cast<type>(mag >> (-shift));
803  if (shift > 0)
804  mag >>= shift;
805  else
806  mag <<= (-shift);
807  out = mag;
808  }
809  return out;
810 #endif
811 }
812 
845 // Normalize function for unsigned exponent
846 // X is treated as mantissa and Y is treated as exp
847 template <typename type1, typename type2>
848 bool normalize(type1& X, type2& Y) {
849  bool b;
850 #ifdef HLS_CATAPULT
851  b = X.normalize(Y);
852  return b;
853 #else
854  const unsigned int W1 = Wrapped<type1>::width;
855  const unsigned int W2 = Wrapped<type2>::width;
856  const bool type2_signed = Wrapped<type2>::is_signed;
857  const unsigned int logW1 = log2_ceil<W1>::val;
858  typedef typename nvhls_t<logW1>::nvuint_t lzd_type;
859  typedef typename nvhls_t<logW1 + 1>::nvint_t signed_lzd_type;
860  lzd_type l = lzd(X);
861  lzd_type shift;
862  type2 min_Y = get_min_val<type2>();
863  // If W>logW1, then (Y-l) can be stored in type2 if it is signed or
864  // signed_type2 if type2 is unsigned
865  if (W2 > logW1) {
866  if (type2_signed) {
867  type2 Y_l = Y - l;
868  if (Y_l < min_Y) {
869  shift = Y - min_Y;
870  Y = min_Y;
871  b = false;
872  } else {
873  shift = l;
874  Y = Y_l;
875  b = true;
876  }
877  } else {
878  typedef typename nvhls_t<W2 + 1>::nvint_t signed_type2;
879  signed_type2 Y_l = Y - l;
880  if (Y_l < ((signed_type2)min_Y)) {
881  shift = Y - min_Y;
882  Y = min_Y;
883  b = false;
884  } else {
885  shift = l;
886  Y = Y_l;
887  b = true;
888  }
889  }
890  } else {
891  signed_lzd_type Y_l = Y - l;
892  if (Y_l < ((signed_lzd_type)min_Y)) {
893  shift = Y - min_Y;
894  Y = min_Y;
895  b = false;
896  } else {
897  shift = l;
898  Y = Y_l;
899  b = true;
900  }
901  }
902  if (X == (type1)0) {
903  Y = min_Y;
904  b = true;
905  }
906  X = left_shift(X, shift);
907  return b;
908 #endif
909 }
910 }
911 ;
912 
913 #endif
type get_min_val()
Minimum Value of a type.
Definition: nvhls_int.h:682
unsigned int lzd(type1 X)
Leading zero detector.
Definition: nvhls_int.h:627
bool normalize(type1 &X, type2 &Y)
Normalize function.
Definition: nvhls_int.h:848
type right_shift(type X, int shift)
Function that performs right shift while preserving sign.
Definition: nvhls_int.h:782
type get_slc(type X, const unsigned int i, const unsigned int j)
Function that returns slice of bits with dynamic range.
Definition: nvhls_int.h:487
type left_shift(type X, int shift)
Function that performs left shift while preserving sign.
Definition: nvhls_int.h:722
type1 set_slc(type1 X, type2 Y, const unsigned int i)
Function that replaces slice of bits.
Definition: nvhls_int.h:387
type2 leading_ones(type1 X)
LeadingOne Detector.
Definition: nvhls_int.h:561
Compute index width of a constant.
Definition: nvhls_int.h:285
Compute Celing of log2 of a constant.
Definition: nvhls_int.h:174
Compute Floor of log2 of a constant.
Definition: nvhls_int.h:142
Compute number of bits to represent a constant.
Definition: nvhls_int.h:118
Compute power of 2 value greater than a given value.
Definition: nvhls_int.h:208
Definition of vendor agnostic integer data types.
Definition: nvhls_int.h:336