pub use self::pins::SpreadPinsOptions;
use parking_lot::{
MappedRwLockReadGuard, MappedRwLockWriteGuard, RwLock, RwLockReadGuard, RwLockWriteGuard,
};
use indexmap::IndexMap;
use std::collections::{HashMap, HashSet};
use std::sync::Arc;
use crate::{Intf, MetadataKey, MetadataValue, Port, Usage};
mod core;
pub use core::ModDefCore;
mod dtypes;
pub use dtypes::{
BoundingBox, Coordinate, Edge, EdgeOrientation, Mat3, Orientation, PhysicalPin, Placement,
Polygon, Range,
};
mod emit;
mod feedthrough;
mod instances;
mod intf;
mod parameterize;
mod placement;
pub use parameterize::{ParameterSpec, ParameterType};
pub use placement::CalculatedPlacement;
mod lefdef;
mod parser;
mod parser_cfg;
pub use parser_cfg::ParserConfig;
mod pins;
mod ports;
mod stub;
mod validate;
mod wrap;
use parser::{parser_param_to_param, parser_port_to_port};
mod hierarchy;
mod lef_parse;
mod tracks;
pub use tracks::{TrackDefinition, TrackDefinitions, TrackOrientation};
use tracks::{TrackOccupancies, TrackOccupancy};
mod edges;
mod shape;
pub use edges::{
BOTTOM_EDGE_INDEX, EAST_EDGE_INDEX, LEFT_EDGE_INDEX, NORTH_EDGE_INDEX, RIGHT_EDGE_INDEX,
SOUTH_EDGE_INDEX, TOP_EDGE_INDEX, WEST_EDGE_INDEX,
};
#[derive(Clone)]
pub struct ModDef {
pub(crate) core: Arc<RwLock<ModDefCore>>,
}
#[macro_export]
macro_rules! for_each_edge_direction {
($macro_name:ident) => {
$macro_name!(west, $crate::mod_def::WEST_EDGE_INDEX);
$macro_name!(left, $crate::mod_def::LEFT_EDGE_INDEX);
$macro_name!(north, $crate::mod_def::NORTH_EDGE_INDEX);
$macro_name!(top, $crate::mod_def::TOP_EDGE_INDEX);
$macro_name!(east, $crate::mod_def::EAST_EDGE_INDEX);
$macro_name!(right, $crate::mod_def::RIGHT_EDGE_INDEX);
$macro_name!(south, $crate::mod_def::SOUTH_EDGE_INDEX);
$macro_name!(bottom, $crate::mod_def::BOTTOM_EDGE_INDEX);
};
}
macro_rules! define_keepout_on_named_edge {
($edge_name:ident, $const_name:path) => {
paste::paste! {
#[doc = concat!(
"Marks the specified tracks on the ",
stringify!($edge_name),
" edge as a keepout region using the provided polygon."
)]
pub fn [<define_keepout_on_ $edge_name _edge>](
&self,
layer: impl AsRef<str>,
track_index: usize,
polygon: &Polygon,
) {
self.define_keepout_on_edge_index($const_name, layer, track_index, polygon);
}
}
};
}
impl ModDef {
pub fn new(name: impl AsRef<str>) -> ModDef {
ModDef {
core: Arc::new(RwLock::new(ModDefCore {
name: name.as_ref().to_string(),
ports: IndexMap::new(),
enum_ports: IndexMap::new(),
interfaces: IndexMap::new(),
instances: IndexMap::new(),
usage: Default::default(),
verilog_import: None,
parameters: IndexMap::new(),
mod_inst_connections: IndexMap::new(),
mod_def_connections: IndexMap::new(),
mod_def_metadata: HashMap::new(),
mod_def_port_metadata: HashMap::new(),
mod_def_intf_metadata: HashMap::new(),
mod_inst_metadata: HashMap::new(),
mod_inst_port_metadata: HashMap::new(),
mod_inst_intf_metadata: HashMap::new(),
shape: None,
layer: None,
inst_placements: IndexMap::new(),
physical_pins: IndexMap::new(),
port_max_distances: IndexMap::new(),
track_definitions: None,
track_occupancies: None,
default_connection_max_distance: Some(0),
specified_net_names: HashSet::new(),
pipeline_counter: 0..,
})),
}
}
fn frozen(&self) -> bool {
self.core.read().verilog_import.is_some()
}
pub fn get_name(&self) -> String {
self.core.read().name.clone()
}
pub fn set_usage(&self, usage: Usage) {
self.core.write().usage = usage;
}
pub fn set_default_connection_max_distance(&self, value: Option<i64>) {
self.core.write().default_connection_max_distance = value;
}
pub fn get_default_connection_max_distance(&self) -> Option<i64> {
self.core.read().default_connection_max_distance
}
pub fn get_usage(&self) -> Usage {
self.core.read().usage.clone()
}
pub fn set_metadata(
&self,
key: impl Into<MetadataKey>,
value: impl Into<MetadataValue>,
) -> Self {
self.core
.write()
.mod_def_metadata
.insert(key.into(), value.into());
self.clone()
}
pub fn get_metadata(&self, key: impl AsRef<str>) -> Option<MetadataValue> {
self.core.read().mod_def_metadata.get(key.as_ref()).cloned()
}
pub fn clear_metadata(&self, key: impl AsRef<str>) -> Self {
self.core.write().mod_def_metadata.remove(key.as_ref());
self.clone()
}
pub fn set_width_height(&self, width: i64, height: i64) {
assert!(width > 0 && height > 0, "Width and height must be positive");
self.set_shape(Polygon::from_width_height(width, height));
}
pub fn set_shape(&self, shape: Polygon) {
assert!(
shape.is_rectilinear(),
"A ModDef shape must be rectilinear."
);
assert!(
shape.is_clockwise(),
"ModDef shape edges must be defined in a clockwise order."
);
assert!(
shape.starts_with_leftmost_vertical_edge(),
"ModDef shapes must start with the leftmost vertical edge."
);
let mut core = self.core.write();
core.track_occupancies = Some(TrackOccupancies::new(shape.num_edges()));
core.shape = Some(shape);
}
pub fn set_layer(&self, layer: impl AsRef<str>) {
let mut core = self.core.write();
core.layer = Some(layer.as_ref().to_string());
}
pub fn get_shape(&self) -> Option<Polygon> {
self.core.read().shape.clone()
}
pub fn get_layer(&self) -> Option<String> {
self.core.read().layer.clone()
}
pub fn get_num_edges(&self) -> usize {
self.core
.read()
.shape
.as_ref()
.map(|s| s.num_edges())
.unwrap_or(0)
}
pub fn set_track_definitions(&self, track_definitions: TrackDefinitions) {
let mut core = self.core.write();
let shape = core
.shape
.as_ref()
.expect("Shape must be set before setting track definitions")
.clone();
core.track_definitions = Some(track_definitions);
let track_defs = core.track_definitions.as_ref().unwrap().clone();
let occupancies = core
.track_occupancies
.as_mut()
.expect("Track occupancies must be initialized before setting track definitions");
for (edge_index, edge_map) in occupancies.0.iter_mut().enumerate() {
let edge = shape.get_edge(edge_index);
for (layer_name, track_def) in track_defs.0.iter() {
if let Some(range) = edge.get_index_range(track_def) {
let length = (range.max.unwrap() - range.min.unwrap() + 1) as usize;
edge_map.insert(layer_name.clone(), TrackOccupancy::new(length));
}
}
}
}
pub fn get_track_definitions(&self) -> Option<MappedRwLockReadGuard<'_, TrackDefinitions>> {
RwLockReadGuard::try_map(self.core.read(), |core| core.track_definitions.as_ref()).ok()
}
pub fn get_track_definitions_mut(
&self,
) -> Option<MappedRwLockWriteGuard<'_, TrackDefinitions>> {
RwLockWriteGuard::try_map(self.core.write(), |core| core.track_definitions.as_mut()).ok()
}
pub fn get_track(&self, name: impl AsRef<str>) -> Option<TrackDefinition> {
let core_borrowed = self.core.read();
let track_definitions = &core_borrowed.track_definitions;
track_definitions
.as_ref()
.and_then(|t| t.get_track(name.as_ref()).cloned())
}
pub fn get_edge(&self, edge_index: usize) -> Option<Edge> {
let core_borrowed = self.core.read();
let shape = &core_borrowed.shape;
shape.as_ref().map(|s| s.get_edge(edge_index))
}
pub fn nearest_relative_track_index(
&self,
edge_index: usize,
layer: impl AsRef<str>,
coordinate: &Coordinate,
) -> Option<usize> {
let layer = layer.as_ref();
let shape = self.get_shape()?;
let track = self.get_track(layer)?;
let edge = shape.get_edge(edge_index);
let orientation = edge.orientation()?;
let track_range = edge.get_index_range(&track)?;
let min_index = track_range.min?;
let max_index = track_range.max?;
let axis_coordinate = match orientation {
EdgeOrientation::North | EdgeOrientation::South => coordinate.y,
EdgeOrientation::East | EdgeOrientation::West => coordinate.x,
};
let absolute_track_index = track.nearest_track_index(axis_coordinate);
if (min_index <= absolute_track_index) && (absolute_track_index <= max_index) {
Some((absolute_track_index - min_index) as usize)
} else {
None
}
}
pub fn mark_pin_range(
&self,
edge_index: usize,
layer: impl AsRef<str>,
min_index: i64,
max_index: i64,
) {
let mut core = self.core.write();
let occupancies = core
.track_occupancies
.as_mut()
.expect("Track occupancies not initialized");
if let Some(occupancy) = occupancies.get_occupancy_mut(edge_index, layer.as_ref()) {
occupancy.mark_pin(min_index, max_index);
}
}
pub fn mark_keepout_range(
&self,
edge_index: usize,
layer: impl AsRef<str>,
min_index: i64,
max_index: i64,
) {
let mut core = self.core.write();
let occupancies = core
.track_occupancies
.as_mut()
.expect("Track occupancies not initialized");
if let Some(occupancy) = occupancies.get_occupancy_mut(edge_index, layer.as_ref()) {
occupancy.mark_keepout(min_index, max_index);
}
}
pub fn mark_pin_and_keepout_ranges(
&self,
edge_index: usize,
layer: impl AsRef<str>,
pin_min_index: i64,
pin_max_index: i64,
keepout_min_index: i64,
keepout_max_index: i64,
) {
let mut core = self.core.write();
let occupancies = core
.track_occupancies
.as_mut()
.expect("Track occupancies not initialized");
if let Some(occupancy) = occupancies.get_occupancy_mut(edge_index, layer.as_ref()) {
occupancy.place_pin_and_keepout(
pin_min_index,
pin_max_index,
keepout_min_index,
keepout_max_index,
);
}
}
for_each_edge_direction!(define_keepout_on_named_edge);
pub fn define_keepout_on_edge_index(
&self,
edge_index: usize,
layer: impl AsRef<str>,
track_index: usize,
polygon: &Polygon,
) {
let layer_ref = layer.as_ref();
let transform = self.track_index_to_transform(edge_index, layer_ref, track_index);
let polygon = polygon.apply_transform(&transform);
let (keepout_min_track, keepout_max_track) =
self.track_range_for_polygon(edge_index, layer_ref, &polygon);
self.mark_keepout_range(edge_index, layer_ref, keepout_min_track, keepout_max_track);
}
pub fn get_layers(&self) -> Vec<String> {
self.core
.read()
.track_definitions
.as_ref()
.map(|td| td.0.keys().cloned().collect())
.unwrap_or_default()
}
pub(crate) fn get_occupancy(
&self,
edge_index: usize,
layer: impl AsRef<str>,
) -> Option<TrackOccupancy> {
self.core
.read()
.track_occupancies
.as_ref()
.and_then(|occupancies| {
occupancies
.get_occupancy(edge_index, layer.as_ref())
.cloned()
})
}
}
pub trait ConvertibleToModDef {
fn to_mod_def(&self) -> ModDef;
fn get_port(&self, name: impl AsRef<str>) -> Port;
fn get_intf(&self, name: impl AsRef<str>) -> Intf;
}
impl ConvertibleToModDef for ModDef {
fn to_mod_def(&self) -> ModDef {
self.clone()
}
fn get_port(&self, name: impl AsRef<str>) -> Port {
self.get_port(name)
}
fn get_intf(&self, name: impl AsRef<str>) -> Intf {
self.get_intf(name)
}
}