use crate::db::{NetlistBase, NetlistUtil, TerminalId, Direction};
pub fn check_drivers_in_cell<N: NetlistBase>(netlist: &N, cell: &N::CellId)
-> Result<(), (Vec<(N::NetId, Vec<TerminalId<N>>)>, Vec<N::NetId>)> {
let cell_name = netlist.cell_name(cell);
log::debug!("Check for drive conflicts and nets without driver in cell '{}'.", cell_name);
let mut drive_conflicts = vec![];
let mut nets_without_driver = vec![];
let mut unconnected_nets = vec![];
for net in netlist.each_internal_net(cell) {
let net_name = netlist.net_name(&net);
log::debug!("Checking net '{:?}'", net_name);
let mut drivers = vec![];
let mut inouts = vec![];
for t in netlist.each_terminal_of_net(&net) {
match &t {
TerminalId::PinId(p) => {
match netlist.pin_direction(p) {
Direction::Input => drivers.push(t),
Direction::InOut => inouts.push(t),
_ => {}
}
}
TerminalId::PinInstId(p) => {
match netlist.pin_direction(&netlist.template_pin(p)) {
Direction::Output => drivers.push(t),
Direction::InOut => inouts.push(t),
_ => {}
}
}
}
}
log::debug!("Number of drivers: {}", drivers.len());
log::debug!("Number of inouts: {}", inouts.len());
if drivers.is_empty() {
if netlist.num_net_terminals(&net) == 0 {
if !netlist.is_constant_net(&net) {
log::warn!("Unconnected net '{:?}' in cell '{}'.", net_name, cell_name);
unconnected_nets.push(net);
}
} else {
log::error!("No driver found on net '{:?}' in cell '{}'.", net_name, cell_name);
if netlist.is_constant_net(&net) {
log::warn!("Constant net '{:?}' in cell '{}' should be connected to a tie cell.", net_name, cell_name);
}
nets_without_driver.push(net);
}
} else if drivers.len() > 1 {
log::error!("Drive conflict. {} drivers found on net '{:?}' in cell '{}'.", drivers.len(), net_name, cell_name);
drive_conflicts.push((net, drivers));
}
}
if drive_conflicts.is_empty() && nets_without_driver.is_empty() {
Ok(())
} else {
Err((drive_conflicts, nets_without_driver))
}
}