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