-
Notifications
You must be signed in to change notification settings - Fork 213
QEP: Verilog AMS interface
Author: Guilherme
Status: active, beta in Qucs 0.0.18
Created: 13/02/2014
This is proposal about the usage of dynamically compiled Verilog-A devices into Qucs. It reuses some of the features already available since 0.0.16 (see Mike Notes). However the changes presented here greatly improve matters on the side of compiling and loading Verilog-A modules dynamically. There will be no need to recompile Qucs and QucsAtor to add new models. Model symbols and properties for Qucs as well as the compiled modules for QucsAtor will be loaded dynamically during runtime. I will enable users to independently add models to Qucs, either their own creations or Verilog-A models/modules available from elsewhere (provided ADMS is capable of handling them).
TODO
The fist alpha release works fine, but many other issues were identified in the process.
These are a few of the issues that need to be addressed.
- cleanup the
ucs.cpp
- cleanup the vacomponent on the UI.
- check that the verilog-a module and file have the same name
- check that the module name is not already in use on qucsator
- move from JSON to XML for dynamic loader icon and parameters. Qt4 series has no JSON writer
- add a netlist component for building the model, similar to
include hdl somemodel.va
that- kick in the model builder
- instruct the simulator to load the model
- add a netlist component to load list of model parameters
- add a UI component or method to load a list of model parameters
- decouple UI and simulator
- investigate auto-diff for the derivatives
- The user has a working has created a nice little project in Qucs
- The user wrote a
module
in Verilog-A (VA
) and wants to include in the simulation.
The following is supported since 0.0.16 (see Mike Notes). Se below for proposal to allow dynamic load
- The
VA
is added to the project- syntax highlight is active
- Press
F9-Edit Text Symbol
, Qucs generate symbol - User edit symbol, save
- save symbol emits C++ code (
[module].dat
) with Lines, Texts, Ports,…, to be integrated into Qucs
- save symbol emits C++ code (
- the
VA
is passed thruqucsMODULEgui.xml
to emit C++ code - the generated code (
.gui.h
,.gui.cpp
)h as to be modified to include the[module].dat
symbol, symbol bounding box and device name - files are added to the build system
- new device is added to via
REGISTER_VERILOGA_
inqucs/qucs/module.cpp
- compile Qucs
-
modify the
F9
function-
Schematic::saveDocument()
callssaveSymbolCpp ()
-
SymbolPaints
is appended as the symbol is drawn. -
does it loadind
[module].sym
appends toSymbolPaints
?? -
modify
Schematic::saveSymbolCpp
inschematic_file.cpp
- it streams the symbol
SymbolPaintings
to C++, terminals, bounding box, texts - each painting has a method to emit c++ ex.
Arrow::saveCpp()
- TODO emit an easy to parse symbol file with Lines, Texts…
- it streams the symbol
-
let us call the modified output
[module]_symbol.dat
-
-
create a modified
qucsMODULEguiLoad.xml
to- process
VA
and generate an easy to parse file containing Description, Properties,… - let us call it
[module]_props.dat
- process
-
add a generic component place holder
vadynamic
derived from base classComponent
Finally, to the actual loading of dynamic modules symbols and properties can take place
-
a function scan the project dir for
[module]_symbol.dat
,[module]_props.dat
-
modify
Module::registerComponent
- create a new
vadynamic
object - assign content of
[module]_symbol.dat
,[module]_props.dat
to new component - register new component into
Q3Dict<Module> Module::Modules
Q3PtrList<Category> Category::Categories
- create a new
-
the netlister should be able to seamlessly read the above
Dict
andPtrList
and emit a valid netlist with the correct device signature (name and properties) -
the new component should show up in the Component Tab for Verilog-A or User defined models
-
user is able to save the schematic, generate netlist
-
for simulation the steps outlined on the next section must be performed.
The dynamic library [module].{so,dylib,dll}
has to be compiled before launching QucsAtor
- The
VA
is run throughadmsXml
with adequate.xml
files-
va2cpp.makefile
generates C++ - TODO Report error messages, minimal checking
- TODO raise error messages all the way up to Qucs
-
- The
C++
is compiled to adynamic library
-
cpp2lib.makefile
compiles dynamic library[module].{so,dylib,dll}
- TODO Report error messages, minimal checking
- TODO raise messages up to Qucs
-
Inspecting the cpp2lib.makefile
you notice that the dynamic library links to libqucs
and leaves the exportedfactorycreate
and factorydef
undefined. These symbols will be defined at load time.
Summary of file changes and new functions that load and release dynamic modules/libraries.
The circuit
base class defines two external factories. Factories will be populated during the load time of the dynamic libraries containing de derived class objects (VA modules) with function pointers which return constructors and definition.
// typedef to make it easier to set up our factory
typedef qucs::circuit *maker_t();
// function typdefs to make it easier to set up our factories
typedef qucs::circuit *creator_t();
typedef struct define_t *defs_t();
// our global factories defined in module.cpp
extern "C" {
extern std::map<std::string, creator_t *, std::less<std::string> > factorycreate;
extern std::map<std::string, defs_t *, std::less<std::string> > factorydef;
}
The global factories (stc::map) to store function pointers from dynamic libraries are defined in module.cpp
:
factorycreate
factorydef
- very similar to the static registration via
registerModule
- Scans the project directory for dynamic libraries
- Load any found library
- Create new modules out of the factory
- Register dynamic modules into the global hash
- Once modules are registered into the hash the simulator does not distinct between static and loaded modules.
- TODO error checking/handling
- Closes any previously opened library
Main QucsAtor source. It makes use of the functions described above:
- module::closeDynamicLibs()
- module::registerDynamicModules ()
The file qucsMODULEcore.xml
was modified to emit the loader interface. It just appends the following snippet to the .core.cpp
file (properly replacing the module name mypotentiometer
in this case). This piece of code is needed to add the dynamic module function pointers into their respective factories during library load.
Note the last argument -A dylib
which is parsed and used to emit the dynamic loader code.
amdsXml ... -e qucsMODULEcore.xml -A dylib
// loader constructor interface
extern "C" {
class va_proxy { public:
va_proxy(){
// register the constructor and the definitions with the global factories
// Note that ::create and ::definition are handled by expanding the CREATOR define constructor
factorycreate["mypotentiometer"] = mypotentiometer::create;
factorydef ["mypotentiometer"] = mypotentiometer::definition;
}
};
// our one instance of the proxy
va_proxy p;
}
It is rather difficult to create and use modules directly from the command line. It is very hard to figure out the correct parameters, ports and to connect circuit elements. Further tools could be created to enable introspection into the VA
and C++
sources and dynamic libraries
. Automatic documentation or a help mechanism could document the component netlist signature enabling users to manually create and edit netlists. Better support should be offered in the future.
The proposed Qucs dynamic loader is inspired after:
Dynamic Class Loading for C++ on Linux, May 01, 2000 By James Norton. http://www.linuxjournal.com/article/3687
The above code recently tested on Linux, Mac OS and Windows can be found at https://github.com/guitorri/draw
Most of the dynamic loader boiler-place code and build system is already in place for Qucs. What remains it so produce the import library
to enable the dynamic library compilation with undefined factory symbols (see 5 Caveats).
The loader is capable of loading a dynamic library and instantiate an object out of it. Support makefiles are provided to manage the compilation steps of the source files and the final library.
What remains is the proper registration of loaded classes into the QucsAtor internal machinery so that they can be used for simulation of netlists.
-
Linux, OSX:
- Working fine, uses dlopen, dlclose to handle the dynamic libraries
-
Windows
- Compiles fine, uses
LoadLibrary
,FreeLibrary
to handle the dynamic libraries - The library links against
libqucs
, which has the factories defined.
- Compiles fine, uses
Code merged on release 0.0.18.
TODO
Tested on:
- Debian 6.0.7, g++ 4.4.5
- Debian 7.1.0, g++ 4.7.2, bison 2.5, flex 2.5.35
- Mac OSX 10.8.5, clang++ LLVM version 4.2 (clang-425.0.28)
- Windows XP, MinGW 4.7 (loader not working, see 5 Caveat)
Qucsator currently rely on a simple scanner for dynamic modules in work dir.
How it is supposed to work:
- It will list (
ls
) the working directory contents looking for libraries - It will try to open each found library and put its handle into a list
- Just by opening the lib it will already populate the factorycreate and factorydef
- The factory is then iterated to create new modules and to add them to the global hash
TODO:
Add destructor for loaded objects- Add other methods (besides search on work dir) to find the libraries
Go to the test project to:
- convert Verilog-A to C++
- compile C++ into shared library
- run
qucsator
to demo the loading and creation of the dynamic objects
This example handles 3 VA modules loaded dynamically. The results are compared agains the original statically compiled VA modules
- see the
inverter.pdf
for a screenshot - the original Qucs
potentiometer
andbsim4v30{n,p}MOS
modules and files where just renamed to differentiate them from the statically models already compiled into Qucsator. - run
build_run.sh
(please adjust PREFIX inside the script), it will:- 'elaborate' the VA to C++
- 'compile' the C++ to dynamic libraries
- run the original netlist with original Qucs static models
- run the modified netlist with dynamically loaded models
- qucsator will load any dynamic lib available in the working dir
- run diff on the original and modified resulting datasets
-
qucsMODULEcoreload.xml
is a slight modification fromqucsMODULEcore.xml
. It appends a few lines of code which allow the dynamic loading of the modules. If anyone knows howadmst
can be used to append to an existing file, we can keep the originalcore
and add another xml for theload
part.
Sorry, this is an old output with just one dynamic component, mypotentiometer
:
~/git/qucs/va_loader_prj $ sh run_mypotentiometer.sh /Users/guilherme/local/qucs-dylib/bin/
/Users/guilherme/local/qucs-dylib/bin//qucsator -i netlist_mypot.txt -o data_pot.dat
The current working directory is: /Users/guilherme/git/qucs/va_loader_prj
/Users/guilherme/git/qucs/va_loader_prj/mypotentiometer.dylib
Try loading: /Users/guilherme/git/qucs/va_loader_prj/mypotentiometer.dylib
factory.size() is 1
factory contains: mypotentiometer
==> quick inspection of definitions...
type: mypotentiometer
nodes: 3
action: 0
required->key: R_pot
parsing netlist...
checking netlist...
subcircuit root
mypotentiometer:POT1 Vin Vout gnd R_pot="10000" Rotation="120" Taper_Coeff="0" LEVEL="1" Max_Rotation="240" Conformity="0.2" Linearity="0.2" Contact_Res="1" Temp_Coeff="100" Tnom="26.85" Temp="26.85"
Vac:V1 Vin gnd U="1V" f="100Hz" Phase="0" Theta="0"
TR:TR1 Type="lin" Start="0" Stop="0.01s" Points="101" IntegrationMethod="Trapezoidal" Order="2" InitialStep="1e-09s" MinStep="1e-16" MaxIter="150" reltol="0.001" abstol="1e-12A" vntol="1e-06V" Temp="26.85" LTEreltol="0.001" LTEabstol="1e-06" LTEfactor="1" Solver="CroutLU" relaxTSR="no" initialDC="yes" MaxStep="0"
netlist content
1 mypotentiometer instances
1 Vac instances
1 TR instances
creating netlist...
input::createCircuit, got: mypotentiometer
input::createCircuit, got: Vac
NOTIFY: TR1: creating node list for initial DC analysis
NOTIFY: TR1: solving initial DC netlist
NOTIFY: TR1: creating node list for transient analysis
NOTIFY: TR1: solving transient netlist
NOTIFY: TR1: average time-step 1.72117e-05, 147 rejections
NOTIFY: TR1: average NR-iterations 2.50602, 0 non-convergences
install XML files to /include/qucs-coreinstall headers to /include/qucs-coreinstall admsXml into the system-
makefile va2cpp- should be generated by qucsator
- or find a way to pass VA model as variable
-
patch the C++ core.cpp to include the unmangled interface- Can it be handled by the XML files during code generation?
-
makefile cpp2lib- either generated by qucsator
- or find a way to pass VA model as variable
- modify circuit.h to
add typedef for factorydefine extern factory symbol
- modify ucs.cpp to
add dlopen header- find project dir, locate the va, cpp, and libs (lauch point for qucsator?)
-
getcdw() current user dir program startedhttp://stackoverflow.com/questions/143174/how-do-i-get-the-directory-that-a-program-is-running-from - check for prefix in front of -i /netlist.txt, in this case the working dir is elsewhere
-
load dylibs from project diradd factoryinstantiate objects via factoryregister object/class into qucsator machinery- add destructor for loaded objects
- add support for OSX, Windows
add libdl (-ldl) to the build (or ../configure LIBS="-ldl" / LDFLAGS='-ldl' make install)-
add -rdynamic/-Wl,-export-dynamic to enable libs back-linking the 'factory' symbol- binary exports all symbols, can increase binary size, use list of needed symbols? http://www.cplusplus.com/forum/unices/25570/
-
removed the -fno-rtti- the dyn. lib could not be loaded,
undefined symbol: _ZTI7circuit
- the dyn. lib could not be loaded,
- otool -L
- ldd
- nm
- readelf -d
- objdump -x
- c++filt
[ Home | Development | Examples ]