use crate::db;
use crate::db::reference_access::*;
use crate::db::traits::TryBoundingBox;
use crate::db::L2NBase;
use num_traits::{Num, NumCast, One, Zero};
pub fn hpwl<C: L2NBase, L>(top: &CellRef<C>) -> L
where
C::Coord: NumCast,
L: Num + NumCast + Zero,
{
top.each_net()
.map(|net| hpwl_for_net(&net))
.map(|l| L::from(l).expect("Failed to cast HPLW of net to other datatype L."))
.fold(Zero::zero(), |acc, x| acc + x)
}
pub fn hpwl_for_net<C: L2NBase>(net: &NetRef<C>) -> C::Coord {
let bbox = net_bounding_box(&net);
let hplw = if let Some(bbox) = bbox {
bbox.width() + bbox.height()
} else {
C::Coord::zero()
};
debug_assert!(
hplw >= C::Coord::zero(),
"Half-perimeter wire length should not be negative."
);
hplw
}
pub fn net_bounding_box<C: L2NBase>(net: &NetRef<C>) -> Option<db::Rect<C::Coord>> {
let mut bbox: Option<db::Rect<_>> = None;
let mut update_bbox = |p: db::Point<C::Coord>| {
if let Some(bbox) = &mut bbox {
*bbox = bbox.add_point(p);
} else {
bbox = Some(db::Rect::new(p, p));
}
};
for pin in net.each_pin() {
update_bbox(pin_location(&pin));
}
for pin_inst in net.each_pin_instance() {
update_bbox(pin_instance_location(&pin_inst));
}
bbox
}
fn pin_instance_location<C: L2NBase>(pin_inst: &PinInstRef<C>) -> db::Point<C::Coord> {
let pin = pin_inst.pin();
let pin_loc = pin_location(&pin);
let chip = pin.base();
chip.get_transform(&pin_inst.cell_instance().id())
.transform_point(pin_loc)
}
fn pin_location<C: L2NBase>(pin: &PinRef<C>) -> db::Point<C::Coord> {
let chip = pin.base();
let mut sum: db::Point<C::Coord> = db::Point::zero();
let mut count = C::Coord::zero();
chip.shapes_of_pin(&pin.id())
.filter_map(|shape_id| {
chip.with_shape(&shape_id, |_layer, shape| {
shape.try_bounding_box().map(|bbox| bbox.center())
})
})
.for_each(|p| {
sum = sum + p;
count = count + C::Coord::one();
});
let avg = if count.is_zero() { sum } else { sum / count };
avg
}
#[test]
fn test_hplw() {
use crate::db;
use crate::db::traits::*;
let mut chip = db::Chip::new();
let cell_top = chip.create_cell("TOP".to_string());
let cell_sub = chip.create_cell("SUB".to_string());
let pin_a = chip.create_pin(&cell_sub, "A".to_string(), db::Direction::Input);
let net1 = chip.create_net(&cell_top, None);
let inst1 = chip.create_cell_instance(&cell_top, &cell_sub, None);
let inst2 = chip.create_cell_instance(&cell_top, &cell_sub, None);
chip.set_transform(
&inst1,
db::SimpleTransform::translate(db::Vector::new(10, 10)),
);
chip.set_transform(
&inst2,
db::SimpleTransform::translate(db::Vector::new(20, 20)),
);
chip.connect_pin_instance(&chip.pin_instance(&inst1, &pin_a), Some(net1.clone()));
chip.connect_pin_instance(&chip.pin_instance(&inst2, &pin_a), Some(net1.clone()));
let wire_length: i32 = hpwl(&chip.cell_ref(&cell_top));
assert_eq!(wire_length, 10 + 10)
}