1use arcstr::ArcStr;
4use rust_decimal::Decimal;
5use scir::ParamValue;
6use serde::{Deserialize, Serialize};
7use std::path::PathBuf;
8use substrate::block::Block;
9use substrate::schematic::{CellBuilder, PrimitiveBinding, Schematic};
10use substrate::simulation::waveform::{TimeWaveform, Waveform};
11use substrate::types::{Array, InOut, Io, Signal, TwoTerminalIo};
12
13use crate::{Primitive, Spectre};
14
15#[derive(Serialize, Deserialize, Debug, Copy, Clone, Hash, PartialEq, Eq)]
17pub struct Pulse {
18 pub val0: Decimal,
20 pub val1: Decimal,
22 pub period: Option<Decimal>,
24 pub rise: Option<Decimal>,
26 pub fall: Option<Decimal>,
28 pub width: Option<Decimal>,
30 pub delay: Option<Decimal>,
32}
33
34#[derive(Serialize, Deserialize, Debug, Clone, Hash, PartialEq, Eq)]
36pub enum Vsource {
37 Dc(Decimal),
39 Ac(AcSource),
41 Pulse(Pulse),
43 Pwl(Waveform<Decimal>),
45}
46
47impl Vsource {
48 #[inline]
50 pub fn dc(value: Decimal) -> Self {
51 Self::Dc(value)
52 }
53
54 #[inline]
56 pub fn pulse(value: Pulse) -> Self {
57 Self::Pulse(value)
58 }
59
60 #[inline]
62 pub fn pwl(value: Waveform<Decimal>) -> Self {
63 Self::Pwl(value)
64 }
65}
66
67impl Block for Vsource {
68 type Io = TwoTerminalIo;
69
70 fn name(&self) -> arcstr::ArcStr {
71 arcstr::format!("uservsource")
74 }
75 fn io(&self) -> Self::Io {
76 Default::default()
77 }
78}
79
80impl Schematic for Vsource {
81 type Schema = Spectre;
82 type NestedData = ();
83
84 fn schematic(
85 &self,
86 io: &substrate::types::schematic::IoNodeBundle<Self>,
87 cell: &mut CellBuilder<<Self as Schematic>::Schema>,
88 ) -> substrate::error::Result<Self::NestedData> {
89 use arcstr::literal;
90 let mut params = Vec::new();
91 match self {
92 Vsource::Dc(dc) => {
93 params.push((literal!("type"), ParamValue::String(literal!("dc"))));
94 params.push((literal!("dc"), ParamValue::Numeric(*dc)));
95 }
96 Vsource::Pulse(pulse) => {
97 params.push((literal!("type"), ParamValue::String(literal!("pulse"))));
98 params.push((literal!("val0"), ParamValue::Numeric(pulse.val0)));
99 params.push((literal!("val1"), ParamValue::Numeric(pulse.val1)));
100 if let Some(period) = pulse.period {
101 params.push((literal!("period"), ParamValue::Numeric(period)));
102 }
103 if let Some(rise) = pulse.rise {
104 params.push((literal!("rise"), ParamValue::Numeric(rise)));
105 }
106 if let Some(fall) = pulse.fall {
107 params.push((literal!("fall"), ParamValue::Numeric(fall)));
108 }
109 if let Some(width) = pulse.width {
110 params.push((literal!("width"), ParamValue::Numeric(width)));
111 }
112 if let Some(delay) = pulse.delay {
113 params.push((literal!("delay"), ParamValue::Numeric(delay)));
114 }
115 }
116 Vsource::Pwl(waveform) => {
117 let mut pwl = String::new();
118 pwl.push('[');
119 for (i, pt) in waveform.values().enumerate() {
120 use std::fmt::Write;
121 if i != 0 {
122 pwl.push(' ');
123 }
124 write!(&mut pwl, "{} {}", pt.t(), pt.x()).unwrap();
125 }
126 pwl.push(']');
127 params.push((literal!("type"), ParamValue::String(literal!("pwl"))));
128 params.push((literal!("wave"), ParamValue::String(pwl.into())));
129 }
130 Vsource::Ac(ac) => {
131 params.push((literal!("type"), ParamValue::String(literal!("dc"))));
132 params.push((literal!("dc"), ParamValue::Numeric(ac.dc)));
133 params.push((literal!("mag"), ParamValue::Numeric(ac.mag)));
134 params.push((literal!("phase"), ParamValue::Numeric(ac.phase)));
135 }
136 };
137
138 let mut prim = PrimitiveBinding::new(Primitive::RawInstance {
139 cell: arcstr::literal!("vsource"),
140 ports: vec!["p".into(), "n".into()],
141 params,
142 });
143 prim.connect("p", io.p);
144 prim.connect("n", io.n);
145 cell.set_primitive(prim);
146 Ok(())
147 }
148}
149
150#[derive(Serialize, Deserialize, Default, Debug, Copy, Clone, Hash, PartialEq, Eq)]
152pub struct AcSource {
153 pub dc: Decimal,
155 pub mag: Decimal,
157 pub phase: Decimal,
159}
160
161#[derive(Serialize, Deserialize, Debug, Copy, Clone, Hash, PartialEq, Eq)]
165pub enum Isource {
166 Dc(Decimal),
168 Ac(AcSource),
170 Pulse(Pulse),
172}
173
174impl Isource {
175 #[inline]
177 pub fn dc(value: Decimal) -> Self {
178 Self::Dc(value)
179 }
180
181 #[inline]
183 pub fn pulse(value: Pulse) -> Self {
184 Self::Pulse(value)
185 }
186
187 #[inline]
189 pub fn ac(value: AcSource) -> Self {
190 Self::Ac(value)
191 }
192}
193
194impl Block for Isource {
195 type Io = TwoTerminalIo;
196
197 fn name(&self) -> arcstr::ArcStr {
198 arcstr::format!("userisource")
201 }
202 fn io(&self) -> Self::Io {
203 Default::default()
204 }
205}
206
207impl Schematic for Isource {
208 type Schema = Spectre;
209 type NestedData = ();
210
211 fn schematic(
212 &self,
213 io: &substrate::types::schematic::IoNodeBundle<Self>,
214 cell: &mut CellBuilder<<Self as Schematic>::Schema>,
215 ) -> substrate::error::Result<Self::NestedData> {
216 use arcstr::literal;
217 let mut params = Vec::new();
218 match self {
219 Isource::Dc(dc) => {
220 params.push((literal!("type"), ParamValue::String(literal!("dc"))));
221 params.push((literal!("dc"), ParamValue::Numeric(*dc)));
222 }
223 Isource::Pulse(pulse) => {
224 params.push((literal!("type"), ParamValue::String(literal!("pulse"))));
225 params.push((literal!("val0"), ParamValue::Numeric(pulse.val0)));
226 params.push((literal!("val1"), ParamValue::Numeric(pulse.val1)));
227 if let Some(period) = pulse.period {
228 params.push((literal!("period"), ParamValue::Numeric(period)));
229 }
230 if let Some(rise) = pulse.rise {
231 params.push((literal!("rise"), ParamValue::Numeric(rise)));
232 }
233 if let Some(fall) = pulse.fall {
234 params.push((literal!("fall"), ParamValue::Numeric(fall)));
235 }
236 if let Some(width) = pulse.width {
237 params.push((literal!("width"), ParamValue::Numeric(width)));
238 }
239 if let Some(delay) = pulse.delay {
240 params.push((literal!("delay"), ParamValue::Numeric(delay)));
241 }
242 }
243 Isource::Ac(ac) => {
244 params.push((literal!("type"), ParamValue::String(literal!("dc"))));
245 params.push((literal!("dc"), ParamValue::Numeric(ac.dc)));
246 params.push((literal!("mag"), ParamValue::Numeric(ac.mag)));
247 params.push((literal!("phase"), ParamValue::Numeric(ac.phase)));
248 }
249 };
250
251 let mut prim = PrimitiveBinding::new(Primitive::RawInstance {
252 cell: arcstr::literal!("isource"),
253 ports: vec!["p".into(), "n".into()],
254 params,
255 });
256 prim.connect("p", io.p);
257 prim.connect("n", io.n);
258 cell.set_primitive(prim);
259 Ok(())
260 }
261}
262
263#[derive(Serialize, Deserialize, Debug, Copy, Clone, Hash, PartialEq, Eq)]
265pub struct Iprobe;
266
267impl Block for Iprobe {
268 type Io = TwoTerminalIo;
269
270 fn name(&self) -> arcstr::ArcStr {
271 arcstr::format!("useriprobe")
274 }
275 fn io(&self) -> Self::Io {
276 Default::default()
277 }
278}
279
280impl Schematic for Iprobe {
281 type Schema = Spectre;
282 type NestedData = ();
283 fn schematic(
284 &self,
285 io: &substrate::types::schematic::IoNodeBundle<Self>,
286 cell: &mut CellBuilder<<Self as Schematic>::Schema>,
287 ) -> substrate::error::Result<Self::NestedData> {
288 let mut prim = PrimitiveBinding::new(Primitive::RawInstance {
289 cell: arcstr::literal!("iprobe"),
290 ports: vec!["in".into(), "out".into()],
291 params: Vec::new(),
292 });
293 prim.connect("in", io.p);
294 prim.connect("out", io.n);
295 cell.set_primitive(prim);
296 Ok(())
297 }
298}
299
300#[derive(Serialize, Deserialize, Debug, Clone, Hash, PartialEq, Eq)]
302pub struct Nport {
303 parameter_file: PathBuf,
304 ports: usize,
305}
306
307impl Nport {
308 pub fn new(ports: usize, parameter_file: impl Into<PathBuf>) -> Self {
310 Self {
311 parameter_file: parameter_file.into(),
312 ports,
313 }
314 }
315}
316
317#[derive(Clone, Debug, Io)]
319pub struct NportIo {
320 pub ports: Array<TwoTerminalIo>,
324}
325
326impl Block for Nport {
327 type Io = NportIo;
328
329 fn name(&self) -> arcstr::ArcStr {
330 arcstr::format!("usernport")
333 }
334 fn io(&self) -> Self::Io {
335 NportIo {
336 ports: Array::new(self.ports, Default::default()),
337 }
338 }
339}
340
341impl Schematic for Nport {
342 type Schema = Spectre;
343 type NestedData = ();
344 fn schematic(
345 &self,
346 io: &substrate::types::schematic::IoNodeBundle<Self>,
347 cell: &mut CellBuilder<<Self as Schematic>::Schema>,
348 ) -> substrate::error::Result<Self::NestedData> {
349 let mut prim = PrimitiveBinding::new(Primitive::RawInstance {
350 cell: arcstr::literal!("nport"),
351 ports: (1..=self.ports)
352 .flat_map(|i| [arcstr::format!("t{i}"), arcstr::format!("b{i}")])
353 .collect(),
354 params: Vec::from_iter([(
355 arcstr::literal!("file"),
356 ParamValue::String(arcstr::format!("{:?}", self.parameter_file)),
357 )]),
358 });
359 for i in 0..self.ports {
360 prim.connect(arcstr::format!("t{}", i + 1), io.ports[i].p);
361 prim.connect(arcstr::format!("b{}", i + 1), io.ports[i].n);
362 }
363 cell.set_primitive(prim);
364 Ok(())
365 }
366}
367
368#[derive(Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)]
370pub struct Resistor {
371 value: Decimal,
373}
374impl Resistor {
375 #[inline]
377 pub fn new(value: impl Into<Decimal>) -> Self {
378 Self {
379 value: value.into(),
380 }
381 }
382
383 #[inline]
385 pub fn value(&self) -> Decimal {
386 self.value
387 }
388}
389impl Block for Resistor {
390 type Io = TwoTerminalIo;
391
392 fn name(&self) -> ArcStr {
393 arcstr::format!("ideal_resistor_{}", self.value)
394 }
395
396 fn io(&self) -> Self::Io {
397 Default::default()
398 }
399}
400
401impl Schematic for Resistor {
402 type Schema = Spectre;
403 type NestedData = ();
404 fn schematic(
405 &self,
406 io: &substrate::types::schematic::IoNodeBundle<Self>,
407 cell: &mut CellBuilder<<Self as Schematic>::Schema>,
408 ) -> substrate::error::Result<Self::NestedData> {
409 let mut prim = PrimitiveBinding::new(Primitive::RawInstance {
410 cell: arcstr::literal!("resistor"),
411 ports: vec![arcstr::literal!("1"), arcstr::literal!("2")],
412 params: Vec::from_iter([(arcstr::literal!("r"), ParamValue::Numeric(self.value()))]),
413 });
414 prim.connect("1", io.p);
415 prim.connect("2", io.n);
416 cell.set_primitive(prim);
417 Ok(())
418 }
419}
420
421#[derive(Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)]
423pub struct Capacitor {
424 value: Decimal,
426}
427
428impl Capacitor {
429 #[inline]
431 pub fn new(value: impl Into<Decimal>) -> Self {
432 Self {
433 value: value.into(),
434 }
435 }
436
437 #[inline]
439 pub fn value(&self) -> Decimal {
440 self.value
441 }
442}
443
444impl Block for Capacitor {
445 type Io = TwoTerminalIo;
446
447 fn name(&self) -> ArcStr {
448 arcstr::format!("capacitor_{}", self.value)
449 }
450
451 fn io(&self) -> Self::Io {
452 Default::default()
453 }
454}
455
456impl Schematic for Capacitor {
457 type Schema = Spectre;
458 type NestedData = ();
459 fn schematic(
460 &self,
461 io: &substrate::types::schematic::IoNodeBundle<Self>,
462 cell: &mut CellBuilder<<Self as Schematic>::Schema>,
463 ) -> substrate::error::Result<Self::NestedData> {
464 let mut prim = PrimitiveBinding::new(Primitive::RawInstance {
465 cell: arcstr::literal!("capacitor"),
466 ports: vec![arcstr::literal!("1"), arcstr::literal!("2")],
467 params: Vec::from_iter([(arcstr::literal!("c"), ParamValue::Numeric(self.value()))]),
468 });
469 prim.connect("1", io.p);
470 prim.connect("2", io.n);
471 cell.set_primitive(prim);
472 Ok(())
473 }
474}
475
476#[derive(Debug, Clone, PartialEq, Hash, Eq, Serialize, Deserialize)]
478pub struct RawInstance {
479 pub cell: ArcStr,
481 pub ports: Vec<ArcStr>,
483 pub params: Vec<(ArcStr, ParamValue)>,
485}
486
487impl RawInstance {
488 #[inline]
490 pub fn with_params(
491 cell: ArcStr,
492 ports: Vec<ArcStr>,
493 params: impl Into<Vec<(ArcStr, ParamValue)>>,
494 ) -> Self {
495 Self {
496 cell,
497 ports,
498 params: params.into(),
499 }
500 }
501 #[inline]
503 pub fn new(cell: ArcStr, ports: Vec<ArcStr>) -> Self {
504 Self {
505 cell,
506 ports,
507 params: Vec::new(),
508 }
509 }
510}
511impl Block for RawInstance {
512 type Io = InOut<Array<Signal>>;
513
514 fn name(&self) -> ArcStr {
515 arcstr::format!("raw_instance_{}", self.cell)
516 }
517
518 fn io(&self) -> Self::Io {
519 InOut(Array::new(self.ports.len(), Default::default()))
520 }
521}
522
523impl Schematic for RawInstance {
524 type Schema = Spectre;
525 type NestedData = ();
526 fn schematic(
527 &self,
528 io: &substrate::types::schematic::IoNodeBundle<Self>,
529 cell: &mut CellBuilder<<Self as Schematic>::Schema>,
530 ) -> substrate::error::Result<Self::NestedData> {
531 let mut prim = PrimitiveBinding::new(Primitive::RawInstance {
532 cell: self.cell.clone(),
533 ports: self.ports.clone(),
534 params: self.params.clone(),
535 });
536 for (i, port) in self.ports.iter().enumerate() {
537 prim.connect(port, io[i]);
538 }
539 cell.set_primitive(prim);
540 Ok(())
541 }
542}