substrate/
context.rs

1//! The global context.
2
3use std::any::{Any, TypeId};
4use std::collections::HashMap;
5use std::marker::PhantomData;
6use std::path::{Path, PathBuf};
7use std::sync::{Arc, RwLock};
8
9use config::Config;
10use gds::GdsUnits;
11use gdsconv::GdsLayer;
12use gdsconv::export::GdsExportOpts;
13use indexmap::IndexMap;
14use substrate::schematic::{CellBuilder, ConvCacheKey, RawCellContentsBuilder};
15use tracing::{Level, span};
16
17use crate::block::Block;
18use crate::cache::Cache;
19use crate::diagnostics::SourceInfo;
20use crate::error::Result;
21use crate::execute::{Executor, LocalExecutor};
22use crate::layout::conv::export_multi_top_layir_lib;
23use crate::layout::element::{Element, NamedPorts, RawCell};
24use crate::layout::error::LayoutError;
25use crate::layout::{Cell as LayoutCell, CellHandle as LayoutCellHandle};
26use crate::layout::{CellBuilder as LayoutCellBuilder, CellLayer};
27use crate::layout::{Layout, LayoutContext};
28use crate::schematic::conv::{ConvError, RawLib, export_multi_top_scir_lib};
29use crate::schematic::schema::{FromSchema, Schema};
30use crate::schematic::{
31    Cell as SchematicCell, CellCacheKey, CellHandle as SchematicCellHandle, CellId, CellMetadata,
32    RawCellInnerBuilder, SchemaCellCacheValue, SchemaCellHandle, Schematic, SchematicContext,
33};
34use crate::simulation::{SimController, SimulationContext, Simulator, Testbench};
35use crate::types::layout::PortGeometryBuilder;
36use crate::types::schematic::{IoNodeBundle, NodeContext, NodePriority, Port, SchematicBundleKind};
37use crate::types::{FlatLen, Flatten, Flipped, HasBundleKind, HasNameTree, NameBuf};
38
39// begin-code-snippet context
40/// The global context.
41///
42/// Stores configuration such as the PDK and tool plugins to use during generation.
43///
44/// Cheaply clonable.
45#[derive(Clone)]
46pub struct Context {
47    pub(crate) inner: Arc<RwLock<ContextInner>>,
48    installations: Arc<HashMap<TypeId, Arc<dyn Any + Send + Sync>>>,
49    /// The executor to which commands should be submitted.
50    pub executor: Arc<dyn Executor>,
51    /// A cache for storing the results of expensive computations.
52    pub cache: Cache,
53}
54// end-code-snippet context
55
56impl Default for Context {
57    fn default() -> Self {
58        let cfg = Config::default().expect("requires valid Substrate configuration");
59
60        Self {
61            inner: Default::default(),
62            installations: Default::default(),
63            executor: Arc::new(LocalExecutor),
64            cache: Cache::new(
65                cfg.cache
66                    .into_cache()
67                    .expect("requires valid Substrate cache configuration"),
68            ),
69        }
70    }
71}
72
73impl Context {
74    /// Creates a new [`Context`].
75    pub fn new() -> Self {
76        Self::default()
77    }
78}
79
80/// An item that can be installed in a context.
81pub trait Installation: Any + Send + Sync {
82    /// A post-installation hook for additional context modifications
83    /// required by the installation.
84    ///
85    /// PDKs, for example, should use this hook to install their layer
86    /// set and standard cell libraries.
87    #[allow(unused_variables)]
88    fn post_install(&self, ctx: &mut ContextBuilder) {}
89}
90
91/// A private item that can be installed in a context after it is built.
92pub trait PrivateInstallation: Any + Send + Sync {}
93
94/// Builder for creating a Substrate [`Context`].
95pub struct ContextBuilder {
96    installations: HashMap<TypeId, Arc<dyn Any + Send + Sync>>,
97    executor: Arc<dyn Executor>,
98    cache: Option<Cache>,
99}
100
101impl Default for ContextBuilder {
102    fn default() -> Self {
103        Self {
104            installations: Default::default(),
105            executor: Arc::new(LocalExecutor),
106            cache: None,
107        }
108    }
109}
110
111impl ContextBuilder {
112    /// Creates a new, uninitialized builder.
113    #[inline]
114    pub fn new() -> Self {
115        Self::default()
116    }
117
118    /// Sets the executor.
119    pub fn executor<E: Executor>(&mut self, executor: E) -> &mut Self {
120        self.executor = Arc::new(executor);
121        self
122    }
123
124    /// Installs the given [`Installation`].
125    ///
126    /// Only one installation of any given type can exist. Overwrites
127    /// conflicting installations of the same type.
128    #[inline]
129    pub fn install<I>(&mut self, installation: I) -> &mut Self
130    where
131        I: Installation,
132    {
133        let installation = Arc::new(installation);
134        self.installations
135            .insert(TypeId::of::<I>(), installation.clone());
136        installation.post_install(self);
137        self
138    }
139
140    /// Sets the desired cache configuration.
141    pub fn cache(&mut self, cache: Cache) -> &mut Self {
142        self.cache = Some(cache);
143        self
144    }
145
146    /// Builds the context based on the configuration in this builder.
147    pub fn build(&mut self) -> Context {
148        let cfg = Config::default().expect("requires valid Substrate configuration");
149
150        Context {
151            inner: Arc::new(RwLock::new(ContextInner::new())),
152            installations: Arc::new(self.installations.clone()),
153            executor: self.executor.clone(),
154            cache: self.cache.clone().unwrap_or_else(|| {
155                Cache::new(
156                    cfg.cache
157                        .into_cache()
158                        .expect("requires valid Substrate cache configuration"),
159                )
160            }),
161        }
162    }
163
164    /// Gets an installation from the context installation map.
165    pub fn get_installation<I: Installation>(&self) -> Option<Arc<I>> {
166        retrieve_installation(&self.installations)
167    }
168}
169
170#[derive(Debug, Default)]
171pub(crate) struct ContextInner {
172    pub(crate) schematic: SchematicContext,
173    layout: LayoutContext,
174    private_installations: HashMap<TypeId, Arc<dyn Any + Send + Sync>>,
175}
176
177impl ContextInner {
178    fn new() -> Self {
179        Self::default()
180    }
181}
182
183impl Context {
184    /// Creates a builder for constructing a context.
185    pub fn builder() -> ContextBuilder {
186        Default::default()
187    }
188
189    /// Allocates a new [`CellId`].
190    fn alloc_cell_id(&self) -> CellId {
191        let mut inner = self.inner.write().unwrap();
192        let SchematicContext { next_id, .. } = &mut inner.schematic;
193        next_id.increment();
194        *next_id
195    }
196
197    /// Steps to create schematic:
198    /// - Check if block has already been generated
199    /// - If not:
200    ///     - Create io_data, returning it immediately
201    ///     - Use io_data and the cell_builder associated with it to
202    ///       generate cell in background
203    /// - If yes:
204    ///     - Retrieve created cell ID, io_data, and handle to cell
205    ///     - being generated and return immediately
206    pub(crate) fn generate_schematic_inner<B: Schematic>(
207        &self,
208        block: Arc<B>,
209    ) -> SchemaCellHandle<B::Schema, B> {
210        let key = CellCacheKey {
211            block: block.clone(),
212            phantom: PhantomData::<B::Schema>,
213        };
214        let block_clone = block.clone();
215        let mut inner = self.inner.write().unwrap();
216        let context = self.clone();
217        let SchematicContext {
218            next_id,
219            cell_cache,
220            ..
221        } = &mut inner.schematic;
222        let (metadata, handle) = cell_cache.generate_partial_blocking(
223            key,
224            |key| {
225                next_id.increment();
226                let (cell_builder, io_data) =
227                    prepare_cell_builder(Some(*next_id), context, key.block.as_ref());
228                let io_data = Arc::new(io_data);
229                (
230                    CellMetadata::<B> {
231                        id: *next_id,
232                        io_data: io_data.clone(),
233                    },
234                    (*next_id, cell_builder, io_data),
235                )
236            },
237            move |_key, (id, mut cell_builder, io_data)| {
238                let res = B::schematic(block_clone.as_ref(), io_data.as_ref(), &mut cell_builder);
239                let fatal = cell_builder.fatal_error;
240                let raw = Arc::new(cell_builder.finish());
241                (!fatal)
242                    .then_some(())
243                    .ok_or(crate::error::Error::CellBuildFatal)
244                    .and(res.map(|data| SchemaCellCacheValue {
245                        raw: raw.clone(),
246                        cell: Arc::new(SchematicCell::new(
247                            id,
248                            io_data,
249                            block_clone,
250                            raw,
251                            Arc::new(data),
252                        )),
253                    }))
254            },
255        );
256
257        SchemaCellHandle {
258            handle: handle.clone(),
259            cell: SchematicCellHandle {
260                id: metadata.id,
261                block,
262                io_data: metadata.io_data.clone(),
263                cell: handle.map(|res| {
264                    Ok(res?
265                        .as_ref()
266                        .map_err(|e| e.clone())
267                        .map(|SchemaCellCacheValue { cell, .. }| cell.clone()))
268                }),
269            },
270        }
271    }
272
273    fn generate_cross_schematic_inner<B: Schematic, S2: FromSchema<B::Schema> + ?Sized>(
274        &self,
275        block: Arc<B>,
276    ) -> SchemaCellHandle<S2, B> {
277        let handle = self.generate_schematic_inner(block);
278        let mut inner = self.inner.write().unwrap();
279        SchemaCellHandle {
280            handle: inner.schematic.cell_cache.generate(
281                ConvCacheKey::<B, S2, B::Schema> {
282                    block: handle.cell.block.clone(),
283                    phantom: PhantomData,
284                },
285                move |_| {
286                    let SchemaCellCacheValue { raw, cell } = handle
287                        .handle
288                        .try_get()
289                        .unwrap()
290                        .as_ref()
291                        .map_err(|e| e.clone())?;
292                    Ok(SchemaCellCacheValue {
293                        raw: Arc::new((**raw).clone().convert_schema::<S2>()?),
294                        cell: cell.clone(),
295                    })
296                },
297            ),
298            cell: handle.cell,
299        }
300    }
301
302    /// Generates a schematic of a block in schema `S1` for use in schema `S2`.
303    ///
304    /// Can only generate a cross schematic with one layer of [`FromSchema`] indirection.
305    pub fn generate_cross_schematic<B: Schematic, S2: FromSchema<B::Schema> + ?Sized>(
306        &self,
307        block: B,
308    ) -> SchemaCellHandle<S2, B> {
309        self.generate_cross_schematic_inner(Arc::new(block))
310    }
311
312    /// Generates a schematic for `block` in the background.
313    ///
314    /// Returns a handle to the cell being generated.
315    pub fn generate_schematic<T: Schematic>(&self, block: T) -> SchemaCellHandle<T::Schema, T> {
316        let block = Arc::new(block);
317        self.generate_schematic_inner(block)
318    }
319
320    /// Export the given block and all sub-blocks as a SCIR library.
321    ///
322    /// Returns a SCIR library and metadata for converting between SCIR and Substrate formats.
323    pub fn export_scir<T: Schematic>(&self, block: T) -> Result<RawLib<T::Schema>, ConvError> {
324        let cell = self.generate_schematic(block);
325        // TODO: Handle errors.
326        let SchemaCellCacheValue { raw, .. } = cell.handle.unwrap_inner();
327        raw.to_scir_lib()
328    }
329
330    /// Export the given cells and all their subcells as a SCIR library.
331    ///
332    /// Returns a SCIR library and metadata for converting between SCIR and Substrate formats.
333    pub fn export_scir_all<S: Schema + ?Sized>(
334        &self,
335        cells: &[&crate::schematic::RawCell<S>],
336    ) -> Result<RawLib<S>, ConvError> {
337        export_multi_top_scir_lib(cells)
338    }
339
340    /// Returns a simulation controller for the given testbench and simulator.
341    pub fn get_sim_controller<S, T>(
342        &self,
343        block: T,
344        work_dir: impl Into<PathBuf>,
345    ) -> Result<SimController<S, T>>
346    where
347        S: Simulator,
348        T: Testbench<S>,
349    {
350        let simulator = self
351            .get_installation::<S>()
352            .expect("Simulator must be installed");
353        let block = Arc::new(block);
354        let cell = self.generate_schematic_inner(block.clone());
355        // TODO: Handle errors.
356        let SchemaCellCacheValue { raw, cell } = cell.handle.unwrap_inner();
357        let lib = raw.to_scir_lib()?;
358        let ctx = SimulationContext {
359            lib: Arc::new(lib),
360            work_dir: work_dir.into(),
361            ctx: self.clone(),
362        };
363        Ok(SimController {
364            tb: cell.clone(),
365            simulator,
366            ctx,
367        })
368    }
369
370    /// Installs the given [`PrivateInstallation`].
371    ///
372    /// Only one installation of any given type can exist. Overwrites
373    /// conflicting installations of the same type.
374    #[inline]
375    pub fn install<I>(&mut self, installation: I) -> Arc<I>
376    where
377        I: PrivateInstallation,
378    {
379        let installation = Arc::new(installation);
380        self.inner
381            .write()
382            .unwrap()
383            .private_installations
384            .insert(TypeId::of::<I>(), installation.clone());
385        installation
386    }
387
388    /// Installs the given [`PrivateInstallation`].
389    ///
390    /// Returns the existing installation if one is present.
391    #[inline]
392    pub fn get_or_install<I>(&self, installation: I) -> Arc<I>
393    where
394        I: PrivateInstallation,
395    {
396        let installation = Arc::new(installation);
397        self.inner
398            .write()
399            .unwrap()
400            .private_installations
401            .entry(TypeId::of::<I>())
402            .or_insert(installation.clone())
403            .clone()
404            .downcast()
405            .unwrap()
406    }
407
408    /// Gets a private installation from the context installation map.
409    pub fn get_private_installation<I: PrivateInstallation>(&self) -> Option<Arc<I>> {
410        retrieve_installation(&self.inner.read().unwrap().private_installations)
411    }
412
413    /// Gets an installation from the context installation map.
414    pub fn get_installation<I: Installation>(&self) -> Option<Arc<I>> {
415        retrieve_installation(&self.installations)
416    }
417
418    /// Generates a layout for `block` in the background.
419    ///
420    /// Returns a handle to the cell being generated.
421    pub fn generate_layout<T: Layout>(&self, block: T) -> LayoutCellHandle<T> {
422        let context_clone = self.clone();
423        let mut inner_mut = self.inner.write().unwrap();
424        let id = inner_mut.layout.get_id();
425        let block = Arc::new(block);
426
427        let span = span!(
428            Level::INFO,
429            "generating layout",
430            block = %block.name(),
431        )
432        .or_current();
433
434        LayoutCellHandle {
435            block: block.clone(),
436            cell: inner_mut.layout.cell_cache.generate(block, move |block| {
437                let block_io = block.io();
438                let mut cell_builder = LayoutCellBuilder::new(context_clone);
439                let _guard = span.enter();
440                let (io, data) = block.layout(&mut cell_builder)?;
441                if block_io.kind() != io.kind() || block_io.kind().len() != io.len() {
442                    tracing::event!(
443                        Level::ERROR,
444                        "layout IO and block IO have different bundle kinds or flattened lengths"
445                    );
446                    return Err(LayoutError::IoDefinition.into());
447                }
448                let ports = IndexMap::from_iter(
449                    block
450                        .io()
451                        .kind()
452                        .flat_names(None)
453                        .into_iter()
454                        .zip(io.flatten_vec()),
455                );
456                Ok(LayoutCell::new(
457                    block.clone(),
458                    data,
459                    io,
460                    Arc::new(cell_builder.finish(id, block.name()).with_ports(ports)),
461                ))
462            }),
463        }
464    }
465
466    /// Exports the layout of a block to a LayIR library.
467    pub fn export_layir<T: Layout>(
468        &self,
469        block: T,
470    ) -> Result<crate::layout::conv::RawLib<<T::Schema as crate::layout::schema::Schema>::Layer>>
471    {
472        let handle = self.generate_layout(block);
473        let cell = handle.try_cell()?;
474        let lib = cell.raw().to_layir_lib()?;
475        Ok(lib)
476    }
477
478    /// Writes a set of layout cells to a LayIR library.
479    pub fn export_layir_all<'a, L: Clone + 'a>(
480        &self,
481        cells: impl IntoIterator<Item = &'a RawCell<L>>,
482    ) -> Result<crate::layout::conv::RawLib<L>> {
483        let cells = cells.into_iter().collect::<Vec<_>>();
484        let lib = export_multi_top_layir_lib(&cells)?;
485        Ok(lib)
486    }
487
488    /// Imports a LayIR library into the context.
489    pub fn import_layir<S: crate::layout::schema::Schema>(
490        &self,
491        lib: layir::Library<S::Layer>,
492        top: layir::CellId,
493    ) -> Result<Arc<crate::layout::element::RawCell<S::Layer>>> {
494        use crate::layout::element::{RawCell, RawInstance};
495        let mut inner = self.inner.write().unwrap();
496        let mut cells: HashMap<layir::CellId, Arc<RawCell<S::Layer>>> = HashMap::new();
497        for id in lib.topological_order() {
498            let cell = lib.cell(id);
499            let sid = inner.layout.get_id();
500            let mut raw = RawCell::new(sid, cell.name());
501            raw.elements
502                .extend(cell.elements().map(|elt| Element::from(elt.clone())));
503            raw.elements.extend(cell.instances().map(|(_, inst)| {
504                Element::Instance(RawInstance::new(
505                    cells[&inst.child()].clone(),
506                    inst.transformation(),
507                ))
508            }));
509            let mut ports = NamedPorts::new();
510            for (name, port) in cell.ports() {
511                let mut pg = PortGeometryBuilder::default();
512                for elt in port.elements() {
513                    if let layir::Element::Shape(s) = elt {
514                        pg.push(s.clone());
515                    }
516                }
517                let pg = pg.build()?;
518                ports.insert(NameBuf::from(name), pg);
519            }
520            raw = raw.with_ports(ports);
521            let cell = Arc::new(raw);
522            cells.insert(id, cell);
523        }
524        Ok(cells.get(&top).unwrap().clone())
525    }
526
527    /// Writes a layout cell to GDS.
528    pub fn write_layout<B: Layout>(
529        &self,
530        block: B,
531        to_gds: impl FnOnce(&layir::Library<CellLayer<B>>) -> (layir::Library<GdsLayer>, GdsUnits),
532        path: impl AsRef<Path>,
533    ) -> Result<()> {
534        let name = block.name();
535        let layir = self.export_layir(block)?;
536        let (layir, units) = to_gds(&layir.layir);
537        let gds = gdsconv::export::export_gds(
538            layir,
539            GdsExportOpts {
540                name,
541                units: Some(units),
542            },
543        );
544        gds.save(path)?;
545        Ok(())
546    }
547
548    /// Writes a set of layout cells to GDS.
549    pub fn write_layout_all<'a, L: Clone + 'a>(
550        &self,
551        cells: impl IntoIterator<Item = &'a RawCell<L>>,
552        to_gds: impl FnOnce(&layir::Library<L>) -> (layir::Library<GdsLayer>, GdsUnits),
553        path: impl AsRef<Path>,
554    ) -> Result<()> {
555        let name = arcstr::literal!("TOP");
556        let layir = self.export_layir_all(cells)?;
557        let (layir, units) = to_gds(&layir.layir);
558        let gds = gdsconv::export::export_gds(
559            layir,
560            GdsExportOpts {
561                name,
562                units: Some(units),
563            },
564        );
565        gds.save(path)?;
566        Ok(())
567    }
568}
569
570fn retrieve_installation<I: Any + Send + Sync>(
571    map: &HashMap<TypeId, Arc<dyn Any + Send + Sync>>,
572) -> Option<Arc<I>> {
573    map.get(&TypeId::of::<I>())
574        .map(|arc| arc.clone().downcast().unwrap())
575}
576
577/// Only public for use in ATOLL. Do NOT use externally.
578///
579/// If the `id` argument is Some, the cell will use the given ID.
580/// Otherwise, a new [`CellId`] will be allocated by calling [`Context::alloc_cell_id`].
581#[doc(hidden)]
582pub fn prepare_cell_builder<
583    T: Block<Io: HasBundleKind<BundleKind: SchematicBundleKind>>,
584    S: substrate::schematic::schema::Schema,
585>(
586    id: Option<CellId>,
587    context: Context,
588    block: &T,
589) -> (CellBuilder<S>, IoNodeBundle<T>) {
590    let id = id.unwrap_or_else(|| context.alloc_cell_id());
591    let mut node_ctx = NodeContext::new();
592    // outward-facing IO (to other enclosing blocks)
593    let io_outward = block.io();
594    // inward-facing IO (this block's IO ports as viewed by the interior of the
595    // block)
596    let io_internal = Flipped(io_outward.clone());
597    // FIXME: the cell's IO should not be attributed to this call site
598    let (nodes, io_data) =
599        node_ctx.instantiate_directed(&io_internal, NodePriority::Io, SourceInfo::from_caller());
600    let cell_name = block.name();
601
602    let names = <<T as Block>::Io as HasBundleKind>::kind(&io_outward).flat_names(None);
603    let outward_dirs = io_outward.flatten_vec();
604    assert_eq!(nodes.len(), names.len());
605    assert_eq!(nodes.len(), outward_dirs.len());
606
607    let ports = nodes
608        .iter()
609        .copied()
610        .zip(outward_dirs)
611        .map(|(node, direction)| Port::new(node, direction))
612        .collect();
613
614    let node_names = HashMap::from_iter(nodes.into_iter().zip(names));
615
616    (
617        CellBuilder {
618            id,
619            cell_name,
620            ctx: context,
621            node_ctx,
622            node_names,
623            fatal_error: false,
624            ports,
625            flatten: false,
626            contents: RawCellContentsBuilder::Cell(RawCellInnerBuilder::default()),
627        },
628        io_data,
629    )
630}