use std::{cmp::min, mem, num::NonZeroUsize};
use awint::{
awint_dag::{
smallvec::{smallvec, SmallVec},
ConcatFieldsType, PState,
},
bw,
};
use dag::{awi, inlawi, inlawi_ty, Awi, Bits, InlAwi};
use crate::{
awi,
awint_dag::{ConcatType, Lineage, Op},
dag,
ensemble::LNode,
};
const USIZE_BITS: usize = usize::BITS as usize;
pub fn create_static_lut(
mut inxs: SmallVec<[PState; 4]>,
mut lut: awi::Awi,
) -> Result<Op<PState>, PState> {
let len = usize::from(u8::try_from(inxs.len()).unwrap());
for i in (0..len).rev() {
let p_state = inxs[i];
if let Some(bit) = p_state.try_get_as_awi() {
debug_assert_eq!(bit.bw(), 1);
inxs.remove(i);
crate::ensemble::LNode::reduce_lut(&mut lut, i, bit.to_bool());
}
}
let len = inxs.len();
for i in (0..len).rev() {
if (lut.bw() > 1) && LNode::reduce_independent_lut(&mut lut, i) {
inxs.remove(i);
}
}
if lut.bw() == 1 {
if lut.is_zero() {
Ok(Op::Literal(awi::Awi::zero(bw(1))))
} else {
Ok(Op::Literal(awi::Awi::umax(bw(1))))
}
} else if (lut.bw() == 2) && lut.get(1).unwrap() {
Err(inxs[0])
} else {
Ok(Op::StaticLut(
ConcatType::from_iter(inxs.iter().cloned()),
lut,
))
}
}
macro_rules! static_lut {
($lhs:ident; $lut:expr; $($inx:expr),*) => {{
match create_static_lut(
smallvec![$(
$inx.state(),
)*],
{use awi::*; awi!($lut)}
) {
Ok(op) => {
$lhs.update_state(
bw(1),
op,
).unwrap_at_runtime();
}
Err(copy) => {
$lhs.set_state(copy);
}
}
}};
}
fn concat(nzbw: NonZeroUsize, vec: SmallVec<[PState; 4]>) -> Awi {
if vec.len() == 1 {
Awi::from_state(vec[0])
} else {
Awi::new(nzbw, Op::Concat(ConcatType::from_smallvec(vec)))
}
}
fn concat_update(bits: &mut Bits, nzbw: NonZeroUsize, vec: SmallVec<[PState; 4]>) {
if vec.len() == 1 {
bits.set_state(vec[0]);
} else {
bits.update_state(nzbw, Op::Concat(ConcatType::from_smallvec(vec)))
.unwrap_at_runtime();
}
}
pub fn reverse(x: &Bits) -> Awi {
let nzbw = x.nzbw();
let mut out = SmallVec::with_capacity(nzbw.get());
for i in 0..x.bw() {
out.push(x.get(x.bw() - 1 - i).unwrap().state())
}
concat(nzbw, out)
}
pub fn selector(inx: &Bits, cap: Option<usize>) -> Vec<inlawi_ty!(1)> {
let num = cap.unwrap_or_else(|| 1usize << inx.bw());
if num == 0 {
panic!();
}
if num == 1 {
return vec![inlawi!(1)]
}
let lb_num = num.next_power_of_two().trailing_zeros() as usize;
let mut signals = Vec::with_capacity(num);
for i in 0..num {
let mut signal = inlawi!(1);
for j in 0..lb_num {
if (i & (1 << j)) == 0 {
static_lut!(signal; 0100; inx.get(j).unwrap(), signal);
} else {
static_lut!(signal; 1000; inx.get(j).unwrap(), signal);
}
}
signals.push(signal);
}
signals
}
pub fn selector_awi(inx: &Bits, cap: Option<usize>) -> Awi {
let num = cap.unwrap_or_else(|| 1usize << inx.bw());
if num == 0 {
panic!();
}
if num == 1 {
return awi!(1)
}
let lb_num = num.next_power_of_two().trailing_zeros() as usize;
let nzbw = NonZeroUsize::new(num).unwrap();
let mut signals = SmallVec::with_capacity(num);
for i in 0..num {
let mut signal = inlawi!(1);
for j in 0..lb_num {
if (i & (1 << j)) == 0 {
static_lut!(signal; 0100; inx.get(j).unwrap(), signal);
} else {
static_lut!(signal; 1000; inx.get(j).unwrap(), signal);
}
}
signals.push(signal.state());
}
concat(nzbw, signals)
}
pub fn static_mux(x0: &Bits, x1: &Bits, inx: &Bits) -> Awi {
debug_assert_eq!(x0.bw(), x1.bw());
debug_assert_eq!(inx.bw(), 1);
let nzbw = x0.nzbw();
let mut signals = SmallVec::with_capacity(nzbw.get());
for i in 0..x0.bw() {
let mut tmp = inlawi!(0);
static_lut!(tmp; 1100_1010; x0.get(i).unwrap(), x1.get(i).unwrap(), inx);
signals.push(tmp.state());
}
concat(nzbw, signals)
}
pub fn general_mux(inputs: &[Awi], inx: &Bits) -> Awi {
debug_assert!(!inputs.is_empty());
let nzbw = inputs[0].nzbw();
let lut_w = NonZeroUsize::new(inputs.len().next_power_of_two()).unwrap();
debug_assert_eq!(1 << inx.bw(), lut_w.get());
let mut out_signals = SmallVec::with_capacity(nzbw.get());
let unknown = Awi::opaque(bw(1));
for out_i in 0..nzbw.get() {
let mut lut = Vec::with_capacity(lut_w.get());
for input in inputs {
lut.push((input.state(), out_i, bw(1)));
}
for _ in lut.len()..lut_w.get() {
lut.push((unknown.state(), 0, bw(1)));
}
let lut = Awi::new(
lut_w,
Op::ConcatFields(ConcatFieldsType::from_iter(lut.iter().cloned())),
);
out_signals.push(Awi::new(bw(1), Op::Lut([lut.state(), inx.state()])).state());
}
concat(nzbw, out_signals)
}
pub fn dynamic_to_static_get(bits: &Bits, inx: &Bits) -> inlawi_ty!(1) {
if bits.bw() == 1 {
return InlAwi::from(bits.to_bool())
}
let lut_w = NonZeroUsize::new(bits.bw().next_power_of_two()).unwrap();
let inx_w = NonZeroUsize::new(lut_w.get().trailing_zeros() as usize).unwrap();
let mut true_inx = Awi::zero(inx_w);
true_inx.field_width(inx, inx_w.get()).unwrap();
let base = if bits.bw() == lut_w.get() {
Awi::from(bits)
} else {
let unknowns =
Awi::opaque(NonZeroUsize::new(lut_w.get().checked_sub(bits.bw()).unwrap()).unwrap());
concat(lut_w, smallvec![bits.state(), unknowns.state()])
};
InlAwi::new(Op::Lut([base.state(), true_inx.state()]))
}
pub fn tsmear_inx(inx: &Bits, num_signals: usize) -> Vec<inlawi_ty!(1)> {
let next_pow = num_signals.next_power_of_two();
let mut lb_num = next_pow.trailing_zeros() as usize;
if next_pow == num_signals {
lb_num += 1;
}
let mut signals = Vec::with_capacity(num_signals);
for i in 0..num_signals {
let mut signal = inlawi!(0);
let mut prefix_equal = inlawi!(1);
for j in (0..lb_num).rev() {
if (i & (1 << j)) == 0 {
let inx_j = inx.get(j).unwrap();
static_lut!(signal; 11111000; inx_j, prefix_equal, signal);
static_lut!(prefix_equal; 0100; inx_j, prefix_equal);
} else {
static_lut!(prefix_equal; 1000; inx.get(j).unwrap(), prefix_equal);
}
}
signals.push(signal);
}
signals
}
pub fn tsmear_awi(inx: &Bits, num_signals: usize) -> Awi {
let next_pow = num_signals.next_power_of_two();
let mut lb_num = next_pow.trailing_zeros() as usize;
if next_pow == num_signals {
lb_num += 1;
}
let nzbw = NonZeroUsize::new(num_signals).unwrap();
let mut signals = SmallVec::with_capacity(num_signals);
for i in 0..num_signals {
let mut signal = inlawi!(0);
let mut prefix_equal = inlawi!(1);
for j in (0..lb_num).rev() {
if (i & (1 << j)) == 0 {
let inx_j = inx.get(j).unwrap();
static_lut!(signal; 11111000; inx_j, prefix_equal, signal);
static_lut!(prefix_equal; 0100; inx_j, prefix_equal);
} else {
static_lut!(prefix_equal; 1000; inx.get(j).unwrap(), prefix_equal);
}
}
signals.push(signal.state());
}
concat(nzbw, signals)
}
pub fn dynamic_to_static_lut(out: &mut Bits, table: &Bits, inx: &Bits) {
debug_assert!(table.bw() == (out.bw().checked_mul(1 << inx.bw()).unwrap()));
let signals = selector(inx, None);
let nzbw = out.nzbw();
let mut tmp_output = SmallVec::with_capacity(nzbw.get());
for j in 0..out.bw() {
let mut column = inlawi!(0);
for (i, signal) in signals.iter().enumerate() {
static_lut!(column; 1111_1000; signal, table.get((i * out.bw()) + j).unwrap(), column);
}
tmp_output.push(column.state());
}
concat_update(out, nzbw, tmp_output)
}
pub fn dynamic_to_static_set(bits: &Bits, inx: &Bits, bit: &Bits) -> Awi {
if bits.bw() == 1 {
return Awi::from(bit)
}
let signals = selector(inx, Some(bits.bw()));
let nzbw = bits.nzbw();
let mut out = SmallVec::with_capacity(nzbw.get());
for (i, signal) in signals.iter().enumerate() {
let mut tmp = inlawi!(0);
static_lut!(tmp; 1101_1000; signal, bit, bits.get(i).unwrap());
out.push(tmp.state());
}
concat(nzbw, out)
}
pub fn resize(x: &Bits, w: NonZeroUsize, signed: bool) -> Awi {
if w == x.nzbw() {
Awi::from_bits(x)
} else if w < x.nzbw() {
Awi::new(
w,
Op::ConcatFields(ConcatFieldsType::from_iter([(x.state(), 0usize, w)])),
)
} else if signed {
let extension = Awi::new(
NonZeroUsize::new(w.get() - x.bw()).unwrap(),
Op::Repeat([x.msb().state()]),
);
concat(w, smallvec![x.state(), extension.state()])
} else {
let zero = Awi::zero(NonZeroUsize::new(w.get() - x.bw()).unwrap());
concat(w, smallvec![x.state(), zero.state()])
}
}
pub fn resize_cond(x: &Bits, w: NonZeroUsize, signed: &Bits) -> Awi {
debug_assert_eq!(signed.bw(), 1);
if w == x.nzbw() {
Awi::from_bits(x)
} else if w < x.nzbw() {
Awi::new(
w,
Op::ConcatFields(ConcatFieldsType::from_iter([(x.state(), 0usize, w)])),
)
} else {
let extension = Awi::new(
NonZeroUsize::new(w.get() - x.bw()).unwrap(),
Op::Repeat([signed.state()]),
);
concat(w, smallvec![x.state(), extension.state()])
}
}
pub fn field_width(lhs: &Bits, rhs: &Bits, width: &Bits) -> Awi {
let min_w = min(lhs.bw(), rhs.bw());
let signals = tsmear_inx(width, min_w);
let nzbw = NonZeroUsize::new(signals.len()).unwrap();
let mut mux_part = SmallVec::with_capacity(nzbw.get());
for (i, signal) in signals.into_iter().enumerate() {
let mut tmp = inlawi!(0);
static_lut!(tmp; 1100_1010; lhs.get(i).unwrap(), rhs.get(i).unwrap(), signal);
mux_part.push(tmp.state());
}
let mux_part = concat(nzbw, mux_part);
if let Some(lhs_rem_hi) = NonZeroUsize::new(lhs.bw() - nzbw.get()) {
Awi::new(
lhs.nzbw(),
Op::ConcatFields(ConcatFieldsType::from_iter([
(mux_part.state(), 0usize, nzbw),
(lhs.state(), nzbw.get(), lhs_rem_hi),
])),
)
} else {
mux_part
}
}
pub fn funnel(x: &Bits, s: &Bits) -> Awi {
debug_assert!((s.bw() < (USIZE_BITS - 1)) && ((2usize << s.bw()) == x.bw()));
let out_w = NonZeroUsize::new(1 << s.bw()).unwrap();
let mut output = SmallVec::with_capacity(out_w.get());
for j in 0..out_w.get() {
let lut = Awi::new(
out_w,
Op::ConcatFields(ConcatFieldsType::from_iter([(x.state(), j, out_w)])),
);
output.push(Awi::new(bw(1), Op::Lut([lut.state(), s.state()])).state());
}
concat(out_w, output)
}
pub fn range_or(x: &Bits, start: &Bits, end: &Bits) -> Awi {
let tmask0 = tsmear_inx(start, x.bw());
let tmask1 = tsmear_inx(end, x.bw());
let mut out = SmallVec::with_capacity(x.bw());
for i in 0..x.bw() {
let mut signal = inlawi!(0);
static_lut!(signal; 1111_0100; tmask0[i], tmask1[i], x.get(i).unwrap());
out.push(signal.state());
}
concat(x.nzbw(), out)
}
pub fn range_and(x: &Bits, start: &Bits, end: &Bits) -> Awi {
let tmask0 = tsmear_inx(start, x.bw());
let tmask1 = tsmear_inx(end, x.bw());
let mut out = SmallVec::with_capacity(x.bw());
for i in 0..x.bw() {
let mut signal = inlawi!(0);
static_lut!(signal; 0100_0000; tmask0[i], tmask1[i], x.get(i).unwrap());
out.push(signal.state());
}
concat(x.nzbw(), out)
}
pub fn range_xor(x: &Bits, start: &Bits, end: &Bits) -> Awi {
let tmask0 = tsmear_inx(start, x.bw());
let tmask1 = tsmear_inx(end, x.bw());
let mut out = SmallVec::with_capacity(x.bw());
for i in 0..x.bw() {
let mut signal = inlawi!(0);
static_lut!(signal; 1011_0100; tmask0[i], tmask1[i], x.get(i).unwrap());
out.push(signal.state());
}
concat(x.nzbw(), out)
}
pub fn field_from(lhs: &Bits, rhs: &Bits, from: &Bits, width: &Bits) -> Awi {
let mut out = Awi::from_bits(lhs);
if let Some(s_w) = Bits::nontrivial_bits(rhs.bw() - 1) {
let mut s = Awi::zero(s_w);
s.resize_(from, false);
let mut x = Awi::opaque(NonZeroUsize::new(2 << s_w.get()).unwrap());
let w = rhs.bw();
let _ = x.field_width(rhs, w);
let tmp = funnel(&x, &s);
let max_width = min(lhs.bw(), rhs.bw());
let mut small_width = Awi::zero(Bits::nontrivial_bits(max_width).unwrap());
small_width.resize_(width, false);
let _ = out.field_width(&tmp, small_width.to_usize());
} else {
let small_width = Awi::from_bool(width.lsb());
let _ = out.field_width(rhs, small_width.to_usize());
}
out
}
pub fn shl(x: &Bits, s: &Bits) -> Awi {
let mut out = Awi::zero(x.nzbw());
if let Some(small_s_w) = Bits::nontrivial_bits(x.bw() - 1) {
let mut small_s = Awi::zero(small_s_w);
small_s.resize_(s, false);
let mut wide_x = Awi::opaque(NonZeroUsize::new(2 << small_s_w.get()).unwrap());
let _ = wide_x.field_to(x.bw(), &Awi::zero(x.nzbw()), x.bw() - 1);
let mut rev_x = Awi::zero(x.nzbw());
rev_x.copy_(x).unwrap();
rev_x.rev_();
let _ = wide_x.field_width(&rev_x, x.bw());
let tmp = funnel(&wide_x, &small_s);
out.resize_(&tmp, false);
out.rev_();
} else {
let small_width = Awi::from_bool(s.lsb());
out.resize_(x, false);
let _ = out.field_width(x, small_width.to_usize());
}
out
}
pub fn lshr(x: &Bits, s: &Bits) -> Awi {
let mut out = Awi::zero(x.nzbw());
if let Some(small_s_w) = Bits::nontrivial_bits(x.bw() - 1) {
let mut small_s = Awi::zero(small_s_w);
small_s.resize_(s, false);
let mut wide_x = Awi::opaque(NonZeroUsize::new(2 << small_s_w.get()).unwrap());
let _ = wide_x.field_to(x.bw(), &Awi::zero(x.nzbw()), x.bw() - 1);
let _ = wide_x.field_width(x, x.bw());
let tmp = funnel(&wide_x, &small_s);
out.resize_(&tmp, false);
} else {
let small_width = Awi::from_bool(s.lsb());
out.resize_(x, false);
let _ = out.field_width(x, small_width.to_usize());
}
out
}
pub fn ashr(x: &Bits, s: &Bits) -> Awi {
let mut out = Awi::zero(x.nzbw());
if let Some(small_s_w) = Bits::nontrivial_bits(x.bw() - 1) {
let mut small_s = Awi::zero(small_s_w);
small_s.resize_(s, false);
let mut wide_x = Awi::opaque(NonZeroUsize::new(2 << small_s_w.get()).unwrap());
let _ = wide_x.field_to(
x.bw(),
&Awi::new(x.nzbw(), Op::Repeat([x.msb().state()])),
x.bw() - 1,
);
let _ = wide_x.field_width(x, x.bw());
let tmp = funnel(&wide_x, &small_s);
out.resize_(&tmp, false);
} else {
let small_width = Awi::from_bool(s.lsb());
out.resize_(x, false);
let _ = out.field_width(x, small_width.to_usize());
}
out
}
pub fn rotl(x: &Bits, s: &Bits) -> Awi {
let mut out = Awi::zero(x.nzbw());
if let Some(small_s_w) = Bits::nontrivial_bits(x.bw() - 1) {
let mut small_s = Awi::zero(small_s_w);
small_s.resize_(s, false);
let mut rev_x = Awi::zero(x.nzbw());
rev_x.copy_(x).unwrap();
rev_x.rev_();
let mut wide_x = Awi::opaque(NonZeroUsize::new(2 << small_s_w.get()).unwrap());
let _ = wide_x.field_to(x.bw(), &rev_x, x.bw() - 1);
let _ = wide_x.field_width(&rev_x, x.bw());
let tmp = funnel(&wide_x, &small_s);
out.resize_(&tmp, false);
out.rev_();
} else {
let small_width = Awi::from_bool(s.lsb());
out.resize_(x, false);
let _ = out.field_width(x, small_width.to_usize());
}
out
}
pub fn rotr(x: &Bits, s: &Bits) -> Awi {
let mut out = Awi::zero(x.nzbw());
if let Some(small_s_w) = Bits::nontrivial_bits(x.bw() - 1) {
let mut small_s = Awi::zero(small_s_w);
small_s.resize_(s, false);
let mut wide_x = Awi::opaque(NonZeroUsize::new(2 << small_s_w.get()).unwrap());
let _ = wide_x.field_to(x.bw(), x, x.bw() - 1);
let _ = wide_x.field_width(x, x.bw());
let tmp = funnel(&wide_x, &small_s);
out.resize_(&tmp, false);
} else {
let small_width = Awi::from_bool(s.lsb());
out.resize_(x, false);
let _ = out.field_width(x, small_width.to_usize());
}
out
}
pub fn bitwise_not(x: &Bits) -> Awi {
let nzbw = x.nzbw();
let mut out = SmallVec::with_capacity(nzbw.get());
for i in 0..x.bw() {
let mut tmp = inlawi!(0);
static_lut!(tmp; 01; x.get(i).unwrap());
out.push(tmp.state());
}
concat(nzbw, out)
}
pub fn bitwise(lhs: &Bits, rhs: &Bits, lut: awi::Awi) -> Awi {
debug_assert_eq!(lhs.bw(), rhs.bw());
debug_assert_eq!(lut.bw(), 4);
let nzbw = lhs.nzbw();
let mut out = SmallVec::with_capacity(nzbw.get());
for i in 0..lhs.bw() {
let mut tmp = inlawi!(0);
tmp.update_state(
bw(1),
Op::StaticLut(
ConcatType::from_iter([lhs.get(i).unwrap().state(), rhs.get(i).unwrap().state()]),
lut.clone(),
),
)
.unwrap_at_runtime();
out.push(tmp.state());
}
concat(nzbw, out)
}
pub fn incrementer(x: &Bits, cin: &Bits, dec: bool) -> (Awi, inlawi_ty!(1)) {
debug_assert_eq!(cin.bw(), 1);
let nzbw = x.nzbw();
let mut out = SmallVec::with_capacity(nzbw.get());
let mut carry = InlAwi::from(cin.to_bool());
if dec {
for i in 0..x.bw() {
let mut tmp = inlawi!(0);
let b = x.get(i).unwrap();
static_lut!(tmp; 1001; carry, b);
out.push(tmp.state());
static_lut!(carry; 1110; carry, b);
}
} else {
for i in 0..x.bw() {
let mut tmp = inlawi!(0);
let b = x.get(i).unwrap();
static_lut!(tmp; 0110; carry, b);
out.push(tmp.state());
static_lut!(carry; 1000; carry, b);
}
}
(concat(nzbw, out), carry)
}
pub fn cin_sum(cin: &Bits, lhs: &Bits, rhs: &Bits) -> (Awi, inlawi_ty!(1), inlawi_ty!(1)) {
debug_assert_eq!(cin.bw(), 1);
debug_assert_eq!(lhs.bw(), rhs.bw());
let w = lhs.bw();
let nzbw = lhs.nzbw();
let mut out = SmallVec::with_capacity(nzbw.get());
let mut carry = InlAwi::from(cin.to_bool());
for i in 0..w {
let mut sum = inlawi!(0);
let mut next_carry = inlawi!(0);
static_lut!(sum; 1001_0110;
carry,
lhs.get(i).unwrap(),
rhs.get(i).unwrap()
);
static_lut!(next_carry; 1110_1000;
carry,
lhs.get(i).unwrap(),
rhs.get(i).unwrap()
);
out.push(sum.state());
carry = next_carry;
}
let mut signed_overflow = inlawi!(0);
let a = lhs.get(w - 1).unwrap().state();
let b = rhs.get(w - 1).unwrap().state();
let c = *out.get(w - 1).unwrap();
signed_overflow
.update_state(
bw(1),
Op::StaticLut(ConcatType::from_iter([a, b, c]), {
use awi::*;
awi!(0001_1000)
}),
)
.unwrap_at_runtime();
(concat(nzbw, out), carry, signed_overflow)
}
pub fn negator(x: &Bits, neg: &Bits) -> Awi {
debug_assert_eq!(neg.bw(), 1);
let nzbw = x.nzbw();
let mut out = SmallVec::with_capacity(nzbw.get());
let mut carry = InlAwi::from(neg.to_bool());
for i in 0..x.bw() {
let mut sum = inlawi!(0);
let mut next_carry = inlawi!(0);
static_lut!(sum; 1001_0110; carry, x.get(i).unwrap(), neg);
static_lut!(next_carry; 0010_1000; carry, x.get(i).unwrap(), neg);
out.push(sum.state());
carry = next_carry;
}
concat(nzbw, out)
}
pub fn field_to(lhs: &Bits, to: &Bits, rhs: &Bits, width: &Bits) -> Awi {
if let Some(s_w) = Bits::nontrivial_bits(lhs.bw() - 1) {
let mut s = Awi::zero(s_w);
s.resize_(to, false);
let mut wide_rhs = Awi::opaque(NonZeroUsize::new(2 << s_w.get()).unwrap());
let mut rev_rhs = Awi::zero(rhs.nzbw());
rev_rhs.copy_(rhs).unwrap();
rev_rhs.rev_();
if let Some(field_to) = lhs.bw().checked_sub(rhs.bw()) {
let _ = wide_rhs.field_to(field_to, &rev_rhs, rhs.bw());
} else {
let field_from = rhs.bw().wrapping_sub(lhs.bw());
let _ = wide_rhs.field_from(&rev_rhs, field_from, lhs.bw());
}
let tmp = funnel(&wide_rhs, &s);
let mut funnel_res = Awi::zero(lhs.nzbw());
funnel_res.resize_(&tmp, false);
funnel_res.rev_();
let s_w = NonZeroUsize::new(s_w.get().checked_add(1).unwrap()).unwrap();
let mut small_to = Awi::zero(s_w);
small_to.usize_(to.to_usize());
let mut small_width = Awi::zero(s_w);
small_width.usize_(width.to_usize());
let mut to_plus_width = small_width;
to_plus_width.add_(&small_to).unwrap();
let tmask = tsmear_inx(&to_plus_width, lhs.bw());
let lmask = tsmear_inx(&small_to, lhs.bw());
let mut out = SmallVec::with_capacity(lhs.bw());
for i in 0..lhs.bw() {
let mut signal = inlawi!(0);
static_lut!(
signal; 1111_1011_0100_0000;
lmask[i], tmask[i], funnel_res.get(i).unwrap(), lhs.get(i).unwrap()
);
out.push(signal.state());
}
concat(lhs.nzbw(), out)
} else {
let mut out = Awi::from_bits(lhs);
let small_width = Awi::from_bool(width.lsb());
let _ = out.field_width(rhs, small_width.to_usize());
out
}
}
pub fn field(lhs: &Bits, to: &Bits, rhs: &Bits, from: &Bits, width: &Bits) -> Awi {
if let Some(s_w) = Bits::nontrivial_bits(lhs.bw() + rhs.bw() - 2) {
let mut s = Awi::zero(s_w);
let mut small_from = Awi::zero(s_w);
let mut small_to = Awi::zero(s_w);
small_from.resize_(from, false);
small_to.resize_(to, false);
s.usize_(rhs.bw() - 1);
s.sub_(&small_from).unwrap();
s.add_(&small_to).unwrap();
let mut wide_rhs = Awi::opaque(NonZeroUsize::new(2 << s_w.get()).unwrap());
let mut rev_rhs = Awi::zero(rhs.nzbw());
rev_rhs.copy_(rhs).unwrap();
rev_rhs.rev_();
let _ = wide_rhs.field_to(lhs.bw() - 1, &rev_rhs, rhs.bw());
let tmp = funnel(&wide_rhs, &s);
let mut funnel_res = Awi::zero(lhs.nzbw());
funnel_res.resize_(&tmp, false);
funnel_res.rev_();
let s_w = NonZeroUsize::new(s_w.get().checked_add(1).unwrap()).unwrap();
let mut small_to = Awi::zero(s_w);
small_to.usize_(to.to_usize());
let mut small_width = Awi::zero(s_w);
small_width.usize_(width.to_usize());
let mut to_plus_width = small_width;
to_plus_width.add_(&small_to).unwrap();
let tmask = tsmear_inx(&to_plus_width, lhs.bw());
let lmask = tsmear_inx(&small_to, lhs.bw());
let mut out = SmallVec::with_capacity(lhs.bw());
for i in 0..lhs.bw() {
let mut signal = inlawi!(0);
static_lut!(
signal; 1111_1011_0100_0000;
lmask[i], tmask[i], funnel_res.get(i).unwrap(), lhs.get(i).unwrap()
);
out.push(signal.state());
}
concat(lhs.nzbw(), out)
} else {
let mut out = Awi::from_bits(lhs);
let small_width = Awi::from_bool(width.lsb());
let _ = out.field_width(rhs, small_width.to_usize());
out
}
}
pub fn equal(lhs: &Bits, rhs: &Bits) -> inlawi_ty!(1) {
let mut ranks = vec![vec![]];
for i in 0..lhs.bw() {
let mut tmp1 = inlawi!(0);
static_lut!(tmp1; 1001; lhs.get(i).unwrap(), rhs.get(i).unwrap());
ranks[0].push(tmp1);
}
loop {
let prev_rank = ranks.last().unwrap();
let rank_len = prev_rank.len();
if rank_len == 1 {
break prev_rank[0]
}
let mut next_rank = vec![];
for i in 0..(rank_len / 2) {
let mut tmp1 = inlawi!(0);
static_lut!(tmp1; 1000; prev_rank[2 * i], prev_rank[2 * i + 1]);
next_rank.push(tmp1);
}
if (rank_len & 1) != 0 {
next_rank.push(*prev_rank.last().unwrap())
}
ranks.push(next_rank);
}
}
pub fn count_ones(x: &Bits) -> Awi {
let mut ranks: Vec<Vec<(Awi, awi::Awi)>> = vec![vec![]];
for i in 0..x.bw() {
ranks[0].push((Awi::from(x.get(i).unwrap()), awi::Awi::from(true)));
}
loop {
let prev_rank = ranks.last().unwrap();
let rank_len = prev_rank.len();
if rank_len == 1 {
break prev_rank[0].0.clone()
}
let mut next_rank = vec![];
let mut i = 0;
loop {
if i >= rank_len {
break
}
let mut next_sum = awi!(0, prev_rank[i].0);
let mut next_max = {
use awi::*;
awi!(0, prev_rank[i].1)
};
loop {
i += 1;
if i >= rank_len {
break
}
let w = next_max.bw();
{
use awi::*;
let mut tmp = Awi::zero(next_max.nzbw());
if tmp
.cin_sum_(
false,
&awi!(zero: .., prev_rank[i].1; ..w).unwrap(),
&next_max,
)
.unwrap()
.0
{
break
}
cc!(tmp; next_max).unwrap();
}
next_sum
.add_(&awi!(zero: .., prev_rank[i].0; ..w).unwrap())
.unwrap();
}
next_rank.push((next_sum, next_max));
}
ranks.push(next_rank);
}
}
pub fn tsmear(x: &Bits) -> Awi {
let mut tmp0 = Awi::from(x);
let mut lvl = 0;
loop {
let s = 1 << lvl;
if s >= x.bw() {
break tmp0
}
let mut tmp1 = tmp0.clone();
tmp1.lshr_(s).unwrap();
tmp0.or_(&tmp1).unwrap();
lvl += 1;
}
}
pub fn leading_zeros(x: &Bits) -> Awi {
let mut tmp = tsmear(x);
tmp.not_();
count_ones(&tmp)
}
pub fn trailing_zeros(x: &Bits) -> Awi {
let mut tmp = Awi::from_bits(x);
tmp.rev_();
let mut tmp = tsmear(&tmp);
tmp.not_();
count_ones(&tmp)
}
pub fn significant_bits(x: &Bits) -> Awi {
count_ones(&tsmear(x))
}
pub fn lut_set(table: &Bits, entry: &Bits, inx: &Bits) -> Awi {
let num_entries = 1 << inx.bw();
debug_assert_eq!(table.bw(), entry.bw() * num_entries);
let signals = selector(inx, Some(num_entries));
let mut out = Awi::from_bits(table);
for (j, signal) in signals.into_iter().enumerate() {
for i in 0..entry.bw() {
let lut_inx = i + (j * entry.bw());
let mut tmp1 = inlawi!(0);
static_lut!(tmp1; 1100_1010;
table.get(lut_inx).unwrap(),
entry.get(i).unwrap(),
signal
);
out.set(lut_inx, tmp1.to_bool()).unwrap();
}
}
out
}
pub fn mul_add(out_w: NonZeroUsize, add: Option<&Bits>, lhs: &Bits, rhs: &Bits) -> Awi {
let (lhs, rhs) = if lhs.bw() < rhs.bw() {
(rhs, lhs)
} else {
(lhs, rhs)
};
let place_map0: &mut Vec<Vec<inlawi_ty!(1)>> = &mut vec![];
let place_map1: &mut Vec<Vec<inlawi_ty!(1)>> = &mut vec![];
for _ in 0..out_w.get() {
place_map0.push(vec![]);
place_map1.push(vec![]);
}
for j in 0..rhs.bw() {
let rhs_j = rhs.get(j).unwrap();
for i in 0..lhs.bw() {
if let Some(place) = place_map0.get_mut(i + j) {
let mut ji = inlawi!(0);
static_lut!(ji; 1000; rhs_j, lhs.get(i).unwrap());
place.push(ji);
}
}
}
if let Some(add) = add {
for i in 0..add.bw() {
if let Some(place) = place_map0.get_mut(i) {
place.push(inlawi!(add[i]).unwrap());
}
}
}
loop {
let mut gt2 = false;
for i in 0..place_map0.len() {
if place_map0[i].len() > 2 {
gt2 = true;
}
}
if !gt2 {
break
}
for i in 0..place_map0.len() {
if let Some(w) = NonZeroUsize::new(place_map0[i].len()) {
let mut column = Awi::zero(w);
for (i, bit) in place_map0[i].drain(..).enumerate() {
column.set(i, bit.to_bool()).unwrap();
}
let row = count_ones(&column);
for j in 0..row.bw() {
if let Some(place) = place_map1.get_mut(i + j) {
place.push(inlawi!(row[j]).unwrap())
}
}
}
}
mem::swap(place_map0, place_map1);
}
let mut out = Awi::zero(out_w);
let mut tmp = Awi::zero(out_w);
for i in 0..out.bw() {
for (j, bit) in place_map0[i].iter().enumerate() {
if j == 0 {
out.set(i, bit.to_bool()).unwrap();
} else if j == 1 {
tmp.set(i, bit.to_bool()).unwrap();
} else {
unreachable!()
}
}
}
out.add_(&tmp).unwrap();
out
}
pub fn division(duo: &Bits, div: &Bits) -> (Awi, Awi) {
debug_assert_eq!(duo.bw(), div.bw());
let original_w = duo.nzbw();
let w = NonZeroUsize::new(original_w.get() + 1).unwrap();
let mut tmp = Awi::zero(w);
tmp.resize_(duo, false);
let duo = tmp;
let mut tmp = Awi::zero(w);
tmp.resize_(div, false);
let div = tmp;
let div_original = div.clone();
let duo_lt_div = duo.ult(&div).unwrap();
let mut short_quo = Awi::zero(w);
let mut short_rem = Awi::zero(w);
short_rem.mux_(&duo, duo_lt_div).unwrap();
let mut short = duo_lt_div;
let mut shl = leading_zeros(&div);
shl.sub_(&leading_zeros(&duo)).unwrap();
let mut shifted_div = Awi::from_bits(&div);
shifted_div.shl_(shl.to_usize()).unwrap();
let reshift = duo.ult(&shifted_div).unwrap();
shl.dec_(!reshift);
let mut reshifted = shifted_div.clone();
reshifted.lshr_(1).unwrap();
let mut div = shifted_div;
div.mux_(&reshifted, reshift).unwrap();
let mut duo = Awi::from_bits(&duo);
duo.sub_(&div).unwrap();
let tmp = selector_awi(&shl, Some(w.get()));
let mut quo = Awi::zero(w);
quo.resize_(&tmp, false);
let b = duo.ult(&div_original).unwrap();
short_quo.mux_(&quo, b & !short).unwrap();
short_rem.mux_(&duo, b & !short).unwrap();
short |= b;
let mut mask = quo.clone();
mask.dec_(false);
div.dec_(false);
let mut i = shl.clone();
for _ in 0..w.get() {
let b = i.is_zero();
i.dec_(b);
let mut tmp0 = div.clone();
tmp0.neg_(!duo.msb());
let mut tmp1 = duo.clone();
tmp1.shl_(1).unwrap();
tmp1.add_(&tmp0).unwrap();
duo.mux_(&tmp1, !b).unwrap();
}
let mut tmp = Awi::zero(w);
tmp.mux_(&div, duo.msb()).unwrap();
duo.add_(&tmp).unwrap();
let mut tmp_quo = duo.clone();
tmp_quo.and_(&mask).unwrap();
tmp_quo.or_(&quo).unwrap();
let mut tmp_rem = duo.clone();
tmp_rem.lshr_(shl.to_usize()).unwrap();
short_quo.mux_(&tmp_quo, !short).unwrap();
short_rem.mux_(&tmp_rem, !short).unwrap();
let mut tmp0 = Awi::zero(original_w);
let mut tmp1 = Awi::zero(original_w);
tmp0.resize_(&short_quo, false);
tmp1.resize_(&short_rem, false);
(tmp0, tmp1)
}