For starters, recall that @(initial_step) means (to Xyce/ADMS at
least) a block of code that should only be executed during the DCOP, and
will never be executed in transient. It is therefore *wholly*
inappropriate to use this block to do things like bias independent
initializations or copying model/instance parameters into local
variables. So what you're doing here is actually dangerous and may
result in transient simulations trying to use uninitialized variables
(because you're only initializing them when it's a DCOP, and I assure
you the values are NOT guaranteed to be preserved between calls as they
are all local variables to updateIntermediateVars and are thrown away
every time this function returns).
Other simulators and Verilog-A compilers may do the right thing here, but this is not right in Xyce/ADMS.
If
you want to isolate initializations of variables that should only take
place once, Xyce/ADMS wants you to put those into "@(initial_instance)"
or "@(initial_model)" blocks (the former is performed once for each
instance of the device in a circuit, the latter for each model card).
To do this in a good, portable way, you could do this:
module foobar(a,b);
inout a,b;
electrical a,b;
parameter real model_parameter = 1 from (0:inf);
parameter real instance_parameter = 2 from (-inf:inf) (*type='instance' *);
real module_scoped_variable1;
real module_scoped_variable2;
analog begin
`ifdef insideADMS
@(initial_model)
`else
@(initial_step)
`endif
begin
module_scoped_variable1 = model_parameter;
end
`ifdef insideADMS
@(initial_instance)
`else
@(initial_step)
`endif
begin
module_scoped_variable2 = instance_parameter;
end
That'll
take care of initializing the two module scoped variables, and
Xyce/ADMS will assure that they are elevated to a level where they
retain values across calls (they are added to the "instance" or "model"
classes precisely because they appear in these @(initial_instance) and
@(initial_model) blocks, which are placed into functions called
"processParams" in the Xyce Instance and Model classes, respectively).
By
putting this ADMS-specific stuff into an ifdef like this, you make the
module something that can be processed in Xyce/ADMS *and* whatever other
simulator was already happy with it unmodified. "insideADMS" is
defined by the ADMS Verilog-A processor itself, so this makes sure only
ADMS ever sees these nonstandard uses.
You
really, really must not put this "initialize once" stuff into
@(initial_step) in Xyce, because it'll be wrong, will only initialize
the variables during DCOP, and will be forgotten when DCOP is over.
Trust me on that one.
Now,
as for the issue where a variable is declared outside an @(initial_step)
block but which is never used except *inside the block*, this appears
to be a bug in Xyce/ADMS. Details (probably too many of them) follow.
Just
because a variable is declared in the Verilog-A doesn't mean that
Xyce/ADMS actually emits the declaration --- it only emits a declaration
for variables that are *assigned to*. But it ignores assignments
inside @(initial_step) for reasons I cannot recall. I might be able to
fix that, but I because I can't recall *why* it's doing that I can't be
sure that a quick fix will be the right fix. If you look at
Xyce/utils/xyceImplementationFile_nosac.xml, you'll see these lines:
<!-- Now let's collect into analog/code/ @assignedVars only those -->
<!-- variables that are assigned to in code EXCLUDING the special blocks -->
<admst:for-each select="analog/code/item">
<!-- if a block and not special -->
<admst:if
test="adms[datatypename='block']/..[name!='initial_instance' and
name!='initial_model' and name != 'initial_step']">
<admst:apply-templates select="." match="collectAssignedVariables"/>
</admst:if>
<!-- if not a block -->
<admst:if test="adms[datatypename!='block']">
<admst:apply-templates select="." match="collectAssignedVariables"/>
</admst:if>
</admst:for-each>
This
is where we collect up all the variables in any block that are assigned
to in that block and are not in the scope of some higher block. You
see it's ignoring @(initial_instance), @(initial_model), and
@(initial_step) here. It is *correct* for it to be doing that for
@(initial_model) and @(initial_instance) (which are not part of the
Verilog-A standard and are recognized only by ADMS, and denote
bias-independent calculations at the instance or model level that
Xyce/ADMS will put into a different function than all the other stuff),
but I believe it is (and always has been) wrong for it to be treating
@(initial_step) that way. Once it has collected up variables that are
assigned to, it uses this to determine which variables should be
declared at which scope in the emitted C++.
@(initial_step)
code isn't really as special as those other (ADMS-specific) events ---
what it causes Xyce/ADMS to emit this sort of C++:
if (getSolverState().dcopFlag)
{
... the contents of the initial_step block...
}
right
into the same "updateIntermediateVars" function that almost all of the
rest of the code goes into (excepting anything in @(initial_model) or
@(initial_instance)). So in fact, all the variables assigned to there
and NOT declared there should be considered in the same scope as the
main body of the module, but at the moment are NOT considered "assigned
to" by this block because of this bug.
But when
you also assign to the same variable *outside* the block the
"collectAssignedVariables" thing picks it up and makes sure it is
declared.
Now, if it were not completely wrong
to be using initial_step here (as far as Xyce/ADMS is concerned, despite
what good, modern, standard-compliant Verilog-A compilers do), I'd say
"simple, just remove the "and name!='initial_step'" bit of that line in
xyceImplementationFile_nosac.xml" and we'd be done. but if you did that
you'd just be inviting all the problems I just enumerated in the first
part of this very long note.
Inserting
thousands of lines of code that simply assign to variables just to work
around this bug is not the thing you really want to do here. If you
switch to using @(initial_instance) and @(initial_model) as appropriate
with those ifdefs I described, you'll have better results. Fixing this
little bug *might* be possible before I retire (which is happening in a
few weeks), but even if I got it fixed using @(initial_step) in this way
is *still* the wrong thing to be doing and it'd just be pushing off the
problems to some other place.
Finally, I'm not sure what you're asking by this line:
parameter real var1 = 7.3; //Xyce requires this for simulation?
---
Unless module attributes are
added to the Verilog-A input, devices added in this manner will all be
"Y" devices, and therefore must be accessed from a netlist using the Y
syntax:
Y<module name> <unique instance name> <node>* <model name> <instance parameter list>
Module attributes may be added to the Verilog-A input to plug the
device into Xyce as a new MOSFET (M), BJT (Q), JFET (J), Resistor (R),
Capacitor (C), or Diode (D) model levels instead of as Y devices.
If the model has model parameters, then a model name is required, and
the model card will be of the same type as the module name:
.model <unique model name> <module name> <model parameter list>----
Here
, while it's explicitly stated that "if the model has model parameters
then a model name is required" it is NOT explicitly stated that if the
model has NO model parameters then a model name must be OMITTED:
Y<module name> <unique instance name> <node>* <instance parameter list>
(I.e.
no model name specified) This applies when the model has no parameters
at all, or when all the parameters have the (* type="instance" *)
attribute (and therefore all parameters are instance parameters and the
model still has no model parameters).
If
you were specifying a model name in your instance line and Xyce was
rejecting it when your module didn't have any parameters at all, then
this is why.
I could
have sworn that the Xyce/ADMS users guide had that little extra detail
added at one point, but it appears to be the case either that I was
imagining things or that it got accidentally deleted when our site got
migrated from one content management system to another (there was a
problem with that, the IT folks who did the migration migrated old
data).
On Thursday, December 8, 2022 at 12:00:14 PM UTC-7 Albert Kumar wrote:
Great
explanation. I've actually got the model working thanks to all your
help and simulation results appear to match expectations. But, I'm not
sure if my understanding is correct or if I'm doing things correctly
[quoted message elided to reduce size]