1use std::collections::HashMap;
7
8use crate::diode::{DiodeModel, DiodeTemp};
9use crate::error::Error;
10use crate::matrix::Var;
11use crate::options::Options;
12use crate::trnoise::NoiseWave;
13
14#[derive(Clone, Debug)]
16pub struct Resistor {
17 pub name: String,
18 pub nodes: [String; 2],
19 pub value: f64,
20}
21
22#[derive(Clone, Copy, Debug, Default)]
28pub(crate) struct ResTemp {
29 pub tc1: f64,
30 pub tc2: f64,
31 pub tnom: Option<f64>,
33 pub temp: Option<f64>,
35 pub dtemp: f64,
39}
40
41#[derive(Clone, Debug)]
43pub struct Capacitor {
44 pub name: String,
45 pub nodes: [String; 2],
46 pub value: f64,
47 pub ic: Option<f64>,
49}
50
51#[derive(Clone, Debug)]
53pub struct Inductor {
54 pub name: String,
55 pub nodes: [String; 2],
56 pub value: f64,
57 pub ic: Option<f64>,
59}
60
61#[derive(Clone, Debug)]
63pub struct Mutual {
64 pub name: String,
65 pub l1: String,
66 pub l2: String,
67 pub k: f64,
68}
69
70#[derive(Clone, Debug)]
72pub struct Vsource {
73 pub name: String,
74 pub nodes: [String; 2],
75 pub dc: Option<f64>,
78 pub wave: Option<crate::srcfn::Wave>,
79 pub ac: Option<(f64, f64)>,
81 pub distof1: Option<(f64, f64)>,
83 pub distof2: Option<(f64, f64)>,
85 pub port: Option<RfPort>,
90}
91
92#[derive(Clone, Copy, Debug, PartialEq)]
98pub struct RfPort {
99 pub num: u32,
101 pub z0: f64,
104}
105
106impl RfPort {
107 pub(crate) fn is_port(&self) -> bool {
109 self.num > 0 && self.z0 > 0.0
110 }
111}
112
113#[derive(Clone, Debug)]
116pub struct Isource {
117 pub name: String,
118 pub nodes: [String; 2],
119 pub dc: Option<f64>,
120 pub wave: Option<crate::srcfn::Wave>,
121 pub ac: Option<(f64, f64)>,
123 pub distof1: Option<(f64, f64)>,
125 pub distof2: Option<(f64, f64)>,
127}
128
129#[derive(Clone, Debug)]
131pub struct Vcvs {
132 pub name: String,
133 pub nodes: [String; 4],
134 pub gain: f64,
135}
136
137#[derive(Clone, Debug)]
139pub struct Vccs {
140 pub name: String,
141 pub nodes: [String; 4],
142 pub gain: f64,
143}
144
145#[derive(Clone, Debug)]
147pub struct Cccs {
148 pub name: String,
149 pub nodes: [String; 2],
150 pub ctrl: String,
151 pub gain: f64,
152}
153
154#[derive(Clone, Debug)]
156pub struct Ccvs {
157 pub name: String,
158 pub nodes: [String; 2],
159 pub ctrl: String,
160 pub gain: f64,
161}
162
163#[derive(Clone, Debug)]
172pub struct Asrc {
173 pub name: String,
174 pub nodes: [String; 2],
175 pub kind: dune_netlist::ir::SourceKind,
176 pub expr: dune_netlist::ir::Expr,
177}
178
179#[derive(Clone, Debug)]
183pub struct Bjt {
184 pub name: String,
185 pub nodes: [String; 4],
187 pub model: crate::bjt::BjtModel,
188 pub area: f64,
189 pub off: bool,
190 pub ic: (f64, f64),
192 pub temp: Option<f64>,
194}
195
196#[derive(Clone, Debug)]
201pub struct Mos1 {
202 pub name: String,
203 pub nodes: [String; 4],
205 pub model: crate::mos1::Mos1Model,
206 pub l: Option<f64>,
207 pub w: Option<f64>,
208 pub ad: Option<f64>,
209 pub as_: Option<f64>,
210 pub pd: f64,
211 pub ps: f64,
212 pub nrd: f64,
214 pub nrs: f64,
215 pub off: bool,
216 pub ic: (f64, f64, f64),
218 pub temp: Option<f64>,
220}
221
222#[derive(Clone, Debug)]
226pub struct Mos2 {
227 pub name: String,
228 pub nodes: [String; 4],
230 pub model: crate::mos2::Mos2Model,
231 pub l: Option<f64>,
232 pub w: Option<f64>,
233 pub ad: Option<f64>,
234 pub as_: Option<f64>,
235 pub pd: f64,
236 pub ps: f64,
237 pub nrd: f64,
238 pub nrs: f64,
239 pub off: bool,
240 pub ic: (f64, f64, f64),
242 pub temp: Option<f64>,
244}
245
246#[derive(Clone, Debug)]
250pub struct Mos3 {
251 pub name: String,
252 pub nodes: [String; 4],
254 pub model: crate::mos3::Mos3Model,
255 pub l: Option<f64>,
256 pub w: Option<f64>,
257 pub ad: Option<f64>,
258 pub as_: Option<f64>,
259 pub pd: f64,
260 pub ps: f64,
261 pub nrd: f64,
262 pub nrs: f64,
263 pub off: bool,
264 pub ic: (f64, f64, f64),
266 pub temp: Option<f64>,
268}
269
270#[derive(Clone, Debug)]
272pub struct Mos6 {
273 pub name: String,
274 pub nodes: [String; 4],
276 pub model: crate::mos6::Mos6Model,
277 pub l: Option<f64>,
278 pub w: Option<f64>,
279 pub ad: Option<f64>,
280 pub as_: Option<f64>,
281 pub pd: f64,
282 pub ps: f64,
283 pub nrd: f64,
285 pub nrs: f64,
286 pub off: bool,
287 pub ic: (f64, f64, f64),
289 pub temp: Option<f64>,
291}
292
293#[derive(Clone, Debug)]
295pub struct Bsim1 {
296 pub name: String,
297 pub nodes: [String; 4],
299 pub model: crate::bsim1::Bsim1Model,
300 pub l: Option<f64>,
301 pub w: Option<f64>,
302 pub ad: Option<f64>,
303 pub as_: Option<f64>,
304 pub pd: f64,
305 pub ps: f64,
306 pub nrd: f64,
307 pub nrs: f64,
308 pub off: bool,
309 pub ic: (f64, f64, f64),
311}
312
313#[derive(Clone, Debug)]
315pub struct Bsim2 {
316 pub name: String,
317 pub nodes: [String; 4],
319 pub model: crate::bsim2::Bsim2Model,
320 pub l: Option<f64>,
321 pub w: Option<f64>,
322 pub ad: Option<f64>,
323 pub as_: Option<f64>,
324 pub pd: f64,
325 pub ps: f64,
326 pub nrd: f64,
327 pub nrs: f64,
328 pub off: bool,
329 pub ic: (f64, f64, f64),
331}
332
333#[derive(Clone, Debug)]
339pub struct Bsim3 {
340 pub name: String,
341 pub nodes: [String; 4],
343 pub model: crate::bsim3::Bsim3Model,
344 pub l: Option<f64>,
345 pub w: Option<f64>,
346 pub ad: f64,
347 pub as_: f64,
348 pub pd: f64,
349 pub ps: f64,
350 pub nrd: f64,
351 pub nrs: f64,
352 pub m: f64,
354 pub delvto: f64,
356 pub mulu0: f64,
358 pub off: bool,
359 pub ic: (f64, f64, f64),
361}
362
363#[derive(Clone, Debug)]
365pub struct Diode {
366 pub name: String,
367 pub nodes: [String; 2],
368 pub model: DiodeModel,
369 pub area: f64,
370 pub off: bool,
371 pub temp: Option<f64>,
374 pub ic: Option<f64>,
376}
377
378#[derive(Clone, Debug)]
382pub struct Jfet {
383 pub name: String,
384 pub nodes: [String; 3],
386 pub model: crate::jfet::JfetModel,
387 pub area: f64,
388 pub off: bool,
389 pub ic: (f64, f64),
391 pub temp: Option<f64>,
393}
394
395#[derive(Clone, Debug)]
399pub struct Mes {
400 pub name: String,
401 pub nodes: [String; 3],
403 pub model: crate::mes::MesModel,
404 pub area: f64,
405 pub off: bool,
406 pub ic: (f64, f64),
408}
409
410#[derive(Clone, Debug)]
415pub struct Ltra {
416 pub name: String,
417 pub nodes: [String; 4],
419 pub model: crate::ltra::LtraModel,
420}
421
422#[derive(Clone, Debug)]
430pub struct Tra {
431 pub name: String,
432 pub nodes: [String; 4],
434 pub z0: f64,
436 pub td: Option<f64>,
438 pub f: Option<f64>,
440 pub nl: Option<f64>,
442 pub ic: [f64; 4],
445}
446
447#[derive(Clone, Debug)]
450pub struct SwitchV {
451 pub name: String,
452 pub nodes: [String; 4],
454 pub model: crate::switch::SwModel,
455 pub on: bool,
458}
459
460#[derive(Clone, Debug)]
464pub struct SwitchI {
465 pub name: String,
466 pub nodes: [String; 2],
467 pub ctrl: String,
468 pub model: crate::switch::CswModel,
469 pub on: bool,
471}
472
473#[derive(Clone, Debug)]
474pub enum Spec {
475 Bjt(Box<Bjt>),
476 Mos1(Box<Mos1>),
477 Mos2(Box<Mos2>),
478 Mos3(Box<Mos3>),
479 Mos6(Box<Mos6>),
480 Bsim1(Box<Bsim1>),
481 Bsim2(Box<Bsim2>),
482 Bsim3(Box<Bsim3>),
483 Resistor(Resistor),
484 Capacitor(Capacitor),
485 Inductor(Inductor),
486 Mutual(Mutual),
487 Vsource(Vsource),
488 Isource(Isource),
489 Vcvs(Vcvs),
490 Vccs(Vccs),
491 Cccs(Cccs),
492 Ccvs(Ccvs),
493 Diode(Diode),
494 Jfet(Box<Jfet>),
495 Mes(Box<Mes>),
496 Ltra(Box<Ltra>),
497 Tra(Box<Tra>),
498 SwitchV(SwitchV),
499 SwitchI(SwitchI),
500 Asrc(Box<Asrc>),
501}
502
503macro_rules! impl_into_spec {
504 ($($t:ident),*) => {$(
505 impl From<$t> for Spec {
506 fn from(s: $t) -> Spec { Spec::$t(s) }
507 }
508 )*};
509}
510impl_into_spec!(
511 Resistor, Capacitor, Inductor, Mutual, Vsource, Isource, Vcvs, Vccs, Cccs, Ccvs, Diode,
512 SwitchV, SwitchI
513);
514
515impl From<Bjt> for Spec {
516 fn from(s: Bjt) -> Spec {
517 Spec::Bjt(Box::new(s))
518 }
519}
520
521impl From<Mos1> for Spec {
522 fn from(s: Mos1) -> Spec {
523 Spec::Mos1(Box::new(s))
524 }
525}
526
527impl From<Mos2> for Spec {
528 fn from(s: Mos2) -> Spec {
529 Spec::Mos2(Box::new(s))
530 }
531}
532
533impl From<Mos3> for Spec {
534 fn from(s: Mos3) -> Spec {
535 Spec::Mos3(Box::new(s))
536 }
537}
538
539impl From<Mos6> for Spec {
540 fn from(s: Mos6) -> Spec {
541 Spec::Mos6(Box::new(s))
542 }
543}
544
545impl From<Bsim1> for Spec {
546 fn from(s: Bsim1) -> Spec {
547 Spec::Bsim1(Box::new(s))
548 }
549}
550
551impl From<Bsim2> for Spec {
552 fn from(s: Bsim2) -> Spec {
553 Spec::Bsim2(Box::new(s))
554 }
555}
556
557impl From<Bsim3> for Spec {
558 fn from(s: Bsim3) -> Spec {
559 Spec::Bsim3(Box::new(s))
560 }
561}
562
563impl From<Jfet> for Spec {
564 fn from(s: Jfet) -> Spec {
565 Spec::Jfet(Box::new(s))
566 }
567}
568
569impl From<Mes> for Spec {
570 fn from(s: Mes) -> Spec {
571 Spec::Mes(Box::new(s))
572 }
573}
574
575impl From<Ltra> for Spec {
576 fn from(s: Ltra) -> Spec {
577 Spec::Ltra(Box::new(s))
578 }
579}
580
581impl From<Asrc> for Spec {
582 fn from(s: Asrc) -> Spec {
583 Spec::Asrc(Box::new(s))
584 }
585}
586
587impl From<Tra> for Spec {
588 fn from(s: Tra) -> Spec {
589 Spec::Tra(Box::new(s))
590 }
591}
592
593impl Spec {
594 pub(crate) fn name(&self) -> &str {
595 match self {
596 Spec::Bjt(s) => &s.name,
597 Spec::Mos1(s) => &s.name,
598 Spec::Mos2(s) => &s.name,
599 Spec::Mos3(s) => &s.name,
600 Spec::Mos6(s) => &s.name,
601 Spec::Bsim1(s) => &s.name,
602 Spec::Bsim2(s) => &s.name,
603 Spec::Bsim3(s) => &s.name,
604 Spec::Resistor(s) => &s.name,
605 Spec::Capacitor(s) => &s.name,
606 Spec::Inductor(s) => &s.name,
607 Spec::Mutual(s) => &s.name,
608 Spec::Vsource(s) => &s.name,
609 Spec::Isource(s) => &s.name,
610 Spec::Vcvs(s) => &s.name,
611 Spec::Vccs(s) => &s.name,
612 Spec::Cccs(s) => &s.name,
613 Spec::Ccvs(s) => &s.name,
614 Spec::Diode(s) => &s.name,
615 Spec::Jfet(s) => &s.name,
616 Spec::Mes(s) => &s.name,
617 Spec::Ltra(s) => &s.name,
618 Spec::Tra(s) => &s.name,
619 Spec::SwitchV(s) => &s.name,
620 Spec::SwitchI(s) => &s.name,
621 Spec::Asrc(s) => &s.name,
622 }
623 }
624}
625
626#[derive(Clone, Default)]
633pub struct Circuit {
634 pub title: String,
635 pub(crate) specs: Vec<Spec>,
636 pub(crate) nodesets: Vec<(String, f64)>,
638 pub(crate) ics: Vec<(String, f64)>,
641 pub(crate) ic_given: HashMap<String, crate::devices::IcGiven>,
646 pub(crate) res_temp: HashMap<String, ResTemp>,
652 pub(crate) dtemp: HashMap<String, f64>,
658 pub(crate) warm: crate::session::WarmSlot,
662}
663
664impl Circuit {
665 pub fn new(title: impl Into<String>) -> Self {
666 Circuit {
667 title: title.into(),
668 ..Circuit::default()
669 }
670 }
671
672 pub fn add(&mut self, spec: impl Into<Spec>) -> Result<(), Error> {
675 let mut spec = spec.into();
676 normalize(&mut spec);
677 let name = spec.name();
678 if name.is_empty() {
679 return Err(Error::Build("device name cannot be empty".into()));
680 }
681 if self.specs.iter().any(|s| s.name() == name) {
682 return Err(Error::Build(format!("device `{name}` already defined")));
683 }
684 if let Spec::Resistor(r) = &spec
685 && (r.value == 0.0 || !r.value.is_finite())
686 {
687 return Err(Error::Build(format!(
690 "resistor `{}` cannot have zero resistance",
691 r.name
692 )));
693 }
694 self.specs.push(spec);
695 Ok(())
696 }
697
698 pub fn nodeset(&mut self, node: impl Into<String>, value: f64) {
700 self.nodesets
701 .push((node.into().to_ascii_lowercase(), value));
702 }
703
704 pub fn ic(&mut self, node: impl Into<String>, value: f64) {
707 self.ics.push((node.into().to_ascii_lowercase(), value));
708 }
709
710 pub(crate) fn set_res_temp(&mut self, name: &str, t: ResTemp) {
713 self.res_temp.insert(name.to_ascii_lowercase(), t);
714 }
715
716 pub(crate) fn set_dtemp(&mut self, name: &str, dtemp: f64) {
719 self.dtemp.insert(name.to_ascii_lowercase(), dtemp);
720 }
721
722 fn instance_temp(&self, name: &str, temp: Option<f64>, opts: &Options) -> f64 {
726 temp.unwrap_or_else(|| opts.temp + self.dtemp.get(name).copied().unwrap_or(0.0))
727 }
728
729 pub(crate) fn set_ic_given(&mut self, name: &str, given: crate::devices::IcGiven) {
732 self.ic_given.insert(name.to_ascii_lowercase(), given);
733 }
734}
735
736fn normalize(spec: &mut Spec) {
737 #[allow(clippy::ptr_arg)] fn lc(s: &mut String) {
739 s.make_ascii_lowercase();
740 }
741 match spec {
742 Spec::Resistor(s) => {
743 lc(&mut s.name);
744 s.nodes.iter_mut().for_each(lc);
745 }
746 Spec::Capacitor(s) => {
747 lc(&mut s.name);
748 s.nodes.iter_mut().for_each(lc);
749 }
750 Spec::Inductor(s) => {
751 lc(&mut s.name);
752 s.nodes.iter_mut().for_each(lc);
753 }
754 Spec::Mutual(s) => {
755 lc(&mut s.name);
756 lc(&mut s.l1);
757 lc(&mut s.l2);
758 }
759 Spec::Vsource(s) => {
760 lc(&mut s.name);
761 s.nodes.iter_mut().for_each(lc);
762 }
763 Spec::Isource(s) => {
764 lc(&mut s.name);
765 s.nodes.iter_mut().for_each(lc);
766 }
767 Spec::Vcvs(s) => {
768 lc(&mut s.name);
769 s.nodes.iter_mut().for_each(lc);
770 }
771 Spec::Vccs(s) => {
772 lc(&mut s.name);
773 s.nodes.iter_mut().for_each(lc);
774 }
775 Spec::Cccs(s) => {
776 lc(&mut s.name);
777 s.nodes.iter_mut().for_each(lc);
778 lc(&mut s.ctrl);
779 }
780 Spec::Ccvs(s) => {
781 lc(&mut s.name);
782 s.nodes.iter_mut().for_each(lc);
783 lc(&mut s.ctrl);
784 }
785 Spec::Diode(s) => {
786 lc(&mut s.name);
787 s.nodes.iter_mut().for_each(lc);
788 }
789 Spec::Bjt(s) => {
790 lc(&mut s.name);
791 s.nodes.iter_mut().for_each(lc);
792 }
793 Spec::Mos1(s) => {
794 lc(&mut s.name);
795 s.nodes.iter_mut().for_each(lc);
796 }
797 Spec::Mos2(s) => {
798 lc(&mut s.name);
799 s.nodes.iter_mut().for_each(lc);
800 }
801 Spec::Mos3(s) => {
802 lc(&mut s.name);
803 s.nodes.iter_mut().for_each(lc);
804 }
805 Spec::Mos6(s) => {
806 lc(&mut s.name);
807 s.nodes.iter_mut().for_each(lc);
808 }
809 Spec::Bsim1(s) => {
810 lc(&mut s.name);
811 s.nodes.iter_mut().for_each(lc);
812 }
813 Spec::Bsim2(s) => {
814 lc(&mut s.name);
815 s.nodes.iter_mut().for_each(lc);
816 }
817 Spec::Bsim3(s) => {
818 lc(&mut s.name);
819 s.nodes.iter_mut().for_each(lc);
820 }
821 Spec::Jfet(s) => {
822 lc(&mut s.name);
823 s.nodes.iter_mut().for_each(lc);
824 }
825 Spec::Mes(s) => {
826 lc(&mut s.name);
827 s.nodes.iter_mut().for_each(lc);
828 }
829 Spec::Ltra(s) => {
830 lc(&mut s.name);
831 s.nodes.iter_mut().for_each(lc);
832 }
833 Spec::Tra(s) => {
834 lc(&mut s.name);
835 s.nodes.iter_mut().for_each(lc);
836 }
837 Spec::SwitchV(s) => {
838 lc(&mut s.name);
839 s.nodes.iter_mut().for_each(lc);
840 }
841 Spec::SwitchI(s) => {
842 lc(&mut s.name);
843 s.nodes.iter_mut().for_each(lc);
844 lc(&mut s.ctrl);
845 }
846 Spec::Asrc(s) => {
847 lc(&mut s.name);
848 s.nodes.iter_mut().for_each(lc);
849 s.expr.visit_refs_mut(&mut |n| lc(n), &mut |d| lc(d));
850 }
851 }
852}
853
854pub(crate) struct Vars {
858 pub names: Vec<String>,
859 pub kinds: Vec<VarKind>,
860}
861
862pub(crate) fn saved_node(name: &str) -> bool {
868 const HIDDEN: [&str; 6] = [
869 "#internal",
870 "#source",
871 "#drain",
872 "#collector",
873 "#emitter",
874 "#base",
875 ];
876 !HIDDEN.iter().any(|h| name.contains(h))
877}
878
879#[derive(Clone, Copy, Debug, PartialEq, Eq)]
880pub(crate) enum VarKind {
881 Ground,
882 Node,
883 Branch,
884}
885
886impl Vars {
887 fn new() -> Self {
888 Vars {
889 names: vec!["0".into()],
890 kinds: vec![VarKind::Ground],
891 }
892 }
893
894 pub fn len(&self) -> usize {
895 self.names.len()
896 }
897
898 fn push(&mut self, name: String, kind: VarKind) -> Var {
899 self.names.push(name);
900 self.kinds.push(kind);
901 self.names.len() - 1
902 }
903}
904
905#[derive(Clone, Debug)]
910pub(crate) struct PortInfo {
911 pub name: String,
912 pub num: u32,
913 pub z0: f64,
914 pub pos: Var,
915 pub neg: Var,
916 pub br: Var,
917}
918
919pub(crate) struct Built {
920 pub vars: Vars,
921 pub devices: Vec<Box<dyn crate::devices::Device>>,
922 pub names: Vec<String>,
925 pub nodesets: Vec<(Var, f64)>,
926 pub ics: Vec<(Var, f64)>,
927 pub sources: HashMap<String, (usize, bool)>,
930 pub ports: Vec<PortInfo>,
932 pub num_states: usize,
934 #[cfg_attr(not(feature = "parallel"), allow(dead_code))]
939 pub state_ranges: Vec<(usize, usize)>,
940 pub notes: Vec<String>,
942 pub warm: crate::session::WarmSlot,
944}
945
946impl Circuit {
947 pub(crate) fn build(&self, opts: &Options) -> Result<Built, Error> {
950 use crate::devices::*;
951
952 let mut vars = Vars::new();
953 let mut node_ids: HashMap<String, Var> = HashMap::new();
954 node_ids.insert("0".into(), 0);
955 let node = |vars: &mut Vars, node_ids: &mut HashMap<String, Var>, name: &str| -> Var {
956 *node_ids
957 .entry(name.to_string())
958 .or_insert_with(|| vars.push(name.to_string(), VarKind::Node))
959 };
960
961 let mut branches: HashMap<String, Var> = HashMap::new();
966 let mut st = crate::state::StateAlloc::new();
967 let mut state_base: Vec<usize> = Vec::with_capacity(self.specs.len());
968 let mut state_ranges: Vec<(usize, usize)> = Vec::with_capacity(self.specs.len());
969 let mut inductors: HashMap<String, (usize, f64)> = HashMap::new(); for spec in &self.specs {
971 let first = st.total();
972 state_base.push(match spec {
973 Spec::Bjt(_) => st.alloc(crate::bjt::BJT_NUM_STATES),
974 Spec::Mos1(_) => st.alloc(crate::mos1::MOS1_NUM_STATES),
975 Spec::Mos2(_) => st.alloc(crate::mos2::MOS2_NUM_STATES),
976 Spec::Mos3(_) => st.alloc(crate::mos3::MOS3_NUM_STATES),
977 Spec::Mos6(_) => st.alloc(crate::mos6::MOS6_NUM_STATES),
978 Spec::Bsim1(_) => st.alloc(crate::bsim1::BSIM1_NUM_STATES),
979 Spec::Bsim2(_) => st.alloc(crate::bsim2::BSIM2_NUM_STATES),
980 Spec::Bsim3(_) => st.alloc(crate::bsim3::BSIM3_NUM_STATES),
981 Spec::Capacitor(_) => st.alloc(2),
982 Spec::Inductor(s) => {
983 let flux = st.alloc(2);
984 inductors.insert(s.name.clone(), (flux, s.value));
985 flux
986 }
987 Spec::Diode(_) => st.alloc(5),
988 Spec::Jfet(_) => st.alloc(crate::jfet::FET3_NUM_STATES),
989 Spec::Mes(_) => st.alloc(crate::mes::MES_NUM_STATES),
990 Spec::SwitchV(_) | Spec::SwitchI(_) => st.alloc(crate::switch::SW_NUM_STATES),
991 Spec::Asrc(s) => st.alloc(crate::asrc::num_states(&s.expr)),
992 _ => 0,
993 });
994 state_ranges.push((first, st.total()));
995 let node_names: &[String] = match spec {
996 Spec::Bjt(s) => &s.nodes,
997 Spec::Mos1(s) => &s.nodes,
998 Spec::Mos2(s) => &s.nodes,
999 Spec::Mos3(s) => &s.nodes,
1000 Spec::Mos6(s) => &s.nodes,
1001 Spec::Bsim1(s) => &s.nodes,
1002 Spec::Bsim2(s) => &s.nodes,
1003 Spec::Bsim3(s) => &s.nodes,
1004 Spec::Resistor(s) => &s.nodes,
1005 Spec::Capacitor(s) => &s.nodes,
1006 Spec::Inductor(s) => &s.nodes,
1007 Spec::Mutual(_) => &[],
1008 Spec::Vsource(s) => &s.nodes,
1009 Spec::Isource(s) => &s.nodes,
1010 Spec::Vcvs(s) => &s.nodes,
1011 Spec::Vccs(s) => &s.nodes,
1012 Spec::Cccs(s) => &s.nodes,
1013 Spec::Ccvs(s) => &s.nodes,
1014 Spec::Diode(s) => &s.nodes,
1015 Spec::Jfet(s) => &s.nodes,
1016 Spec::Mes(s) => &s.nodes,
1017 Spec::Ltra(s) => &s.nodes,
1018 Spec::Tra(s) => &s.nodes,
1019 Spec::SwitchV(s) => &s.nodes,
1020 Spec::SwitchI(s) => &s.nodes,
1021 Spec::Asrc(s) => &s.nodes,
1022 };
1023 for n in node_names {
1024 node(&mut vars, &mut node_ids, n);
1025 }
1026 if let Spec::Asrc(s) = spec {
1030 let mut refs = Vec::new();
1031 let mut e = s.expr.clone();
1032 e.visit_refs_mut(&mut |n| refs.push(n.clone()), &mut |_| {});
1033 for n in &refs {
1034 node(&mut vars, &mut node_ids, n);
1035 }
1036 if s.kind == dune_netlist::ir::SourceKind::Voltage {
1037 let br = vars.push(s.name.clone(), VarKind::Branch);
1038 branches.insert(s.name.clone(), br);
1039 }
1040 }
1041 match spec {
1042 Spec::Vsource(s) => {
1043 let br = vars.push(s.name.clone(), VarKind::Branch);
1044 branches.insert(s.name.clone(), br);
1045 if s.port.is_some_and(|p| p.is_port()) {
1049 node(&mut vars, &mut node_ids, &format!("{}#res", s.name));
1050 }
1051 }
1052 Spec::Inductor(s) => {
1053 let br = vars.push(s.name.clone(), VarKind::Branch);
1054 branches.insert(s.name.clone(), br);
1055 }
1056 Spec::Vcvs(s) => {
1057 let br = vars.push(s.name.clone(), VarKind::Branch);
1058 branches.insert(s.name.clone(), br);
1059 }
1060 Spec::Ccvs(s) => {
1061 let br = vars.push(s.name.clone(), VarKind::Branch);
1062 branches.insert(s.name.clone(), br);
1063 }
1064 Spec::Ltra(s) => {
1068 node(&mut vars, &mut node_ids, &format!("{}#i1", s.name));
1069 node(&mut vars, &mut node_ids, &format!("{}#i2", s.name));
1070 }
1071 Spec::Tra(s) => {
1074 for suffix in ["i1", "i2", "int1", "int2"] {
1075 node(&mut vars, &mut node_ids, &format!("{}#{suffix}", s.name));
1076 }
1077 }
1078 Spec::Diode(s) if s.model.rs != 0.0 => {
1081 node(&mut vars, &mut node_ids, &format!("{}#internal", s.name));
1082 }
1083 Spec::Jfet(s) => {
1086 if s.model.rs != 0.0 {
1087 node(&mut vars, &mut node_ids, &format!("{}#source", s.name));
1088 }
1089 if s.model.rd != 0.0 {
1090 node(&mut vars, &mut node_ids, &format!("{}#drain", s.name));
1091 }
1092 }
1093 Spec::Mes(s) => {
1094 if s.model.rs != 0.0 {
1095 node(&mut vars, &mut node_ids, &format!("{}#source", s.name));
1096 }
1097 if s.model.rd != 0.0 {
1098 node(&mut vars, &mut node_ids, &format!("{}#drain", s.name));
1099 }
1100 }
1101 Spec::Bjt(s) => {
1104 if s.model.rc != 0.0 {
1105 node(&mut vars, &mut node_ids, &format!("{}#collector", s.name));
1106 }
1107 if s.model.rb != 0.0 {
1108 node(&mut vars, &mut node_ids, &format!("{}#base", s.name));
1109 }
1110 if s.model.re != 0.0 {
1111 node(&mut vars, &mut node_ids, &format!("{}#emitter", s.name));
1112 }
1113 }
1114 Spec::Mos1(s) => {
1117 if s.model.needs_prime(s.nrd) {
1118 node(&mut vars, &mut node_ids, &format!("{}#drain", s.name));
1119 }
1120 if s.model.needs_prime(s.nrs) {
1121 node(&mut vars, &mut node_ids, &format!("{}#source", s.name));
1122 }
1123 }
1124 Spec::Mos2(s) => {
1125 if s.model.needs_prime(s.nrd) {
1126 node(
1127 &mut vars,
1128 &mut node_ids,
1129 &format!("{}#internal#drain", s.name),
1130 );
1131 }
1132 if s.model.needs_prime(s.nrs) {
1133 node(
1134 &mut vars,
1135 &mut node_ids,
1136 &format!("{}#internal#source", s.name),
1137 );
1138 }
1139 }
1140 Spec::Mos3(s) => {
1141 if s.model.needs_prime(s.nrd) {
1142 node(
1143 &mut vars,
1144 &mut node_ids,
1145 &format!("{}#internal#drain", s.name),
1146 );
1147 }
1148 if s.model.needs_prime(s.nrs) {
1149 node(
1150 &mut vars,
1151 &mut node_ids,
1152 &format!("{}#internal#source", s.name),
1153 );
1154 }
1155 }
1156 Spec::Mos6(s) => {
1158 if s.model.needs_prime(s.nrd) {
1159 node(&mut vars, &mut node_ids, &format!("{}#drain", s.name));
1160 }
1161 if s.model.needs_prime(s.nrs) {
1162 node(&mut vars, &mut node_ids, &format!("{}#source", s.name));
1163 }
1164 }
1165 Spec::Bsim1(s) => {
1167 if s.model.needs_prime(s.nrd) {
1168 node(&mut vars, &mut node_ids, &format!("{}#drain", s.name));
1169 }
1170 if s.model.needs_prime(s.nrs) {
1171 node(&mut vars, &mut node_ids, &format!("{}#source", s.name));
1172 }
1173 }
1174 Spec::Bsim2(s) => {
1175 if s.model.needs_prime(s.nrd) {
1176 node(&mut vars, &mut node_ids, &format!("{}#drain", s.name));
1177 }
1178 if s.model.needs_prime(s.nrs) {
1179 node(&mut vars, &mut node_ids, &format!("{}#source", s.name));
1180 }
1181 }
1182 Spec::Bsim3(s) => {
1184 if s.model.needs_prime(s.nrd) {
1185 node(&mut vars, &mut node_ids, &format!("{}#drain", s.name));
1186 }
1187 if s.model.needs_prime(s.nrs) {
1188 node(&mut vars, &mut node_ids, &format!("{}#source", s.name));
1189 }
1190 }
1191 _ => {}
1192 }
1193 }
1194 let num_states = st.total();
1195
1196 let mut devices: Vec<Box<dyn Device>> = Vec::new();
1198 let mut names: Vec<String> = Vec::new();
1199 let mut sources: HashMap<String, (usize, bool)> = HashMap::new();
1200 let mut ports: Vec<PortInfo> = Vec::new();
1201 let mut notes = Vec::new();
1202 let get = |node_ids: &HashMap<String, Var>, n: &str| node_ids[n];
1203 let mut bsim3_models: Vec<crate::bsim3::Bsim3Knots> = Vec::new();
1207 for (spec, &base) in self.specs.iter().zip(&state_base) {
1208 names.push(spec.name().to_string());
1209 match spec {
1210 Spec::Bjt(s) => {
1211 let col = get(&node_ids, &s.nodes[0]);
1212 let bse = get(&node_ids, &s.nodes[1]);
1213 let emi = get(&node_ids, &s.nodes[2]);
1214 let sub = get(&node_ids, &s.nodes[3]);
1215 let prime = |rz: f64, suffix: &str, outer: Var| {
1216 if rz != 0.0 {
1217 node_ids[&format!("{}#{suffix}", s.name)]
1218 } else {
1219 outer
1220 }
1221 };
1222 let primes = [
1223 prime(s.model.rc, "collector", col),
1224 prime(s.model.rb, "base", bse),
1225 prime(s.model.re, "emitter", emi),
1226 ];
1227 let temp = self.instance_temp(&s.name, s.temp, opts);
1228 let bt = crate::bjt::BjtTemp::new(&s.name, &s.model, temp, opts.tnom);
1229 notes.extend(bt.notes.iter().cloned());
1230 devices.push(Box::new(crate::bjt::BjtI::new(
1231 [col, bse, emi, sub],
1232 primes,
1233 bt,
1234 s.area,
1235 s.off,
1236 s.ic,
1237 base,
1238 )));
1239 }
1240 Spec::Mos1(s) => {
1241 let d = get(&node_ids, &s.nodes[0]);
1242 let gt = get(&node_ids, &s.nodes[1]);
1243 let so = get(&node_ids, &s.nodes[2]);
1244 let b = get(&node_ids, &s.nodes[3]);
1245 let dp = if s.model.needs_prime(s.nrd) {
1246 node_ids[&format!("{}#drain", s.name)]
1247 } else {
1248 d
1249 };
1250 let sp = if s.model.needs_prime(s.nrs) {
1251 node_ids[&format!("{}#source", s.name)]
1252 } else {
1253 so
1254 };
1255 let geom = crate::mos1::MosGeom {
1256 l: s.l.unwrap_or(opts.defl),
1257 w: s.w.unwrap_or(opts.defw),
1258 ad: s.ad.unwrap_or(opts.defad),
1259 as_: s.as_.unwrap_or(opts.defas),
1260 pd: s.pd,
1261 ps: s.ps,
1262 nrd: s.nrd,
1263 nrs: s.nrs,
1264 };
1265 let temp = self.instance_temp(&s.name, s.temp, opts);
1266 let mt = crate::mos1::Mos1Temp::new(&s.name, &s.model, &geom, temp, opts.tnom)
1267 .map_err(Error::Build)?;
1268 notes.extend(mt.notes.iter().cloned());
1269 devices.push(Box::new(crate::mos1::Mos1I::new(
1270 [d, gt, so, b],
1271 [dp, sp],
1272 mt,
1273 geom,
1274 s.off,
1275 s.ic,
1276 base,
1277 )));
1278 }
1279 Spec::Mos2(s) => {
1280 let d = get(&node_ids, &s.nodes[0]);
1281 let gt = get(&node_ids, &s.nodes[1]);
1282 let so = get(&node_ids, &s.nodes[2]);
1283 let b = get(&node_ids, &s.nodes[3]);
1284 let dp = if s.model.needs_prime(s.nrd) {
1285 node_ids[&format!("{}#internal#drain", s.name)]
1286 } else {
1287 d
1288 };
1289 let sp = if s.model.needs_prime(s.nrs) {
1290 node_ids[&format!("{}#internal#source", s.name)]
1291 } else {
1292 so
1293 };
1294 let geom = crate::mos1::MosGeom {
1295 l: s.l.unwrap_or(opts.defl),
1296 w: s.w.unwrap_or(opts.defw),
1297 ad: s.ad.unwrap_or(opts.defad),
1298 as_: s.as_.unwrap_or(opts.defas),
1299 pd: s.pd,
1300 ps: s.ps,
1301 nrd: s.nrd,
1302 nrs: s.nrs,
1303 };
1304 let temp = self.instance_temp(&s.name, s.temp, opts);
1305 let mt = crate::mos2::Mos2Temp::new(&s.name, &s.model, &geom, temp, opts.tnom)
1306 .map_err(Error::Build)?;
1307 notes.extend(mt.notes.iter().cloned());
1308 devices.push(Box::new(crate::mos2::Mos2I::new(
1309 [d, gt, so, b],
1310 [dp, sp],
1311 mt,
1312 geom,
1313 s.off,
1314 s.ic,
1315 base,
1316 )));
1317 }
1318 Spec::Mos3(s) => {
1319 let d = get(&node_ids, &s.nodes[0]);
1320 let gt = get(&node_ids, &s.nodes[1]);
1321 let so = get(&node_ids, &s.nodes[2]);
1322 let b = get(&node_ids, &s.nodes[3]);
1323 let dp = if s.model.needs_prime(s.nrd) {
1324 node_ids[&format!("{}#internal#drain", s.name)]
1325 } else {
1326 d
1327 };
1328 let sp = if s.model.needs_prime(s.nrs) {
1329 node_ids[&format!("{}#internal#source", s.name)]
1330 } else {
1331 so
1332 };
1333 let geom = crate::mos1::MosGeom {
1334 l: s.l.unwrap_or(opts.defl),
1335 w: s.w.unwrap_or(opts.defw),
1336 ad: s.ad.unwrap_or(opts.defad),
1337 as_: s.as_.unwrap_or(opts.defas),
1338 pd: s.pd,
1339 ps: s.ps,
1340 nrd: s.nrd,
1341 nrs: s.nrs,
1342 };
1343 let temp = self.instance_temp(&s.name, s.temp, opts);
1344 let mt = crate::mos3::Mos3Temp::new(&s.name, &s.model, &geom, temp, opts.tnom)
1345 .map_err(Error::Build)?;
1346 devices.push(Box::new(crate::mos3::Mos3I::new(
1347 [d, gt, so, b],
1348 [dp, sp],
1349 mt,
1350 geom,
1351 s.off,
1352 s.ic,
1353 base,
1354 )));
1355 }
1356 Spec::Mos6(s) => {
1357 let d = get(&node_ids, &s.nodes[0]);
1358 let gt = get(&node_ids, &s.nodes[1]);
1359 let so = get(&node_ids, &s.nodes[2]);
1360 let b = get(&node_ids, &s.nodes[3]);
1361 let dp = if s.model.needs_prime(s.nrd) {
1362 node_ids[&format!("{}#drain", s.name)]
1363 } else {
1364 d
1365 };
1366 let sp = if s.model.needs_prime(s.nrs) {
1367 node_ids[&format!("{}#source", s.name)]
1368 } else {
1369 so
1370 };
1371 let geom = crate::mos1::MosGeom {
1373 l: s.l.unwrap_or(opts.defl),
1374 w: s.w.unwrap_or(opts.defw),
1375 ad: s.ad.unwrap_or(opts.defad),
1376 as_: s.as_.unwrap_or(opts.defas),
1377 pd: s.pd,
1378 ps: s.ps,
1379 nrd: if s.nrd == 0.0 { 1.0 } else { s.nrd },
1380 nrs: if s.nrs == 0.0 { 1.0 } else { s.nrs },
1381 };
1382 let temp = self.instance_temp(&s.name, s.temp, opts);
1383 let mt = crate::mos6::Mos6Temp::new(&s.name, &s.model, &geom, temp, opts.tnom)
1384 .map_err(Error::Build)?;
1385 notes.extend(mt.notes.iter().cloned());
1386 devices.push(Box::new(crate::mos6::Mos6I::new(
1387 [d, gt, so, b],
1388 [dp, sp],
1389 mt,
1390 geom,
1391 s.off,
1392 s.ic,
1393 base,
1394 )));
1395 }
1396 Spec::Bsim1(s) => {
1397 let d = get(&node_ids, &s.nodes[0]);
1398 let gt = get(&node_ids, &s.nodes[1]);
1399 let so = get(&node_ids, &s.nodes[2]);
1400 let b = get(&node_ids, &s.nodes[3]);
1401 let dp = if s.model.needs_prime(s.nrd) {
1402 node_ids[&format!("{}#drain", s.name)]
1403 } else {
1404 d
1405 };
1406 let sp = if s.model.needs_prime(s.nrs) {
1407 node_ids[&format!("{}#source", s.name)]
1408 } else {
1409 so
1410 };
1411 let geom = crate::mos1::MosGeom {
1414 l: s.l.unwrap_or(5e-6),
1415 w: s.w.unwrap_or(5e-6),
1416 ad: s.ad.unwrap_or(0.0),
1417 as_: s.as_.unwrap_or(0.0),
1418 pd: s.pd,
1419 ps: s.ps,
1420 nrd: s.nrd,
1421 nrs: s.nrs,
1422 };
1423 let sz = crate::bsim1::Bsim1Size::new(&s.name, &s.model, &geom)
1424 .map_err(Error::Build)?;
1425 devices.push(Box::new(crate::bsim1::Bsim1I::new(
1426 [d, gt, so, b],
1427 [dp, sp],
1428 sz,
1429 geom,
1430 s.off,
1431 s.ic,
1432 base,
1433 )));
1434 }
1435 Spec::Bsim2(s) => {
1436 let d = get(&node_ids, &s.nodes[0]);
1437 let gt = get(&node_ids, &s.nodes[1]);
1438 let so = get(&node_ids, &s.nodes[2]);
1439 let b = get(&node_ids, &s.nodes[3]);
1440 let dp = if s.model.needs_prime(s.nrd) {
1441 node_ids[&format!("{}#drain", s.name)]
1442 } else {
1443 d
1444 };
1445 let sp = if s.model.needs_prime(s.nrs) {
1446 node_ids[&format!("{}#source", s.name)]
1447 } else {
1448 so
1449 };
1450 let geom = crate::mos1::MosGeom {
1453 l: s.l.unwrap_or(5e-6),
1454 w: s.w.unwrap_or(5e-6),
1455 ad: s.ad.unwrap_or(0.0),
1456 as_: s.as_.unwrap_or(0.0),
1457 pd: s.pd,
1458 ps: s.ps,
1459 nrd: s.nrd,
1460 nrs: s.nrs,
1461 };
1462 let sz = crate::bsim2::Bsim2Size::new(&s.name, &s.model, &geom)
1463 .map_err(Error::Build)?;
1464 devices.push(Box::new(crate::bsim2::Bsim2I::new(
1465 [d, gt, so, b],
1466 [dp, sp],
1467 sz,
1468 geom,
1469 s.off,
1470 s.ic,
1471 base,
1472 )));
1473 }
1474 Spec::Bsim3(s) => {
1475 let d = get(&node_ids, &s.nodes[0]);
1476 let gt = get(&node_ids, &s.nodes[1]);
1477 let so = get(&node_ids, &s.nodes[2]);
1478 let b = get(&node_ids, &s.nodes[3]);
1479 let dp = if s.model.needs_prime(s.nrd) {
1480 node_ids[&format!("{}#drain", s.name)]
1481 } else {
1482 d
1483 };
1484 let sp = if s.model.needs_prime(s.nrs) {
1485 node_ids[&format!("{}#source", s.name)]
1486 } else {
1487 so
1488 };
1489 let geom = crate::bsim3::Bsim3Geom {
1490 l: s.l.unwrap_or(5e-6),
1491 w: s.w.unwrap_or(5e-6),
1492 ad: s.ad,
1493 as_: s.as_,
1494 pd: s.pd,
1495 ps: s.ps,
1496 nrd: s.nrd,
1497 nrs: s.nrs,
1498 m: s.m,
1499 delvto: s.delvto,
1500 mulu0: s.mulu0,
1501 };
1502 let (model, mt, pp) = crate::bsim3::Bsim3Knots::resolve(
1503 &mut bsim3_models,
1504 &s.name,
1505 &s.model,
1506 geom.l,
1507 geom.w,
1508 opts.temp,
1509 opts.tnom,
1510 &mut notes,
1511 )
1512 .map_err(Error::Build)?;
1513 devices.push(Box::new(crate::bsim3::Bsim3I::new(
1514 [d, gt, so, b],
1515 [dp, sp],
1516 model,
1517 mt,
1518 pp,
1519 geom,
1520 s.off,
1521 s.ic,
1522 base,
1523 )));
1524 }
1525 Spec::Resistor(s) => {
1526 let rt = self.res_temp.get(&s.name).copied().unwrap_or_default();
1527 devices.push(Box::new(ResistorI::with_temp(
1528 s.value,
1529 rt,
1530 opts,
1531 get(&node_ids, &s.nodes[0]),
1532 get(&node_ids, &s.nodes[1]),
1533 )));
1534 }
1535 Spec::Capacitor(s) => {
1536 devices.push(Box::new(CapacitorI::new(
1537 s.value,
1538 s.ic,
1539 get(&node_ids, &s.nodes[0]),
1540 get(&node_ids, &s.nodes[1]),
1541 base,
1542 )));
1543 }
1544 Spec::Inductor(s) => {
1545 devices.push(Box::new(InductorI::new(
1546 s.value,
1547 s.ic.unwrap_or(0.0),
1548 get(&node_ids, &s.nodes[0]),
1549 get(&node_ids, &s.nodes[1]),
1550 branches[&s.name],
1551 base,
1552 )));
1553 }
1554 Spec::Mutual(s) => {
1555 for l in [&s.l1, &s.l2] {
1556 if !inductors.contains_key(l) {
1557 return Err(Error::Build(format!(
1558 "`{}`: coupled inductor `{l}` does not exist",
1559 s.name
1560 )));
1561 }
1562 }
1563 let (flux1, l1) = inductors[&s.l1];
1564 let (flux2, l2) = inductors[&s.l2];
1565 devices.push(Box::new(MutualI::new(
1567 s.k,
1568 (l1 * l2).abs().sqrt(),
1569 branches[&s.l1],
1570 branches[&s.l2],
1571 flux1,
1572 flux2,
1573 )));
1574 }
1575 Spec::Vsource(s) => {
1576 sources.insert(s.name.clone(), (devices.len(), true));
1577 let pos = get(&node_ids, &s.nodes[0]);
1578 let neg = get(&node_ids, &s.nodes[1]);
1579 let br = branches[&s.name];
1580 let noise = NoiseWave::from_wave(s.wave.as_ref(), opts, &s.name)?;
1581 let mut dev = VsourceI::new(s.dc, s.wave.clone(), s.ac, pos, neg, br)
1582 .with_disto(s.distof1, s.distof2)
1583 .with_noise(noise);
1584 if let Some(p) = s.port.filter(RfPort::is_port) {
1585 let res = get(&node_ids, &format!("{}#res", s.name));
1586 dev = dev.with_port(res, p.z0);
1587 ports.push(PortInfo {
1588 name: s.name.clone(),
1589 num: p.num,
1590 z0: p.z0,
1591 pos,
1592 neg,
1593 br,
1594 });
1595 }
1596 devices.push(Box::new(dev));
1597 }
1598 Spec::Isource(s) => {
1599 sources.insert(s.name.clone(), (devices.len(), false));
1600 let noise = NoiseWave::from_wave(s.wave.as_ref(), opts, &s.name)?;
1601 devices.push(Box::new(
1602 IsourceI::new(
1603 s.dc,
1604 s.wave.clone(),
1605 s.ac,
1606 get(&node_ids, &s.nodes[0]),
1607 get(&node_ids, &s.nodes[1]),
1608 )
1609 .with_disto(s.distof1, s.distof2)
1610 .with_noise(noise),
1611 ));
1612 }
1613 Spec::Vcvs(s) => {
1614 let n = [
1615 get(&node_ids, &s.nodes[0]),
1616 get(&node_ids, &s.nodes[1]),
1617 get(&node_ids, &s.nodes[2]),
1618 get(&node_ids, &s.nodes[3]),
1619 ];
1620 devices.push(Box::new(VcvsI::new(s.gain, n, branches[&s.name])));
1621 }
1622 Spec::Vccs(s) => {
1623 let n = [
1624 get(&node_ids, &s.nodes[0]),
1625 get(&node_ids, &s.nodes[1]),
1626 get(&node_ids, &s.nodes[2]),
1627 get(&node_ids, &s.nodes[3]),
1628 ];
1629 devices.push(Box::new(VccsI::new(s.gain, n)));
1630 }
1631 Spec::Cccs(s) => {
1632 let ctrl = ctrl_branch(&branches, &s.name, &s.ctrl)?;
1633 devices.push(Box::new(CccsI::new(
1634 s.gain,
1635 get(&node_ids, &s.nodes[0]),
1636 get(&node_ids, &s.nodes[1]),
1637 ctrl,
1638 )));
1639 }
1640 Spec::Asrc(s) => {
1641 let pos = get(&node_ids, &s.nodes[0]);
1642 let neg = get(&node_ids, &s.nodes[1]);
1643 let voltage = s.kind == dune_netlist::ir::SourceKind::Voltage;
1644 if voltage && pos == neg {
1647 return Err(Error::Build(format!(
1648 "`{}`: voltage B source is shorted (both nodes `{}`)",
1649 s.name, s.nodes[0]
1650 )));
1651 }
1652 let tree = crate::asrc::Tree::new(&s.expr);
1653 let mut cols = Vec::with_capacity(tree.vars.len());
1654 for v in &tree.vars {
1655 cols.push(match v {
1656 crate::asrc::VarRef::Node(n) => get(&node_ids, n),
1657 crate::asrc::VarRef::Branch(d) => {
1660 branches.get(d).copied().ok_or_else(|| {
1661 Error::Build(format!(
1662 "`{}`: unknown controlling source `{d}`",
1663 s.name
1664 ))
1665 })?
1666 }
1667 });
1668 }
1669 let br = if voltage { branches[&s.name] } else { 0 };
1670 devices.push(Box::new(crate::asrc::AsrcI::new(
1671 s.kind, pos, neg, br, tree, cols, base,
1672 )));
1673 }
1674 Spec::Ccvs(s) => {
1675 let ctrl = ctrl_branch(&branches, &s.name, &s.ctrl)?;
1676 devices.push(Box::new(CcvsI::new(
1677 s.gain,
1678 get(&node_ids, &s.nodes[0]),
1679 get(&node_ids, &s.nodes[1]),
1680 branches[&s.name],
1681 ctrl,
1682 )));
1683 }
1684 Spec::Diode(s) => {
1685 let pos = get(&node_ids, &s.nodes[0]);
1686 let neg = get(&node_ids, &s.nodes[1]);
1687 let pos_prime = if s.model.rs != 0.0 {
1688 get(&node_ids, &format!("{}#internal", s.name))
1689 } else {
1690 pos
1691 };
1692 let temp = self.instance_temp(&s.name, s.temp, opts);
1693 let t = DiodeTemp::new(
1694 &s.name,
1695 &s.model,
1696 s.area,
1697 1.0,
1698 temp,
1699 opts.tnom,
1700 opts.reltol,
1701 );
1702 notes.extend(t.notes.iter().cloned());
1703 devices.push(Box::new(crate::diode::DiodeI::new(
1704 pos,
1705 neg,
1706 pos_prime,
1707 t,
1708 s.area,
1709 s.off,
1710 s.ic.unwrap_or(0.0),
1711 base,
1712 crate::diode::DiodeSensBase {
1713 name: s.name.clone(),
1714 model: s.model.clone(),
1715 temp,
1716 m: 1.0,
1717 default_tnom: opts.tnom,
1718 reltol: opts.reltol,
1719 },
1720 )));
1721 }
1722 Spec::Jfet(s) => {
1723 let (nodes, primes) =
1724 fet3_vars(&node_ids, &s.name, &s.nodes, s.model.rd, s.model.rs);
1725 let temp = self.instance_temp(&s.name, s.temp, opts);
1726 let t = crate::jfet::JfetTemp::new(&s.name, &s.model, temp, opts.tnom);
1727 notes.extend(t.notes.iter().cloned());
1728 devices.push(Box::new(crate::jfet::JfetI::new(
1729 nodes, primes, t, s.area, s.off, s.ic, base,
1730 )));
1731 }
1732 Spec::Mes(s) => {
1733 let (nodes, primes) =
1734 fet3_vars(&node_ids, &s.name, &s.nodes, s.model.rd, s.model.rs);
1735 let t = crate::mes::MesTemp::new(&s.model);
1736 devices.push(Box::new(crate::mes::MesI::new(
1737 nodes, primes, t, s.area, s.off, s.ic, base,
1738 )));
1739 }
1740 Spec::Ltra(s) => {
1741 let n = [
1742 get(&node_ids, &s.nodes[0]),
1743 get(&node_ids, &s.nodes[1]),
1744 get(&node_ids, &s.nodes[2]),
1745 get(&node_ids, &s.nodes[3]),
1746 ];
1747 let br = [
1748 get(&node_ids, &format!("{}#i1", s.name)),
1749 get(&node_ids, &format!("{}#i2", s.name)),
1750 ];
1751 let mut p =
1752 crate::ltra::LtraParams::new(&s.name, &s.model, opts.reltol, opts.abstol)
1753 .map_err(Error::Build)?;
1754 if opts.trytocompact {
1755 p.try_to_compact();
1756 }
1757 if opts.compat == crate::options::Compat::Dune {
1758 p.default_linear();
1759 }
1760 notes.extend(p.notes.iter().cloned());
1761 devices.push(Box::new(
1762 crate::ltra::LtraI::new(p, n, br)
1763 .with_fit(opts.ltra_fit)
1764 .with_slope_floor(opts.ltra_slope_rate().is_some()),
1765 ));
1766 }
1767 Spec::Tra(s) => {
1768 let n = [
1769 get(&node_ids, &s.nodes[0]),
1770 get(&node_ids, &s.nodes[1]),
1771 get(&node_ids, &s.nodes[2]),
1772 get(&node_ids, &s.nodes[3]),
1773 ];
1774 let v = |suffix: &str| get(&node_ids, &format!("{}#{suffix}", s.name));
1775 let p = crate::tra::TraParams::new(&s.name, s.z0, s.td, s.f, s.nl, s.ic)
1776 .map_err(Error::Build)?;
1777 devices.push(Box::new(crate::tra::TraI::new(
1778 p,
1779 n,
1780 [v("i1"), v("i2")],
1781 [v("int1"), v("int2")],
1782 )));
1783 }
1784 Spec::SwitchV(s) => {
1785 let m = &s.model;
1786 let p = crate::switch::SwitchParams::new(m.vt, m.vh, m.ron, m.roff, opts.gmin);
1787 let ctrl = crate::switch::Control::Voltage {
1788 pos: get(&node_ids, &s.nodes[2]),
1789 neg: get(&node_ids, &s.nodes[3]),
1790 };
1791 devices.push(Box::new(crate::switch::SwitchInst::new(
1792 p,
1793 get(&node_ids, &s.nodes[0]),
1794 get(&node_ids, &s.nodes[1]),
1795 ctrl,
1796 s.on,
1797 base,
1798 )));
1799 }
1800 Spec::SwitchI(s) => {
1801 let branch = ctrl_branch(&branches, &s.name, &s.ctrl)?;
1803 let m = &s.model;
1804 let p = crate::switch::SwitchParams::new(m.it, m.ih, m.ron, m.roff, opts.gmin);
1805 devices.push(Box::new(crate::switch::SwitchInst::new(
1806 p,
1807 get(&node_ids, &s.nodes[0]),
1808 get(&node_ids, &s.nodes[1]),
1809 crate::switch::Control::Current { branch },
1810 s.on,
1811 base,
1812 )));
1813 }
1814 }
1815 }
1816
1817 for (spec, dev) in self.specs.iter().zip(devices.iter_mut()) {
1819 if let Some(&g) = self.ic_given.get(spec.name()) {
1820 dev.set_ic_given(g);
1821 }
1822 }
1823
1824 let mut nodesets = Vec::new();
1826 for (name, v) in &self.nodesets {
1827 match node_ids.get(name) {
1828 Some(&var) if var != 0 => nodesets.push((var, *v)),
1829 Some(_) => notes.push(".nodeset on ground ignored".to_string()),
1830 None => notes.push(format!(".nodeset names unknown node `{name}`")),
1831 }
1832 }
1833 let mut ics = Vec::new();
1834 for (name, v) in &self.ics {
1835 match node_ids.get(name) {
1836 Some(&var) if var != 0 => ics.push((var, *v)),
1837 Some(_) => notes.push(".ic on ground ignored".to_string()),
1838 None => notes.push(format!(".ic names unknown node `{name}`")),
1839 }
1840 }
1841
1842 let ports = check_ports(ports)?;
1845 Ok(Built {
1846 vars,
1847 devices,
1848 names,
1849 nodesets,
1850 ics,
1851 sources,
1852 ports,
1853 num_states,
1854 state_ranges,
1855 notes,
1856 warm: self.warm.share(),
1857 })
1858 }
1859}
1860
1861fn check_ports(mut ports: Vec<PortInfo>) -> Result<Vec<PortInfo>, Error> {
1868 let count = ports.len();
1869 let mut seen = vec![false; count + 1];
1870 for p in ports.iter().rev() {
1871 let n = p.num as usize;
1872 if n > count {
1873 return Err(Error::Build(format!("{}: incorrect port ordering", p.name)));
1874 }
1875 if std::mem::replace(&mut seen[n], true) {
1876 return Err(Error::Build(format!("{}: duplicate port Index", p.name)));
1877 }
1878 }
1879 ports.sort_by_key(|p| p.num);
1880 Ok(ports)
1881}
1882
1883fn fet3_vars(
1885 node_ids: &HashMap<String, Var>,
1886 name: &str,
1887 nodes: &[String; 3],
1888 rd: f64,
1889 rs: f64,
1890) -> ([Var; 3], [Var; 2]) {
1891 let d = node_ids[&nodes[0]];
1892 let g = node_ids[&nodes[1]];
1893 let s = node_ids[&nodes[2]];
1894 let dp = if rd != 0.0 {
1895 node_ids[&format!("{name}#drain")]
1896 } else {
1897 d
1898 };
1899 let sp = if rs != 0.0 {
1900 node_ids[&format!("{name}#source")]
1901 } else {
1902 s
1903 };
1904 ([d, g, s], [dp, sp])
1905}
1906
1907fn ctrl_branch(branches: &HashMap<String, Var>, name: &str, ctrl: &str) -> Result<Var, Error> {
1908 if !ctrl.starts_with('v') {
1909 return Err(Error::Build(format!(
1910 "`{name}`: controlling source `{ctrl}` must be a voltage source"
1911 )));
1912 }
1913 branches
1914 .get(ctrl)
1915 .copied()
1916 .ok_or_else(|| Error::Build(format!("`{name}`: controlling source `{ctrl}` not found")))
1917}