1 #pragma once
2 // adapt_integer_and_posit.hpp: adapter functions to convert integer<size> type and posit<nbits,es> types
3 //
4 // Copyright (C) 2017-2021 Stillwater Supercomputing, Inc.
5 //
6 // This file is part of the UNIVERSAL project, which is released under an MIT Open Source license.
7 #include <iostream>
8 
9 // include this adapter before the src/tgt types that you want to connect
10 #include <universal/internal/bitblock/bitblock.hpp>
11 #include <universal/internal/value/value.hpp>
12 
13 // if included, set the compilation flag that will enable the operator=(const TargetType&) in the SourceType.
14 #ifndef ADAPTER_POSIT_AND_INTEGER
15 #define ADAPTER_POSIT_AND_INTEGER 1
16 #else
17 #define ADAPTER_POSIT_AND_INTEGER 0
18 #endif // ADAPTER_POSIT_AND_INTEGER
19 
20 namespace sw::universal {
21 
22 // forward references
23 template<size_t nbits, size_t es> class posit;
24 template<size_t nbits, size_t es> int scale(const posit<nbits, es>&);
25 template<size_t nbits, size_t es, size_t fbits> internal::bitblock<fbits+1> significant(const posit<nbits, es>&);
26 template<size_t nbits, typename BlockType> class integer;
27 
28 /*
29   Why is the convert function not part of the Integer or Posit types?
30   It would tightly couple the types, which we want to avoid.
31   If we want to productize these convertions we would need a new
32   layer in the module design that sits above the Universal types. TODO
33  */
34 
35 // convert a Posit to an Integer
36 template<size_t nbits, size_t es, size_t ibits, typename BlockType>
convert_p2i(const posit<nbits,es> & p,integer<ibits,BlockType> & v)37 inline void convert_p2i(const posit<nbits, es>& p, integer<ibits, BlockType>& v) {
38 	// get the scale of the posit value
39 	int scale = sw::universal::scale(p);
40 	if (scale < 0) {
41 		v = 0;
42 		return;
43 	}
44 	if (scale == 0) {
45 		v = 1;
46 	}
47 	else {
48 		// gather all the fraction bits
49 		// bitblock<p.fhbits> significant = significant<p.nbits, p.es, p.fbits>(p);
50 		sw::universal::internal::bitblock<posit<nbits, es>::fhbits> significant = sw::universal::significant<nbits, es, posit<nbits, es>::fbits>(p);
51 		// the radix point is at fbits, to make an integer out of this
52 		// we shift that radix point fbits to the right.
53 		// that is equivalent to a scale of 2^fbits
54 		v.clear();
55 		int msb = (v.nbits < p.fbits + 1) ? v.nbits : p.fbits + 1;
56 		for (int i = msb-1; i >= 0; --i) {
57 			v.setbit(i, significant[i]);
58 		}
59 		int shift = scale - p.fbits;  // if scale > fbits we need to shift left
60 		v <<= shift;
61 		if (p.isneg()) {
62 			v.flip();
63 			v += 1;
64 		}
65 	}
66 }
67 
68 /////////////////////////////////////////////////////////////////////////
69 // convert an Integer to a Posit
70 template<size_t ibits, typename BlockType, size_t nbits, size_t es>
convert_i2p(const integer<ibits,BlockType> & w,posit<nbits,es> & p)71 inline void convert_i2p(const integer<ibits, BlockType>& w, posit<nbits, es>& p) {
72 	using namespace std;
73 
74 	bool sign = w < 0;
75 	bool isZero = w == 0;
76 	bool isInf = false;
77 	bool isNan = false;
78 	long _scale = scale(w);
79 	integer<ibits, BlockType> w2 = sign ? twosComplement(w) : w;
80 	int msb = findMsb(w2);
81 	internal::bitblock<nbits> fraction_without_hidden_bit;
82 	int fbit = nbits - 1;
83 	for (int i = msb - 1; i >= 0; --i) {
84 		fraction_without_hidden_bit.set(fbit, w2.at(i));
85 		--fbit;
86 	}
87 	internal::value<nbits> v;
88 	v.set(sign, _scale, fraction_without_hidden_bit, isZero, isInf, isNan);
89 	p = v;
90 }
91 
92 } // namespace sw::universal
93