libreda_lefdef/
export.rs

1// Copyright (c) 2021-2021 Thomas Kramer.
2// SPDX-FileCopyrightText: 2022 Thomas Kramer <code@tkramer.ch>
3//
4// SPDX-License-Identifier: AGPL-3.0-or-later
5
6//! Export libreda-db structures to LEF and DEF.
7
8use libreda_db::prelude as db;
9use libreda_db::prelude::reference_access::*;
10use libreda_db::prelude::{
11    Angle, CoordinateType, Direction, MapPointwise, Scale, TerminalId, ToPolygon, TryBoundingBox,
12    TryCastCoord,
13};
14use libreda_db::traits::*;
15
16use crate::common::{Orient, PinDirection};
17use crate::def_ast::{Component, Net, NetTerminal, Pin, DEF};
18use crate::def_writer::write_def;
19use crate::import::transform_to_def_orient;
20use crate::lef_ast::{Shape, SignalUse, LEF};
21use num_traits::{NumCast, PrimInt};
22use std::cmp::Ordering;
23use std::collections::HashMap;
24use std::fmt::Formatter;
25
26/// Error type returned from LEF/DEF output functions.
27#[derive(Debug, Clone)]
28pub enum LefDefExportError {
29    /// A named entry such as a MACRO already exists in the LEF or DEF structure.
30    NameAlreadyExists(String),
31    /// A layer in the database has no name defined in the name-mapping, hence cannot be written to LEF or DEF.
32    UnknownLayerName,
33    /// Unspecified error.
34    Other(String),
35}
36
37impl std::fmt::Display for LefDefExportError {
38    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
39        match self {
40            LefDefExportError::NameAlreadyExists(name) => {
41                write!(f, "Name already exists in LEF/DEF structure: {}", name)
42            }
43            LefDefExportError::UnknownLayerName => {
44                write!(f, "No LEF/DEF layer name is known for a data-base layer.")
45            }
46            LefDefExportError::Other(msg) => write!(f, "{}", msg),
47        };
48
49        Ok(())
50    }
51}
52
53// /// Convert a LEF shape into a database shape with the correct units.
54// fn convert_geometry<C: CoordinateType + NumCast>(dbu_per_micron: u64, shape: &Shape) -> db::Geometry<C> {
55//     let dbu_per_micron = dbu_per_micron as f64;
56//     // Convert the LEF geometry into a database geometry.
57//     let geo: db::Geometry<f64> = match shape {
58//         Shape::Path(width, points) => {
59//             db::Path::new(points, *width)
60//                 .scale(dbu_per_micron).into()
61//         }
62//         Shape::Rect(p1, p2) => {
63//             db::Rect::new(p1, p2)
64//                 .scale(dbu_per_micron).into()
65//         }
66//         Shape::Polygon(points) => {
67//             db::SimplePolygon::new(points.clone())
68//                 .scale(dbu_per_micron).into()
69//         }
70//     };
71//     let geo: db::Geometry<C> = geo.try_cast()
72//         .expect("Cast from float failed."); // This should actually not fail.
73//     geo
74// }
75
76/// Control the export into DEF structures.
77#[derive(Clone)]
78pub struct DEFExportOptions<C: L2NBase> {
79    /// Enable the export of nets. Default is `true`.
80    pub export_nets: bool,
81    /// Also export nets which don't connect to anything else.
82    pub keep_unconnected_nets: bool,
83    /// Export components (cell instances). Default is `true`.
84    pub export_components: bool,
85    /// Provide alternative names for layers. For all other layers
86    /// the default name defined in the [`trait@L2NBase`] type will be used.
87    pub layer_mapping: HashMap<C::LayerId, String>,
88    /// Take the die-area from this layer.
89    /// The layer must contain a single shape.
90    pub outline_layer: Option<C::LayerId>,
91}
92
93impl<C: L2NBase> Default for DEFExportOptions<C> {
94    fn default() -> Self {
95        Self {
96            export_nets: true,
97            keep_unconnected_nets: false,
98            export_components: true,
99            layer_mapping: Default::default(),
100            outline_layer: Default::default(),
101        }
102    }
103}
104
105fn get_cell_outline_bbox<C, Crd>(
106    cell: &CellRef<C>,
107    outline_layer: &C::LayerId,
108) -> Option<db::Rect<Crd>>
109where
110    Crd: NumCast + Ord + CoordinateType + PrimInt + std::fmt::Display,
111    C: L2NBase<Coord = Crd>,
112{
113    let shapes: Vec<_> = cell.each_shape_per_layer(outline_layer).collect();
114
115    if shapes.len() == 1 {
116        let shape = shapes.first().unwrap();
117        let geometry = shape.geometry_cloned();
118        let bbox = geometry.try_bounding_box();
119        if bbox.is_none() {
120            log::error!(
121                "Outline shape of cell '{}' has no defined bounding box.",
122                cell.name()
123            );
124        }
125        bbox
126    } else {
127        log::error!(
128            "Cell '{}' should have exactly one outline shape but has {}.",
129            cell.name(),
130            shapes.len()
131        );
132        None
133    }
134}
135
136/// Populate a [`DEF`] structure from a type implementing the [`trait@L2NBase`] trait.
137pub fn export_db_to_def<C, Crd>(
138    options: &DEFExportOptions<C>,
139    chip: &C,
140    top_cell: &C::CellId,
141    def: &mut DEF,
142) -> Result<(), LefDefExportError>
143where
144    Crd: NumCast + Ord + CoordinateType + PrimInt + std::fmt::Display,
145    C: L2NBase<Coord = Crd>,
146{
147    log::info!("Export cell to DEF structure: {}", chip.cell_name(top_cell));
148
149    // Set the design name.
150    def.design_name = Some(chip.cell_name(top_cell).into());
151
152    // Set distance units.
153    def.units = chip.dbu().to_u32().ok_or_else(|| {
154        LefDefExportError::Other(format!(
155            "Cannot convert DBU ({}) into a unsigned 32-bit integer.",
156            chip.dbu()
157        ))
158    })?;
159
160    let top = chip.cell_ref(top_cell);
161
162    if options.outline_layer.is_none() {
163        return Err(LefDefExportError::Other(
164            "Outline layer must be specified in export options.".into(),
165        ));
166    }
167    let outline_layer = options
168        .outline_layer
169        .as_ref()
170        .expect("outline_layer is not specified.");
171
172    // Set die area.
173    {
174        let top_cell_outline_shapes: Vec<_> = chip.each_shape_id(top_cell, outline_layer).collect();
175
176        if top_cell_outline_shapes.len() == 1 {
177            // There is exactly one outline shape.
178            let shape_id = top_cell_outline_shapes.first().unwrap();
179            let geometry = chip.with_shape(shape_id, |_layer, s| s.clone());
180            let polygon = geometry.to_polygon().exterior;
181            if let Some(rpolygon) = db::SimpleRPolygon::try_new(polygon.points()) {
182                let rpolygon: db::SimpleRPolygon<i32> = rpolygon.try_cast().ok_or_else(|| {
183                    LefDefExportError::Other(
184                        "Failed to convert DIEAREA into i32 coordinates.".into(),
185                    )
186                })?; // Convert coordinate data type.
187                def.die_area = Some(rpolygon);
188            } else {
189                log::error!("Failed to convert die area into a rectilinear polygon.");
190            }
191        } else {
192            log::warn!(
193                "Top cell should have exactly one outline shape but has {}. DIEAREA is not set.",
194                top_cell_outline_shapes.len()
195            );
196        }
197    }
198
199    // Find all macro outlines. They are needed to express the position of the components because
200    // the positions are relative to the lower-left corner of the rotated and flipped macro.
201    let macro_outlines = {
202        let mut macro_outlines = HashMap::new();
203        let mut cells_without_outline: Vec<CellRef<C>> = Vec::new();
204        for subcell in top.each_cell_dependency() {
205            if let Some(outline) = get_cell_outline_bbox(&subcell, outline_layer) {
206                macro_outlines.insert(subcell.id(), outline);
207            } else {
208                cells_without_outline.push(subcell);
209            }
210        }
211        if !cells_without_outline.is_empty() {
212            log::error!(
213                "Number of cells without outline: {}",
214                cells_without_outline.len()
215            );
216            for cell in &cells_without_outline {
217                log::error!("Cell '{}' has no outline.", cell.name());
218            }
219            return Err(LefDefExportError::Other(format!(
220                "{} cells have no outline.",
221                cells_without_outline.len()
222            )));
223        }
224        macro_outlines
225    };
226
227    // Create components (child instances inside the top cell)
228    // Also get a mapping of the possibly created instance names.
229    let instance_names = export_instances_to_def(options, top.clone(), &macro_outlines, def)?;
230
231    // Export nets.
232    let net_names = export_nets_and_pins_to_def(options, top.clone(), &instance_names, def)?;
233
234    Ok(())
235}
236
237// Sort by Option<String> such that `Nones` come at the end of a sorted list.
238fn compare_name<S: Ord>(a: &Option<S>, b: &Option<S>) -> Ordering {
239    match (a, b) {
240        (None, None) => Ordering::Equal,
241        (_, None) => Ordering::Less,
242        (None, _) => Ordering::Greater,
243        (Some(a), Some(b)) => a.cmp(&b),
244    }
245}
246
247/// Populate a [`DEF`] structure with the component instances.
248/// Return a name mapping from instance IDs to their DEF names.
249/// The mapping contains possibly generated instance names.
250fn export_instances_to_def<C, Crd>(
251    options: &DEFExportOptions<C>,
252    top: CellRef<C>,
253    macro_outlines: &HashMap<C::CellId, db::Rect<Crd>>,
254    def: &mut DEF,
255) -> Result<HashMap<C::CellInstId, String>, LefDefExportError>
256where
257    Crd: NumCast + Ord + CoordinateType + PrimInt,
258    C: L2NBase<Coord = Crd>,
259{
260    log::info!("Export instances to DEF: {}", top.num_child_instances());
261
262    // Create components.
263    let mut instances: Vec<_> = top.each_cell_instance().collect();
264    // Sort the instances by name. Instances without name will come at the end.
265    instances.sort_by(|a, b| compare_name(&a.name(), &b.name()));
266
267    // Generate names for unnamed instances.
268    let mut instance_names = HashMap::new();
269    let mut instance_name_counter = 1;
270    let mut get_instance_name = |inst: &CellInstRef<C>| -> String {
271        let name = instance_names.entry(inst.id()).or_insert_with(|| {
272            if let Some(name) = inst.name() {
273                name.into()
274            } else {
275                loop {
276                    let new_name = format!("__{}__", instance_name_counter);
277                    instance_name_counter += 1;
278                    if top.cell_instance_by_name(new_name.as_str()).is_none() {
279                        // Name is still free.
280                        break new_name;
281                    }
282                }
283            }
284        });
285        name.clone()
286    };
287
288    // Export components.
289    for inst in instances {
290        // Set component name.
291        let mut component = Component::default();
292        component.name = get_instance_name(&inst);
293        // Set model/template name
294        component.model_name = inst.template().name().into();
295
296        // Set the component placement.
297        let is_fixed = false; // TODO
298        let tf = inst.get_transform();
299        // Compute displacement (coordinate of lower left corner of the rotated bounding box).
300        let displacement: db::Point<_> = {
301            let outline = macro_outlines
302                .get(&inst.template_id())
303                .expect("Macro outline not found.");
304            let outline_transformed = outline.transform(|p| tf.transform_point(p));
305            outline_transformed.lower_left().cast()
306        };
307        let orient = transform_to_def_orient(&tf);
308        component.position = Some((displacement, orient, is_fixed));
309
310        def.components.push(component)
311    }
312
313    // Return the name mapping.
314    Ok(instance_names)
315}
316
317/// Populate a [`DEF`] structure with nets and top-level pins.
318/// Return a name mapping from net IDs to their DEF names.
319/// The mapping contains possibly generated instance names.
320///
321/// # Parameters
322/// * `instance_names`: Mapping from cell instance IDs to their DEF names. This is generated by `export_instances_to_def()`.
323fn export_nets_and_pins_to_def<C, Crd>(
324    options: &DEFExportOptions<C>,
325    top: CellRef<C>,
326    instance_names: &HashMap<C::CellInstId, String>,
327    def: &mut DEF,
328) -> Result<HashMap<C::NetId, String>, LefDefExportError>
329where
330    C: L2NBase<Coord = Crd>,
331{
332    log::info!("Export nets to DEF: {}", top.num_internal_nets());
333
334    // Export nets.
335    // Generate names for unnamed instances.
336    let mut net_names = HashMap::new();
337    let mut net_name_generator = 1;
338    let mut create_new_net_name = |prefix: &str| -> String {
339        loop {
340            let new_name = format!("__{}{}__", prefix, net_name_generator);
341            net_name_generator += 1;
342            if top.net_by_name(new_name.as_str()).is_none() {
343                // Name is still free.
344                break new_name;
345            }
346        }
347    };
348    let mut get_net_name = |net: &NetRef<C>| -> String {
349        let name = net_names.entry(net.id()).or_insert_with(|| {
350            if let Some(name) = net.name() {
351                name.into()
352            } else {
353                create_new_net_name("")
354            }
355        });
356        name.clone()
357    };
358
359    let mut nets: Vec<_> = top.each_net().collect();
360    nets.sort_by(|a, b| compare_name(&a.name(), &b.name()));
361
362    // Convert all nets.
363    for net_ref in nets {
364        // Create the DEF net.
365        let mut net = Net::default();
366        // Set the name.
367        net.name = Some(get_net_name(&net_ref).to_string());
368
369        // Set connected terminals.
370        for pin in net_ref.each_pin() {
371            net.terminals.push(NetTerminal::IoPin(pin.name().into()));
372        }
373        for pin in net_ref.each_pin_instance() {
374            net.terminals.push(NetTerminal::ComponentPin {
375                component_name: instance_names
376                    .get(&pin.cell_instance().id())
377                    .expect("Cell instance not found.")
378                    .to_string(),
379                pin_name: pin.pin().name().into(),
380            });
381        }
382
383        if !net.terminals.is_empty() || options.keep_unconnected_nets {
384            def.nets.push(net);
385        }
386    }
387
388    // Create external pins.
389    let mut pins: Vec<_> = top.each_pin().collect();
390    pins.sort_by_key(|pin| pin.name());
391
392    for pin_ref in pins {
393        let mut pin = Pin::default();
394        // Set the pin name.
395        pin.pin_name = pin_ref.name().into();
396        // Set the net name attached to the pin or create a dummy net if none is attached (required by DEF).
397        pin.net_name = pin_ref
398            .net()
399            .map(|net| {
400                net_names
401                    .get(&net.id())
402                    .expect("Net name not found.")
403                    .clone()
404            })
405            .unwrap_or_else(|| {
406                // There is no net connected to the external pin but DEF requires
407                // that a net is specified.
408                // Create an unconnected dummy net.
409                let new_net_name = create_new_net_name("pin_unconnected");
410
411                // Make sure the new net is also listed in the NETS section.
412                let mut net = Net::default();
413                net.name = Some(new_net_name.clone());
414                def.nets.push(net);
415
416                new_net_name
417            });
418
419        // Append the newly created pin to the list of pins.
420        def.pins.push(pin);
421    }
422
423    Ok(net_names)
424}
425
426#[test]
427fn test_export_to_def() {
428    use db::traits::*;
429    use libreda_db::prelude as db;
430
431    let mut chip = db::Chip::new();
432    let outline_layer = chip.create_layer(1, 0);
433    let top_cell = chip.create_cell("TOP".to_string());
434
435    // Create pins of the top cell.
436    let pin_a = chip.create_pin(&top_cell, "Input_A".to_string(), db::Direction::Input);
437    let pin_b = chip.create_pin(&top_cell, "Output_Y".to_string(), db::Direction::Output);
438
439    // Create nets in the top cell.
440    let net_a = chip.create_net(&top_cell, Some("net_a".to_string()));
441    let net_b = chip.create_net(&top_cell, Some("net_b".to_string()));
442
443    chip.connect_pin(&pin_a, Some(net_a.clone()));
444    chip.connect_pin(&pin_b, Some(net_b.clone()));
445
446    // Create a sub cell.
447    let sub_cell = chip.create_cell("SUB".to_string());
448    // Create cell outline.
449    chip.insert_shape(
450        &sub_cell,
451        &outline_layer,
452        db::Rect::new((0, 0), (10, 10)).into(),
453    );
454
455    // Create sub cell instances in TOP.
456    let inst1 = chip.create_cell_instance(&top_cell, &sub_cell, Some("inst1".to_string()));
457
458    chip.set_transform(
459        &inst1,
460        db::SimpleTransform::new(true, Angle::R0, 1, (100, 200).into()),
461    );
462
463    chip.create_cell_instance(&top_cell, &sub_cell, Some("inst2".to_string()));
464    // Create unnamed instances.
465    chip.create_cell_instance(&top_cell, &sub_cell, None);
466    chip.create_cell_instance(&top_cell, &sub_cell, None);
467
468    let mut def = DEF::default();
469    let mut export_options = DEFExportOptions::default();
470    export_options.outline_layer = Some(outline_layer);
471    let result = export_db_to_def(&export_options, &chip, &top_cell, &mut def);
472    if result.is_err() {
473        dbg!(&result);
474    }
475    result.expect("DEF export failed.");
476
477    let mut buffer: Vec<u8> = Vec::new();
478    write_def(&mut buffer, &def).expect("Writing DEF failed.");
479
480    let def_string = String::from_utf8(buffer).expect("DEF writer output is not valid UTF-8.");
481    println!("{}", &def_string);
482
483    // Check export of position of instance 1
484    assert!(def_string.contains("+ PLACED ( 100 190 ) FS"));
485}