Error generating C++ code for BSIM CMG models

240 views
Skip to first unread message

Brian Carlson

unread,
May 10, 2017, 8:33:17 PM5/10/17
to xyce-users
Hi,

I am attempting to recompile the BSIM CMG models as they are simulating slowly, probably due to a lack of specification for bias-independent model parameters in the verilog-a code. As a starting point, I'm simply trying to recompile the example provided by Xyce using the following command:

buildxyceplugin -o bsimcmg-1100 *.va .

This results in the following log:
***********************************************************************************************************
buildxyceplugin log begun at Wed May 10 16:05:09 MST 2017\n
 script invoked as: \n /usr/local/bin/buildxyceplugin -o bsimcmg-1100 bsimcmg.va .
 ----------------
Building C++ for Verilog-A input file 'bsimcmg.va'...
[info...] admsXml-2.3.6 (e24d007) May 10 2017 15:11:53
[fatal..] node: case not handled
[fatal..] see [.adms.implicit.xml:314]
***********************************************************************************************************

Looking at the line in the file .adms.implicit.xml as the log suggests, it appears a datatype of "node" is getting passed in, but I am not sure how to troubleshoot further. For the record, I have successfully compiled and simulated other examples from the 6.6 release with good results. The BSIM CMG specifically is proving to be problematic. Also, I'll go ahead and note that I am using adms-2.3.6. I was hoping to receive some insight as what the issue might be or how to proceed in troubleshooting this issue. I'm aware that a new release is expected soon, but I've been told that no new developments have been made for models for smaller process nodes such as the BSIM CMG.

Thanks

xyce-users

unread,
May 10, 2017, 11:23:29 PM5/10/17
to xyce-users
The quick-and-dirty "buildxyceplugin" script is not quite robust enough to do all that is necessary to process BSIMCMG 110 for Xyce.

Please see the Makefile in Xyce-6.6/utils/ADMS/examples/BSIMCMG110.0.0_20160101/code, and look over README_Xyce and the "make_bsimcmg_usable.diff" patch file.

BSIMCMG 110 made use of some Verilog-A constructs that ADMS does not support (specifically $port_connected(), to make the "t" node optional).  To make this work required use of Xyce-specific ifdefs that you simply can't pass in using the buildxyceplugin script.  This is why you're getting that error from ADMS, because the required symbol is not defined to work around this ADMS limitation. 

If you really want to build a plugin for BSIMCMG 110, you'll have to do it by hand, mimicking the steps that buildxyceplugin goes through, but with extra admsXml command-line options the way the Makefile does (specifically, you need to add "-D__XYCE__=1", or, alternatively, add "`define __XYCE__" to the bsimcmg.va file).  You will also have to apply the patch file to get the optional node handling hacked in after ADMS is done creating C++, but before compiling that C++ and linking it into a shared library.

And you will likely be disappointed, because it won't be any faster than the one that's bundled in Xyce --- we have already made the modifications necessary to assure that bias-independent calculations are isolated and performed only at initialization (or when model or instance parameters are changed, as would happen with a .step loop).  These are documented in the README_Xyce file in the BSIMCMG 110 directory.  The source of your slow simulations is certainly not the inappropriate recalculation of bias-independent terms on every evaluation of the model.

xyce-users

unread,
May 11, 2017, 10:30:20 AM5/11/17
to xyce-users, xyce-...@googlegroups.com

On Wednesday, May 10, 2017 at 9:23:29 PM UTC-6, xyce-users wrote:

And you will likely be disappointed, because it won't be any faster than the one that's bundled in Xyce --- we have already made the modifications necessary to assure that bias-independent calculations are isolated and performed only at initialization (or when model or instance parameters are changed, as would happen with a .step loop).  These are documented in the README_Xyce file in the BSIMCMG 110 directory.  The source of your slow simulations is certainly not the inappropriate recalculation of bias-independent terms on every evaluation of the model.

Just a quick comment that, while simply recompiling the code will not result in a speed improvement, things could possibly be done in the Verilog A to improve speed. For example, not all models break out the bias-independent calculations, so the ADMS/Xyce backend will create code that runs those calculations at every iteration. Having said that, in the Xyce implementation the BSIMCMG code has been hand-modified to wrap the "CMGBiasIndepCalc" block in an "@(initial_instance)" pseudo-event to help with that problem. This isn't to say that more couldn't be done, though. Look at the README_Xyce file in the ...ADMS/examples/BSIMCMG... directory for more information on what was done.

xyce-users

unread,
May 11, 2017, 10:57:29 AM5/11/17
to xyce-users, xyce-...@googlegroups.com

This comment is really just restating what I stated in the first place and can potentially confuse the issue here.

The one "thing [that] could possibly be done in the Verilog-A to improve speed" mentioned in this comment is exactly the one that I'm saying isn't something that's going to help:  BSIM CMG code in Xyce has already had this particular optimization applied, and it is explained in the very README_Xyce that I referred to in my first reply. 

The original posting stated  "they are simulating slowly, probably due to a lack of specification for bias-independent model parameters in the verilog-a code."  The answer to this is no.  It is probably *NOT* lack of specification for bias-independent variable evaluation in the specific case under discussion here.

More could certainly be done to improve the speed of the C++ code generated by our ADMS code generator, but wrapping the bias-independent stuff is usually the low hanging fruit we've already picked, as it is here.  Further performance improvements will likely be difficult to realize, and probably not by making small deltas on the Verilog-A source.

If profiling indicates that this simulation is slow because the updateIntermediateVars function is dominating the run time, the most likely culprit is the evaluation of derivatives by Sacado.  I expect that this is the case, but it could only properly be concluded after really doing profiling of the code on the problem in question.  Replacing Sacado's automatic differentiation with hand-coded derivatives could possibly help, but this is a huge task and would be terribly error-prone.  Rewriting the Xyce/ADMS back-end to do differentiation itself instead of relying on Sacado is a huge task as well.

If one wanted to try to make further optimizations of the BSIM-CMG code, the most productive way to approach it will probably be to hand-optimize the generated C++ after profiling it carefully rather than starting all the way back at the Verilog-A.  This could be done by workng directly on the code in Xyce/src/DeviceModelPKG/ADMS/src/N_DEV_ADMSbsimcmg_110.C in the Xyce 6.6 source code. 

Thomas Russo

unread,
May 11, 2017, 11:45:30 AM5/11/17
to xyce-users, xyce-...@googlegroups.com
At the risk of getting into the weeds on this, I have one more (long) comment.

While the bias-independent calculations in the CMGBiasIndepCalcn block are in fact being evaluated only once (unless model or instance parameters change during a simulation), there is ONE possible source of redundant calculations that could come from the "CMGTempDepCalc" block. 

These are NOT "bias independent" calculations, though, because in BSIM CMG the device internal temperature rise is a solution variable --- therefore the temperature-dependent code is "bias" dependent in that sense, and treated as such by ADMS.  It cannot be put in the same place as the real bias-independent code; it must live in updateIntermediateVars and these variables must be updated each time based on the value of the "t" node solution variable.

However, in the one specific case where the self-heating model is turned off by setting the model parameter SHMOD to zero or the model parameter RTH to zero, all of these temperature-dependent variables are being recalculated unnecessarily even though the temperature isn't changing.  These variables are all Sacado templated types, because they *could* be dependent on solution variables, and derivatives with respect to solution variables would be required.  There are quite a lot of those variables, and in the specific use case where SHMOD=0 or RTH=0, reevaluating them would be wasteful.  And because of their number and the derivative computation issue, it could be a significant waste.

If (and only if) the problem in question in this thread is one where the self-heating model is turned off explicitly in the model card, then these temperature-dependent quantities ARE being recomputed unnecessarily.  If profiling indicates that these computations are a serious real expense, then it might be worthwhile to try to do something to reduce them.  If the problem in question has the self-heating model turned on, this is NOT the source of the slow simulation, as those variables *must* be recomputed in that case and this entire discussion is a red herring.

Assuming one determines that the temperature-dependent calculations are the issue, there could be ways to address it.

This would not be easy to address from either the Verilog-A side or the ADMS code generation step, because in processing the code ADMS detects that variables are *potentially* solution-dependent, and as long as they are even potentially dependent on solution, they *have* to be computed in updateIntermediateVars.  ADMS cannot detect "these are solution dependent in this case, and bias-independent in this other case."   Similarly, there is no way in Verilog-A to express such a conditional dependence.

This is a situation where one would probably have to hand-modify the C++ for updateIntermediateVars to compute the temperature-dependent quantities only once when  SHMOD and/or RTH is zero, or better yet, only compute them when the operating temperature (the variable DevTemp) has changed since the last call.  This would not be as simple as inserting a conditional.   When ADMS has determined that a quantity is bias dependent, the C++ will generally have been created so that the variable is local to updateIntermediateVars.  One would have to move variable declarations around so they are not local to updateIntermediateVars in order that they retain their values between calls --- their declarations would have to be in the instance class instead.  One would need additional variables to keep track of  "DevTemp at last call" and "Have I ever initialized these variables?"  There are additional pitfalls one would have to be careful about if one were going down this path, and probably quite a few I can't think of on the spur of the moment.

Brian Carlson

unread,
May 15, 2017, 3:29:47 PM5/15/17
to xyce-users
I'm attempting to eliminate any irrelevant calculations in the "CMGTempDepCalc" block per Tom's suggestion by directly editing the 
C++ code. Before making any serious edits, I'm trying to compile the device as level '111' as is, to make sure I can successfully run it as a plugin. I'm getting a "No model card found" error, leading me to believe the device is not actually getting compiled as a level 111.

So far I've changed the Traits struct as shown below:

  static const char *name() {return "BSIM-CMG FINFET v111.0.0";}
  static const char *deviceTypeName() {return "m level 111";}

I've also changed the Register Device as shown below"

void registerDevice()
{
  Config<Traits>::addConfiguration()
    .registerDevice("m", 111)
    .registerModelType("nmos", 111)
    .registerModelType("pmos", 111);
}

I'm not seeing any other code that pertains to model levels. I was able to recompile other models to new levels from the Verilog-A, and resulting C++ code seemed to contain the changes I've implemented. Is there something else I've missed in the code?

Brian Carlson

unread,
May 19, 2017, 3:29:41 PM5/19/17
to xyce-users
I'll answer my own question. I wasn't including the *bootstrap.C file in my project, so it wasn't getting compiled into the model. Including this in the build successfully gives me a model that behaves identically to the level 110 mosfet, but registered at level 111.

After running my own model I get the expected behavior, however the plugin is significantly slower than the already slow built-in CMG 110. This is without modifying the code (aside from changing the device level). Is it a known issue that plugins run slower than built-in models? The same speed issue is happening with other models that are compiled as plugins. I am most likely going to re-build Xyce with my own model built in, however I thought I'd ask whether this is likely to make any difference in simulation time before spending a couple hours on a rebuild.

xyce-users

unread,
May 19, 2017, 3:49:03 PM5/19/17
to xyce-users
There is no known issue that should make shared library plugins any slower than code built in with Xyce, and I do not immediately see why it would be the case.  We have not done a thorough analysis of the question, though.  Anything I suggested as a possible reason for your observed behavior would be a guess. 

Internally, we have really only used the plugin capability in the early stages of porting models to Xyce or for rapid turn-around while developing new models, and not in any production capability.  So questions of relative performance have never come up, and have never been examined.

xyce-users

unread,
May 22, 2017, 1:46:43 PM5/22/17
to xyce-users
Since Brian has reported off-line that the optimizations described below helped his speed issues, I took a look today at how it might be done without resorting to manually hacking the generated C++.  It is not actually that difficult to modify the BSIM-CMG Verilog-A input to accomplish this, although it is a little ugly.  Unfortunately, this is coming too late to be in the iminent Xyce 6.7 release, but since it works well, it will be in Release 6.8 in the fall.

Here's what I did:
  - Added a variable "TempLast" to the main analog block.
  - Set "TempLast" to "-999" in the @(initial_instance) block
  - For every variable that appears on the left-hand side of an assignment in CMCTempDepCalc, assign the value "0" to that variable inside the @(initial_instance block).  The effect of doing this is to cause Xyce/ADMS to declare those variables as members of the instance class instead of as local variables in updateIntermediateVars.  This is the ugly part, but it is easily accomplished with some editor scripting.
  - Put "if (DevTemp != TempLast)" in front of the CMGTempDepCalc block, so it only gets executed if the temperature has changed since last time.
  - put "TempLast = DevTemp;" inside the CMGTempDepCalc block.

I've attached a patch file that accomplishes all of these steps.

By doing this, the temperature dependent variables will retain their values across newton iterations and time steps, and will only be updated when they have to be (because temperature has changed).  It will also force them to be recomputed if they are invalidated by sweeping any model or instance parameters using a ".STEP" loop.  I have observed as much as a 30% improvement on residual load times for the "inverter_transient" BSIM-CMG test in our test suite, since it does not use the self-heating model.

The attached patch file, when applied to the Verilog-A source for BSIM-CMG 110 (in Xyce-6.6/utils/ADMS/examples/BSIMCMG110.0.0_20160101/code/, will apply this optimization.  You can see it's actually a fairly minor change.  If you want to apply this in your copy of Xyce 6.6, you would need to apply the patch, regenerate the C++ code (using "make all-source" in that directory) and copy the .C and .h file produced to Xyce-6.6/src/DeviceModelPKG/ADMS/src and /include (respectively).  If you rebuild Xyce, the optimization will be there.  If you've not clobbered your build directory from your last compilation, only this one file would be recompiled.

Instructions for getting this into Xyce 6.7 when it is released would be very slightly different: we did a code reorganization, and .h and .C files are no longer in separate subdirectories; for Xyce 6.7, you will copy both the .C and .h files to Xyce-6.7/src/DeviceModelPKG/ADMS instead.
bsimcmg_optim.patch
Reply all
Reply to author
Forward
0 new messages