132 lines
4.9 KiB
ReStructuredText
132 lines
4.9 KiB
ReStructuredText
|
|
Loadable Target API (ivl_target)
|
|
================================
|
|
|
|
In addition to the standard VPI API, Icarus Verilog supports a non-standard
|
|
loadable target module API. This API helps C programmers write modules that
|
|
Icarus Verilog can use to generate code. These modules are used at compile
|
|
time to write the elaborated design to the simulation or netlist files. For
|
|
example, the vvp code generator is a loadable target module that writes vvp
|
|
code into the specified file.
|
|
|
|
Loadable target modules gain access to the 'elaborated' design. That means,
|
|
the source files have been checked for syntax and correctness, any synthesis
|
|
and general optimization steps have been performed, and what is left is a
|
|
design that reflects but is not exactly the same as the input Verilog source
|
|
code. This relieves the modules of the burden of supporting all the odd
|
|
corners and complexities of the Verilog language.
|
|
|
|
The Target Module API
|
|
---------------------
|
|
|
|
The API is defined in the header file "ivl_target.h" which is installed with
|
|
Icarus Verilog. The header defines the functions that the module writer can
|
|
use to get at the elaborated design during the course of writing the output
|
|
format.
|
|
|
|
The target module API function "target_design" is special in that the API does
|
|
not provide this function: The target module itself provides it. When the
|
|
compiler loads the target module, it invokes the "target_design" function with
|
|
a handle to the design. This is the point where the target module takes over
|
|
to process the design.
|
|
|
|
Compiling Target Modules
|
|
------------------------
|
|
|
|
Compiling loadable target modules is similar to compiling VPI modules, in that
|
|
the module must be compiled with the "-fPIC" flag to gcc, and linked with the
|
|
"-shared" flag. The module that you compile is then installed in a place where
|
|
the "iverilog" command can find it, and configuration files are adjusted to
|
|
account for the new module.
|
|
|
|
This code::
|
|
|
|
# include <ivl_target.h>
|
|
|
|
int target_design(ivl_design_t des)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
is an example module that we can write into the file "empty.c"; and let us
|
|
compile it into the module file "empty.tgt" like so::
|
|
|
|
% gcc -o empty.tgt -fpic -shared empty.c
|
|
|
|
This makes the "empty.tgt" file an a dynamically loaded shared object.
|
|
|
|
Creating the Target Config File
|
|
-------------------------------
|
|
|
|
The target config file tells the Icarus Verilog core how to process your new
|
|
code generator. The ivl core expects two configuration files: the name.conf
|
|
and the name-s.config files. The "-s" version is what is used if the user
|
|
gives the "-S" (synthesis) flag on the command line.
|
|
|
|
The stub target, included in most distributions, demonstrates the config
|
|
files. The "stub.conf" file is::
|
|
|
|
functor:cprop
|
|
functor:nodangle
|
|
-t:dll
|
|
flag:DLL=stub.tgt
|
|
|
|
and the "stub-s.conf" file is::
|
|
|
|
functor:synth2
|
|
functor:synth
|
|
functor:syn-rules
|
|
functor:cprop
|
|
functor:nodangle
|
|
-t:dll
|
|
flag:DLL=stub.tgt
|
|
|
|
Note that the "stub-s.conf" file contains more lines to invoke internal
|
|
synthesis functions, whereas the "stub.conf" invokes only the basic
|
|
optimization steps.
|
|
|
|
In general, only the last line (The "flag:DLL=<name>.tgt" record) varies for
|
|
each target. For your target, replace the <name> with the name of your target
|
|
and you have a configuration file ready to install. Note that this is the name
|
|
of your target module. This is in fact how the config file tells the compiler
|
|
the name of your module.
|
|
|
|
The rest of the config file is best taken as boiler plate and installed as is,
|
|
with one difference. If your target is a synthesis target (for example a mosis
|
|
code generator or a pld code generator) that expects synthesis to happen, then
|
|
it makes the most sense to create both your config file like the "stub-s.conf"
|
|
config file. This causes the compiler to do synthesis for your target whether
|
|
the user gives the "-S" flag or not.
|
|
|
|
Installing the Target Module
|
|
----------------------------
|
|
|
|
Finally, the "empty.conf", the "empty-s.conf" and the "empty.tgt" files need
|
|
to be installed. Where they go depends on your system, but in Linux they are
|
|
normally installed in "/usr/lib/ivl".
|
|
|
|
|
|
LPM Devices
|
|
-----------
|
|
|
|
All LPM devices support a small set of common LPM functions, as
|
|
described in the ivl_target header file. The ivl_lpm_t object has a
|
|
type enumerated by ivl_lpm_type_t, and that type is accessible via the
|
|
ivl_lpm_type function.
|
|
|
|
The following are type specific aspects of LPM devices.
|
|
|
|
* IVL_LPM_UFUNC
|
|
|
|
This LPM represents a user defined function. It is a way to connect
|
|
behavioral code into a structural network. The UFUNC device has a
|
|
vector output and a set of inputs. The ivl_lpm_define function returns
|
|
the definition as an ivl_scope_t object.
|
|
|
|
The output vector is accessible through the ivl_lpm_q, and the output
|
|
has the width defined by ivl_lpm_width. This similar to most every
|
|
other LPM device with outputs.
|
|
|
|
There are ivl_lpm_size() input ports, each with the width
|
|
ivl_lpm_data2_width(). The actual nexus is indexed by ivl_lpm_data2().
|