ASIC place & route framework. This crate contains interface definitions of the core parts of the place & route flow.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

107 lines
4.6 KiB

/*
* Copyright (c) 2020-2021 Thomas Kramer.
*
* This file is part of LibrEDA
* (see https://codeberg.org/libreda).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//! Traits for simple placement engines that care about standard-cells only and cannot handle obstructions.
pub use libreda_db::prelude::{SInt, UInt, WindingNumber, TryCastCoord};
pub use libreda_db::netlist::traits::*;
pub use libreda_db::prelude as db;
pub use libreda_db::iron_shapes::prelude::{Point, SimplePolygon};
use std::collections::{HashMap, HashSet};
use log::{debug, info, warn};
/// Traits for simple placement engines that care about standard-cells only and cannot handle obstructions.
pub trait SimpleStdCellPlacer<N: NetlistBase> {
/// Get the name of the placement engine.
fn name(&self) -> &str;
/// Define width and height of the standard cells.
fn set_cell_dimensions(&mut self, _cell_dimensions: HashMap<N::CellId, db::Rect<db::Coord>>) {
debug!("set_cell_dimensions is not implemented.")
}
/// Find the rough positions of all circuit instances inside `circuit`.
///
/// # Parameters
///
/// * `netlist`: The netlist holding the connectivity information.
/// * `circuit_id`: The ID of the circuit containing all the standard-cell instances to be placed.
/// * `core_area`: The region where the cells are allowed to be placed.
/// * `initial_positions`: Initial positions of the cells. For movable instances this can serve as a hint for the optimization, fixed instances must have a position defined.
/// * `fixed_instances`: A set of instances that have fixed positions and cannot be moved.
///
/// # Returns
///
/// Returns a `HashMap` which maps circuit instances to positions.
fn find_cell_positions_impl(&self,
netlist: &N,
circuit_id: &N::CellId,
core_area: &SimplePolygon<db::Coord>,
initial_positions: &HashMap<N::CellInstId, Point<db::Coord>>,
fixed_instances: &HashSet<N::CellInstId>,
) -> HashMap<N::CellInstId, Point<db::Coord>>;
/// Calls `find_cell_positions_impl()` before and after doing some sanity checks.
fn find_cell_positions(&self,
netlist: &N,
circuit_id: &N::CellId,
core_area: &SimplePolygon<db::Coord>,
initial_positions: &HashMap<N::CellInstId, Point<db::Coord>>,
fixed_instances: &HashSet<N::CellInstId>,
// net_weights: &HashMap<N::NetId, f64>,
) -> HashMap<N::CellInstId, Point<SInt>> {
// Debug output.
debug!("Running placer '{}'.", self.name());
debug!("Number of cells: {}", netlist.num_child_instances(circuit_id));
debug!("Number of initial positions: {}", initial_positions.len());
debug!("Number of fixed cells: {}", fixed_instances.len());
// TODO: Sanity checks.
// Assert that all fixed instances are given a position.
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.");
info!("Run placement engine.");
let positions = self.find_cell_positions_impl(
netlist,
circuit_id,
core_area,
initial_positions,
fixed_instances,
);
debug!("Placement engine done.");
// Check that the positions actually lie in the core area.
let core_area: SimplePolygon<i64> = core_area.cast(); // Convert to i64 to avoid overflows.
let num_outliers = positions.iter()
.filter(|(idx, p)| !fixed_instances.contains(idx) && !core_area.contains_point(p.cast()))
.count();
if num_outliers > 0 {
warn!("{} cells were placed outside of the core area.", num_outliers);
}
positions
}
}