This shows you the differences between two versions of the page.
| — |
gnucap:manual:tech:nodes [2025/05/16 10:29] (current) felixs created (outline) |
||
|---|---|---|---|
| Line 1: | Line 1: | ||
| + | ===== Node procedure ===== | ||
| + | |||
| + | ==== On read-in ==== | ||
| + | |||
| + | A NODE_MAP belongs to a CARD_LIST, which stores a circuit. Read-in is implemented in a lang_* plugin. | ||
| + | At this time, the NODE_MAP is populated as needed whenever a connection is made. | ||
| + | |||
| + | <code> | ||
| + | loop(devices) { | ||
| + | parse_ports: | ||
| + | set_port_by_name | set_port_by_index | ||
| + | calls node_t::new_node, NODE_MAP::new_node | ||
| + | which enters to node_map (per scope) | ||
| + | (n_()) (_nnn) points to a USER_NODE in scope()->nodes() | ||
| + | (t_()) (_idx) flat, global id number (==_nnn->user_number) | ||
| + | (m_()) (_m) INVALID_NODE (==-1) | ||
| + | (link()) node_t*. union find structure. | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | special cases: | ||
| + | The first node in the toplevel scope (position 0) is reserved for ground, named "0". | ||
| + | Floating ports in subcircuit instances have e_()==INVALID_NODE. | ||
| + | |||
| + | NODE_MAP stores (by pointer) instances of USER_NODE. A USER_NODE has a node_t at n_(0), it stores the index aka user number. | ||
| + | This way, a USER_NODE acts as a one-port device with a connection to the node at its index. | ||
| + | |||
| + | A Port in a device that is not connected during read-in will later be assigned to a floating node. In modelgen-verilog, The $port_connected function | ||
| + | indicates this situation following Verilog-AMS LRM Section 6.5.6. | ||
| + | |||
| + | |||
| + | === modules === | ||
| + | defining modules { | ||
| + | all_new, makes_own_scope | ||
| + | "name" is the name of the port for outside, not used by spice and spectre. | ||
| + | "value" is for inside | ||
| + | |||
| + | "all_new" disallows ground and dups, because the internal name may be used externally. | ||
| + | Dups are allowed internally. Not sure if it works. | ||
| + | } | ||
| + | |||
| + | Done with read-in. | ||
| + | |||
| + | ==== expansion ==== | ||
| + | |||
| + | === two cases === | ||
| + | A CARD_LIST is expanded to prepare the circuit for simulation. This may either happen immediately | ||
| + | after read-in, | ||
| + | or after taking a copy, as when instantiating a clone of a subcircuit. A subcircuit clone | ||
| + | lacks the USER_NODEs in its NODE_MAP. | ||
| + | |||
| + | === SIM_DATA === | ||
| + | |||
| + | in SIM_DATA::init(scope) { | ||
| + | if (is_first_expand) (no nodes allocated yet) { | ||
| + | 0. map_toplevel_nodes | ||
| + | a node_t vector has been allocated (in scope->nodes()) | ||
| + | connect all nodes in subdevices and USER_NODES to the respective node_t in that vector. | ||
| + | i.e. call map_subckt_node(&top_nodes[0], *ci) on all their net_nodes | ||
| + | 1. scope->expand() .. includes precalc_first, expand_first, expand, expand_last | ||
| + | For devices that have a subckt, expand() makes a copy. | ||
| + | Code to do this is per devicetype, with too much duplicated code. | ||
| + | Using DEV_SUBCKT::expand(). | ||
| + | Which usually does: | ||
| + | renew_subckt() .. which is really new_subckt(), makes an empty one. | ||
| + | subckt()->expand() .. recursive .. does real copy here | ||
| + | node links: node_t::link() reference to parent in union forest. | ||
| + | 2 -- node allocation | ||
| + | node_t::allocate() allocate a node if needed. | ||
| + | |||
| + | |||
| + | === node_t::map() === | ||
| + | |||
| + | connect a node_t to the effective NODE instance that contains the simulation data. | ||
| + | set _nnn to point to a LOGIC_NODE. | ||
| + | set _m=_nnn->matrix_number(); | ||
| + | |||
| + | |||