ngspice/KiCad syntax error, bug, or undocumented features?

@holger Herr Holger, I am getting confused about some hidden syntax rules (or bugs?) in ngspice or in KiCad. The issue at hand this time is a weird interpretation of special characters that seems to be undocumented. For example, I created an XSPICE model for an inverter with hysteresis. Look at the lines showing various ways to define .model Analog_Hys hyst. I can use various characters like {xxx} or 'xxx' and the simulation works as expected. I can remove altogether all these symbols, except for the last lone one, and the simulation still works, but only if the last character is } and not '. If I remove the last lone character }, the simulation does not work anymore. And finally, if I keep only the last two characters ', the simulation works again. Is this the expected behavior, is there some documentation about it?

Mit freundlichen Grüßen,
Adi

*********************************************************************************************************
* RANGE is a SLEW RATE specific global parameter, not passed to the model
* BUFFER_SIZE provide discrete time step response precision (DELAY/BUFFER_SIZE)
* XSPICE Ngspice User Manual, Inverter and hysteresis
*
* PINSEQ:          1       = NULL FORBIDDEN, VECTOR NO, analog, input
*                  | 2     = NULL FORBIDDEN, VECTOR NO, analog, output
*                  | |
*******************|*|*******************************************************************************
.SUBCKT X0_INV_HYS 1 2 PARAMS:
+ VCC               = 3.3           // NULL PERMITTED, VECTOR NO, real, no limits (hidden vcc parameter default 3.3)
+ X_RT              = 2.0e-9        // NULL PERMITTED, VECTOR NO, real, no limits, technology internal raise time, (default 2.0e-9)
+ X_FT              = 2.0e-9        // NULL PERMITTED, VECTOR NO, real, no limits, technology internal fall time, (default 2.0e-9)
+ X_DU              = 2.0e-9        // NULL PERMITTED, VECTOR NO, real, no limits, technology delay unit, no default
+ X_CLK_DELAY       = {X_DU}        // NULL PERMITTED, VECTOR NO, real, 1.0e-12 lower limit, no upper limit (default 1.0e-9), digital models only
+ X_SET_DELAY       = {X_DU}        // NULL PERMITTED, VECTOR NO, real, 1.0e-12 lower limit, no upper limit (default 1.0e-9), digital models only
+ X_RESET_DELAY     = {X_DU}        // NULL PERMITTED, VECTOR NO, real, 1.0e-12 lower limit, no upper limit (default 1.0e-9), digital models only
+ X_IC              = 0             // NULL PERMITTED, VECTOR NO, integer, 0 lower limit, 2 upper limit, output initial state (default 0)
+ X_DATA_LOAD       = 1.0e-12       // NULL PERMITTED, VECTOR NO, real, no limits, data loading capacitance (default 1.0e-12)
+ X_CLK_LOAD        = 1.0e-12       // NULL PERMITTED, VECTOR NO, real, no limits, clock loading capacitance (default 1.0e-12)
+ X_SET_LOAD        = 1.0e-12       // NULL PERMITTED, VECTOR NO, real, no limits, set loading capacitance (default 1.0e-12)
+ X_RESET_LOAD      = 1.0e-12       // NULL PERMITTED, VECTOR NO, real, no limits, reset loading capacitance (default 1.0e-12)
+ X_INPUT_LOAD      = 1.0e-12       // NULL PERMITTED, VECTOR NO, real, no limits, input loading capacitance (default 1.0e-12)
+ X_RISE_DELAY      = {X_DU}        // NULL PERMITTED, VECTOR NO, real, 1.0e-12 lower limit, no upper limit (default 1.0e-9)
+ X_FALL_DELAY      = {X_DU}        // NULL PERMITTED, VECTOR NO, real, 1.0e-12 lower limit, no upper limit (default 1.0e-9)
+ X_T_RISE          = {X_DU}        // NULL PERMITTED, VECTOR NO, real, no limits, hybrid XHDA_Bridge models only
+ X_T_FALL          = {X_DU}        // NULL PERMITTED, VECTOR NO, real, no limits, hybrid XHDA_Bridge models only
+ X_HAS_DELAY_CNT   = 0             // NULL PERMITTED, VECTOR NO, boolean, FALSE uses {delay}, TRUE uses cntrl input (default 0)
+ X_DELMIN          = {X_RT+X_FT}   // NULL PERMITTED, VECTOR NO, real, 0 lower limit, no upper limit (default 0)
+ X_DELMAX          = {20*X_DELMIN} // NULL PERMITTED, VECTOR NO, real, 0 lower limit, no upper limit (default 0)
+ X_DELAY           = {X_DELMIN/3}  // NULL PERMITTED, VECTOR NO, real, no limits (default 0)
+ X_BUFFER_SIZE     = 1024          // NULL PERMITTED, VECTOR NO, integer, 1 lower limit, no upper limit (default 1024)
+ X_RAISE_SLOPE     = {1/X_Rt}      // NULL PERMITTED, VECTOR NO, real, no limits, (Default = 1.0e9), set in V/s, 0.5G for Vcc = 1
+ X_FALL_SLOPE      = {1/X_Ft}      // NULL PERMITTED, VECTOR NO, real, no limits, (Default = 1.0e9), set in V/s, 0.5G for Vcc = 1
+ X_RANGE           = 0.1           // NULL PERMITTED, VECTOR NO, real, no limits, (Default = 0.1), for SLEW RATE only
+ X_IN_LOW          = {VCC*0.66}    // NULL PERMITTED, VECTOR NO, real, no limits (default 1.0), analog and hybrid models only
+ X_IN_HIGH         = {VCC*0.33}    // NULL PERMITTED, VECTOR NO, real, no limits (default 2.0), analog and hybrid models only
+ X_HYST            = {VCC*0.1}     // NULL PERMITTED, VECTOR NO, real, 0 lower limit, no upper limit (Default = 0.1)
+ X_OUT_LOWER_LIMIT = 0             // NULL PERMITTED, VECTOR NO, real, no limits (Default = 0)
+ X_OUT_UPPER_LIMIT = {VCC}         // NULL PERMITTED, VECTOR NO, real, no limits (Default = 1)
+ X_INPUT_DOMAIN    = 0.01          // NULL PERMITTED, VECTOR NO, real, no limits (Default = 0.1), input smoothing domain
+ X_FRACTION        = 1             // NULL PERMITTED, VECTOR NO, boolean 0 or 1 (default 1)
+ X_OUT_LOW         = 0             // NULL PERMITTED, VECTOR NO, real, no limits, hybrid and analog models only
+ X_OUT_HIGH        = {VCC}         // NULL PERMITTED, VECTOR NO, real, no limits, hybrid and analog models only
+ X_OUT_UNDEF       = {VCC/2}       // NULL PERMITTED, VECTOR NO, real, no limits, defaults to the arithmetic mean, hybrid XHDA_Bridge models only

* MODELS SECTION
*.model Analog_Hys hyst (in_low='X_IN_LOW' in_high='X_IN_HIGH' hyst='X_HYST' out_lower_limit='X_OUT_LOWER_LIMIT' out_upper_limit='X_OUT_UPPER_LIMIT' input_domain='X_INPUT_DOMAIN' fraction='X_FRACTION')
*.model Analog_Hys hyst (in_low={X_IN_LOW} in_high={X_IN_HIGH} hyst={X_HYST} out_lower_limit={X_OUT_LOWER_LIMIT} out_upper_limit={X_OUT_UPPER_LIMIT} input_domain={X_INPUT_DOMAIN} fraction={X_FRACTION})
*.model Analog_Hys hyst (in_low=X_IN_LOW in_high=X_IN_HIGH hyst=X_HYST out_lower_limit=X_OUT_LOWER_LIMIT out_upper_limit=X_OUT_UPPER_LIMIT input_domain=X_INPUT_DOMAIN fraction=X_FRACTION})
.model Analog_Hys hyst (in_low=X_IN_LOW in_high=X_IN_HIGH hyst=X_HYST out_lower_limit=X_OUT_LOWER_LIMIT out_upper_limit=X_OUT_UPPER_LIMIT input_domain=X_INPUT_DOMAIN fraction='X_FRACTION')
*
.model my_inverter d_inverter (rise_delay='X_RISE_DELAY' fall_delay='X_FALL_DELAY' input_load='X_INPUT_LOAD')
*
* HYSTERESIS SECTION
A_HYST 1 12 Analog_Hys
*
* INVERTER SECTION
A_INV 12 2 my_inverter
*
.ENDS X0_INV_HYS

*$

The rule is to put parameters to be replaced into {…}.

Anything else may work (for compatibility reasons with externally provided models), but there may be corner cases which do not work.

In addition, traditionally ngspice did not allow ‘-’ in a subcircuit name. You need to set the compatibility mode to PS and LT to enable it.

We have to check if we generally may allow ‘-’.