substrate/schematic/
pex.rs

1//! Utilities for tracking nested data through parasitic extraction.
2
3use std::sync::Arc;
4
5use scir::{Library, NamedSliceOne, NetlistLibConversion, SliceOnePath};
6
7use crate::{
8    simulation::{
9        Analysis, Simulator,
10        data::{Save, SaveKey, Saved},
11    },
12    types::schematic::{NestedNode, RawNestedNode},
13};
14
15use super::{
16    Cell, ContextView, HasContextView, HasNestedView, InstancePath, NestedView, Schematic,
17    conv::{ConvertedNodePath, RawLib},
18    schema::Schema,
19};
20
21/// Captures information for mapping nodes/elements between schematic and extracted netlists.
22pub struct PexContext<S: Schema> {
23    /// The source spice file for this DSPF extracted view.
24    lib: Arc<RawLib<S>>,
25    conv: Arc<NetlistLibConversion>,
26    path: InstancePath,
27}
28
29impl<S: Schema> Clone for PexContext<S> {
30    fn clone(&self) -> Self {
31        Self {
32            lib: self.lib.clone(),
33            conv: self.conv.clone(),
34            path: self.path.clone(),
35        }
36    }
37}
38
39/// A schema that can convert element paths to strings.
40pub trait StringPathSchema: Schema {
41    /// Convert a node path to a raw string.
42    fn node_path(lib: &Library<Self>, conv: &NetlistLibConversion, path: &SliceOnePath) -> String;
43}
44
45impl<S: StringPathSchema> HasContextView<PexContext<S>> for NestedNode {
46    type ContextView = RawNestedNode;
47
48    fn context_view(&self, parent: &PexContext<S>) -> ContextView<Self, PexContext<S>> {
49        let n = self;
50        let path = parent.lib.convert_node_path(&n.path()).unwrap();
51        let path = match path {
52            ConvertedNodePath::Cell(path) => path,
53            ConvertedNodePath::Primitive {
54                instances, port, ..
55            } => SliceOnePath::new(instances.clone(), NamedSliceOne::new(port.clone())),
56        };
57        let path = parent.lib.scir.simplify_path(path);
58        RawNestedNode::new(
59            parent.path.clone(),
60            S::node_path(&parent.lib.scir, &parent.conv, &path),
61        )
62    }
63}
64
65/// Nested data exposed by an extracted view of a circuit.
66pub struct PexData<T: Schematic> {
67    cell: Cell<Arc<T>>,
68    lib: Arc<RawLib<T::Schema>>,
69    conv: Arc<NetlistLibConversion>,
70}
71
72impl<T: Schematic> Clone for PexData<T> {
73    fn clone(&self) -> Self {
74        Self {
75            cell: self.cell.clone(),
76            lib: self.lib.clone(),
77            conv: self.conv.clone(),
78        }
79    }
80}
81
82impl<T: Schematic> PexData<T> {
83    /// Creates a new [`PexData`].
84    pub fn new(
85        cell: Cell<Arc<T>>,
86        lib: Arc<RawLib<T::Schema>>,
87        conv: Arc<NetlistLibConversion>,
88    ) -> Self {
89        Self { cell, lib, conv }
90    }
91}
92
93/// The nested view of [`PexData`].
94pub struct NestedPexData<T: Schematic> {
95    cell: Cell<Arc<T>>,
96    ctx: PexContext<T::Schema>,
97}
98
99impl<T: Schematic> Clone for NestedPexData<T> {
100    fn clone(&self) -> Self {
101        Self {
102            cell: self.cell.clone(),
103            ctx: self.ctx.clone(),
104        }
105    }
106}
107
108impl<T: Schematic> NestedPexData<T>
109where
110    T::NestedData: HasContextView<PexContext<T::Schema>>,
111{
112    /// Access the underlying data.
113    pub fn data(&self) -> ContextView<T::NestedData, PexContext<T::Schema>> {
114        self.cell.context_data(&self.ctx)
115    }
116}
117
118impl<T: Schematic> HasNestedView for PexData<T> {
119    type NestedView = NestedPexData<T>;
120    fn nested_view(&self, parent: &InstancePath) -> NestedView<Self> {
121        NestedPexData {
122            cell: self.cell.clone(),
123            ctx: PexContext {
124                lib: self.lib.clone(),
125                conv: self.conv.clone(),
126                path: parent.clone(),
127            },
128        }
129    }
130}
131
132impl<T: Schematic> HasNestedView for NestedPexData<T> {
133    type NestedView = NestedPexData<T>;
134    fn nested_view(&self, parent: &InstancePath) -> NestedView<Self> {
135        NestedPexData {
136            cell: self.cell.clone(),
137            ctx: PexContext {
138                lib: self.ctx.lib.clone(),
139                conv: self.ctx.conv.clone(),
140                path: self.ctx.path.prepend(parent),
141            },
142        }
143    }
144}
145
146impl<S: Simulator, A: Analysis, T: Schematic> Save<S, A> for NestedPexData<T>
147where
148    T::NestedData: HasContextView<PexContext<T::Schema>>,
149    ContextView<T::NestedData, PexContext<T::Schema>>: Save<S, A>,
150{
151    type SaveKey = SaveKey<ContextView<T::NestedData, PexContext<T::Schema>>, S, A>;
152    type Saved = Saved<ContextView<T::NestedData, PexContext<T::Schema>>, S, A>;
153
154    fn save(
155        &self,
156        ctx: &substrate::simulation::SimulationContext<S>,
157        opts: &mut <S as Simulator>::Options,
158    ) -> <Self as Save<S, A>>::SaveKey {
159        self.data().save(ctx, opts)
160    }
161
162    fn from_saved(
163        output: &<A as Analysis>::Output,
164        key: &<Self as Save<S, A>>::SaveKey,
165    ) -> <Self as Save<S, A>>::Saved {
166        <ContextView<T::NestedData, PexContext<T::Schema>> as Save<S, A>>::from_saved(output, key)
167    }
168}