use libreda_db::prelude as db;
use libreda_db::prelude::{Scale, Direction, TryCastCoord, CoordinateType, Angle, TerminalId};
use libreda_db::traits::*;
use libreda_db::prelude::reference_access::*;
use crate::lef_ast::{LEF, Shape, SignalUse};
use crate::def_ast::{DEF, NetTerminal, Component, Net, Pin};
use crate::common::{PinDirection, Orient};
use num_traits::{NumCast, PrimInt};
use std::fmt::Formatter;
use std::collections::HashMap;
use std::cmp::Ordering;
use crate::def_writer::write_def;
#[derive(Debug, Clone)]
pub enum LefDefExportError {
Other(String),
}
impl std::fmt::Display for LefDefExportError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
LefDefExportError::Other(msg) => write!(f, "{}", msg)
};
Ok(())
}
}
fn convert_geometry<C: CoordinateType + NumCast>(dbu_per_micron: u64, shape: &Shape) -> db::Geometry<C> {
let dbu_per_micron = dbu_per_micron as f64;
let geo: db::Geometry<f64> = match shape {
Shape::Path(width, points) => {
db::Path::new(points, *width)
.scale(dbu_per_micron).into()
}
Shape::Rect(p1, p2) => {
db::Rect::new(p1, p2)
.scale(dbu_per_micron).into()
}
Shape::Polygon(points) => {
db::SimplePolygon::new(points.clone())
.scale(dbu_per_micron).into()
}
};
let geo: db::Geometry<C> = geo.try_cast()
.expect("Cast from float failed."); geo
}
#[derive(Clone)]
pub struct DEFExportOptions<C: L2NBase> {
pub export_nets: bool,
pub export_components: bool,
pub layer_mapping: HashMap<C::LayerId, String>,
pub outline_layer: Option<C::LayerId>,
}
impl<C: L2NBase> Default for DEFExportOptions<C> {
fn default() -> Self {
Self {
export_nets: true,
export_components: true,
layer_mapping: Default::default(),
outline_layer: Default::default(),
}
}
}
pub fn export_db_to_def<C, Crd>(options: &DEFExportOptions<C>,
chip: &C,
top_cell: &C::CellId,
def: &mut DEF, ) -> Result<(), LefDefExportError>
where Crd: NumCast + Ord + CoordinateType + PrimInt,
C: L2NBase<Coord=Crd> {
log::info!("Export cell to DEF structure: {}", chip.cell_name(top_cell));
def.design_name = Some(chip.cell_name(top_cell).into());
let top = chip.cell_ref(top_cell);
let instance_names = export_instances_to_def(options, top.clone(), def)?;
let net_names = export_nets_and_pins_to_def(options, top.clone(), &instance_names, def)?;
Ok(())
}
fn compare_name<S: Ord>(a: &Option<S>, b: &Option<S>) -> Ordering {
match (a, b) {
(None, None) => Ordering::Equal,
(_, None) => Ordering::Less,
(None, _) => Ordering::Greater,
(Some(a), Some(b)) => a.cmp(&b),
}
}
fn export_instances_to_def<C, Crd>(options: &DEFExportOptions<C>,
top: CellRef<C>,
def: &mut DEF) -> Result<HashMap<C::CellInstId, String>, LefDefExportError>
where Crd: NumCast + Ord + CoordinateType + PrimInt,
C: L2NBase<Coord=Crd> {
log::info!("Export instances to DEF: {}", top.num_child_instances());
let mut instances: Vec<_> = top.each_cell_instance().collect();
instances.sort_by(|a, b| compare_name(&a.name(), &b.name()));
let mut instance_names = HashMap::new();
let mut instance_name_counter = 1;
let mut get_instance_name = |inst: &CellInstRef<C>| -> String {
let name = instance_names.entry(inst.id())
.or_insert_with(|| {
if let Some(name) = inst.name() {
name.into()
} else {
loop {
let new_name = format!("__{}__", instance_name_counter);
instance_name_counter += 1;
if top.cell_instance_by_name(new_name.as_str()).is_none() {
break new_name;
}
}
}
});
name.clone()
};
for inst in instances {
let mut component = Component::default();
component.name = get_instance_name(&inst);
component.model_name = inst.template().name().into();
let is_fixed = false; let tf = inst.get_transform();
let displacement: db::Point<_> = tf.displacement.cast().into();
let orient = match tf.rotation {
Angle::R0 => Orient::N,
Angle::R90 => Orient::W,
Angle::R180 => Orient::S,
Angle::R270 => Orient::E
};
let orient = if tf.mirror {
orient.flipped()
} else {
orient
};
component.position = Some((displacement, orient, is_fixed));
def.components.push(component)
}
Ok(instance_names)
}
fn export_nets_and_pins_to_def<C, Crd>(options: &DEFExportOptions<C>,
top: CellRef<C>,
instance_names: &HashMap<C::CellInstId, String>,
def: &mut DEF) -> Result<HashMap<C::NetId, String>, LefDefExportError>
where C: L2NBase<Coord=Crd>
{
let mut net_names = HashMap::new();
let mut net_name_generator = 1;
let mut create_new_net_name = |prefix: &str| -> String {
loop {
let new_name = format!("__{}{}__", prefix, net_name_generator);
net_name_generator += 1;
if top.net_by_name(new_name.as_str()).is_none() {
break new_name;
}
}
};
let mut get_net_name = |net: &NetRef<C>| -> String {
let name = net_names.entry(net.id())
.or_insert_with(|| {
if let Some(name) = net.name() {
name.into()
} else {
create_new_net_name("")
}
});
name.clone()
};
let mut nets: Vec<_> = top.each_net().collect();
nets.sort_by(|a, b| compare_name(&a.name(), &b.name()));
for net_ref in nets {
let mut net = Net::default();
net.name = Some(get_net_name(&net_ref).to_string());
for pin in net_ref.each_pin() {
net.terminals.push(NetTerminal::IoPin(pin.name().into()));
}
for pin in net_ref.each_pin_instance() {
net.terminals.push(
NetTerminal::ComponentPin {
component_name: instance_names.get(&pin.cell_instance().id())
.expect("Cell instance not found.")
.to_string(),
pin_name: pin.pin().name().into(),
});
}
def.nets.push(net);
}
let mut pins: Vec<_> = top.each_pin().collect();
pins.sort_by_key(|pin| pin.name());
for pin_ref in pins {
let mut pin = Pin::default();
pin.pin_name = pin_ref.name().into();
pin.net_name = pin_ref.net()
.map(|net|
net_names.get(&net.id())
.expect("Net name not found.")
.clone()
)
.unwrap_or_else(|| {
let new_net_name = create_new_net_name("pin_unconnected");
let mut net = Net::default();
net.name = Some(new_net_name.clone());
def.nets.push(net);
new_net_name
});
def.pins.push(pin);
}
Ok(net_names)
}
#[test]
fn test_export_to_def() {
use libreda_db::prelude as db;
use db::traits::*;
let mut chip = db::Chip::new();
let top_cell = chip.create_cell("TOP".to_string());
let pin_a = chip.create_pin(&top_cell, "Input_A".to_string(), db::Direction::Input);
let pin_b = chip.create_pin(&top_cell, "Output_Y".to_string(), db::Direction::Output);
let net_a = chip.create_net(&top_cell, Some("net_a".to_string()));
let net_b = chip.create_net(&top_cell, Some("net_b".to_string()));
chip.connect_pin(&pin_a, Some(net_a.clone()));
chip.connect_pin(&pin_b, Some(net_b.clone()));
let sub_cell = chip.create_cell("SUB".to_string());
chip.create_cell_instance(&top_cell, &sub_cell, Some("inst1".to_string()));
chip.create_cell_instance(&top_cell, &sub_cell, Some("inst2".to_string()));
chip.create_cell_instance(&top_cell, &sub_cell, None);
chip.create_cell_instance(&top_cell, &sub_cell, None);
let mut def = DEF::default();
let result = export_db_to_def(&DEFExportOptions::default(), &chip, &top_cell, &mut def);
if result.is_err() {
dbg!(&result);
}
result.expect("DEF export failed.");
let mut buffer: Vec<u8> = Vec::new();
write_def(&mut buffer, &def).expect("Writing DEF failed.");
let def_string = String::from_utf8(buffer)
.expect("DEF writer output is not valid UTF-8.");
println!("{}", &def_string);
}