substrate/layout/
conv.rs

1//! Conversions between layout formats.
2
3use std::collections::HashMap;
4
5use layir::Cell;
6use layir::Direction;
7use layir::LibraryBuilder;
8use layir::Port;
9
10use super::element::Element;
11use super::element::RawCell;
12
13use super::element::CellId as SubCellId;
14use layir::CellId as LayCellId;
15
16/// Metadata associated with a conversion from a Substrate schematic to a LayIR library.
17///
18/// Provides helpers for retrieving LayIR objects from their Substrate IDs.
19#[derive(Debug, Default, Clone)]
20pub struct LayirLibConversion {
21    /// Map from Substrate cell IDs to cell conversion metadata.
22    pub(crate) cells: HashMap<SubCellId, layir::CellId>,
23}
24
25#[derive(Debug, Clone)]
26pub(crate) struct LayirLibExportContext<L> {
27    lib: layir::LibraryBuilder<L>,
28    conv: LayirLibConversion,
29}
30
31/// A LayIR library with associated conversion metadata.
32pub struct RawLib<L> {
33    /// The LayIR library.
34    pub layir: layir::Library<L>,
35    /// Associated conversion metadata.
36    ///
37    /// Can be used to retrieve LayIR objects from their corresponding Substrate IDs.
38    pub conv: LayirLibConversion,
39}
40
41impl<L> Default for LayirLibExportContext<L> {
42    fn default() -> Self {
43        Self {
44            lib: LibraryBuilder::new(),
45            conv: LayirLibConversion::default(),
46        }
47    }
48}
49
50impl<L> LayirLibExportContext<L> {
51    #[inline]
52    fn new() -> Self {
53        Self::default()
54    }
55}
56
57/// Error when exporting a layout cell to LayIR.
58#[derive(thiserror::Error, Clone, Debug)]
59#[error("error exporting layout cell to LayIR")]
60pub struct LayirExportError;
61
62impl<L: Clone> RawCell<L> {
63    /// Export this cell and all subcells as a LayIR library.
64    ///
65    /// Returns the LayIR library and metadata for converting between LayIR and Substrate formats.
66    ///
67    /// Consider using [`export_multi_top_layir_lib`] if you need to export multiple cells
68    /// to the same LayIR library.
69    pub(crate) fn to_layir_lib(&self) -> Result<RawLib<L>, LayirExportError> {
70        let mut lib_ctx = LayirLibExportContext::new();
71        self.to_layir_cell(&mut lib_ctx)?;
72
73        Ok(RawLib {
74            layir: lib_ctx.lib.build().map_err(|_| LayirExportError)?,
75            conv: lib_ctx.conv,
76        })
77    }
78
79    /// Exports this [`RawCell`] to a LayIR cell if it has not already been exported. Should only be called
80    /// on top cells or un-flattened cells.
81    fn to_layir_cell(
82        &self,
83        lib_ctx: &mut LayirLibExportContext<L>,
84    ) -> Result<LayCellId, LayirExportError> {
85        if let Some(conv) = lib_ctx.conv.cells.get(&self.id) {
86            return Ok(*conv);
87        }
88
89        let mut cell = Cell::new(self.name.clone());
90        for elt in self.elements() {
91            match elt {
92                Element::Instance(inst) => {
93                    let child = inst.raw_cell().to_layir_cell(lib_ctx)?;
94                    let inst = layir::Instance::with_transformation(
95                        child,
96                        inst.raw_cell().name.clone(),
97                        inst.trans,
98                    );
99                    cell.add_instance(inst);
100                }
101                Element::Shape(shape) => {
102                    cell.add_element(shape.clone());
103                }
104                Element::Text(text) => {
105                    cell.add_element(text.clone());
106                }
107            }
108        }
109        for (name, port) in self.ports() {
110            // TODO: use correct port directions
111            let mut lport = Port::new(Direction::InOut);
112            lport.add_element(port.primary.clone());
113            for shape in port.unnamed_shapes.iter() {
114                lport.add_element(shape.clone());
115            }
116            for (_, shape) in port.named_shapes.iter() {
117                lport.add_element(shape.clone());
118            }
119            cell.add_port(arcstr::format!("{}", name), lport);
120        }
121        let id = lib_ctx.lib.add_cell(cell);
122        lib_ctx.conv.cells.insert(self.id, id);
123        Ok(id)
124    }
125}
126
127/// Export a collection of cells and all their subcells as a LayIR library.
128///
129/// Returns the LayIR library and metadata for converting between LayIR and Substrate formats.
130/// The resulting LayIR library will **not** have a top cell set.
131/// If you want a LayIR library with a known top cell, consider using [`RawCell::to_layir_lib`] instead.
132pub(crate) fn export_multi_top_layir_lib<L: Clone>(
133    cells: &[&RawCell<L>],
134) -> Result<RawLib<L>, LayirExportError> {
135    let mut lib_ctx = LayirLibExportContext::new();
136
137    for &cell in cells {
138        cell.to_layir_cell(&mut lib_ctx)?;
139    }
140
141    Ok(RawLib {
142        layir: lib_ctx.lib.build().map_err(|_| LayirExportError)?,
143        conv: lib_ctx.conv,
144    })
145}