1use crate::{InstanceTail, SimSignal, Spectre};
4use arcstr::ArcStr;
5use scir::{NamedSliceOne, SliceOnePath};
6use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8use substrate::{
9 schematic::conv::ConvertedNodePath,
10 simulation::{
11 Analysis, SimulationContext, Simulator, SupportedBy,
12 data::{Save, SaveOutput},
13 },
14 types::schematic::{NestedNode, NestedTerminal, RawNestedNode},
15};
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct DcOp;
20
21#[derive(Debug, Clone)]
23pub struct OpOutput {
24 pub raw_values: HashMap<ArcStr, f64>,
26 pub(crate) saved_values: HashMap<u64, ArcStr>,
28}
29
30#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)]
32pub struct VoltageSaveKey(pub(crate) u64);
33
34#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
36pub struct CurrentSaveKey(pub(crate) Vec<u64>);
37
38impl Analysis for DcOp {
39 type Output = OpOutput;
40}
41
42impl SupportedBy<Spectre> for DcOp {
43 fn into_input(self, inputs: &mut Vec<<Spectre as Simulator>::Input>) {
44 inputs.push(self.into());
45 }
46 fn from_output(
47 outputs: &mut impl Iterator<Item = <Spectre as Simulator>::Output>,
48 ) -> <Self as Analysis>::Output {
49 let item = outputs.next().unwrap();
50 item.try_into().unwrap()
51 }
52}
53
54impl Save<Spectre, DcOp> for SaveOutput {
55 type SaveKey = ();
56 type Saved = OpOutput;
57
58 fn save(
59 &self,
60 _ctx: &SimulationContext<Spectre>,
61 _opts: &mut <Spectre as Simulator>::Options,
62 ) -> <Self as Save<Spectre, DcOp>>::SaveKey {
63 }
64
65 fn from_saved(
66 output: &<DcOp as Analysis>::Output,
67 _key: &<Self as Save<Spectre, DcOp>>::SaveKey,
68 ) -> <Self as Save<Spectre, DcOp>>::Saved {
69 output.clone()
70 }
71}
72
73impl Save<Spectre, DcOp> for NestedNode {
74 type SaveKey = VoltageSaveKey;
75 type Saved = f64;
76
77 fn save(
78 &self,
79 ctx: &SimulationContext<Spectre>,
80 opts: &mut <Spectre as Simulator>::Options,
81 ) -> <Self as Save<Spectre, DcOp>>::SaveKey {
82 opts.save_dc_voltage(SimSignal::ScirVoltage(
83 match ctx.lib.convert_node_path(&self.path()).unwrap() {
84 ConvertedNodePath::Cell(path) => path.clone(),
85 ConvertedNodePath::Primitive {
86 instances, port, ..
87 } => SliceOnePath::new(instances.clone(), NamedSliceOne::new(port.clone())),
88 },
89 ))
90 }
91
92 fn from_saved(
93 output: &<DcOp as Analysis>::Output,
94 key: &<Self as Save<Spectre, DcOp>>::SaveKey,
95 ) -> <Self as Save<Spectre, DcOp>>::Saved {
96 *output
97 .raw_values
98 .get(output.saved_values.get(&key.0).unwrap())
99 .unwrap()
100 }
101}
102
103impl Save<Spectre, DcOp> for RawNestedNode {
104 type SaveKey = VoltageSaveKey;
105 type Saved = f64;
106
107 fn save(
108 &self,
109 ctx: &SimulationContext<Spectre>,
110 opts: &mut <Spectre as Simulator>::Options,
111 ) -> <Self as Save<Spectre, DcOp>>::SaveKey {
112 let itail = InstanceTail {
113 instance: ctx.lib.convert_instance_path(self.instances()).unwrap(),
114 tail: self.tail().clone(),
115 };
116 opts.save_dc_voltage(itail)
117 }
118
119 fn from_saved(
120 output: &<DcOp as Analysis>::Output,
121 key: &<Self as Save<Spectre, DcOp>>::SaveKey,
122 ) -> <Self as Save<Spectre, DcOp>>::Saved {
123 *output
124 .raw_values
125 .get(output.saved_values.get(&key.0).unwrap())
126 .unwrap()
127 }
128}
129
130pub struct NestedTerminalOutput {
132 pub v: f64,
134 pub i: f64,
136}
137
138impl Save<Spectre, DcOp> for NestedTerminal {
139 type SaveKey = (VoltageSaveKey, CurrentSaveKey);
140 type Saved = NestedTerminalOutput;
141
142 fn save(
143 &self,
144 ctx: &SimulationContext<Spectre>,
145 opts: &mut <Spectre as Simulator>::Options,
146 ) -> <Self as Save<Spectre, DcOp>>::SaveKey {
147 (
148 <NestedNode as Save<Spectre, DcOp>>::save(self, ctx, opts),
149 CurrentSaveKey(
150 ctx.lib
151 .convert_terminal_path(&self.path())
152 .unwrap()
153 .into_iter()
154 .flat_map(|path| {
155 opts.save_tran_current(SimSignal::ScirCurrent(match path {
156 ConvertedNodePath::Cell(path) => path.clone(),
157 ConvertedNodePath::Primitive {
158 instances, port, ..
159 } => SliceOnePath::new(
160 instances.clone(),
161 NamedSliceOne::new(port.clone()),
162 ),
163 }))
164 .0
165 })
166 .collect(),
167 ),
168 )
169 }
170
171 fn from_saved(
172 output: &<DcOp as Analysis>::Output,
173 key: &<Self as Save<Spectre, DcOp>>::SaveKey,
174 ) -> <Self as Save<Spectre, DcOp>>::Saved {
175 let v = *output
176 .raw_values
177 .get(output.saved_values.get(&key.0.0).unwrap())
178 .unwrap();
179 let i = key
180 .1
181 .0
182 .iter()
183 .map(|key| {
184 output
185 .raw_values
186 .get(output.saved_values.get(key).unwrap())
187 .unwrap()
188 })
189 .sum();
190
191 NestedTerminalOutput { v, i }
192 }
193}