This shows you the differences between two versions of the page.
gnucap:manual:tech:modelgen [2023/05/05 03:57] felixs illustrate ddt |
gnucap:manual:tech:modelgen [2023/12/21 18:02] (current) felixs more branch details |
||
---|---|---|---|
Line 4: | Line 4: | ||
been part of the Gnucap project from early on. Modelgen reads device | been part of the Gnucap project from early on. Modelgen reads device | ||
descriptions and emits C++ code to be compiled into plugins. Support for | descriptions and emits C++ code to be compiled into plugins. Support for | ||
- | Verilog-AMS compact models will be implemented in a modelgen successor, | + | Verilog-AMS compact models has been implemented in a modelgen successor, |
"modelgen-verilog", following the design patterns and device architecture. | "modelgen-verilog", following the design patterns and device architecture. | ||
Major technical advantages of the latter are automatic differentiation and | Major technical advantages of the latter are automatic differentiation and | ||
Line 10: | Line 10: | ||
subsequent Verilog-AMS features. | subsequent Verilog-AMS features. | ||
- | This work has been carried out with financial support from the NGI0 Entrust | + | This work is carried out with financial support from the NGI0 Entrust |
Fund, see [[gnucap:projects:nlnet:verilogAMS]]. | Fund, see [[gnucap:projects:nlnet:verilogAMS]]. | ||
- | === Preprocessing === | + | TODO: there is some overlap with [[verilog]]. |
+ | |||
+ | ==== Preprocessing ==== | ||
Verilog-AMS inherits a few "compiler directives" from IEEE Std 1364-2005 Verilog HDL. The important ones are '`define', '`include', '`if(n)def', '`else', '`endif'. These are dealt with in the input stage of the model compiler, where we also strip comments and whitespace. | Verilog-AMS inherits a few "compiler directives" from IEEE Std 1364-2005 Verilog HDL. The important ones are '`define', '`include', '`if(n)def', '`else', '`endif'. These are dealt with in the input stage of the model compiler, where we also strip comments and whitespace. | ||
Line 25: | Line 27: | ||
The preprocessor functionality is exposed to users through the '--pp' option, it displays the input stream as it will be parsed. The complementary '--dump' option prints the final state of the data base, i.e. after parsing. | The preprocessor functionality is exposed to users through the '--pp' option, it displays the input stream as it will be parsed. The complementary '--dump' option prints the final state of the data base, i.e. after parsing. | ||
- | === Computing Partial Derivatives === | + | ==== Branches and Contributions ==== |
+ | |||
+ | In Verilog-AMS, analog behaviour is modelled in terms of controlled sources. | ||
+ | Sources of either flow or potential nature are expressed implicitly as | ||
+ | contribution statements to branches. A branch basically refers to a pair of nodes, | ||
+ | but details matter when it comes to named branches and switch branches. | ||
+ | In Gnucap these controlled sources are represented by subdevices derived from ELEMENT. | ||
+ | |||
+ | It is the model compilers responsibility to identify the branches that require | ||
+ | sources to be instanciated, select the suitable one. A branch that has a | ||
+ | contribution associated with it anywhere in the module (reachable or not), becomes | ||
+ | a source branch. Otherwise, if there is a an access statement anywhere in an expression, | ||
+ | the branch becomes a probe branch. A flow probe is essentially a potential source, | ||
+ | and implemented as such. | ||
+ | |||
+ | We use variants of "d_poly_g", the transconductance ELEMENT used in (legacy) | ||
+ | modelgen, which provides current sources with voltage control. The ELEMENTs | ||
+ | used in modelgen-verilog are tailored to the contribution type (flow, potential, | ||
+ | switch), and add current control. | ||
+ | |||
+ | In Gnucap, the model evaluation involves 5 phases on the component level. These are | ||
+ | |||
+ | - check if evaluation is required | ||
+ | - read probes | ||
+ | - evaluate analog expressions | ||
+ | - load (followed by solving the matrix in the simulator) | ||
+ | - check for convergence | ||
+ | |||
+ | The first and last step involve tolerances specified through disciplines. | ||
+ | Ultimately, disciplines need to become part of the nodes, currently they are | ||
+ | directly attached to the source ELEMENTs. | ||
+ | |||
+ | ==== Named Branches ==== | ||
+ | |||
+ | A named branch is an additional path between two nodes that can be a source/switch or a probe following the rules above. | ||
+ | It is implemented as an additional and independent ELEMENT, sharing the output ports. | ||
+ | |||
+ | ==== Probes ==== | ||
+ | |||
+ | A branch that has no contribution statement associated with it, but is used in an access function anywhere in the module becomes a probe branch. According to the LRM, 5.4.2.1, it's not allowed to "use" both the flow and the potential of such a branch. What it means is, | ||
+ | a flow probe cannot co-exist with a potential probe (on the same probe branch) within the same module, regardless of the use. | ||
+ | There is no ELEMENT instanciated for a potential probe branch. A flow probe branch requires one, as it works similar to a | ||
+ | zero-potential source. | ||
+ | |||
+ | ==== Computing Partial Derivatives ==== | ||
In Verilog-A, analog components are essentially modelled as controlled sources. In this section, think of a current source controlled by voltage sources. For example, a linear admittance would boil down to a contribution statement like | In Verilog-A, analog components are essentially modelled as controlled sources. In this section, think of a current source controlled by voltage sources. For example, a linear admittance would boil down to a contribution statement like | ||
Line 67: | Line 113: | ||
NB: This is similar in principle to the ADMS approach, but a little less obfuscated. Of course, we also keep track of unused derivatives, but (at the time of writing), pass them to the C++ compiler as literal zeroes. Gcc is pretty good at optimising them out... | NB: This is similar in principle to the ADMS approach, but a little less obfuscated. Of course, we also keep track of unused derivatives, but (at the time of writing), pass them to the C++ compiler as literal zeroes. Gcc is pretty good at optimising them out... | ||
- | === Branches and Contributions === | ||
- | |||
- | In Verilog-AMS, analog behaviour is modelled in terms of controlled sources. | ||
- | Sources of either flow or potential nature are expressed implicitly as | ||
- | contribution statements to branches i.e. pairs of nodes. In Gnucap these | ||
- | controlled sources are represented by subdevices derived from ELEMENT. | ||
- | |||
- | We use variants of "d_poly_g", the transconductance ELEMENT used in (legacy) | ||
- | modelgen. Unlike Verilog-AMS, modelgen only provides current sources with | ||
- | voltage control. One variant "d_vaflow" adds current controls, and the other | ||
- | "d_vapot" implements voltage output. | ||
- | |||
- | It is the model compilers responsibility to identify the branches that require | ||
- | sources to be instanciated, select the suitable one and connect the controls | ||
- | and their derivatives accordingly, following evaluation. In Gnucap, the | ||
- | model evaluation involves 5 phases on the component level. These are | ||
- | |||
- | - check if evaluation is required | ||
- | - read probes | ||
- | - evaluate analog expressions | ||
- | - load (followed by solving the matrix in the simulator) | ||
- | - check for convergence | ||
- | |||
- | The first and last step involve tolerances specified through disciplines. | ||
- | Ultimately, disciplines need to become part of the nodes, currently they are | ||
- | directly attached to the branches. | ||
- | === Filter operators === | + | ==== Filter operators ==== |
Verilog-AMS defines ''ddt'' and ''idt'' operators as a means to describe dynamic | Verilog-AMS defines ''ddt'' and ''idt'' operators as a means to describe dynamic | ||
Line 115: | Line 135: | ||
t0 = f1(t0); | t0 = f1(t0); | ||
t0 = ddt(t0); // (*) | t0 = ddt(t0); // (*) | ||
- | t0 = f2(0); | + | t0 = f2(t0); |
I(p,n) <+ t0; | I(p,n) <+ t0; | ||
</code> | </code> |