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}