Skip to content

Commit

Permalink
subckts - default values working
Browse files Browse the repository at this point in the history
  • Loading branch information
Harnesser committed Sep 28, 2023
1 parent ef73e6d commit 4698882
Show file tree
Hide file tree
Showing 9 changed files with 76 additions and 60 deletions.
10 changes: 6 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
# Changelog

## [0.8.0] Subcircuits <<Unreleased>>
Allow nets to be named something other than integers. Subcircuits!
## [0.8.0] Subcircuits
Subcircuits! See the circuit `ngspice/param_fullwave_rectifier.spi`.

### Added
- Nodes can have names now, but integers still work.
- Subcircuits with are supported
- Basic Bracket Expression with 1 identifier supported:
* e.g. `cval={top_cval}`

### Changed
- Nodes can have names now, but integers still work

### Fixed


## [0.7.0] SPICE Deck Reader
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ In SPICE decks:
* Engineering notation is supported, e.g. `1k` is 1000
* A control block with a small list of commands between `.control` and `.endc` is
supported
* Subcircuits with limited bracket expressions are supported


Unsupported Stuff
-----------------
A _huge_ list of things are _not_ supported. Everything not listed above, which
includes:
* DC Sweeps are not supported
* Sub-circuits are not supported
* MOSFETs and other transistors are not supported
* Noise Analysis is not supported
* Circuit topology checks are not supported
Expand Down
10 changes: 2 additions & 8 deletions WHERE_I_LEFT_IT.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
Fixed parameter lookup, by the looks of it...
Fixed parameter default lookup. Clippy'd and added tests to make
sure that the parameters propagated properly.

This still doesn't work:

```spice
Xsystem1 IN_p gnd vp1 vn1 system cval=1uF
Xsystem2 IN_p gnd vp2 vn2 system ; FIXME cval=10uF
Xsystem3 IN_p gnd vp3 vn3 system cval=100uF
```
11 changes: 11 additions & 0 deletions doc/dev/devlog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@

This is a personal project. It does not have to be rigourously tested.

## 2023-09-28 Subcircuits with Parameters
This seems to work now, and even bracket expressions with a single identifier
are supported in the parameter overrides.

The circuit `param_fullwave_rectifier.spi` instantiates 3 versions of a
bridge rectifier subsystem. The capacitor value in the `rc_load` subcircuit
is parameterised, passed down from the instantiation of the subsystem at the
toplevel.

I'm quite pleased with this.

## 2023-09-23 Parameters - Numerical Literals
Refactored the `multi_` subcircuit example to have 3 instantiations of the
`system`. A system is:
Expand Down
6 changes: 3 additions & 3 deletions ngspice/param_fullwave_rectifier.spi
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ V3 vstack2 IN_p SIN(0 1 3e3) ; flip to differentiate between "multi_"
.subckt system sinp sinn soutp soutn cval=10uF
Xbridge sinp sinn midnode soutn bridge
Rd midnode soutp 1
Xload soutp soutn r_load cvalo={cval}
Xload soutp soutn rc_load cvalo={cval}
.ends

* Load
.subckt r_load in1 in2 cvalo=1nF
.subckt rc_load in1 in2 cvalo=1nF
* Split R so we have internal nodes
Rl1 in1 la 200
Rl2 la lb 300
Expand All @@ -41,7 +41,7 @@ V3 vstack2 IN_p SIN(0 1 3e3) ; flip to differentiate between "multi_"
.ends

Xsystem1 IN_p gnd vp1 vn1 system cval=1uF
Xsystem2 IN_p gnd vp2 vn2 system cval=10uF
Xsystem2 IN_p gnd vp2 vn2 system ; DEFAULT cval=10uF
Xsystem3 IN_p gnd vp3 vn3 system cval=100uF

.control
Expand Down
2 changes: 1 addition & 1 deletion src/bracket_expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::fmt;
macro_rules! trace {
($fmt:expr $(, $($arg:tt)*)?) => {
// uncomment the line below for tracing prints
println!(concat!("<bktexpr> ", $fmt), $($($arg)*)?);
//println!(concat!("<bktexpr> ", $fmt), $($($arg)*)?);
};
}

Expand Down
12 changes: 12 additions & 0 deletions src/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,4 +343,16 @@ impl Circuit {
}
}

/// Find a parameter value
///
/// `N` is small..
pub fn get_param_value(&self, name: &str) -> Option<f64> {
for p in &self.params {
if p.name == name {
return p.value
}
}
None
}

}
71 changes: 29 additions & 42 deletions src/expander.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ use crate::bracket_expression::{Expression};
macro_rules! trace {
($fmt:expr $(, $($arg:tt)*)?) => {
// uncomment the line below for tracing prints
println!(concat!("<expand> ", $fmt), $($($arg)*)?);
//println!(concat!("<expand> ", $fmt), $($($arg)*)?);
};
}

Expand All @@ -71,9 +71,9 @@ pub fn expand(ckts: &[Circuit]) -> Circuit {
let mut ckt = ckts[0].clone();
let hier: Vec<String> = vec![];

println!("------------------------------------------------");
trace!("------------------------------------------------");
expand_instances(ckts, &mut ckt, 0, &hier);
println!("------------------------------------------------");
trace!("------------------------------------------------");

ckt.build_node_id_lut();
ckt
Expand All @@ -99,8 +99,8 @@ fn expand_instances(

let mut hier = inhier.to_owned();

println!("-- Deal with instances of maybe subcircuits -- {} --",
inhier.len());
// println!("-- Deal with instances of maybe subcircuits -- {} --",
// inhier.len());
trace!("expand_instances() -> {}", hier.join("."));

// Set up aliases for parameters
Expand Down Expand Up @@ -154,8 +154,9 @@ fn expand_instances(
let lookup_param_name = hier.join(".");
hier.pop(); // lut-name

let lut = get_param_value(ckt, &lookup_param_name);
let lut = ckt.get_param_value(&lookup_param_name);

#[allow(clippy::manual_map)] // cos of the trace!
if let Some(val) = lut {
trace!("Found value for identifier in param");
Some(val)
Expand Down Expand Up @@ -184,16 +185,11 @@ fn expand_instances(

} // for p in parameters

// now we can expand primitives...
if inst.subckt == "/device" {
expand_primitive(ckts, ckt, ckt_id, inst, inhier);
} else { // expand subckts
// ... and subcircuits

trace!("WHUT: {}", hier.join(" "));

// expand params for this instance that might be
// picking up defaults
// Make sure we don't leave out any parameters that have defaults
// and are not overridden. The problem is that I don't know if I'm a
// subcircuit here...
if inst.subckt != "/device" {
trace!("Looking for nonoverridden parameters");
let mut subckt_id = 0;

// find the subckt definition index
Expand All @@ -210,19 +206,19 @@ fn expand_instances(

hier.push(inst.name.to_string());
hier.push(param_def.name.to_string()); // param-name
let lookup_param_name = hier.join(".");
let param_full_name = hier.join(".");
hier.pop(); // param-name
hier.pop(); // inst-name

println!("Looking for subckt inst param : {}", lookup_param_name);
trace!("Looking for subckt inst param : {}", param_full_name);

let lut = get_param_value(ckt, &lookup_param_name);
let lut = ckt.get_param_value(&param_full_name);

if let Some(_) = lut {
trace!("param '{}' already defined, skipping", lookup_param_name);
if lut.is_some() {
trace!("param '{}' already defined, skipping", param_full_name);
continue;
}
println!("{:?}", param_def);
trace!("Need a default from {:?}", param_def);

let param_default_value = match &param_def.defval {

Expand All @@ -239,7 +235,7 @@ fn expand_instances(
let lookup_param_name = hier.join(".");
hier.pop(); // lut-name

let lut = get_param_value(ckt, &lookup_param_name);
let lut = ckt.get_param_value(&lookup_param_name);
trace!("IIIIIIIIIIII {}", lookup_param_name);
if let Some(val) = lut {
trace!("HHHHHH asdfasdf-asdf HJASDFASDF");
Expand All @@ -252,12 +248,10 @@ fn expand_instances(

_ => {
panic!("*FATAL* just can't get enough");
None
}
};

if let Some(value) = param_default_value {
let param_full_name = hier.join(".");
trace!("Subckt Parameter Default : {} = {}",
param_full_name, value);
ckt.params.push( Parameter {
Expand All @@ -268,12 +262,15 @@ fn expand_instances(
});
};
} // for
}

expand_subckt(ckts, ckt, ckt_id, inst, &hier);

} // expand subckts

// not popping here - leaving the hier at the enclosing scope
// now we can expand primitives...
if inst.subckt == "/device" {
expand_primitive(ckts, ckt, ckt_id, inst, inhier);
} else {
expand_subckt(ckts, ckt, ckt_id, inst, &hier);
}

} // insts
}
Expand Down Expand Up @@ -391,7 +388,7 @@ fn expand_primitive(
let param_full_name = hier.join(".");
hier.pop();

let param_lut = get_param_value(ckt, &param_full_name);
let param_lut = ckt.get_param_value(&param_full_name);
let value = if let Some(rval) = param_lut {
rval
} else {
Expand All @@ -408,7 +405,7 @@ fn expand_primitive(
let param_full_name = hier.join(".");
hier.pop();

let param_lut = get_param_value(ckt, &param_full_name);
let param_lut = ckt.get_param_value(&param_full_name);
let value = if let Some(cval) = param_lut {
cval
} else {
Expand Down Expand Up @@ -449,17 +446,6 @@ fn find_subckt_index(ckts: &[Circuit], name: &str) -> Option<usize> {
None
}

/// Find a parameter value
///
/// `N` is small..
fn get_param_value(ckt: &Circuit, name: &str) -> Option<f64> {
for p in &ckt.params {
if p.name == name {
return p.value
}
}
None
}

/// Connect a primitive
fn local_connect(
Expand All @@ -477,6 +463,7 @@ fn local_connect(
let node_name = hier.join(".");
_ = hier.pop();

#[allow(clippy::manual_map)] // cos of the trace!
let gnid = ckt.add_node(&node_name);
trace!("Primitive connection: '{}' -> {}", node_name, gnid);
gnid
Expand Down
12 changes: 11 additions & 1 deletion src/spice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,6 @@ impl Reader {
}
continue;
}
println!("$$$$$$ {}", self.c);
self.ckts[self.c].add_node(nn);
num_ports += 1;
}
Expand Down Expand Up @@ -583,6 +582,13 @@ fn extract_identifier(text: &str) -> String {
#[cfg(test)]
mod tests {

// how do I use the one from tests::common?
pub fn assert_nearly(x: f64, expected: f64) {
const EPSILON: f64 = 1e-9;
let delta = (x - expected).abs();
assert!( delta < EPSILON, "{} isn't approximately {}", x, expected);
}

// If node count for the expanded circuit goes wrong and the SPICE file hasn't
// changed, it's usually the hierarchy stack that's passed around not getting
// pushed or popped symmetrically in the Expander.
Expand Down Expand Up @@ -687,5 +693,9 @@ mod tests {
// assert_eq!(ckt.nodes.len(), 8); // this has aliase
assert_eq!(ckt.node_id_lut.len(), 22); // HARDCODED! 6x 3 + 4

// check if the parameters propagated...
assert_nearly(ckt.get_param_value("Xsystem1.Xload.cvalo").unwrap(), 1e-6);
assert_nearly(ckt.get_param_value("Xsystem2.Xload.cvalo").unwrap(), 10e-6);
assert_nearly(ckt.get_param_value("Xsystem3.Xload.cvalo").unwrap(), 100e-6);
}
}

0 comments on commit 4698882

Please sign in to comment.