use crate::def_ast::{Component, DEF};
use crate::lef_ast::LEF;
use libreda_db::traits::{HierarchyBase, HierarchyIds, LayoutBase, NetlistBase};
use std::borrow::Borrow;
use std::hash::Hash;
use itertools::Itertools;
use libreda_db::prelude as db;
use std::collections::{HashMap, HashSet};
use crate::lef_impl::{CellId, CellInstId};
struct LEFDEF<'a> {
lef: &'a LEF,
def: &'a DEF,
components_by_name: HashMap<&'a str, &'a Component>,
macro_references: HashMap<&'a str, Vec<&'a Component>>,
}
const DEFAULT_TOP_NAME: &str = "TOP";
impl<'a> LEFDEF<'a> {
pub fn new(lef: &'a LEF, def: &'a DEF) -> Self {
let mut components_by_name: HashMap<&str, &Component> = Default::default();
let mut macro_references: HashMap<&str, Vec<&Component>> = Default::default();
for c in &def.components {
components_by_name.insert(c.name.as_str(), c);
macro_references
.entry(c.model_name.as_str())
.or_insert(vec![])
.push(c);
}
Self {
lef,
def,
components_by_name,
macro_references,
}
}
fn top_cell_name(&self) -> &str {
self.def
.design_name
.as_ref()
.map(|n| n.as_str())
.unwrap_or(DEFAULT_TOP_NAME)
}
fn top_cell(&self) -> CellId {
CellId(self.top_cell_name().to_string())
}
pub fn def(&self) -> &DEF {
self.def
}
pub fn lef(&self) -> &LEF {
self.lef
}
fn component_by_name(&self, name: &str) -> Option<&Component> {
self.components_by_name.get(name).copied()
}
}
impl<'a> HierarchyIds for LEFDEF<'a> {
type CellId = CellId;
type CellInstId = CellInstId;
}
impl<'a> HierarchyBase for LEFDEF<'a> {
type NameType = String;
fn cell_by_name(&self, name: &str) -> Option<Self::CellId> {
if name == self.top_cell_name() {
Some(CellId(name.to_string()))
} else {
self.lef.cell_by_name(name)
}
}
fn cell_instance_by_name(
&self,
CellId(parent_cell): &Self::CellId,
name: &str,
) -> Option<Self::CellInstId> {
if parent_cell.as_str() == self.top_cell_name() {
self.def
.components
.iter()
.find(|c| c.name.as_str() == name)
.map(|_| CellInstId(name.into()))
} else {
None
}
}
fn cell_name(&self, CellId(cell_name): &Self::CellId) -> Self::NameType {
cell_name.clone()
}
fn cell_instance_name(
&self,
CellInstId(cell_inst): &Self::CellInstId,
) -> Option<Self::NameType> {
Some(cell_inst.clone())
}
fn parent_cell(&self, cell_instance: &Self::CellInstId) -> Self::CellId {
CellId(self.top_cell_name().into())
}
fn template_cell(&self, CellInstId(name): &Self::CellInstId) -> Self::CellId {
let model_name = &self
.component_by_name(name.as_str())
.expect("Component not found.")
.model_name;
CellId(model_name.into())
}
fn for_each_cell<F>(&self, mut f: F)
where
F: FnMut(Self::CellId) -> (),
{
f(self.top_cell());
self.lef.for_each_cell(f)
}
fn for_each_cell_instance<F>(&self, cell: &Self::CellId, mut f: F)
where
F: FnMut(Self::CellInstId) -> (),
{
for component in &self.def.components {
f(CellInstId(component.name.to_string()))
}
}
fn for_each_cell_dependency<F>(&self, CellId(cell_name): &Self::CellId, mut f: F)
where
F: FnMut(Self::CellId) -> (),
{
if cell_name == self.top_cell_name() {
let dependent_cells: HashSet<_> = self
.def
.components
.iter()
.map(|c| c.model_name.as_str())
.collect();
for cell in dependent_cells {
f(CellId(cell.to_string()))
}
}
}
fn for_each_dependent_cell<F>(&self, CellId(cell_name): &Self::CellId, mut f: F)
where
F: FnMut(Self::CellId) -> (),
{
if self.macro_references.contains_key(cell_name.as_str()) {
f(self.top_cell())
}
}
fn for_each_cell_reference<F>(&self, CellId(cell_name): &Self::CellId, mut f: F)
where
F: FnMut(Self::CellInstId) -> (),
{
if let Some(references) = self.macro_references.get(cell_name.as_str()) {
references
.iter()
.for_each(|c| f(CellInstId(c.name.clone())))
}
}
fn num_child_instances(&self, CellId(cell_name): &Self::CellId) -> usize {
if cell_name == self.top_cell_name() {
self.def.components.len()
} else {
0
}
}
fn num_cells(&self) -> usize {
self.lef.library.macros.len() + 1 }
}
#[test]
fn test_lefdef_hierarchy_view() {
use crate::def_parser::read_def_chars;
use crate::lef_parser::read_lef_chars;
let data = r#"
# Parts from gscl45nm.lef.
VERSION 5.5 ;
NAMESCASESENSITIVE ON ;
BUSBITCHARS "[]" ;
DIVIDERCHAR "/" ;
PROPERTYDEFINITIONS
LAYER contactResistance REAL ;
END PROPERTYDEFINITIONS
UNITS
DATABASE MICRONS 2000 ;
END UNITS
MANUFACTURINGGRID 0.0025 ;
LAYER poly
TYPE MASTERSLICE ;
END poly
LAYER contact
TYPE CUT ;
SPACING 0.075 ;
PROPERTY contactResistance 10.5 ;
END contact
LAYER metal1
TYPE ROUTING ;
DIRECTION HORIZONTAL ;
PITCH 0.19 ;
WIDTH 0.065 ;
SPACING 0.065 ;
RESISTANCE RPERSQ 0.38 ;
END metal1
LAYER via1
TYPE CUT ;
SPACING 0.075 ;
PROPERTY contactResistance 5.69 ;
END via1
LAYER OVERLAP
TYPE OVERLAP ;
END OVERLAP
VIA M2_M1_via DEFAULT
LAYER metal1 ;
RECT -0.0675 -0.0325 0.0675 0.0325 ;
LAYER via1 ;
RECT -0.0325 -0.0325 0.0325 0.0325 ;
LAYER metal2 ;
RECT -0.035 -0.0675 0.035 0.0675 ;
END M2_M1_via
VIARULE M2_M1 GENERATE
LAYER metal1 ;
ENCLOSURE 0 0.035 ;
LAYER metal2 ;
ENCLOSURE 0 0.035 ;
LAYER via1 ;
RECT -0.0325 -0.0325 0.0325 0.0325 ;
SPACING 0.14 BY 0.14 ;
END M2_M1
VIARULE M1_POLY GENERATE
LAYER poly ;
ENCLOSURE 0 0 ;
LAYER metal1 ;
ENCLOSURE 0 0.035 ;
LAYER contact ;
RECT -0.0325 -0.0325 0.0325 0.0325 ;
SPACING 0.14 BY 0.14 ;
END M1_POLY
SPACING
SAMENET metal1 metal1 0.065 ;
SAMENET metal2 metal2 0.07 ;
SAMENET metal6 metal6 0.14 ;
SAMENET metal5 metal5 0.14 ;
SAMENET metal4 metal4 0.14 ;
SAMENET metal3 metal3 0.07 ;
SAMENET metal7 metal7 0.4 ;
SAMENET metal8 metal8 0.4 ;
SAMENET metal9 metal9 0.8 ;
SAMENET metal10 metal10 0.8 ;
END SPACING
SITE CoreSite
CLASS CORE ;
SIZE 0.38 BY 2.47 ;
END CoreSite
MACRO INVX1
CLASS CORE ;
ORIGIN 0 0 ;
FOREIGN INVX1 0 0 ;
SIZE 0.57 BY 2.47 ;
SYMMETRY X Y ;
SITE CoreSite ;
PIN A
DIRECTION INPUT ;
USE SIGNAL ;
PORT
LAYER metal1 ;
RECT 0.1575 0.4875 0.2575 0.6225 ;
END
END A
PIN Y
DIRECTION OUTPUT ;
USE SIGNAL ;
PORT
LAYER metal1 ;
RECT 0.3475 0.2175 0.4125 1.815 ;
RECT 0.3125 0.2175 0.4475 0.4225 ;
END
END Y
PIN gnd
DIRECTION INOUT ;
USE GROUND ;
SHAPE ABUTMENT ;
PORT
LAYER metal1 ;
RECT 0.1625 -0.065 0.2275 0.4225 ;
RECT 0 -0.065 0.57 0.065 ;
END
END gnd
PIN vdd
DIRECTION INOUT ;
USE POWER ;
SHAPE ABUTMENT ;
PORT
LAYER metal1 ;
RECT 0.1625 1.265 0.2275 2.535 ;
RECT 0 2.405 0.57 2.535 ;
END
END vdd
END INVX1
MACRO INVX2
CLASS CORE ;
ORIGIN 0 0 ;
FOREIGN INVX1 0 0 ;
SIZE 0.57 BY 2.47 ;
SYMMETRY X Y ;
SITE CoreSite ;
PIN A
DIRECTION INPUT ;
USE SIGNAL ;
PORT
LAYER metal1 ;
RECT 0.1575 0.4875 0.2575 0.6225 ;
END
END A
PIN Y
DIRECTION OUTPUT ;
USE SIGNAL ;
PORT
LAYER metal1 ;
RECT 0.3475 0.2175 0.4125 1.815 ;
RECT 0.3125 0.2175 0.4475 0.4225 ;
END
END Y
PIN gnd
DIRECTION INOUT ;
USE GROUND ;
SHAPE ABUTMENT ;
PORT
LAYER metal1 ;
RECT 0.1625 -0.065 0.2275 0.4225 ;
RECT 0 -0.065 0.57 0.065 ;
END
END gnd
PIN vdd
DIRECTION INOUT ;
USE POWER ;
SHAPE ABUTMENT ;
PORT
LAYER metal1 ;
RECT 0.1625 1.265 0.2275 2.535 ;
RECT 0 2.405 0.57 2.535 ;
END
END vdd
END INVX2
END LIBRARY
"#;
let result = read_lef_chars(data.chars());
let lef = result.expect("LEF parsing failed.");
let def_data = r#"
VERSION 5.7 ;
DIVIDERCHAR "/" ;
BUSBITCHARS "[]" ;
DESIGN test_design ;
UNITS DISTANCE MICRONS 2000 ;
TECHNOLOGY FreePDK45 ;
DIEAREA ( 0 0 ) ( 10000 10000 ) ;
COMPONENTS 3 ;
- _1_ INVX1 ;
- _2_ INVX2 ;
- _3_ INVX2 ;
END COMPONENTS
NETS 6 ;
- IN ( PIN IN ) ;
- OUT ( PIN OUT ) ;
- net1 ( _1_ A ) ;
END NETS
END DESIGN
"#;
let result = read_def_chars(def_data.chars());
let def = result.expect("DEF parsing failed.");
let lefdef = LEFDEF::new(&lef, &def);
let top = lefdef
.cell_by_name("test_design")
.expect("Top cell not found.");
assert_eq!(lefdef.num_child_instances(&top), 3);
let mut instance_names: Vec<_> = lefdef
.each_cell_instance(&top)
.map(|inst| {
lefdef
.cell_instance_name(&inst)
.expect("Instance has no name.")
})
.collect();
instance_names.sort();
assert_eq!(instance_names, vec!["_1_", "_2_", "_3_"]);
}