pub use libreda_db::iron_shapes::prelude::{Point, SimplePolygon};
pub use libreda_db::prelude as db;
pub use libreda_db::prelude::traits::*;
pub use libreda_db::prelude::{SInt, TryCastCoord, UInt, WindingNumber};
use std::collections::{HashMap, HashSet};
use crate::db::{L2NBase, SimpleTransform};
use crate::place::mixed_size_placer::{MixedSizePlacer, PlacementError};
use crate::place::placement_problem::PlacementProblem;
use log;
pub trait SimpleStdCellPlacer<N: NetlistBase> {
fn name(&self) -> &str;
fn find_cell_positions_impl(
&self,
netlist: &N,
top_cell: &N::CellId,
core_area: &SimplePolygon<db::Coord>,
initial_positions: &HashMap<N::CellInstId, Point<db::Coord>>,
fixed_instances: &HashSet<N::CellInstId>,
cell_outlines: &HashMap<N::CellId, db::Rect<db::Coord>>,
net_weights: &HashMap<N::NetId, f64>,
) -> HashMap<N::CellInstId, Point<db::Coord>>;
fn find_cell_positions(
&self,
netlist: &N,
cell_id: &N::CellId,
core_area: &SimplePolygon<db::Coord>,
initial_positions: &HashMap<N::CellInstId, Point<db::Coord>>,
fixed_instances: &HashSet<N::CellInstId>,
cell_outlines: &HashMap<N::CellId, db::Rect<db::Coord>>,
net_weights: &HashMap<N::NetId, f64>,
) -> HashMap<N::CellInstId, Point<SInt>> {
log::debug!("Running placer '{}'.", self.name());
log::debug!("Number of cells: {}", netlist.num_child_instances(cell_id));
log::debug!("Number of initial positions: {}", initial_positions.len());
log::debug!("Number of fixed cells: {}", fixed_instances.len());
let num_without_position = fixed_instances
.iter()
.filter(|i| !initial_positions.contains_key(i))
.count();
assert_eq!(
num_without_position, 0,
"Some fixed instances have no position."
);
log::info!("Run placement engine.");
let positions = self.find_cell_positions_impl(
netlist,
cell_id,
core_area,
initial_positions,
fixed_instances,
cell_outlines,
net_weights,
);
log::debug!("Placement engine done.");
let core_area: SimplePolygon<i64> = core_area.cast(); let num_outliers = positions
.iter()
.filter(|(idx, p)| {
!fixed_instances.contains(idx) && !core_area.contains_point(p.cast())
})
.count();
if num_outliers > 0 {
log::warn!(
"{} cells were placed outside of the core area.",
num_outliers
);
}
positions
}
}
pub struct PlacerAdapter<P> {
placer: P,
}
impl<P> PlacerAdapter<P> {
pub fn new(simple_stcell_placer: P) -> Self {
PlacerAdapter {
placer: simple_stcell_placer,
}
}
}
impl<P: SimpleStdCellPlacer<C>, C: L2NBase<Coord = db::Coord>> MixedSizePlacer<C>
for PlacerAdapter<P>
{
fn name(&self) -> &str {
self.placer.name()
}
fn find_cell_positions_impl(
&self,
placement_problem: &dyn PlacementProblem<C>,
) -> Result<HashMap<C::CellInstId, SimpleTransform<C::Coord>>, PlacementError> {
let netlist = placement_problem.fused_layout_netlist();
let top_cell = placement_problem.top_cell();
let core_area = {
let placement_region = placement_problem.placement_region();
if placement_region.len() != 1 {
return Err(PlacementError::Other(format!(
"Expect exactly one polygon marking the placement region. Found {}.",
placement_region.len()
)));
}
let placement_region = &placement_region[0];
placement_region.to_simple_polygon()
};
let all_instances = netlist.each_cell_instance_vec(&top_cell);
let initial_positions = all_instances
.iter()
.map(|inst| {
let pos = placement_problem.initial_position(inst);
(inst.clone(), pos.transform_point(Point::zero()))
})
.collect();
let fixed_instances = placement_problem.get_fixed_instances();
let cell_outlines = netlist
.each_cell_dependency(&top_cell)
.filter_map(|cell| {
placement_problem
.cell_outline(&cell)
.map(|outline| (cell, outline))
})
.collect();
let net_weights: HashMap<C::NetId, f64> = netlist
.each_internal_net(&top_cell)
.map(|net| (net.clone(), placement_problem.net_weight(&net)))
.collect();
let displacements = self.placer.find_cell_positions(
netlist,
&top_cell,
&core_area,
&initial_positions,
&fixed_instances,
&cell_outlines,
&net_weights,
);
let transforms = displacements
.into_iter()
.map(|(inst, displacement)| (inst, SimpleTransform::translate(displacement)))
.collect();
Ok(transforms)
}
}