use log;
use crate::lef_ast::{LEF, TechnologyLef, Layer};
use crate::lef_ast;
use libreda_db::prelude as db;
use db::traits::*;
use libreda_db::technology::layerstack;
use libreda_db::technology::rules;
use std::marker::PhantomData;
use std::collections::HashMap;
use num_traits::{FromPrimitive, ToPrimitive};
use libreda_db::prelude::technology::layerstack::{RoutingLayerType, RoutingLayerStack};
pub struct LEFDesignRuleAdapter<'a, L: db::LayoutBase> {
lef: &'a LEF,
layer_mapping: HashMap<L::LayerId, &'a lef_ast::Layer>,
layer_stack: Vec<(L::LayerId, &'a lef_ast::Layer)>,
ty: PhantomData<L>,
}
impl<'a, L> LEFDesignRuleAdapter<'a, L>
where L: db::LayoutBase,
L::Coord: ToPrimitive {
fn db_distance_to_lef(&self, db_distance: L::Coord) -> f64 {
let dbu = self.lef.technology.units.database_microns as f64;
db_distance.to_f64()
.expect("Conversion from LEF distance unit to database distance unit failed.")
/ dbu
}
}
impl<'a, L> LEFDesignRuleAdapter<'a, L>
where L: db::LayoutBase,
L::Coord: FromPrimitive {
fn lef_distance_to_db(&self, lef_distance: f64) -> L::Coord {
let dbu = self.lef.technology.units.database_microns as f64;
L::Coord::from_f64(lef_distance * dbu)
.expect("Conversion from LEF distance unit to database distance unit failed.")
}
}
impl<'a, L> LEFDesignRuleAdapter<'a, L>
where L: db::LayoutBase,
L::Coord: FromPrimitive + ToPrimitive {
pub fn new(lef: &'a LEF, layout: &L) -> Self {
Self::new_from_layer_mapping(lef, &Self::extract_layer_mapping_from_layout(layout))
}
pub fn new_from_layer_mapping(lef: &'a LEF, layer_ids_by_name: &HashMap<String, L::LayerId>) -> Self {
let mut new = Self {
lef,
layer_mapping: Default::default(),
layer_stack: Default::default(),
ty: Default::default(),
};
new.create_layer_mapping(layer_ids_by_name);
new
}
fn extract_layer_mapping_from_layout(layout: &L) -> HashMap<String, L::LayerId> {
layout.each_layer()
.filter_map(|layer_id| {
let layer_name = layout.layer_info(&layer_id).name.as_ref().map(|n| n.to_string());
layer_name.map(|name| (name, layer_id))
})
.collect()
}
fn create_layer_mapping(&mut self, layer_ids_by_name: &HashMap<String, L::LayerId>) {
let lef_layers_by_name= self.lef.technology.layers.iter()
.map(|layer| (layer.name(), layer));
let lef_layers_by_layer_id: Vec<_> = lef_layers_by_name
.filter_map(|(layer_name, layer)| {
let layer_id = layer_ids_by_name.get(layer_name);
layer_id.map(|id| (id.clone(), layer))
})
.collect();
self.layer_mapping = lef_layers_by_layer_id.iter()
.cloned()
.collect();
self.layer_stack = lef_layers_by_layer_id;
}
}
impl<'a, L: db::LayoutBase> layerstack::RoutingLayerStack for LEFDesignRuleAdapter<'a, L> {
type LayerId = L::LayerId;
fn layer_stack(&self) -> Vec<RoutingLayerType<Self::LayerId>> {
self.layer_stack.iter()
.filter_map(|(id, layer)| match layer {
Layer::MasterSlice(_) => None,
Layer::Cut(_) => Some(RoutingLayerType::Cut(id.clone())),
Layer::Routing(_) => Some(RoutingLayerType::Routing(id.clone())),
})
.collect()
}
}
impl<'a, L: db::LayoutBase> rules::RuleBase for LEFDesignRuleAdapter<'a, L> {
type LayerId = L::LayerId;
type Distance = L::Coord;
type Area = L::Coord;
}
impl<'a, L: db::LayoutBase> rules::MinimumSpacing for LEFDesignRuleAdapter<'a, L>
where L::Coord: ToPrimitive + FromPrimitive {
fn min_spacing_absolute(&self, layer_id: &Self::LayerId) -> Option<Self::Distance> {
self.layer_mapping.get(layer_id)
.and_then(|layer| match layer {
Layer::MasterSlice(_) => unimplemented!("Min spacing for MASTERSLICE layers."),
Layer::Cut(_) => unimplemented!("Min spacing for CUT layers."),
Layer::Routing(routing_layer) => {
get_absolute_min_spacing_of_routing_layer(routing_layer)
}
})
.map(|d| self.lef_distance_to_db(d))
}
fn min_spacing(&self, layer_id: &Self::LayerId, run_length: Self::Distance, width: Self::Distance) -> Option<Self::Distance> {
let run_length = self.db_distance_to_lef(run_length);
let width = self.db_distance_to_lef(width);
self.layer_mapping.get(layer_id)
.and_then(|layer| match layer {
Layer::MasterSlice(_) => unimplemented!("Min spacing for MASTERSLICE layers."),
Layer::Cut(_) => unimplemented!("Min spacing for CUT layers."),
Layer::Routing(routing_layer) => {
get_min_spacing_of_routing_layer(routing_layer, run_length, width)
}
})
.map(|d| self.lef_distance_to_db(d))
}
}
fn get_absolute_min_spacing_of_routing_layer(routing_layer: &lef_ast::RoutingLayer) -> Option<f64> {
if let Some(spacing_table) = &routing_layer.spacing_table {
spacing_table.spacings.first()
.and_then(|spacings| spacings.first())
.copied()
.or(Some(0.))
} else {
None
}
}
fn get_min_spacing_of_routing_layer(routing_layer: &lef_ast::RoutingLayer,
parallel_runlength: f64,
width: f64) -> Option<f64> {
if let Some(spacing_table) = &routing_layer.spacing_table {
let row = spacing_table.spacings.iter()
.zip(&spacing_table.widths)
.filter(|(row, &w)| w <= width )
.last()
.map(|(row, _)| row);
row.and_then(|row| {
row.iter()
.zip(&spacing_table.parallel_run_lengths)
.filter(|(spacing, &run_length)| run_length <= parallel_runlength)
.last()
.map(|(&spacing, _)| spacing)
})
} else {
None
}
}
impl<'a, L: db::LayoutBase> rules::MinimumWidth for LEFDesignRuleAdapter<'a, L>
where L: db::LayoutBase,
L::Coord: FromPrimitive {
fn min_width(&self, layer_id: &Self::LayerId, shape_length: Option<Self::Distance>) -> Option<Self::Distance> {
self.layer_mapping.get(layer_id)
.and_then(|layer| match layer {
Layer::MasterSlice(_) => unimplemented!("Minimum width for LEF 'masterslice' layers is not implemented."),
Layer::Cut(_) => unimplemented!("Minimum width for LEF 'cut' layers is not implemented."),
Layer::Routing(routing_layer) => routing_layer.min_width
})
.map(|d| self.lef_distance_to_db(d))
}
}
#[cfg(test)]
mod tests {
use libreda_db::prelude as db;
use db::traits::*;
use db::technology::rules::*;
use crate::lef_parser::read_lef_chars;
use crate::lef_tech_adapter::LEFDesignRuleAdapter;
const LEF_DATA: &'static str = r#"
VERSION 5.5 ;
NAMESCASESENSITIVE ON ;
BUSBITCHARS "[]" ;
DIVIDERCHAR "/" ;
PROPERTYDEFINITIONS
LAYER contactResistance REAL ;
END PROPERTYDEFINITIONS
UNITS
DATABASE MICRONS 1000 ;
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 ;
MINWIDTH 0.05 ;
SPACING 0.065 ;
RESISTANCE RPERSQ 0.38 ;
SPACINGTABLE
PARALLELRUNLENGTH 0.0 1.0
WIDTH 0.0 0.1 0.3
WIDTH 0.5 0.4 0.5
;
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
END LIBRARY
"#;
#[test]
fn test_lef_rule_adapter() {
let lef = read_lef_chars(LEF_DATA.chars())
.expect("Failed to parse LEF");
let mut layout = db::Chip::new();
let layer1 = layout.create_layer(1, 0);
layout.set_layer_name(&layer1, Some("metal1".into()));
dbg!(&lef.technology);
let rules = LEFDesignRuleAdapter::new(&lef, &layout);
assert_eq!(rules.min_width(&layer1, None), Some(50));
assert_eq!(rules.min_spacing_absolute(&layer1), Some(100));
assert_eq!(rules.min_spacing(&layer1, 0, 0), Some(100));
assert_eq!(rules.min_spacing(&layer1, 999, 0), Some(100));
assert_eq!(rules.min_spacing(&layer1, 1000, 0), Some(300));
assert_eq!(rules.min_spacing(&layer1, 0, 499), Some(100));
assert_eq!(rules.min_spacing(&layer1, 0, 500), Some(400));
}
}