> This is a **DRAFT** [TOC] # Preface Device models take a central place in circuit simulators making up large percentages of the codebase (over 90% for ngspice for example). Since the development of compact models is a challenging area of research, the models are generally not created by the simulator developers. Rather they are written and published as Verilog-A files ( especially since the [CMC](https://si2.org/cmc/) has made this a requirment for membership ). Currently many simulators impliment models into their own system by hand because an FOSS Verilog-A compiler has not been available. This process takes a lot of developer time, leads to implimentation bugs, outdated models (potentially leading to bugs already fixed in newever version) and only allows a limited set of models in a simulator. The OpenVAF Project is an OpenSource VerilogA compiler that has been developed to adress these issues. It is a state of the Art compiler allowing the compilation of all publically available compact models known to the author. OpenVAF differentiates itself to prior Art such as [ADMS](https://github.com/Qucs/ADMS) by compiling the compact models straight to machine code instead of requiring simulators to impliment the backend of the compiler themselves. To this end modern compiler construction techniques are employed to analyse the source code. The interface between simulator and compact model is however simulator specific and can not be automatically generated by OpenVAF. It is up to the simulator developers to develop an interface that can load models compiled using OpenVAF. Therefore a simulator independent interface is required that can be loaded by simulator specific implimentations. To this end the "**O**pen **S**imulator **Device** **I**nterface" (hence forth OSDI) has been developed and is specified in this document # Overview The OSDI is made up of into three primary components: * **Simulator Libary** - Provided to OpenVAF to allow compilation of simulator specific aspects of the Verilog-A language. * **Model Libary** - Executable model code that can be dynamically loaded by the simulator * **Model Info Store** - Information about the model (such as parameters and terminals and branches) > Link to relevant sections > [name=DSPOM] The Verilog-A allows a variety of System function calls that can not be completly compiled in a simulator agnostic manner (for example `limexp`). As such OpenVAF requires a **Simulator Libary** that is linked to models at which implimentens the simulator specific part of these functions. This libary has to be provided as a static libary during the compilation of the model. As a result of this compilation OpenVAF produces a shared libary and a [bincode](https://github.com/servo/bincode) file. > compress into an archive? > * userfriendly (one file to copy around) > * decompressing makes simulator startup slower > * probably just as an option (if users want that they have to decompress themselves) > [name=DSPOM] The shared libary is called **Model Libary** and provides the main logic of the model as functions that are modeled after the `SPICEdev` struct from SPICE3. However the shared libary only contains functions that contain logic derived from user specified imperative code (the analog block). Other information about static properties of the model - such as branches and ports (terminals) - are provided as a serialized bincode file called the **Model Info Store**. These components will first be formally specified in an implimentation agnostic way. Afterwards practical guide to impliment OSDI into an simulator using the [offical OSDI libary](https://gitlab.com/DSPOM/OSDI) are provided # Formal definition ## Simulator Libary The simulator libary is a static libary provided to the model compiler when generating the OCDI from Verilog-A. It is simulator specifica but shall **not link to the Simulator**. All functions exposed in this libary must adhere to the **C-Calliong Convention**. The Verilog-A standard allows some function calls to call to simulator specific fuctions with use provided names (such as `$limit(V(x,y),"pnjlimit")`). The functions that the Simulator Libary has to impliment can therefore not be fully specified as a header file here. Instead this specification first describes all functions that every valid Simulator Libary has to impliment. Afterwards each mechanism that may require additional functions is touched upon in a seperate subsection. ### Standard functions The following functions **have** to be implimented by **every** Simulator Libary: #### Limited exponential > [name=Accellera: The Verilog-AMS Standard 2.4, Section 4.5.13] > [color=#f0e38e] The `limexp()` function is an operator whose internal state contains information about the argument on previous iterations. It returns a real value which is the exponential of its single real argument, however, it internally limits the change of its output from iteration to iteration in order to improve convergence. On any iteration where the change in the output of the `limexp()` function is bounded, the simulator is prevented from terminating the iteration. Thus, the simulator can only converge when the output of limexp() equals the exponential of the input. The general form is: > ``` Verilog > limexp ( expr ) > ``` > The apparent behavior of `limexp()` is not distinguishable from `exp()`, except using limexp() to model semiconductor junctions generally results in dramatically improved convergence. There are different ways of implementing limiting algorithms for the exponential. A compiler targetting OSDI shall generate an `exp` call for an `limexp` call and pass the result together with the value from the previous iteration to the `limexp` function defined in the Simulator Libary. The value returned by this function will be used instead of the exp value and stored for the next iteration. The `limexp` function in the simulator libary shall have the following interface: ``` C double limexp(void* ctk, double previous_iteraton, double current_iteration); ``` ### Time derivative The time derivative operator (`ddt(x)` in Verilog) needs special consideration during Simulation, because their feedback leads to differential equations during. Furthermore it will perform differently in different analysis modes (DC/AC/Transiant). As such the implimentation is highly simulator specific.The Simulator Libary shall provide a function with the following declaration to this end: ```C void ddt(void* ctk, void** statevectors, size_t offset, double* derivatives, size_t derivative_count) ``` The `statevectors` parameter points to an array of state vectors (each entry is a timestep where 0 is the current time step). The `offset` parameter indicates the distance of the variable to be derived from the start of the state vector. (The time derivative is stored at `offset+1`). The `derivatvies` argument contains a list of all partial derivatives of the argument. The `ddt` function shall overwrite these values with the partial derivative of the time derivative of x. An example for a simple capacitor: `ddt(C*V(x))`. In this case `statevector[n][offset]` contains the charge `C*V(x)` of the `n`th time step. While `statevector[n][offset+1]` contains the current of the `n`th time step (for the current time step `n=0` this value defaults 0). The `ddt` function shall calculate the current which is usually achieved with a second order implicit integral method (example uses TRAPEZOIDAL method): ```C statevector[0][offset+1] = - statevector[1][offset+1] * ckt->CKTag[1] + ckt->CKTag[0] * ( statevector[0][offset] - statevector[1][offset]); ``` The time derivative is usually just calculated by multiplying the capacity with a linear factor ```C derivatives[0] = derivatives[i]*ckt->CKTag[0] ``` Since `ddt` needs to be valid for any input the amount of partial derivatives may change and as such we need a loop ```C for (size_t i = 0;i<derivative_count;i++){ derivatives[i] = derivatives[i]*ckt->CKTag[0] } ``` #### Other calls > More will come here ### $limit > [name=Accellera: The Verilog-AMS Standard 2.4, Section 9.17.3] > [color=#f0e38e] Other nonlinearities besides the exponential are present in semiconductor device compact models. The `$limit()` function provides a method to indicate these nonlinearities to the simulator and, if necessary, recommend a function to use to limit the change of its output from iteration to iteration. Syntax 9-12 shows the methods of using the $limit() function. > ``` > limit_call ::= > $limit ( access_function_reference ) > | $limit ( access_function_reference , string, arg_list ) > | $limit ( access_function_reference , analog_function_identifier , arg_list ) > ``` > >When the simulator has converged, the return value of the $limit() function is the value of the access function reference, within appropriate tolerances. For some analysis types or solution methods, such as damped Newton-Raphson, the return value of the $limit() function may depend on the value of the access function and internal state of the function. In all cases, the simulator is responsible for determining if limiting should be applied and what the return value is on a given iteration. When more than one argument is supplied to the $limit() function, the second argument recommends a function to use to compute the return value. When the second argument is a string, it refers to a built-in function of the simulator. The two most common such functions are `pnjlim` and `fetlim`, which are found in SPICE and many SPICE-like simulators. Simulators may support other built-in functions and need not support `pnjlim` or `fetlim`. The `$limit` tasks allows users to call arbitrary simulator specific functions. These functions need to be provided with the Simulator Libary otherwise a compiler error shall occur. This is in contradition to the Verilog-AMS standard wich requires the simulator to select an appropriate limit funciton upon encountering an unkown call. OSDI currently specifies no way for the simulator to specify which limiting function shall be used and as such doesn't support this aspect of the Verilog-A language. > Wie soll das auch gehen? > Höchsten eine standard limit function für jede anzahl n von parametern? > [name=DSPOM] As such every call to `$limit` requires a function name to be specified (see example) ``` Verilog // allowed according to standard but not compataible with OCMI $limit(VAL) $limit(VAL,arg1,..argn) // allowed by compilers that target OCDI $limit(VAL,"name") $limit(VAL,"name",arg1,arg2,..,argn) ``` A function that was called from Verilog with $n$ parameters ($n$ may be zero) shall be defined in the Simulator Libary with the following interface: ``` C double lim_name(double previous_iteraton, double current_iteration, double: arg1, double: arg2,.., double argn); ``` Currently only real valued arguments are supported. This can change in the future. Furthermore the only internal state that is allowed is the previous iteration of the loop ### Other mechanisms > More will follow here ## Model Libary The model libary is a dynmaicall linked libary (`.so`/`.dll`) emitted as the result of compilation by a Verilog-A compiler targeting OSDI. It contains all code derived from a Verilog model that a simulator can execute. The Model Libary is made up of multiple functions oftentimes corresponding to functions in the `SPICEdev` struct oftentimes used in Simulator based on `SPICE3`. All functions exposed by the Model Libary must adhere to the C Calling Convention. > Just quickly wrote some functions down this will change > [name=DSPOM] ### load ``` C int load(void** state_vector, double** currents); ``` ### Temperature update ``` C int update_temp(double temp, void** state_vector); ``` ### Noise Update ``` C int update_temp(double* noise_sources, void** state_vector); ``` ### Check modelcard ``` C int check_modelcard(void* modelcard); ``` ## Model Info Store The model info store contains static information about the model such as Ports, Nets and Parameters and is an artifact of model compilation. There is no formal specification for the model info store yet instead the reference OSDI libary currently defines the specification in terms of what it impliments (this will channge in the future) # Partical Guide This section will describe how to integrate OSDI model generated by OpenVAF into your simulator. For practical purposes you should refrain from implimenting your own implimentation of the Model Info Store and instead use the [offical OSDI libary](https://gitlab.com/DSPOM/OSDI) which has a permissive license allowing inclusion into every project. The OSDI libary impliments a set of structs that allow representing the Model Info Store in memory and functions to serialize and deserialize this representation to a File quickly. > Write this when OSDI libary is actually implimented > [name=DSPOM]