Use Cases
In the following, use cases for Aarith will be shown. (So far, we only present one)
The FAU Adder
The FAU Adder (see [Echavarria2016]) splits the operands into a most-significant part (MSP) and least-significant part
(LSP) and cuts the carry chain in between these parts. To reduce the error, some bits of the LSP (shared_bits
in total)
are used the predict the carry.
The following code implements the FAU adder. This piece of code is intended to show how easily individual bits ca be accessed when designing hardware units.
1template <size_t width, size_t lsp_width, size_t shared_bits = 0>
2uinteger<width + 1> FAUadder(const uinteger<width>& a, const uinteger<width>& b)
3{
4
5 // make sure that the parameters
6 static_assert(shared_bits <= lsp_width);
7 static_assert(lsp_width < width);
8 static_assert(lsp_width > 0);
9
10 //***********************
11 // Extract MSP and LSP
12 // can't use structured binding (i.e. `` auto [msp, lsp] = split<lsp_index>(a)``) as msp and lsp need
13 // not bee of same width
14 constexpr size_t lsp_index = lsp_width - 1;
15 const auto a_split = split<lsp_index>(a);
16 const auto b_split = split<lsp_index>(b);
17
18 const uinteger<lsp_width> a_lsp = a_split.second;
19 const uinteger<lsp_width> b_lsp = b_split.second;
20
21 constexpr size_t msp_width = width - lsp_width;
22 const uinteger<msp_width> a_msp = a_split.first;
23 const uinteger<msp_width> b_msp = b_split.first;
24 //***********************
25
26 // sum up LSP including the computation of the carry
27 uinteger<lsp_width + 1> lsp_sum = expanding_add(a_lsp, b_lsp);
28
29 // remove the carry for later use
30 uinteger<lsp_width> lsp = width_cast<lsp_width>(lsp_sum);
31
32 bool predicted_carry = false;
33 // conditionally perform carry prediction
34 if constexpr (shared_bits > 0)
35 {
36 // extract the shared bit of both operands
37 uinteger<shared_bits> a_shared = bit_range<lsp_index, lsp_index - (shared_bits - 1)>(a);
38 uinteger<shared_bits> b_shared = bit_range<lsp_index, lsp_index - (shared_bits - 1)>(b);
39
40 // compute the carry
41 uinteger<shared_bits + 1> shared_sum = expanding_add(a_shared, b_shared);
42
43 predicted_carry = shared_sum.msb();
44 }
45
46 // if there was a carry but we did not predict one (i.e. it wasn't used in the MSP)
47 // we need to perform an all1 error correction
48 if (lsp_sum.msb() && !predicted_carry)
49 {
50 lsp = lsp.all_ones();
51 }
52
53 // finally put MSP and LSP together
54 const uinteger<msp_width + 1> msp = expanding_add(a_msp, b_msp, predicted_carry);
55
56 uinteger<width + 1> result{lsp};
57
58 const auto extended_msp = width_cast<width + 1>(msp);
59 result = add(result, extended_msp << lsp_width);
60 return result;
61}