use logiclib::*;
use LogicVal::*;
const LIBERTY: &str = include_str!("sky130_dff_simplify.lib");
fn eval<'i>(
table: &'i[LogicVal],
logicpin: &LogicOutputPin,
input: &[LogicVal]
) -> &'i[LogicVal] {
let n_inputs = logicpin.related_inputs.len();
let n_internals = logicpin.num_internals as usize;
assert_eq!(input.len(), n_inputs + n_internals);
let mut index = 0;
for (i, v) in input.iter().enumerate().rev() {
let base = if i < n_inputs {
match logicpin.related_inputs.get_index(i).unwrap().1 {
true => 7,
false => 5
}
}
else { 4 };
let v = *v as u8 as usize;
assert!(v < base);
index = index * base + v;
}
let i = logicpin.table_start + index * (1 + n_internals);
&table[i..i + n_internals + 1]
}
macro_rules! check_tb {
($tb:ident;
$($lp:ident => {
$([$($inp:ident),+] => [$($out:ident),+]),+
}),+) => {
$($(assert_eq!(
eval($tb, &$lp, &[$($inp),+]), &[$($out),+],
concat!("Pin ", stringify!($lp),
" failed on case ", stringify!([$($inp),+])));)+
)+
}
}
#[test]
#[allow(non_snake_case)]
fn test_sky130() {
clilog::init_stderr_color_debug();
let parsed = libertyparse::Liberty::parse_str(LIBERTY)
.expect("parse error");
let logiclib = LogicLib::from(&parsed);
let tb = logiclib.truthtable.as_ref();
clilog::info!("Table size: {} = sum({:?})", tb.len(),
logiclib.logic_cells.iter()
.map(|(_, lc)| lc.output_pins.iter()
.filter_map(|(_, lp)| match lp.as_ref() {
Ok(lp) => Some(lp.table_size),
Err(_) => None
}))
.flatten().collect::<Vec<_>>());
let a211oi = logiclib.logic_cells
.get("sky130_fd_sc_hd__a211oi_1").unwrap();
let a211oi_Y = a211oi.output_pins
.get("Y").unwrap().as_ref().unwrap();
assert_eq!(format!("{:?}", a211oi_Y.related_inputs),
r#"{"A1": false, "A2": false, "B1": false, "C1": false}"#);
let ff = logiclib.logic_cells
.get("sky130_fd_sc_hd__dfbbn_1").unwrap();
let ff_Q = ff.output_pins
.get("Q").unwrap().as_ref().unwrap();
assert_eq!(format!("{:?}", ff_Q.related_inputs),
r#"{"CLK_N": true, "D": false, "RESET_B": false, "SET_B": false}"#);
let latch_precontrol = logiclib.logic_cells
.get("sky130_fd_sc_hd__sdlclkp_4").unwrap();
let latch_precontrol_GCLK = latch_precontrol.output_pins
.get("GCLK").unwrap().as_ref().unwrap();
assert_eq!(format!("{:?}", latch_precontrol_GCLK.related_inputs),
r#"{"CLK": false, "GATE": false, "SCE": false}"#);
check_tb! {
tb;
a211oi_Y => {
[L, L, L, L] => [H],
[L, H, L, L] => [H],
[H, H, L, L] => [L],
[H, H, H, H] => [L],
[L, L, H, L] => [L],
[L, H, L, H] => [L],
[X, L, H, L] => [L],
[X, Z, L, L] => [X],
[U, U, L, L] => [U],
[U, U, U, H] => [L],
[H, H, U, U] => [L],
[L, U, L, L] => [H],
[U, L, X, L] => [X],
[X, L, L, U] => [U]
},
ff_Q => {
[L, U, H, H, L, H] => [L, L, H],
[L, U, H, H, H, L] => [H, H, L],
[U, U, L, H, H, L] => [L, L, H],
[U, U, H, L, L, L] => [H, H, L],
[U, U, L, L, L, H] => [H, H, L],
[R, U, H, H, H, L] => [H, H, L],
[F, L, H, H, H, L] => [L, L, H],
[F, H, H, H, H, L] => [H, H, L]
},
latch_precontrol_GCLK => {
[H, U, U, H] => [H, H],
[H, U, U, L] => [L, L],
[L, H, L, L] => [L, H],
[L, H, H, L] => [L, H],
[L, H, U, L] => [U, U], [L, L, L, H] => [L, L]
}
};
}