csa-rhdl 0.1.0

Carry-save adder compressor trees composed via comp-cat-rs, with hdl-cat backend
Documentation
//! Width arithmetic for the compressor tree.
//!
//! When `M` operands of width `W` are summed, the exact result needs
//! `W + ceil_log2(M)` bits.  A carry-save compressor tree outputs two
//! vectors `(C, S)` whose sum is the exact answer; to hold that sum
//! safely we use the supranational upper bound `W + ceil_log2(M * 2)`.

/// Ceiling of base-2 logarithm.
///
/// Returns `0` for `n == 0` and `n == 1`, `1` for `n == 2`,
/// `2` for `n ∈ {3, 4}`, etc.
///
/// # Examples
///
/// ```
/// use csa_rhdl::width::ceil_log2;
/// assert_eq!(ceil_log2(0), 0);
/// assert_eq!(ceil_log2(1), 0);
/// assert_eq!(ceil_log2(2), 1);
/// assert_eq!(ceil_log2(3), 2);
/// assert_eq!(ceil_log2(4), 2);
/// assert_eq!(ceil_log2(9), 4);
/// ```
#[must_use]
pub const fn ceil_log2(n: usize) -> usize {
    match n {
        0 | 1 => 0,
        _ => (usize::BITS - (n - 1).leading_zeros()) as usize,
    }
}

/// Output width of a registered compressor for `m` operands of width `w`.
///
/// Uses the supranational upper bound `w + ceil_log2(m * 2)`.
///
/// # Examples
///
/// ```
/// use csa_rhdl::width::csa_out_width;
/// assert_eq!(csa_out_width(9, 16), 21);
/// assert_eq!(csa_out_width(3, 8), 11);
/// ```
#[must_use]
pub const fn csa_out_width(m: usize, w: usize) -> usize {
    w + ceil_log2(m.saturating_mul(2))
}

#[cfg(test)]
mod tests {
    use super::{ceil_log2, csa_out_width};

    #[test]
    fn ceil_log2_table() {
        let table: [(usize, usize); 10] = [
            (0, 0),
            (1, 0),
            (2, 1),
            (3, 2),
            (4, 2),
            (5, 3),
            (7, 3),
            (8, 3),
            (9, 4),
            (16, 4),
        ];
        table
            .iter()
            .for_each(|(n, want)| assert_eq!(ceil_log2(*n), *want, "ceil_log2({n})"));
    }

    #[test]
    fn out_width_supranational_bound() {
        assert_eq!(csa_out_width(9, 16), 21);
        assert_eq!(csa_out_width(5, 8), 12);
    }
}