OpenVAF follows the Verilog-AMS Language Reference Manual 2.4.0 language standard. The current goal is to support only the analog (Verilog-A) subset defined within this standard, digital models can not (yet) be parsed.
Furthermore, the OpenVAF compiler is primarily aimed at compact modeling. For better facilitating compact modeling (and for reducing the scope of the implementation) the behavior of the compiler sometimes differs from the standard. In this document all differences between the language subset implemented by OpenVAF and the Verilog-A subset of the Verilog-AMS Language Reference Manual are documented.
Some features in the Verilog-AMS Language Reference Manual are aimed at behavioral modeling or describing entire circuits. These features are hard or even impossible support when statically compiling compact models. Therefore OpenVAF purposefully does not implement these features. Here all language features not implemented by OpenVAF are laid out.
final_stepcan't be parsed
The Verilog-AMS standard allows to mark statements with event control.
Such statements are only executed when the indicated event has occurred.
The events are usually not used in compact models as they may introduce discontinuities.
Therefore OpenVAF only supports the
final_step events for initialization code.
There are four kinds of events specified in the standard. They are listed here with an example and an indication to show whether OpenVAF currently supports this syntax:
@foo) not supported
@(cross(V(smpl) - thresh, dir))) not supported
@(initial_step or cross(V(smpl)-2.5,+1))not supported
Arithmetic bit shifts are not allowed in analog blocks, yet they are a sub-set of the Verilog-AMS standard that is not excluded for Verilog-A. To avoid having to maintain unused code, the arithmetic bit shift operator is not supported by the compiler.
Some features that are not part of the Verilog-A standard have been added to OpenVAF. The need for these features arose when OpenVAF was used in practice for compact model compilation and parameter, extraction. Below is a table that lists these additional features and a corresponding example.
In the following section each feature -including a motivation- is explained in detail. To make it easy to remain standard-compliant, OpenVAF will emit a warning by default when any one of the listed features is used.
The Verilog-AMS Language Reference Manual allows calculating derivatives with the
ddx analog filter.
However, only derivatives w.r.t. node voltages
V(node) or branch currents (
I(branch)) are allowed.
For parameter extraction derivatives by ambient Temperature (
$temperature) may be of interest for extracting temperature dependencies.
The behavior of the
ddx analog filter is extended so that
ddx(foo,$temperature) is valid.
When such a derivative is evaluated, all voltages and currents are assumed to be independent of temperature.
Apart from this the
ddx filter behaves identical as when used with nodes/branches,
the derivative of the temperature is calculated by repeated application of the chain rule.
x = ddx($temperature,$temperature) y = ddx(v(node),$temperature) z = ddx(i(branch),$temperature) // x = 1, y=z=0 foo = 20*exp($temperature/10)+V(node) bar = ddx(foo,$temperature) // bar = 2*exp($temperature/10)
Equations of compact models usually depend upon voltage differences
V(a,b) (or equivalently branch voltage
The derivatives of these model Equations are required/useful during parameter extraction and for use in circuit simulators. However, Verilog-A only allows derivatives w.r.t. to node potentials.
Usually, such voltage derivatives are instead calculated with respect to the derivative of the voltage's
ddx(foo,V(a,b) = ddx(foo,V(a)).
This approach can fail when an equation depends on multiple branch voltages, as is demonstrated by the example below.
For ensuring correct behavior it is therefore more desirable to calculate the derivative by
foo = V(a,b) + V(c,a) dfoo1 = ddx(foo, V(a)) dfoo2 = ddx(foo,V(a,b)) // dfoo1 = 0, dfoo2 = 1
The behavior of the
ddx analog filter is extended so that
ddx(foo,V(node1,node2)) is valid.
Branch currents are treated as constants. Voltage derivatives w.r.t.
V(node1,node2) are implemented as follows:
V(branchX)is 1 if the branches nodes are
branch (node1, node2) branchX
V(branchX)is -1 if the branches nodes are
branch (node2, node1) branchX
ddx filter behaves identical as when used with nodes/branches.
The derivative of the argument is calculated by repeated application of the chain rule.
... branch (b,e) br_be; begin Vt = $vt; Ib = Isbc*exp(V(b,c)/Vt) + Isbe*exp(V(br_be)/Vt); gbc = ddx(Ib, V(b,c)); // gbc = Isbc/Vt*exp(V(b,c)/Vt) gbe = ddx(Ib, V(b,e)); // gbe = Isbe/Vt*exp(V(b,c)/Vt) end ...
For performance reasons ODIC uses voltage derivatives instead of potential derivatives to calculate the Jacobian matrix entries.
Consider a network with two nodes
b which are connected by a single branch
br_ab whose current only depends upon the voltage difference of the two nodes.
The matrix entries can then be calculated as follows:
ddx(I(<a>),V(a))=ddx(I(<b>),V(b)) = ddx(I(br_ab),V(a,b)) ddx(I(<a>),V(b))= ddx(I(<a>),V(b)) = - ddx(I(br_ab),V(a,b))
Almost all equations in compact models have above form using this technique effectively enables to reduce the number of derivatives by a factor of 4. Considering how complicated and therefore computationally expensive such derivatives can be, it is unlikely even modern compilers could optimize these duplication's away completely, and even if, it would reduce compile time significantly. Therefore it is preferable for OSDIC to calculate derivatives by voltage difference and then calculate the Matrix entries from the results.
commit 03285546c2db01b4d3fdde57f9e2ab790ba28c15 Author: DSPOM <email@example.com> Date: 2022-07-05T10:43:13+02:00 Update repo links