mirror of
https://codeberg.org/LibrEDA/libreda-db
synced 2026-05-30 00:55:10 +08:00
move core traits to libreda-core crate
This commit is contained in:
@@ -22,6 +22,7 @@ num-traits = "0.2"
|
||||
num-derive = "0.4"
|
||||
portrait = "0.3.0" # For delegating trait implementations.
|
||||
petgraph = "0.6"
|
||||
libreda-core = { version = "0.0.1", path = "../libreda-core", features = ["serde"] }
|
||||
iron-shapes = { version = "0.1.1", path = "../iron-shapes", features = ["serde"] }
|
||||
iron-shapes-booleanop = { version = "0.1", path = '../iron-shapes-booleanop' }
|
||||
serde = { version = "1", optional = true, features = ["derive", "rc"] }
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2023 Thomas Kramer
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
//! Blanket implementations of hierarchy traits for reference types, `Rc`, `Arc` and `Box`.
|
||||
|
||||
use super::traits::*;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
macro_rules! blanket {
|
||||
($type:ty, $trait:ident) => {
|
||||
#[portrait::fill(portrait::delegate(T; *self))]
|
||||
impl<T> $trait for $type where T: $trait {}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! blanket_ids {
|
||||
($type:ty, $trait:ident) => {
|
||||
#[portrait::fill(portrait::delegate(T))]
|
||||
impl<T> $trait for $type where T: $trait {}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! blanket_id_impls {
|
||||
($trait:ident) => {
|
||||
blanket_ids!(&T, $trait);
|
||||
blanket_ids!(&mut T, $trait);
|
||||
blanket_ids!(Rc<T>, $trait);
|
||||
blanket_ids!(Arc<T>, $trait);
|
||||
blanket_ids!(Box<T>, $trait);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! blanket_impls {
|
||||
($trait:ident) => {
|
||||
blanket!(&T, $trait);
|
||||
blanket!(&mut T, $trait);
|
||||
blanket!(Rc<T>, $trait);
|
||||
blanket!(Arc<T>, $trait);
|
||||
blanket!(Box<T>, $trait);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! blanket_impls_mut {
|
||||
($trait:ident) => {
|
||||
blanket!(&mut T, $trait);
|
||||
blanket!(Box<T>, $trait);
|
||||
};
|
||||
}
|
||||
|
||||
blanket_id_impls!(HierarchyIds);
|
||||
blanket_impls!(HierarchyBase);
|
||||
blanket_impls_mut!(HierarchyEdit);
|
||||
|
||||
blanket_id_impls!(NetlistIds);
|
||||
blanket_impls!(NetlistBase);
|
||||
blanket_impls_mut!(NetlistEdit);
|
||||
|
||||
blanket_id_impls!(LayoutIds);
|
||||
blanket_impls!(LayoutBase);
|
||||
blanket_impls_mut!(LayoutEdit);
|
||||
|
||||
blanket_impls!(L2NBase);
|
||||
blanket_impls_mut!(L2NEdit);
|
||||
@@ -26,12 +26,11 @@ use std::borrow::{Borrow, BorrowMut};
|
||||
use std::collections::HashMap;
|
||||
use std::hash::Hash;
|
||||
|
||||
use crate::netlist::direction::Direction;
|
||||
// use crate::rc_string::RcString;
|
||||
use std::fmt::Debug;
|
||||
|
||||
use crate::layout::types::LayerInfo;
|
||||
use crate::property_storage::{PropertyStore, PropertyValue};
|
||||
use crate::property_storage::PropertyStore;
|
||||
use libreda_core::prelude::{Direction, LayerInfo, PropertyValue};
|
||||
|
||||
// Use an alternative hasher that has better performance for integer keys.
|
||||
use fnv::{FnvHashMap, FnvHashSet};
|
||||
|
||||
@@ -6,5 +6,4 @@
|
||||
//! Concept of 'hierarchy' which is used in layouts and netlists.
|
||||
|
||||
pub mod prelude;
|
||||
pub mod traits;
|
||||
pub mod util;
|
||||
|
||||
@@ -5,5 +5,4 @@
|
||||
|
||||
//! Include the most important structs and traits from this module.
|
||||
|
||||
pub use super::traits::*;
|
||||
pub use super::util::*;
|
||||
|
||||
@@ -1,421 +0,0 @@
|
||||
// Copyright (c) 2020-2021 Thomas Kramer.
|
||||
// SPDX-FileCopyrightText: 2022 Thomas Kramer
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
//! Basic traits that for the representation of chip data structures.
|
||||
|
||||
#![allow(unused_variables)]
|
||||
#![allow(missing_docs)] // Necessary because portrait does not generate docs.
|
||||
|
||||
use crate::prelude::PropertyValue;
|
||||
use crate::traits::{IdType, IdTypeMT};
|
||||
use std::borrow::Borrow;
|
||||
use std::hash::Hash;
|
||||
|
||||
/// Identifier types used for components of hierarchical netlists and layouts.
|
||||
#[portrait::make]
|
||||
pub trait HierarchyIds {
|
||||
/// Cell/module identifier type.
|
||||
type CellId: IdType;
|
||||
/// Cell instance identifier type.
|
||||
type CellInstId: IdType;
|
||||
}
|
||||
|
||||
/// Helper trait which constrains [`trait@HierarchyBase`] for such that ID types
|
||||
/// are [`Send`] and [`Sync`] as commonly used for parallel algorithms.
|
||||
#[portrait::make]
|
||||
pub trait HierarchyBaseMT:
|
||||
HierarchyBase<CellId = Self::CellIdMT, CellInstId = Self::CellInstIdMT> + Sync
|
||||
{
|
||||
/// Identifier type for cells.
|
||||
type CellIdMT: IdTypeMT;
|
||||
/// Identifier type for cell instances.
|
||||
type CellInstIdMT: IdTypeMT;
|
||||
}
|
||||
|
||||
impl<H> HierarchyBaseMT for H
|
||||
where
|
||||
H: HierarchyBase + Sync,
|
||||
H::CellId: Send + Sync,
|
||||
H::CellInstId: Send + Sync,
|
||||
{
|
||||
type CellIdMT = H::CellId;
|
||||
type CellInstIdMT = H::CellInstId;
|
||||
}
|
||||
|
||||
/// Most basic trait for the hierarchical flyweight pattern which is
|
||||
/// used to efficiently represent chip layouts and netlists.
|
||||
///
|
||||
/// ## Component relations
|
||||
///
|
||||
/// A netlist consists of cells which are templates for cell instances.
|
||||
/// Each cell may contain such instances of other cells.
|
||||
///
|
||||
/// The following diagram illustrates how this composition graph can be traversed using the functions
|
||||
/// defined by `HierarchyBase`.
|
||||
///
|
||||
/// ```txt
|
||||
/// each_cell_dependency
|
||||
/// +---------------------------+
|
||||
/// | |
|
||||
/// + v
|
||||
/// +----------------+ each_dependent_cell +------------------+
|
||||
/// |Circuit (Top) |<----------------------+|Circuit (Sub) |
|
||||
/// +----------------+ +------------------+
|
||||
/// |+ ^| | ^ + |
|
||||
/// ||each_instance || | | | |
|
||||
/// || || | | | |
|
||||
/// || |parent | | | |
|
||||
/// || || | | | |
|
||||
/// ||+-----------+ || | | | |
|
||||
/// +--> |>|Inst1 (Sub)|-+| | | | |
|
||||
/// | ||+-----------+ | | | | |
|
||||
/// | || | | | | |
|
||||
/// | || | +-|---|------------+
|
||||
/// | || | | |
|
||||
/// | ||+-----------+ | template | |
|
||||
/// +--> |>|Inst2 (Sub)|+----------------------------+ |
|
||||
/// | | +-----------+ | |
|
||||
/// | | | |
|
||||
/// | | | |
|
||||
/// | +----------------+ |
|
||||
/// | |
|
||||
/// | each_reference |
|
||||
/// +----------------------------------------------------+
|
||||
/// ```
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// Basic hierchy operations:
|
||||
///
|
||||
/// ```
|
||||
/// use libreda_db::chip::Chip;
|
||||
/// use libreda_db::traits::{HierarchyBase, HierarchyEdit};
|
||||
///
|
||||
/// // Create a simple hierarchical structure.
|
||||
/// let mut chip = Chip::new();
|
||||
/// let top_cell = chip.create_cell("MyTopCell".into());
|
||||
/// let sub_cell = chip.create_cell("MySubCell".into());
|
||||
/// // Create an instance of `sub_cell` inside `top_cell`.
|
||||
/// let inst = chip.create_cell_instance(&top_cell, &sub_cell, Some("inst1".into()));
|
||||
///
|
||||
/// // Get all cells.
|
||||
/// assert_eq!(chip.each_cell().count(), 2);
|
||||
///
|
||||
/// // Iterate over child instances.
|
||||
/// assert_eq!(chip.each_cell_instance(&top_cell).next().as_ref(), Some(&inst));
|
||||
///
|
||||
/// // Get the template of an instance.
|
||||
/// assert_eq!(&chip.template_cell(&inst), &sub_cell);
|
||||
///
|
||||
/// // Get the parent of an instance.
|
||||
/// assert_eq!(&chip.parent_cell(&inst), &top_cell);
|
||||
/// ```
|
||||
#[portrait::make(import(crate::prelude::PropertyValue))]
|
||||
pub trait HierarchyBase: HierarchyIds {
|
||||
/// Type for names of cells, instances, etc.
|
||||
type NameType: Eq
|
||||
+ Hash
|
||||
+ From<String>
|
||||
+ Into<String>
|
||||
+ Clone
|
||||
+ Borrow<String>
|
||||
+ Borrow<str>
|
||||
+ PartialOrd
|
||||
+ Ord
|
||||
+ std::fmt::Display
|
||||
+ std::fmt::Debug;
|
||||
|
||||
/// Find a cell by its name.
|
||||
/// Return the cell with the given name. Returns `None` if the cell does not exist.
|
||||
fn cell_by_name(&self, name: &str) -> Option<Self::CellId>;
|
||||
|
||||
/// Find a cell instance by its name.
|
||||
/// Returns `None` if the name does not exist.
|
||||
fn cell_instance_by_name(
|
||||
&self,
|
||||
parent_cell: &Self::CellId,
|
||||
name: &str,
|
||||
) -> Option<Self::CellInstId>;
|
||||
|
||||
/// Get the name of the cell.
|
||||
fn cell_name(&self, cell: &Self::CellId) -> Self::NameType;
|
||||
|
||||
/// Get the name of the cell instance.
|
||||
fn cell_instance_name(&self, cell_inst: &Self::CellInstId) -> Option<Self::NameType>;
|
||||
|
||||
/// Get the ID of the parent cell of this instance.
|
||||
fn parent_cell(&self, cell_instance: &Self::CellInstId) -> Self::CellId;
|
||||
|
||||
/// Get the ID of the template cell of this instance.
|
||||
fn template_cell(&self, cell_instance: &Self::CellInstId) -> Self::CellId;
|
||||
|
||||
/// Call a function on each cell of the netlist.
|
||||
fn for_each_cell<F>(&self, f: F)
|
||||
where
|
||||
F: FnMut(Self::CellId);
|
||||
|
||||
/// Get a `Vec` of all cell IDs in this netlist.
|
||||
fn each_cell_vec(&self) -> Vec<Self::CellId> {
|
||||
let mut v = Vec::new();
|
||||
self.for_each_cell(|c| v.push(c));
|
||||
v
|
||||
}
|
||||
|
||||
/// Iterate over all cells.
|
||||
fn each_cell(&self) -> Box<dyn Iterator<Item = Self::CellId> + '_> {
|
||||
Box::new(self.each_cell_vec().into_iter())
|
||||
}
|
||||
|
||||
/// Call a function on each instance in this cell.
|
||||
fn for_each_cell_instance<F>(&self, cell: &Self::CellId, f: F)
|
||||
where
|
||||
F: FnMut(Self::CellInstId);
|
||||
|
||||
/// Get a `Vec` of the IDs of all instances in this cell.
|
||||
fn each_cell_instance_vec(&self, cell: &Self::CellId) -> Vec<Self::CellInstId> {
|
||||
let mut v = Vec::new();
|
||||
self.for_each_cell_instance(cell, |c| v.push(c));
|
||||
v
|
||||
}
|
||||
|
||||
/// Iterate over all instances in a cell.
|
||||
fn each_cell_instance(
|
||||
&self,
|
||||
cell: &Self::CellId,
|
||||
) -> Box<dyn Iterator<Item = Self::CellInstId> + '_> {
|
||||
Box::new(self.each_cell_instance_vec(cell).into_iter())
|
||||
}
|
||||
|
||||
/// Call a function for each cell that is a child of this `cell`.
|
||||
fn for_each_cell_dependency<F>(&self, cell: &Self::CellId, f: F)
|
||||
where
|
||||
F: FnMut(Self::CellId);
|
||||
|
||||
/// Get a `Vec` of each cell that is a child of this `cell`.
|
||||
fn each_cell_dependency_vec(&self, cell: &Self::CellId) -> Vec<Self::CellId> {
|
||||
let mut v = Vec::new();
|
||||
self.for_each_cell_dependency(cell, |c| v.push(c));
|
||||
v
|
||||
}
|
||||
|
||||
/// Iterate over all cells that are instantiated in this `cell`.
|
||||
fn each_cell_dependency<'a>(
|
||||
&'a self,
|
||||
cell: &Self::CellId,
|
||||
) -> Box<dyn Iterator<Item = Self::CellId> + 'a> {
|
||||
Box::new(self.each_cell_dependency_vec(cell).into_iter())
|
||||
}
|
||||
|
||||
/// Count all cells that are dependencies of `cell`.
|
||||
fn num_cell_dependencies(&self, cell: &Self::CellId) -> usize {
|
||||
// Inefficient default implementation.
|
||||
let mut counter = 0;
|
||||
self.for_each_cell_dependency(cell, |_| counter += 1);
|
||||
counter
|
||||
}
|
||||
|
||||
/// Call a function for each cell that directly depends on `cell`.
|
||||
fn for_each_dependent_cell<F>(&self, cell: &Self::CellId, f: F)
|
||||
where
|
||||
F: FnMut(Self::CellId);
|
||||
|
||||
/// Get a `Vec` of each cell that directly depends on `cell`.
|
||||
fn each_dependent_cell_vec(&self, cell: &Self::CellId) -> Vec<Self::CellId> {
|
||||
let mut v = Vec::new();
|
||||
self.for_each_dependent_cell(cell, |c| v.push(c));
|
||||
v
|
||||
}
|
||||
|
||||
/// Iterate over each cell that directly depends on `cell`.
|
||||
fn each_dependent_cell<'a>(
|
||||
&'a self,
|
||||
cell: &Self::CellId,
|
||||
) -> Box<dyn Iterator<Item = Self::CellId> + 'a> {
|
||||
Box::new(self.each_dependent_cell_vec(cell).into_iter())
|
||||
}
|
||||
|
||||
/// Count all cells that are directly dependent on `cell`, i.e. contain an instance of `cell`.
|
||||
fn num_dependent_cells(&self, cell: &Self::CellId) -> usize {
|
||||
// Inefficient default implementation.
|
||||
let mut counter = 0;
|
||||
self.for_each_dependent_cell(cell, |_| counter += 1);
|
||||
counter
|
||||
}
|
||||
|
||||
/// Iterate over all instances of this `cell`, i.e. instances that use this cell as
|
||||
/// a template.
|
||||
fn for_each_cell_reference<F>(&self, cell: &Self::CellId, f: F)
|
||||
where
|
||||
F: FnMut(Self::CellInstId);
|
||||
|
||||
/// Get a `Vec` with all cell instances referencing this cell.
|
||||
fn each_cell_reference_vec(&self, cell: &Self::CellId) -> Vec<Self::CellInstId> {
|
||||
let mut v = Vec::new();
|
||||
self.for_each_cell_reference(cell, |c| v.push(c));
|
||||
v
|
||||
}
|
||||
|
||||
/// Iterate over all instances of this `cell`, i.e. instances that use this cell as
|
||||
/// a template.
|
||||
fn each_cell_reference(
|
||||
&self,
|
||||
cell: &Self::CellId,
|
||||
) -> Box<dyn Iterator<Item = Self::CellInstId> + '_> {
|
||||
// Provide an inefficient default implementation.
|
||||
Box::new(self.each_cell_reference_vec(cell).into_iter())
|
||||
}
|
||||
|
||||
/// Count all instantiations of `cell`.
|
||||
fn num_cell_references(&self, cell: &Self::CellId) -> usize {
|
||||
// Inefficient default implementation.
|
||||
let mut counter = 0;
|
||||
self.for_each_cell_reference(cell, |_| counter += 1);
|
||||
counter
|
||||
}
|
||||
|
||||
/// Get the number of cell instances inside the `cell`.
|
||||
fn num_child_instances(&self, cell: &Self::CellId) -> usize;
|
||||
|
||||
/// Get the number of cell templates.
|
||||
fn num_cells(&self) -> usize;
|
||||
|
||||
/// Get a property of the top-level chip data structure.
|
||||
fn get_chip_property(&self, key: &Self::NameType) -> Option<PropertyValue> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Get a property of a cell.
|
||||
fn get_cell_property(
|
||||
&self,
|
||||
cell: &Self::CellId,
|
||||
key: &Self::NameType,
|
||||
) -> Option<PropertyValue> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Get a property of a cell instance.
|
||||
fn get_cell_instance_property(
|
||||
&self,
|
||||
inst: &Self::CellInstId,
|
||||
key: &Self::NameType,
|
||||
) -> Option<PropertyValue> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Edit functions for a hierarchical flyweight structure like a netlist or a cell-based layout.
|
||||
#[portrait::make(import(crate::prelude::PropertyValue))]
|
||||
pub trait HierarchyEdit: HierarchyBase {
|
||||
///// Create a new empty data structure.
|
||||
//fn new() -> Self;
|
||||
|
||||
/// Create a new and empty cell template.
|
||||
/// A cell template can be be instantiated in other cells.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use libreda_db::prelude::*;
|
||||
/// let mut chip = Chip::new();
|
||||
/// let my_cell = chip.create_cell("myCell".into());
|
||||
///
|
||||
/// assert_eq!(chip.num_cells(), 1);
|
||||
/// assert_eq!(chip.cell_by_name("myCell"), Some(my_cell));
|
||||
/// ```
|
||||
fn create_cell(&mut self, name: Self::NameType) -> Self::CellId;
|
||||
|
||||
/// Remove a cell and all the instances of it.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use libreda_db::prelude::*;
|
||||
/// let mut chip = Chip::new();
|
||||
/// let top = chip.create_cell("TOP".into());
|
||||
/// assert_eq!(chip.num_cells(), 1);
|
||||
/// chip.remove_cell(&top);
|
||||
/// assert_eq!(chip.num_cells(), 0);
|
||||
/// ```
|
||||
fn remove_cell(&mut self, cell_id: &Self::CellId);
|
||||
|
||||
/// Create a new instance of `template_cell` in `parent_cell`.
|
||||
/// Recursive instantiation is forbidden and might panic.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use libreda_db::prelude::*;
|
||||
/// let mut chip = Chip::new();
|
||||
/// let top = chip.create_cell("TOP".into());
|
||||
/// let sub = chip.create_cell("SUB".into());
|
||||
///
|
||||
/// // Create two instances of "SUB" inside "TOP".
|
||||
/// let inst1 = chip.create_cell_instance(&top, &sub, Some("sub1".into())); // Create named instance.
|
||||
/// let inst2 = chip.create_cell_instance(&top, &sub, None); // Create unnamed instance.
|
||||
///
|
||||
/// assert_eq!(chip.num_child_instances(&top), 2);
|
||||
/// assert_eq!(chip.num_cell_references(&sub), 2);
|
||||
/// ```
|
||||
fn create_cell_instance(
|
||||
&mut self,
|
||||
parent_cell: &Self::CellId,
|
||||
template_cell: &Self::CellId,
|
||||
name: Option<Self::NameType>,
|
||||
) -> Self::CellInstId;
|
||||
|
||||
/// Remove cell instance if it exists.
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use libreda_db::prelude::*;
|
||||
/// let mut chip = Chip::new();
|
||||
/// let top = chip.create_cell("TOP".into());
|
||||
/// let sub = chip.create_cell("SUB".into());
|
||||
///
|
||||
/// // Create two instances of "SUB" inside "TOP".
|
||||
/// let inst1 = chip.create_cell_instance(&top, &sub, Some("sub1".into())); // Create named instance.
|
||||
/// let inst2 = chip.create_cell_instance(&top, &sub, None); // Create unnamed instance.
|
||||
///
|
||||
/// assert_eq!(chip.num_child_instances(&top), 2);
|
||||
/// assert_eq!(chip.num_cell_references(&sub), 2);
|
||||
///
|
||||
/// chip.remove_cell_instance(&inst2);
|
||||
///
|
||||
/// assert_eq!(chip.num_child_instances(&top), 1);
|
||||
/// assert_eq!(chip.num_cell_references(&sub), 1);
|
||||
/// ```
|
||||
fn remove_cell_instance(&mut self, inst: &Self::CellInstId);
|
||||
|
||||
/// Change the name of a cell instance.
|
||||
///
|
||||
/// Clears the name when `None` is passed.
|
||||
///
|
||||
/// # Panics
|
||||
/// Panics if an instance with this name already exists in the parent cell.
|
||||
fn rename_cell_instance(&mut self, inst: &Self::CellInstId, new_name: Option<Self::NameType>);
|
||||
|
||||
/// Change the name of a cell.
|
||||
///
|
||||
/// # Panics
|
||||
/// Panics if a cell with this name already exists.
|
||||
fn rename_cell(&mut self, cell: &Self::CellId, new_name: Self::NameType);
|
||||
|
||||
/// Set a property of the top-level chip data structure..
|
||||
fn set_chip_property(&mut self, key: Self::NameType, value: PropertyValue) {}
|
||||
|
||||
/// Set a property of a cell.
|
||||
fn set_cell_property(
|
||||
&mut self,
|
||||
cell: &Self::CellId,
|
||||
key: Self::NameType,
|
||||
value: PropertyValue,
|
||||
) {
|
||||
}
|
||||
|
||||
/// Set a property of a cell instance.
|
||||
fn set_cell_instance_property(
|
||||
&mut self,
|
||||
inst: &Self::CellInstId,
|
||||
key: Self::NameType,
|
||||
value: PropertyValue,
|
||||
) {
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,8 @@
|
||||
|
||||
//! Utility functions for dealing with the hierarchy of netlists or layouts.
|
||||
|
||||
use super::traits::{HierarchyBase, HierarchyEdit};
|
||||
use fnv::FnvHashSet;
|
||||
use libreda_core::traits::{HierarchyBase, HierarchyEdit};
|
||||
|
||||
/// Non-modifying utility functions for the cell hierarchy..
|
||||
/// Import the this trait to use the utility functions all types that implement the `HierarchyBase` trait.
|
||||
|
||||
@@ -12,10 +12,6 @@
|
||||
//! Each cell instance also holds the placement information, i.e. the location, rotation, mirroring and
|
||||
//! possibly magnification.
|
||||
|
||||
pub use libreda_core::layout::*;
|
||||
pub mod prelude;
|
||||
|
||||
pub mod io;
|
||||
|
||||
pub mod traits;
|
||||
pub mod types;
|
||||
pub mod util;
|
||||
|
||||
@@ -5,8 +5,5 @@
|
||||
|
||||
//! The `prelude` helps to import most commonly used modules.
|
||||
|
||||
pub use super::io::*;
|
||||
pub use super::traits::*;
|
||||
pub use super::types::*;
|
||||
pub use super::util::*;
|
||||
pub use iron_shapes::prelude::*;
|
||||
pub use libreda_core::layout::prelude::*;
|
||||
|
||||
@@ -1,262 +0,0 @@
|
||||
// Copyright (c) 2020-2021 Thomas Kramer.
|
||||
// SPDX-FileCopyrightText: 2022 Thomas Kramer
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
//! Traits for layout data types.
|
||||
|
||||
#![allow(unused_variables)]
|
||||
#![allow(missing_docs)] // Necessary because portrait does not generate docs.
|
||||
|
||||
use crate::layout::types::{LayerInfo, UInt};
|
||||
use crate::prelude::PropertyValue;
|
||||
use crate::prelude::{Geometry, Rect};
|
||||
use crate::traits::{
|
||||
HierarchyBase, HierarchyBaseMT, HierarchyEdit, HierarchyIds, IdType, IdTypeMT,
|
||||
};
|
||||
use iron_shapes::transform::SimpleTransform;
|
||||
use iron_shapes::CoordinateType;
|
||||
use num_traits::Num;
|
||||
use std::hash::Hash;
|
||||
|
||||
/// Helper trait which constrains [`trait@LayoutBase`] for such that ID types
|
||||
/// are [`Send`] and [`Sync`] as commonly used for parallel algorithms.
|
||||
#[portrait::make]
|
||||
pub trait LayoutBaseMT:
|
||||
LayoutBase<LayerId = Self::LayerIdMT, ShapeId = Self::ShapeIdMT> + HierarchyBaseMT
|
||||
{
|
||||
/// Identifier for layers.
|
||||
type LayerIdMT: IdTypeMT;
|
||||
/// Identifier for shapes.
|
||||
type ShapeIdMT: IdTypeMT;
|
||||
}
|
||||
|
||||
impl<L> LayoutBaseMT for L
|
||||
where
|
||||
L: LayoutBase + HierarchyBaseMT,
|
||||
L::LayerId: Send + Sync,
|
||||
L::ShapeId: Send + Sync,
|
||||
{
|
||||
type LayerIdMT = L::LayerId;
|
||||
type ShapeIdMT = L::ShapeId;
|
||||
}
|
||||
|
||||
/// Define ID types used in layouts.
|
||||
#[portrait::make(import(crate::prelude::*))]
|
||||
pub trait LayoutIds: HierarchyIds {
|
||||
/// Number type used for coordinates and distances.
|
||||
type Coord: CoordinateType + std::fmt::Debug + std::fmt::Display + Hash + 'static + Send + Sync;
|
||||
/// Number type for areas.
|
||||
/// This is possibly another type then `Coord` for the following reasons:
|
||||
/// * Distances and areas are semantically different.
|
||||
/// * In practice `i32` is a good choice for coordinates. However, computing areas in `i32` might
|
||||
/// easily lead to overflows. Hence a 64-bit integer type might be a better choice.
|
||||
type Area: Num + Copy + PartialOrd + From<Self::Coord> + 'static + Send + Sync;
|
||||
/// Layer identifier type.
|
||||
type LayerId: IdType;
|
||||
/// Shape identifier type.
|
||||
type ShapeId: IdType;
|
||||
}
|
||||
|
||||
/// Most basic trait of a layout.
|
||||
///
|
||||
/// This traits specifies methods for accessing the components of a layout.
|
||||
#[portrait::make(import(crate::prelude::*))]
|
||||
pub trait LayoutBase: LayoutIds + HierarchyBase {
|
||||
/// Get the distance unit used in this layout in 'pixels per micron'.
|
||||
fn dbu(&self) -> Self::Coord;
|
||||
|
||||
/// Iterate over all defined layers.
|
||||
fn each_layer(&self) -> Box<dyn Iterator<Item = Self::LayerId> + '_>;
|
||||
|
||||
/// Get the `LayerInfo` data structure for this layer.
|
||||
fn layer_info(&self, layer: &Self::LayerId) -> LayerInfo<Self::NameType>;
|
||||
|
||||
/// Find layer index by the (index, data type) tuple.
|
||||
fn find_layer(&self, index: UInt, datatype: UInt) -> Option<Self::LayerId>;
|
||||
|
||||
/// Find layer index by the name.
|
||||
fn layer_by_name(&self, name: &str) -> Option<Self::LayerId>;
|
||||
|
||||
/// Compute the bounding box of the shapes on one layer.
|
||||
/// The bounding box also includes all child cell instances.
|
||||
fn bounding_box_per_layer(
|
||||
&self,
|
||||
cell: &Self::CellId,
|
||||
layer: &Self::LayerId,
|
||||
) -> Option<Rect<Self::Coord>>;
|
||||
|
||||
/// Compute the bounding box of the cell over all layers.
|
||||
/// The bounding box is not defined if the cell is empty. In this
|
||||
/// case return `None`.
|
||||
fn bounding_box(&self, cell: &Self::CellId) -> Option<Rect<Self::Coord>> {
|
||||
self.each_layer()
|
||||
.map(|layer| self.bounding_box_per_layer(cell, &layer))
|
||||
.fold(None, |a, b| match (a, b) {
|
||||
(None, None) => None,
|
||||
(Some(a), None) | (None, Some(a)) => Some(a),
|
||||
(Some(a), Some(b)) => Some(a.add_rect(&b)),
|
||||
})
|
||||
}
|
||||
|
||||
/// Iterate over the IDs of all shapes in the cell on a specific layer.
|
||||
fn each_shape_id(
|
||||
&self,
|
||||
cell: &Self::CellId,
|
||||
layer: &Self::LayerId,
|
||||
) -> Box<dyn Iterator<Item = Self::ShapeId> + '_>;
|
||||
|
||||
/// Call a function for each shape on this layer.
|
||||
fn for_each_shape<F>(&self, cell: &Self::CellId, layer: &Self::LayerId, f: F)
|
||||
where
|
||||
F: FnMut(&Self::ShapeId, &Geometry<Self::Coord>);
|
||||
|
||||
/// Access a shape by its ID.
|
||||
fn with_shape<F, R>(&self, shape_id: &Self::ShapeId, f: F) -> R
|
||||
where
|
||||
F: FnMut(&Self::LayerId, &Geometry<Self::Coord>) -> R;
|
||||
|
||||
/// Get a clone of the shape geometry.
|
||||
fn shape_geometry(&self, shape_id: &Self::ShapeId) -> Geometry<Self::Coord> {
|
||||
self.with_shape(shape_id, |_, geo| geo.clone())
|
||||
}
|
||||
|
||||
/// Get the layer of a shape.
|
||||
fn shape_layer(&self, shape_id: &Self::ShapeId) -> Self::LayerId {
|
||||
self.with_shape(shape_id, |layer, _| layer.clone())
|
||||
}
|
||||
|
||||
/// Get the parent cell and the layer of a shape as a (cell, layer) tuple.
|
||||
fn parent_of_shape(&self, shape_id: &Self::ShapeId) -> (Self::CellId, Self::LayerId);
|
||||
|
||||
/// Call a function `f` for each shape of this cell and its sub cells.
|
||||
/// Along to the geometric shape `f` also gets a transformation as argument.
|
||||
/// The transformation describes the actual position of the geometric shape relative to the `cell`.
|
||||
fn for_each_shape_recursive<F>(&self, cell: &Self::CellId, layer: &Self::LayerId, mut f: F)
|
||||
where
|
||||
F: FnMut(SimpleTransform<Self::Coord>, &Self::ShapeId, &Geometry<Self::Coord>),
|
||||
{
|
||||
// This recursive iteration through the cells is implemented iteratively.
|
||||
// A plain recursive implementation is more difficult to handle due to the type system.
|
||||
|
||||
// Stack for resolved recursion.
|
||||
let mut stack = Vec::new();
|
||||
stack.push((cell.clone(), SimpleTransform::identity()));
|
||||
|
||||
while let Some((cell, tf)) = stack.pop() {
|
||||
// Push child instances.
|
||||
self.for_each_cell_instance(&cell, |inst| {
|
||||
let template = self.template_cell(&inst);
|
||||
let transform = self.get_transform(&inst);
|
||||
let tf2 = transform.then(&tf);
|
||||
stack.push((template, tf2));
|
||||
});
|
||||
|
||||
// Process shapes of this cell.
|
||||
self.for_each_shape(&cell, layer, |id, g| f(tf, id, g));
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the geometric transform that describes the location of a cell instance relative to its parent.
|
||||
fn get_transform(&self, cell_inst: &Self::CellInstId) -> SimpleTransform<Self::Coord>;
|
||||
|
||||
/// Get a property of a shape.
|
||||
fn get_shape_property(
|
||||
&self,
|
||||
shape: &Self::ShapeId,
|
||||
key: &Self::NameType,
|
||||
) -> Option<PropertyValue> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Access shapes and instances in a layout based on their locations.
|
||||
#[portrait::make]
|
||||
pub trait RegionSearch: LayoutBase {
|
||||
/// Iterate over the IDs of all shapes (on all layers) whose bounding-box overlaps with the `search_region`.
|
||||
fn each_shape_in_region(
|
||||
&self,
|
||||
cell: &Self::CellId,
|
||||
search_region: &Rect<Self::Coord>,
|
||||
) -> Box<dyn Iterator<Item = Self::ShapeId> + '_> {
|
||||
let cell = cell.clone(); // Get an owned ID.
|
||||
let search_region = *search_region; // Get an owned rectangle.
|
||||
Box::new(self.each_layer().flat_map(move |layer_id| {
|
||||
self.each_shape_in_region_per_layer(&cell, &layer_id, &search_region)
|
||||
}))
|
||||
}
|
||||
|
||||
/// Iterate over the IDs of all shapes (on a specific layer) whose bounding-box overlaps with the `search_region`.
|
||||
fn each_shape_in_region_per_layer(
|
||||
&self,
|
||||
cell: &Self::CellId,
|
||||
layer_id: &Self::LayerId,
|
||||
search_region: &Rect<Self::Coord>,
|
||||
) -> Box<dyn Iterator<Item = Self::ShapeId> + '_>;
|
||||
|
||||
/// Iterate over the IDs of all instances within the `cell` whose bounding-box overlaps with the `search_region`.
|
||||
fn each_cell_instance_in_region(
|
||||
&self,
|
||||
cell: &Self::CellId,
|
||||
search_region: &Rect<Self::Coord>,
|
||||
) -> Box<dyn Iterator<Item = Self::CellInstId> + '_>;
|
||||
}
|
||||
|
||||
/// Trait for layouts that support editing.
|
||||
#[portrait::make(import(crate::prelude::*))]
|
||||
pub trait LayoutEdit: LayoutBase + HierarchyEdit {
|
||||
/// Set the distance unit used in this layout in 'pixels per micron'.
|
||||
fn set_dbu(&mut self, dbu: Self::Coord) {} // TODO: Remove default implementation.
|
||||
|
||||
/// Create a new layer.
|
||||
/// Use `set_layer_name()` to define a name.
|
||||
fn create_layer(&mut self, index: UInt, datatype: UInt) -> Self::LayerId;
|
||||
|
||||
/// Create a new layer with a specific ID. This is used to clone layer-stacks between layouts while preserving their IDs.
|
||||
/// Returns an `Err` when the ID already exists.
|
||||
fn create_layer_with_id(
|
||||
&mut self,
|
||||
layer_id: Self::LayerId,
|
||||
index: UInt,
|
||||
datatype: UInt,
|
||||
) -> Result<(), ()>;
|
||||
|
||||
/// Set the name of a layer or clear the layer name when passing `None`.
|
||||
/// This method should not change the ID of the layer.
|
||||
/// Returns the previous name of the layer.
|
||||
fn set_layer_name(
|
||||
&mut self,
|
||||
layer: &Self::LayerId,
|
||||
name: Option<Self::NameType>,
|
||||
) -> Option<Self::NameType>;
|
||||
|
||||
/// Insert a geometric shape into the parent cell.
|
||||
fn insert_shape(
|
||||
&mut self,
|
||||
parent_cell: &Self::CellId,
|
||||
layer: &Self::LayerId,
|
||||
geometry: Geometry<Self::Coord>,
|
||||
) -> Self::ShapeId;
|
||||
|
||||
/// Remove shape from the parent cell.
|
||||
fn remove_shape(&mut self, shape_id: &Self::ShapeId) -> Option<Geometry<Self::Coord>>;
|
||||
|
||||
/// Replace the geometry of a shape.
|
||||
fn replace_shape(
|
||||
&mut self,
|
||||
shape_id: &Self::ShapeId,
|
||||
geometry: Geometry<Self::Coord>,
|
||||
) -> Geometry<Self::Coord>;
|
||||
|
||||
/// Set the geometric transform that describes the location of a cell instance relative to its parent.
|
||||
fn set_transform(&mut self, cell_inst: &Self::CellInstId, tf: SimpleTransform<Self::Coord>);
|
||||
|
||||
/// Set a property of a shape.
|
||||
fn set_shape_property(
|
||||
&mut self,
|
||||
shape: &Self::ShapeId,
|
||||
key: Self::NameType,
|
||||
value: PropertyValue,
|
||||
) {
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
// Copyright (c) 2020-2021 Thomas Kramer.
|
||||
// SPDX-FileCopyrightText: 2022 Thomas Kramer
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
//! Data types used in the data base.
|
||||
|
||||
/// Default unsigned integer type.
|
||||
pub type UInt = u32;
|
||||
/// Default signed integer type.
|
||||
pub type SInt = i32;
|
||||
|
||||
/// Integer coordinate type.
|
||||
pub type Coord = i32;
|
||||
|
||||
/// Meta-data of a layer.
|
||||
#[derive(Clone, Hash, PartialEq, Debug)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct LayerInfo<NameType> {
|
||||
/// Identifier of the layer.
|
||||
pub index: UInt,
|
||||
/// Identifier of the layer.
|
||||
pub datatype: UInt,
|
||||
/// Name of the layer.
|
||||
pub name: Option<NameType>,
|
||||
}
|
||||
@@ -88,6 +88,9 @@ extern crate num_derive;
|
||||
pub use iron_shapes;
|
||||
pub use iron_shapes_booleanop;
|
||||
|
||||
pub use libreda_core as core;
|
||||
pub use libreda_core::technology;
|
||||
|
||||
/// Helpers for deriving trait implementations of core traits.
|
||||
pub mod derive {
|
||||
pub use portrait::delegate;
|
||||
@@ -105,14 +108,10 @@ pub mod netlist;
|
||||
pub mod prelude;
|
||||
pub mod profile;
|
||||
pub mod property_storage;
|
||||
pub mod rc_string;
|
||||
pub mod reference_access;
|
||||
pub mod rw_reference_access;
|
||||
pub mod traits;
|
||||
pub mod undo;
|
||||
|
||||
pub mod technology;
|
||||
|
||||
mod blanket_impl;
|
||||
mod library;
|
||||
mod slab_alloc;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
//! ID of an arc (net segment). The arc is defined by two terminals (pin or pin instance).
|
||||
|
||||
use super::prelude::*;
|
||||
use libreda_core::prelude::*;
|
||||
use std::hash::Hash;
|
||||
|
||||
/// An arc represents the direct path from one pin to another.
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
// Copyright (c) 2020-2021 Thomas Kramer.
|
||||
// SPDX-FileCopyrightText: 2022 Thomas Kramer
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
//! The type of a pin is specified by a signal direction.
|
||||
|
||||
/// Signal type for pins.
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, Default)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub enum Direction {
|
||||
/// No direction specified.
|
||||
#[default]
|
||||
None,
|
||||
/// Data input.
|
||||
Input,
|
||||
/// Data output.
|
||||
Output,
|
||||
/// Input and output.
|
||||
InOut,
|
||||
/// Clock input.
|
||||
Clock,
|
||||
/// Power VDD.
|
||||
Supply,
|
||||
/// Power ground.
|
||||
Ground,
|
||||
}
|
||||
|
||||
impl Direction {
|
||||
/// Check if this direction is 'input'.
|
||||
pub fn is_input(&self) -> bool {
|
||||
self == &Direction::Input
|
||||
}
|
||||
/// Check if this direction is 'output'.
|
||||
pub fn is_output(&self) -> bool {
|
||||
self == &Direction::Output
|
||||
}
|
||||
|
||||
/// Check if this direciton is either 'Supply' or 'Ground'.
|
||||
pub fn is_power(&self) -> bool {
|
||||
matches!(self, Direction::Supply | Direction::Ground)
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
// Copyright (c) 2020-2021 Thomas Kramer.
|
||||
// SPDX-FileCopyrightText: 2022 Thomas Kramer
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
//! Input and output interface definitions for netlists.
|
||||
//!
|
||||
//! Implementations for the various netlist formats are located in other crates.
|
||||
|
||||
use crate::netlist::traits::{NetlistBase, NetlistEdit};
|
||||
use std::io::{Read, Write};
|
||||
|
||||
/// Read a netlist from a byte stream.
|
||||
pub trait NetlistReader {
|
||||
/// Type of error that could happen while reading a netlist.
|
||||
type Error;
|
||||
|
||||
/// Read a netlist from a byte stream and populate the netlist data structure.
|
||||
fn read_into_netlist<R: Read, N: NetlistEdit>(
|
||||
&self,
|
||||
reader: &mut R,
|
||||
netlist: &mut N,
|
||||
) -> Result<(), Self::Error>;
|
||||
|
||||
/// Read a netlist from a byte stream.
|
||||
fn read_netlist<R: Read, N: NetlistEdit + Default>(
|
||||
&self,
|
||||
reader: &mut R,
|
||||
) -> Result<N, Self::Error> {
|
||||
let mut netlist = N::default();
|
||||
self.read_into_netlist(reader, &mut netlist)?;
|
||||
Ok(netlist)
|
||||
}
|
||||
}
|
||||
|
||||
/// Write a netlist to a byte stream.
|
||||
pub trait NetlistWriter {
|
||||
/// Type of error that could happen while writing a netlist.
|
||||
type Error;
|
||||
|
||||
/// Write the netlist data structure to a byte stream.
|
||||
fn write_netlist<W: Write, N: NetlistBase>(
|
||||
&self,
|
||||
writer: &mut W,
|
||||
netlist: &N,
|
||||
) -> Result<(), Self::Error>;
|
||||
}
|
||||
@@ -22,10 +22,13 @@
|
||||
//! [`NetlistBase`]: trait@traits::NetlistBase
|
||||
//! [`NetlistEdit`]: trait@traits::NetlistEdit
|
||||
|
||||
pub use libreda_core::netlist::prelude::*;
|
||||
|
||||
pub mod arc_id;
|
||||
pub mod direction;
|
||||
pub mod io;
|
||||
pub mod prelude;
|
||||
pub mod terminal_id;
|
||||
pub mod traits;
|
||||
pub mod util;
|
||||
|
||||
/// Re-export of traits related to netlists.
|
||||
pub mod traits {
|
||||
pub use super::util::{NetlistEditUtil, NetlistUtil};
|
||||
pub use libreda_core::netlist::traits::*;
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
// Copyright (c) 2020-2021 Thomas Kramer.
|
||||
// SPDX-FileCopyrightText: 2022 Thomas Kramer
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
//! The `prelude` helps to import most commonly used modules.
|
||||
|
||||
pub use super::arc_id::*;
|
||||
pub use super::direction::*;
|
||||
pub use super::io::*;
|
||||
pub use super::terminal_id::*;
|
||||
pub use super::traits::*;
|
||||
pub use super::util::*;
|
||||
@@ -1,80 +0,0 @@
|
||||
// Copyright (c) 2020-2022 Thomas Kramer.
|
||||
// SPDX-FileCopyrightText: 2022 Thomas Kramer
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
//! Generalization of pins and pin instances.
|
||||
|
||||
use super::prelude::*;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
/// A terminal is a generalization of pins and pin instances.
|
||||
pub enum TerminalId<N: NetlistIds + ?Sized> {
|
||||
/// Terminal is a pin.
|
||||
PinId(N::PinId),
|
||||
/// Terminal is a pin instance.
|
||||
PinInstId(N::PinInstId),
|
||||
}
|
||||
|
||||
impl<N1> TerminalId<N1>
|
||||
where
|
||||
N1: NetlistIds,
|
||||
{
|
||||
/// Cast the ID to other netlist types.
|
||||
pub fn cast<N2>(self) -> TerminalId<N2>
|
||||
where
|
||||
N2: NetlistIds<PinId = N1::PinId, PinInstId = N1::PinInstId>,
|
||||
{
|
||||
match self {
|
||||
TerminalId::PinId(p) => TerminalId::PinId(p),
|
||||
TerminalId::PinInstId(p) => TerminalId::PinInstId(p),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: NetlistIds + ?Sized> std::fmt::Debug for TerminalId<N>
|
||||
where
|
||||
N::PinId: std::fmt::Debug,
|
||||
N::PinInstId: std::fmt::Debug,
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
TerminalId::PinId(p) => write!(f, "{:?}", p),
|
||||
TerminalId::PinInstId(p) => write!(f, "{:?}", p),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: NetlistIds + ?Sized> Hash for TerminalId<N> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
match self {
|
||||
TerminalId::PinId(p) => p.hash(state),
|
||||
TerminalId::PinInstId(p) => p.hash(state),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: NetlistIds + ?Sized> Eq for TerminalId<N> {}
|
||||
|
||||
impl<N: NetlistIds + ?Sized> PartialEq for TerminalId<N> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::PinId(p1), Self::PinId(p2)) => p1 == p2,
|
||||
(Self::PinInstId(p1), Self::PinInstId(p2)) => p1 == p2,
|
||||
(_, _) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: NetlistIds + ?Sized> Clone for TerminalId<N>
|
||||
where
|
||||
N::PinId: Clone,
|
||||
N::PinInstId: Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
TerminalId::PinId(p) => Self::PinId(p.clone()),
|
||||
TerminalId::PinInstId(p) => Self::PinInstId(p.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,375 +0,0 @@
|
||||
// Copyright (c) 2020-2021 Thomas Kramer.
|
||||
// SPDX-FileCopyrightText: 2022 Thomas Kramer
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
//! Traits for netlist data types.
|
||||
//!
|
||||
//! Instead of putting a netlist data structure into the center of the world,
|
||||
//! this data base concentrates on the way *how* a netlist can be accessed and modified.
|
||||
//! The basic necessary operations are defined in the [`NetlistBase'] trait and in the
|
||||
//! [`NetlistEdit`] trait.
|
||||
//!
|
||||
//! More complex operations on netlist are provided by the [`NetlistUtil`] and [`NetlistEditUtil`] traits.
|
||||
//!
|
||||
//! [`NetlistBase`]: trait@NetlistBase
|
||||
//! [`NetlistEdit`]: trait@NetlistEdit
|
||||
//! [`NetlistUtil`]: trait@crate::netlist::util::NetlistUtil
|
||||
//! [`NetlistEditUtil`]: trait@crate::netlist::util::NetlistEditUtil
|
||||
|
||||
#![allow(missing_docs)] // Necessary because portrait does not generate docs.
|
||||
|
||||
use super::prelude::*;
|
||||
pub use super::util::{NetlistEditUtil, NetlistUtil};
|
||||
pub use crate::traits::{HierarchyBase, HierarchyEdit};
|
||||
use crate::traits::{HierarchyBaseMT, HierarchyIds, IdType, IdTypeMT};
|
||||
|
||||
/// Identifier types used for components of netlists.
|
||||
#[portrait::make]
|
||||
pub trait NetlistIds: HierarchyIds {
|
||||
/// Pin identifier type. Uniquely identifies a pin in the whole netlist.
|
||||
type PinId: IdType;
|
||||
/// Pin instance identifier type. Uniquely identifies a pin instance in the whole netlist.
|
||||
/// A pin instance is a pin of a circuit instance.
|
||||
type PinInstId: IdType;
|
||||
/// Net identifier type. Uniquely identifies a net in the whole netlist.
|
||||
type NetId: IdType;
|
||||
}
|
||||
|
||||
/// Helper trait which constrains [`trait@NetlistBase`] for such that ID types
|
||||
/// are [`Send`] and [`Sync`] as commonly used for parallel algorithms.
|
||||
#[portrait::make]
|
||||
pub trait NetlistBaseMT:
|
||||
NetlistBase<PinId = Self::PinIdMT, PinInstId = Self::PinInstIdMT, NetId = Self::NetIdMT>
|
||||
+ HierarchyBaseMT
|
||||
{
|
||||
/// ID of a pin.
|
||||
type PinIdMT: IdTypeMT;
|
||||
/// ID of a pin instance.
|
||||
type PinInstIdMT: IdTypeMT;
|
||||
/// ID of a net.
|
||||
type NetIdMT: IdTypeMT;
|
||||
}
|
||||
|
||||
impl<N> NetlistBaseMT for N
|
||||
where
|
||||
N: NetlistBase + HierarchyBaseMT,
|
||||
N::PinId: Send + Sync,
|
||||
N::PinInstId: Send + Sync,
|
||||
N::NetId: Send + Sync,
|
||||
{
|
||||
type PinIdMT = N::PinId;
|
||||
type PinInstIdMT = N::PinInstId;
|
||||
type NetIdMT = N::NetId;
|
||||
}
|
||||
|
||||
/// Most basic trait for traversing a netlist.
|
||||
/// A netlist extends the `HierarchyBase` and hence is hierarchical.
|
||||
/// `NetlistBase` extends the components of the hierarchy with pins and nets.
|
||||
/// Each cell can have pins. Each cell instance has pin instances that correspond one-to-one
|
||||
/// to the pins of the template cell. Cells can contain nets. Each pin and each pin instance can be
|
||||
/// connected to one or zero nets. A net can be connected to an arbitrary number of pins and pin instances.
|
||||
///
|
||||
/// Pins must have a name and also a signal direction.
|
||||
///
|
||||
/// Nets *can* have a name.
|
||||
///
|
||||
#[portrait::make(import(crate::prelude::Direction))]
|
||||
pub trait NetlistBase: HierarchyBase + NetlistIds {
|
||||
/// Get the ID of the template pin of this pin instance.
|
||||
fn template_pin(&self, pin_instance: &Self::PinInstId) -> Self::PinId;
|
||||
|
||||
/// Get the signal direction of the pin.
|
||||
fn pin_direction(&self, pin: &Self::PinId) -> Direction;
|
||||
|
||||
/// Get the name of the pin.
|
||||
fn pin_name(&self, pin: &Self::PinId) -> Self::NameType;
|
||||
|
||||
/// Find a pin by its name.
|
||||
/// Returns `None` if no such pin can be found.
|
||||
fn pin_by_name(&self, parent_circuit: &Self::CellId, name: &str) -> Option<Self::PinId>;
|
||||
|
||||
/// Get the ID of the parent circuit of this pin.
|
||||
fn parent_cell_of_pin(&self, pin: &Self::PinId) -> Self::CellId;
|
||||
|
||||
/// Get the ID of the circuit instance that holds this pin instance.
|
||||
fn parent_of_pin_instance(&self, pin_inst: &Self::PinInstId) -> Self::CellInstId;
|
||||
|
||||
/// Get the ID of a pin instance given the cell instance and the pin ID.
|
||||
fn pin_instance(&self, cell_inst: &Self::CellInstId, pin: &Self::PinId) -> Self::PinInstId {
|
||||
// Inefficient default implementation.
|
||||
self.each_pin_instance(cell_inst)
|
||||
.find(|inst| &self.template_pin(inst) == pin)
|
||||
.expect("No such pin found in this cell.")
|
||||
}
|
||||
|
||||
/// Get the ID of the parent circuit of this net.
|
||||
fn parent_cell_of_net(&self, net: &Self::NetId) -> Self::CellId;
|
||||
|
||||
/// Get the internal net attached to this pin.
|
||||
fn net_of_pin(&self, pin: &Self::PinId) -> Option<Self::NetId>;
|
||||
|
||||
/// Get the external net attached to this pin instance.
|
||||
fn net_of_pin_instance(&self, pin_instance: &Self::PinInstId) -> Option<Self::NetId>;
|
||||
|
||||
/// Get the net of the logical constant zero.
|
||||
fn net_zero(&self, parent_circuit: &Self::CellId) -> Self::NetId;
|
||||
|
||||
/// Get the net of the logical constant one.
|
||||
fn net_one(&self, parent_circuit: &Self::CellId) -> Self::NetId;
|
||||
|
||||
/// Find a net by its name inside the parent circuit.
|
||||
/// Returns `None` if no such net can be found.
|
||||
fn net_by_name(&self, parent_circuit: &Self::CellId, name: &str) -> Option<Self::NetId>;
|
||||
|
||||
/// Get the name of the net.
|
||||
fn net_name(&self, net: &Self::NetId) -> Option<Self::NameType>;
|
||||
|
||||
/// Call a function for each pin of the circuit.
|
||||
fn for_each_pin<F>(&self, circuit: &Self::CellId, f: F)
|
||||
where
|
||||
F: FnMut(Self::PinId);
|
||||
|
||||
/// Get a `Vec` with the IDs of all pins of this circuit.
|
||||
fn each_pin_vec(&self, circuit: &Self::CellId) -> Vec<Self::PinId> {
|
||||
let mut v = Vec::new();
|
||||
self.for_each_pin(circuit, |c| v.push(c));
|
||||
v
|
||||
}
|
||||
|
||||
/// Iterate over all pins of a circuit.
|
||||
fn each_pin<'a>(
|
||||
&'a self,
|
||||
circuit: &Self::CellId,
|
||||
) -> Box<dyn Iterator<Item = Self::PinId> + 'a> {
|
||||
Box::new(self.each_pin_vec(circuit).into_iter())
|
||||
}
|
||||
|
||||
// /// Find the position of the pin.
|
||||
// fn pin_position(&self, pin: &Self::PinId) -> usize {
|
||||
// self.for_each_pin(&self.parent_cell_of_pin(pin))
|
||||
// .enumerate()
|
||||
// .find(|(_, p)| p == pin)
|
||||
// .map(|(idx, _)| idx)
|
||||
// .expect("pin ID does not exist")
|
||||
// }
|
||||
|
||||
/// Call a function for each pin instance of the circuit instance.
|
||||
fn for_each_pin_instance<F>(&self, circuit_inst: &Self::CellInstId, f: F)
|
||||
where
|
||||
F: FnMut(Self::PinInstId);
|
||||
|
||||
/// Get a `Vec` with the IDs of all pin instance of this circuit instance.
|
||||
fn each_pin_instance_vec(&self, circuit_instance: &Self::CellInstId) -> Vec<Self::PinInstId> {
|
||||
let mut v = Vec::new();
|
||||
self.for_each_pin_instance(circuit_instance, |c| v.push(c));
|
||||
v
|
||||
}
|
||||
|
||||
/// Iterate over all pin instances of a circuit.
|
||||
fn each_pin_instance<'a>(
|
||||
&'a self,
|
||||
circuit_instance: &Self::CellInstId,
|
||||
) -> Box<dyn Iterator<Item = Self::PinInstId> + 'a> {
|
||||
Box::new(self.each_pin_instance_vec(circuit_instance).into_iter())
|
||||
}
|
||||
|
||||
/// Iterate over all external nets connected to the circuit instance.
|
||||
/// A net might appear more than once.
|
||||
fn each_external_net<'a>(
|
||||
&'a self,
|
||||
circuit_instance: &Self::CellInstId,
|
||||
) -> Box<dyn Iterator<Item = Self::NetId> + 'a> {
|
||||
Box::new(
|
||||
self.each_pin_instance(circuit_instance)
|
||||
.flat_map(move |pin_id| self.net_of_pin_instance(&pin_id)),
|
||||
)
|
||||
}
|
||||
|
||||
/// Iterate over all external nets connected to the circuit instance.
|
||||
/// A net might appear more than once.
|
||||
fn for_each_external_net<F>(&self, circuit_instance: &Self::CellInstId, mut f: F)
|
||||
where
|
||||
F: FnMut(Self::NetId),
|
||||
{
|
||||
self.for_each_pin_instance(circuit_instance, |i| {
|
||||
self.net_of_pin_instance(&i)
|
||||
.iter()
|
||||
.cloned()
|
||||
.for_each(|n| f(n))
|
||||
});
|
||||
}
|
||||
|
||||
/// Get a vector of all external nets connected to the circuit instance.
|
||||
/// A net might appear more than once.
|
||||
fn each_external_net_vec(&self, circuit_instance: &Self::CellInstId) -> Vec<Self::NetId> {
|
||||
let mut v = Vec::new();
|
||||
self.for_each_external_net(circuit_instance, |n| v.push(n));
|
||||
v
|
||||
}
|
||||
|
||||
/// Call a function for net of the circuit.
|
||||
fn for_each_internal_net<F>(&self, circuit: &Self::CellId, f: F)
|
||||
where
|
||||
F: FnMut(Self::NetId);
|
||||
|
||||
/// Get a `Vec` with all nets in this circuit.
|
||||
fn each_internal_net_vec(&self, circuit: &Self::CellId) -> Vec<Self::NetId> {
|
||||
let mut v = Vec::new();
|
||||
self.for_each_internal_net(circuit, |c| v.push(c));
|
||||
v
|
||||
}
|
||||
|
||||
/// Iterate over all defined nets inside a circuit.
|
||||
fn each_internal_net<'a>(
|
||||
&'a self,
|
||||
circuit: &Self::CellId,
|
||||
) -> Box<dyn Iterator<Item = Self::NetId> + 'a> {
|
||||
Box::new(self.each_internal_net_vec(circuit).into_iter())
|
||||
}
|
||||
|
||||
/// Return the number of nets defined inside a cell.
|
||||
fn num_internal_nets(&self, circuit: &Self::CellId) -> usize {
|
||||
// Inefficient default implementation.
|
||||
let mut counter = 0;
|
||||
self.for_each_internal_net(circuit, |_| counter += 1);
|
||||
counter
|
||||
}
|
||||
|
||||
/// Get the number of pins that are connected to this net.
|
||||
fn num_net_pins(&self, net: &Self::NetId) -> usize {
|
||||
let mut n = 0;
|
||||
self.for_each_pin_of_net(net, |_| n += 1);
|
||||
n
|
||||
}
|
||||
|
||||
/// Get the number of pin instances that are connected to this net.
|
||||
fn num_net_pin_instances(&self, net: &Self::NetId) -> usize {
|
||||
let mut n = 0;
|
||||
self.for_each_pin_instance_of_net(net, |_| n += 1);
|
||||
n
|
||||
}
|
||||
|
||||
/// Get the number of terminals that are connected to this net.
|
||||
fn num_net_terminals(&self, net: &Self::NetId) -> usize {
|
||||
self.num_net_pins(net) + self.num_net_pin_instances(net)
|
||||
}
|
||||
|
||||
/// Get the number of pins of a circuit.
|
||||
fn num_pins(&self, circuit: &Self::CellId) -> usize;
|
||||
|
||||
/// Call a function for each pin connected to this net.
|
||||
fn for_each_pin_of_net<F>(&self, net: &Self::NetId, f: F)
|
||||
where
|
||||
F: FnMut(Self::PinId);
|
||||
|
||||
/// Get a `Vec` with all pin IDs connected to this net.
|
||||
fn each_pin_of_net_vec(&self, net: &Self::NetId) -> Vec<Self::PinId> {
|
||||
let mut v = Vec::new();
|
||||
self.for_each_pin_of_net(net, |c| v.push(c));
|
||||
v
|
||||
}
|
||||
|
||||
/// Iterate over all pins of a net.
|
||||
fn each_pin_of_net<'a>(
|
||||
&'a self,
|
||||
net: &Self::NetId,
|
||||
) -> Box<dyn Iterator<Item = Self::PinId> + 'a> {
|
||||
Box::new(self.each_pin_of_net_vec(net).into_iter())
|
||||
}
|
||||
|
||||
/// Call a function for each pin instance connected to this net.
|
||||
fn for_each_pin_instance_of_net<F>(&self, net: &Self::NetId, f: F)
|
||||
where
|
||||
F: FnMut(Self::PinInstId);
|
||||
|
||||
/// Get a `Vec` with all pin instance IDs connected to this net.
|
||||
fn each_pin_instance_of_net_vec(&self, net: &Self::NetId) -> Vec<Self::PinInstId> {
|
||||
let mut v = Vec::new();
|
||||
self.for_each_pin_instance_of_net(net, |c| v.push(c));
|
||||
v
|
||||
}
|
||||
|
||||
/// Iterate over all pins of a net.
|
||||
fn each_pin_instance_of_net<'a>(
|
||||
&'a self,
|
||||
net: &Self::NetId,
|
||||
) -> Box<dyn Iterator<Item = Self::PinInstId> + 'a> {
|
||||
Box::new(self.each_pin_instance_of_net_vec(net).into_iter())
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait for netlists that support editing.
|
||||
///
|
||||
/// This includes:
|
||||
///
|
||||
/// * creation and removal of pins and nets
|
||||
/// * connecting pins and pin instances to nets
|
||||
/// * renaming nets
|
||||
/// * renaming pins
|
||||
///
|
||||
/// More complex operations which can be build on top of the basic operations
|
||||
/// are provided by the [`NetlistEditUtil`] trait.
|
||||
///
|
||||
/// [`NetlistEditUtil`]: crate::netlist::util::NetlistEditUtil
|
||||
#[portrait::make(import(crate::prelude::Direction))]
|
||||
pub trait NetlistEdit: NetlistBase + HierarchyEdit {
|
||||
// /// Create a multi-bit port.
|
||||
// /// Internally creates a pin for every bit of the port.
|
||||
// fn create_bus(&mut self, circuit: &Self::CellId, name: Self::NameType, direction: Direction, width: usize) -> Vec<Self::PinId>;
|
||||
|
||||
/// Create a new pin in this cell.
|
||||
/// Also adds the pin to all instances of the cell.
|
||||
fn create_pin(
|
||||
&mut self,
|
||||
cell: &Self::CellId,
|
||||
name: Self::NameType,
|
||||
direction: Direction,
|
||||
) -> Self::PinId;
|
||||
|
||||
/// Remove the pin from this circuit and from all instances of this circuit.
|
||||
fn remove_pin(&mut self, id: &Self::PinId);
|
||||
|
||||
/// Change the name of the pin, returns the old name.
|
||||
/// # Panics
|
||||
/// Panics when the name is already occupied.
|
||||
fn rename_pin(&mut self, pin: &Self::PinId, new_name: Self::NameType) -> Self::NameType;
|
||||
|
||||
/// Create a net net that lives in the `parent` circuit.
|
||||
fn create_net(&mut self, parent: &Self::CellId, name: Option<Self::NameType>) -> Self::NetId;
|
||||
|
||||
/// Set a new name for the net. This might panic if the name already exists.
|
||||
/// Returns the old name.
|
||||
fn rename_net(
|
||||
&mut self,
|
||||
net_id: &Self::NetId,
|
||||
new_name: Option<Self::NameType>,
|
||||
) -> Option<Self::NameType>;
|
||||
|
||||
/// Delete the net if it exists and disconnect all connected terminals.
|
||||
fn remove_net(&mut self, net: &Self::NetId);
|
||||
|
||||
/// Connect a pin to a net.
|
||||
/// Returns the old connected net, if any.
|
||||
fn connect_pin(&mut self, pin: &Self::PinId, net: Option<Self::NetId>) -> Option<Self::NetId>;
|
||||
|
||||
/// Disconnect the pin from any connected net.
|
||||
/// Returns the old connected net, if any.
|
||||
fn disconnect_pin(&mut self, pin: &Self::PinId) -> Option<Self::NetId> {
|
||||
self.connect_pin(pin, None)
|
||||
}
|
||||
|
||||
/// Connect a pin instance to a net.
|
||||
/// Returns the old connected net, if any.
|
||||
fn connect_pin_instance(
|
||||
&mut self,
|
||||
pin: &Self::PinInstId,
|
||||
net: Option<Self::NetId>,
|
||||
) -> Option<Self::NetId>;
|
||||
|
||||
/// Disconnect the pin instance from any connected net.
|
||||
/// Returns the old connected net, if any.
|
||||
fn disconnect_pin_instance(&mut self, pin_instance: &Self::PinInstId) -> Option<Self::NetId> {
|
||||
self.connect_pin_instance(pin_instance, None)
|
||||
}
|
||||
}
|
||||
@@ -7,30 +7,19 @@
|
||||
|
||||
pub use crate::chip::Chip;
|
||||
pub use crate::flat_view::FlatView;
|
||||
pub use crate::hierarchy::prelude::*;
|
||||
pub use crate::l2n::*;
|
||||
pub use crate::layout::prelude::*;
|
||||
pub use crate::netlist::prelude::*;
|
||||
pub use crate::layout::util::*;
|
||||
pub use crate::netlist::util::*;
|
||||
pub use crate::profile::*;
|
||||
pub use crate::property_storage::PropertyValue;
|
||||
pub use crate::rc_string::RcString;
|
||||
pub use crate::reference_access;
|
||||
pub use crate::reference_access::*;
|
||||
pub use crate::technology;
|
||||
pub use crate::technology::prelude::*;
|
||||
pub use crate::traits::*;
|
||||
pub use libreda_core::prelude::*;
|
||||
|
||||
/// Re-export of most traits.
|
||||
/// This can be useful if only traits should be used but not the rest.
|
||||
pub mod traits {
|
||||
pub use crate::hierarchy::traits::*;
|
||||
pub use crate::hierarchy::util::*;
|
||||
pub use crate::l2n::*;
|
||||
pub use crate::layout::traits::*;
|
||||
pub use crate::layout::util::*;
|
||||
pub use crate::netlist::traits::*;
|
||||
pub use crate::netlist::util::*;
|
||||
pub use crate::reference_access::*;
|
||||
pub use crate::traits::*;
|
||||
pub use iron_shapes::traits::*;
|
||||
pub use libreda_core::traits::*;
|
||||
}
|
||||
|
||||
@@ -5,174 +5,10 @@
|
||||
|
||||
//! Container structs for user defined properties.
|
||||
|
||||
use crate::rc_string::RcString;
|
||||
use libreda_core::prelude::{PropertyValue, RcString};
|
||||
use std::borrow::Borrow;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryInto;
|
||||
use std::hash::Hash;
|
||||
use std::sync::Arc;
|
||||
|
||||
// trait AnyValue: Any + Clone + std::fmt::Debug {}
|
||||
|
||||
/// Property value type.
|
||||
/// Properties can hold different types that are encapsulated in this enum.
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub enum PropertyValue {
|
||||
/// Property is a string.
|
||||
String(RcString),
|
||||
/// Property is a byte string.
|
||||
Bytes(Vec<u8>),
|
||||
/// Property is a signed integer.
|
||||
SInt(i32),
|
||||
/// Property is an unsigned integer.
|
||||
UInt(u32),
|
||||
/// Property is a float.
|
||||
Float(f64),
|
||||
// /// Dynamically typed value.
|
||||
// Any(Box<dyn AnyValue>),
|
||||
}
|
||||
|
||||
impl PropertyValue {
|
||||
/// Try to get a string value.
|
||||
pub fn get_string(&self) -> Option<RcString> {
|
||||
match self {
|
||||
PropertyValue::String(s) => Some(s.clone()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to get a `&str` value. Works for `String` property values.
|
||||
pub fn get_str(&self) -> Option<&str> {
|
||||
match self {
|
||||
PropertyValue::String(s) => Some(s.as_str()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to get a byte string value.
|
||||
pub fn get_bytes(&self) -> Option<&Vec<u8>> {
|
||||
match self {
|
||||
PropertyValue::Bytes(s) => Some(s),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to get a float value.
|
||||
pub fn get_float(&self) -> Option<f64> {
|
||||
match self {
|
||||
PropertyValue::Float(v) => Some(*v),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to get an i32 value.
|
||||
pub fn get_sint(&self) -> Option<i32> {
|
||||
match self {
|
||||
PropertyValue::SInt(v) => Some(*v),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to get an i32 value.
|
||||
pub fn get_uint(&self) -> Option<u32> {
|
||||
match self {
|
||||
PropertyValue::UInt(v) => Some(*v),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
// /// Try to get a dynamically typed value.
|
||||
// pub fn get_any(&self) -> Option<&Box<dyn AnyValue>> {
|
||||
// match self {
|
||||
// PropertyValue::Any(v) => Some(v),
|
||||
// _ => None
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
// pub enum PropertyKey {
|
||||
// String(String),
|
||||
//
|
||||
// }
|
||||
|
||||
impl From<String> for PropertyValue {
|
||||
fn from(v: String) -> Self {
|
||||
PropertyValue::String(v.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Arc<String>> for PropertyValue {
|
||||
fn from(v: Arc<String>) -> Self {
|
||||
PropertyValue::String(v.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Arc<String>> for PropertyValue {
|
||||
fn from(v: &Arc<String>) -> Self {
|
||||
PropertyValue::String(v.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for PropertyValue {
|
||||
fn from(v: &str) -> Self {
|
||||
PropertyValue::String(v.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<u8>> for PropertyValue {
|
||||
fn from(v: Vec<u8>) -> Self {
|
||||
PropertyValue::Bytes(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryInto<&'a str> for &'a PropertyValue {
|
||||
type Error = ();
|
||||
|
||||
fn try_into(self) -> Result<&'a str, Self::Error> {
|
||||
if let PropertyValue::String(s) = self {
|
||||
Ok(s.as_str())
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i32> for PropertyValue {
|
||||
fn from(v: i32) -> Self {
|
||||
PropertyValue::SInt(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryInto<i32> for &PropertyValue {
|
||||
type Error = ();
|
||||
|
||||
fn try_into(self) -> Result<i32, Self::Error> {
|
||||
if let PropertyValue::SInt(v) = self {
|
||||
Ok(*v)
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for PropertyValue {
|
||||
fn from(v: u32) -> Self {
|
||||
PropertyValue::UInt(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for PropertyValue {
|
||||
fn from(v: f64) -> Self {
|
||||
PropertyValue::Float(v)
|
||||
}
|
||||
}
|
||||
|
||||
// impl From<Box<dyn Any>> for PropertyValue {
|
||||
// fn from(v: Box<dyn Any>) -> Self {
|
||||
// PropertyValue::Any(v)
|
||||
// }
|
||||
// }
|
||||
|
||||
/// Look-up table for property values.
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -238,51 +74,3 @@ impl<K: Hash + Eq> PropertyStore<K> {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait for associating user defined properties with a type.
|
||||
pub trait WithProperties {
|
||||
/// Property key type.
|
||||
type Key: Hash + Eq;
|
||||
|
||||
/// Call a function with maybe the property storage as argument.
|
||||
///
|
||||
/// The property store might not always be initialized. For instance for
|
||||
/// objects without any defined properties, it will likely be `None`.
|
||||
fn with_properties<F, R>(&self, f: F) -> R
|
||||
where
|
||||
F: FnOnce(Option<&PropertyStore<Self::Key>>) -> R;
|
||||
|
||||
/// Get mutable reference to the property storage.
|
||||
fn with_properties_mut<F, R>(&self, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&mut PropertyStore<Self::Key>) -> R;
|
||||
|
||||
/// Get a property value by the property key.
|
||||
fn property<Q: ?Sized>(&self, key: &Q) -> Option<PropertyValue>
|
||||
where
|
||||
Self::Key: Borrow<Q>,
|
||||
Q: Eq + Hash,
|
||||
{
|
||||
self.with_properties(|p| p.and_then(|p| p.get(key).cloned()))
|
||||
}
|
||||
|
||||
/// Get a string property value by key.
|
||||
/// If the property value is not a string `None` is returned.
|
||||
fn property_str<Q: ?Sized>(&self, key: &Q) -> Option<RcString>
|
||||
where
|
||||
Self::Key: Borrow<Q>,
|
||||
Q: Eq + Hash,
|
||||
{
|
||||
self.with_properties(|p| p.and_then(|p| p.get_string(key).cloned()))
|
||||
}
|
||||
|
||||
/// Insert a property.
|
||||
/// Returns the old property value if there was already a property stored under this key.
|
||||
fn set_property<V: Into<PropertyValue>>(
|
||||
&self,
|
||||
key: Self::Key,
|
||||
value: V,
|
||||
) -> Option<PropertyValue> {
|
||||
self.with_properties_mut(|p| p.insert(key, value))
|
||||
}
|
||||
}
|
||||
|
||||
112
src/rc_string.rs
112
src/rc_string.rs
@@ -1,112 +0,0 @@
|
||||
// Copyright (c) 2020-2021 Thomas Kramer.
|
||||
// SPDX-FileCopyrightText: 2022 Thomas Kramer
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
//! `RcString` is a simple data structure for the representation of strings.
|
||||
//! In contrast to `String`, `RcString` can be efficiently cloned. It is intended
|
||||
//! to be used in cases where objects are indexed by a human readable name.
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! ```
|
||||
//! use libreda_db::rc_string::RcString;
|
||||
//!
|
||||
//! let a: String = "A".to_string();
|
||||
//!
|
||||
//! let a1_rc = RcString::from(a);
|
||||
//! let a2_rc = RcString::from("A");
|
||||
//!
|
||||
//! // No string data is copied here.
|
||||
//! let a3_rc = a1_rc.clone();
|
||||
//!
|
||||
//! assert_eq!(a1_rc, a2_rc);
|
||||
//! assert_eq!(a1_rc, a3_rc);
|
||||
//!
|
||||
//! ```
|
||||
|
||||
use iron_shapes::point::Deref;
|
||||
use std::borrow::Borrow;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Resource counted string, used for names.
|
||||
/// `RcString`s can be efficiently cloned.
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct RcString {
|
||||
string: Arc<String>,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for RcString {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(self.string.as_str(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl RcString {
|
||||
/// Create a new resource counted string.
|
||||
pub fn new(string: String) -> Self {
|
||||
RcString {
|
||||
string: Arc::new(string),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for RcString {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.string.hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for RcString {
|
||||
type Target = String;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.string.deref()
|
||||
}
|
||||
}
|
||||
|
||||
impl Borrow<str> for RcString {
|
||||
fn borrow(&self) -> &str {
|
||||
self.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl Borrow<String> for RcString {
|
||||
fn borrow(&self) -> &String {
|
||||
self.string.deref()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for RcString {
|
||||
fn from(string: String) -> Self {
|
||||
Self::new(string)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Arc<String>> for RcString {
|
||||
fn from(string: Arc<String>) -> Self {
|
||||
Self { string }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Arc<String>> for RcString {
|
||||
fn from(string: &Arc<String>) -> Self {
|
||||
Self {
|
||||
string: string.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for RcString {
|
||||
fn from(s: &str) -> Self {
|
||||
Self::new(s.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RcString> for String {
|
||||
fn from(val: RcString) -> Self {
|
||||
val.string.to_string()
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
use crate::traits::HierarchyBase;
|
||||
use libreda_core::traits::HierarchyBase;
|
||||
|
||||
/// Trait that provides object-like read access to a cell hierarchy structure and its elements.
|
||||
pub trait HierarchyReferenceAccess: HierarchyBase {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// Copyright (c) 2020-2021 Thomas Kramer.
|
||||
// SPDX-FileCopyrightText: 2022 Thomas Kramer
|
||||
// SPDX-FileCopyrightText: 2020-2024 Thomas Kramer
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
use crate::netlist::prelude::*;
|
||||
use crate::traits::NetlistBase;
|
||||
use crate::netlist::*;
|
||||
|
||||
use super::hierarchy_reference_access::*;
|
||||
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
// Copyright (c) 2020-2021 Thomas Kramer.
|
||||
// SPDX-FileCopyrightText: 2022 Thomas Kramer
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
//! Definition of the metal layer stack as it is needed for routers.
|
||||
|
||||
use super::rules::RuleBase;
|
||||
|
||||
/// A routing layer is either a 'via' or 'routing/metal' layer.
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||
pub enum RoutingLayerType {
|
||||
/// Via layer.
|
||||
Cut,
|
||||
/// Routing layer.
|
||||
Routing,
|
||||
}
|
||||
|
||||
/// Annotate a layer ID as 'via' or 'routing' layer.
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||
pub struct RoutingLayer<LayerId> {
|
||||
/// ID of the layer. This identifies the layer in the data-base structures.
|
||||
pub id: LayerId,
|
||||
/// Type of the routing layer (via or metal).
|
||||
pub layer_type: RoutingLayerType,
|
||||
}
|
||||
|
||||
impl<LayerId> RoutingLayer<LayerId> {
|
||||
/// Associate a layer ID with a layer type.
|
||||
pub fn new(id: LayerId, layer_type: RoutingLayerType) -> Self {
|
||||
Self { id, layer_type }
|
||||
}
|
||||
|
||||
/// Get the a reference to the ID of the layer.
|
||||
pub fn as_id(&self) -> &LayerId {
|
||||
&self.id
|
||||
}
|
||||
|
||||
/// Get the ID of the layer.
|
||||
pub fn id(self) -> LayerId {
|
||||
self.id
|
||||
}
|
||||
|
||||
/// Type of the layer.
|
||||
pub fn layer_type(&self) -> RoutingLayerType {
|
||||
self.layer_type
|
||||
}
|
||||
|
||||
/// Check if layer is a via/cut layer.
|
||||
pub fn is_via_layer(&self) -> bool {
|
||||
match self.layer_type() {
|
||||
RoutingLayerType::Cut => true,
|
||||
RoutingLayerType::Routing => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if layer is a metal layer.
|
||||
pub fn is_metal_layer(&self) -> bool {
|
||||
match self.layer_type() {
|
||||
RoutingLayerType::Cut => false,
|
||||
RoutingLayerType::Routing => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Define standardized access for routing and via layers.
|
||||
pub trait RoutingLayerStack: RuleBase {
|
||||
/// Get the stack of routing and via layers in process order.
|
||||
fn layer_stack(&self) -> Vec<RoutingLayer<Self::LayerId>>;
|
||||
|
||||
/// Get the layer ids of the layer stack (routing layers and via layers).
|
||||
fn layer_stack_ids(&self) -> Vec<Self::LayerId> {
|
||||
self.layer_stack().into_iter().map(|l| l.id).collect()
|
||||
}
|
||||
|
||||
/// Get the stack of routing metal layers in process order.
|
||||
fn routing_layer_stack(&self) -> Vec<Self::LayerId> {
|
||||
self.layer_stack()
|
||||
.into_iter()
|
||||
.filter(|l| l.is_metal_layer())
|
||||
.map(|l| l.id())
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Get the stack of via layers in process order.
|
||||
fn via_layer_stack(&self) -> Vec<Self::LayerId> {
|
||||
self.layer_stack()
|
||||
.into_iter()
|
||||
.filter(|l| l.is_via_layer())
|
||||
.map(|l| l.id())
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Find the closest metal layer above the given layer.
|
||||
fn get_upper_metal_layer(&self, layer: &Self::LayerId) -> Option<Self::LayerId> {
|
||||
self.layer_stack()
|
||||
.into_iter()
|
||||
.skip_while(|l| l.as_id() != layer)
|
||||
.skip(1)
|
||||
.find(|l| l.is_metal_layer())
|
||||
.map(|l| l.id())
|
||||
}
|
||||
|
||||
/// Find the closest metal layer under the given layer.
|
||||
fn get_lower_metal_layer(&self, layer: &Self::LayerId) -> Option<Self::LayerId> {
|
||||
self.layer_stack()
|
||||
.into_iter()
|
||||
.rev()
|
||||
.skip_while(|l| l.as_id() != layer)
|
||||
.skip(1)
|
||||
.find(|l| l.is_metal_layer())
|
||||
.map(|l| l.id())
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
// Copyright (c) 2020-2021 Thomas Kramer.
|
||||
// SPDX-FileCopyrightText: 2022 Thomas Kramer
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
//! Traits and datastructures for the representation of technology related properties,
|
||||
//! especially design rules.
|
||||
pub mod layerstack;
|
||||
pub mod prelude;
|
||||
pub mod rules;
|
||||
@@ -1,8 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2022 Thomas Kramer
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
//! Helper to include all traits and structures related to design rules and technology descriptions.
|
||||
|
||||
pub use super::layerstack::*;
|
||||
pub use super::rules::*;
|
||||
@@ -1,88 +0,0 @@
|
||||
// Copyright (c) 2020-2021 Thomas Kramer.
|
||||
// SPDX-FileCopyrightText: 2022 Thomas Kramer
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
//! Traits that define how certain design rules are represented.
|
||||
//!
|
||||
//! TBD
|
||||
|
||||
use crate::prelude::Orientation2D;
|
||||
use num_traits::Num;
|
||||
|
||||
/// Define essential types used for expressing design rules.
|
||||
pub trait RuleBase {
|
||||
/// Type used as layer identifier.
|
||||
type LayerId: Eq + Clone;
|
||||
}
|
||||
|
||||
/// Define essential types used for expressing design rules based on distance relations.
|
||||
pub trait DistanceRuleBase: RuleBase {
|
||||
/// Type used to express distances.
|
||||
type Distance: Num + Copy + PartialOrd;
|
||||
/// Type used to express areas.
|
||||
type Area: Num + Copy + PartialOrd;
|
||||
}
|
||||
|
||||
/// Minimum spacing rules between shapes on the same layer.
|
||||
pub trait MinimumSpacing: DistanceRuleBase {
|
||||
/// Absolute minimum spacing between two shapes on the `layer`.
|
||||
fn min_spacing_absolute(&self, layer: &Self::LayerId) -> Option<Self::Distance>;
|
||||
|
||||
/// Minimum spacing between two shapes on the `layer` dependent on the geometries.
|
||||
fn min_spacing(
|
||||
&self,
|
||||
layer: &Self::LayerId,
|
||||
run_length: Self::Distance,
|
||||
width: Self::Distance,
|
||||
) -> Option<Self::Distance>;
|
||||
|
||||
// Use another MinimumSpacing instance for same-net spacing.
|
||||
// fn min_spacing_same_net(layer: &Self::LayerId) -> Self::Distance;
|
||||
}
|
||||
|
||||
/// Minimum width rules.
|
||||
pub trait MinimumWidth: DistanceRuleBase {
|
||||
/// Minimal width of a shape with a certain length.
|
||||
fn min_width(
|
||||
&self,
|
||||
layer: &Self::LayerId,
|
||||
shape_length: Option<Self::Distance>,
|
||||
) -> Option<Self::Distance>;
|
||||
}
|
||||
|
||||
/// Default width rules.
|
||||
pub trait DefaultWidth: DistanceRuleBase {
|
||||
/// Default width of a wire segment of a certain length.
|
||||
fn default_width(
|
||||
&self,
|
||||
layer: &Self::LayerId,
|
||||
shape_length: Option<Self::Distance>,
|
||||
) -> Option<Self::Distance>;
|
||||
}
|
||||
|
||||
/// Preferred routing direction on metal layers.
|
||||
pub trait PreferredRoutingDirection: RuleBase {
|
||||
/// Get the preferred routing direction on this metal layer.
|
||||
fn preferred_routing_direction(&self, layer: &Self::LayerId) -> Option<Orientation2D>;
|
||||
}
|
||||
|
||||
/// Rules commonly used for routing.
|
||||
pub trait RoutingRules:
|
||||
PreferredRoutingDirection + DefaultWidth + MinimumSpacing + MinimumWidth
|
||||
{
|
||||
/// Get the default routing pitch on this layer for x and y directions.
|
||||
fn default_pitch(&self, layer: &Self::LayerId) -> Option<(Self::Distance, Self::Distance)>;
|
||||
|
||||
/// Get the default routing pitch for wires with the preferred routing direction.
|
||||
/// Return `None` if no default pitch or no routing direction is defined for this layer.
|
||||
fn default_pitch_preferred_direction(&self, layer: &Self::LayerId) -> Option<Self::Distance> {
|
||||
let pitch = self.default_pitch(layer)?;
|
||||
let preferred_direction = self.preferred_routing_direction(layer)?;
|
||||
|
||||
match preferred_direction {
|
||||
Orientation2D::Horizontal => Some(pitch.1),
|
||||
Orientation2D::Vertical => Some(pitch.0),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,17 +5,10 @@
|
||||
|
||||
//! Re-export all traits defined in this crate.
|
||||
|
||||
pub use crate::hierarchy::traits::*;
|
||||
pub use crate::l2n::*;
|
||||
pub use crate::layout::traits::*;
|
||||
pub use crate::netlist::traits::*;
|
||||
|
||||
/// Trait used for identifier types.
|
||||
pub trait IdType: std::fmt::Debug + Clone + Eq + std::hash::Hash + 'static {}
|
||||
|
||||
impl<T> IdType for T where T: std::fmt::Debug + Clone + Eq + std::hash::Hash + 'static {}
|
||||
|
||||
/// Traid used for thread-safe.
|
||||
pub trait IdTypeMT: IdType + Sync + Send {}
|
||||
|
||||
impl<T> IdTypeMT for T where T: IdType + Sync + Send {}
|
||||
pub use crate::hierarchy::util::*;
|
||||
pub use crate::layout::util::*;
|
||||
pub use crate::netlist::util::*;
|
||||
pub use libreda_core::l2n::*;
|
||||
pub use libreda_core::layout::traits::*;
|
||||
pub use libreda_core::netlist::traits::*;
|
||||
pub use libreda_core::traits::*;
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
//! For example if a cell is deleted this can be undone. The restored cell, pins, instances, etc.
|
||||
//! will have the same properties but different IDs.
|
||||
|
||||
use crate::layout::prelude::{Geometry, SimpleTransform};
|
||||
use crate::netlist::direction::Direction;
|
||||
use crate::prelude::PropertyValue;
|
||||
use crate::traits::*;
|
||||
use libreda_core::netlist::direction::Direction;
|
||||
use libreda_core::prelude::PropertyValue;
|
||||
use libreda_core::prelude::{Geometry, SimpleTransform};
|
||||
use libreda_core::traits::*;
|
||||
use std::ops::Deref;
|
||||
|
||||
/// Undo operations on the netlist.
|
||||
|
||||
@@ -11,9 +11,3 @@ fn chip_is_normal_type() {
|
||||
use libreda_db::chip::Chip;
|
||||
is_normal::<Chip>();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rc_string_is_normal_type() {
|
||||
use libreda_db::rc_string::RcString;
|
||||
is_normal::<RcString>();
|
||||
}
|
||||
|
||||
@@ -249,6 +249,8 @@ fn test_rename_net() {
|
||||
|
||||
#[test]
|
||||
fn test_flatten_circuit_instance() {
|
||||
use libreda_db::prelude::*;
|
||||
|
||||
let mut chip = Chip::new();
|
||||
|
||||
// Create cells.
|
||||
|
||||
Reference in New Issue
Block a user