The VPI interface to Verilog

Verilog, as a language designed for verifying logic allows to describe a hardware setup in a very general way. Simulators, such as Icarus Verilog can then be used to simulate this hardware setup. Tools such as gtkwave can be used to verify the output of a circuit by looking at the waveforms the simulation generates.

Simulavr comes with an interface to (Icarus) Verilog. If the ./configure script finds the necessary header file for the interface, the so called VPI (Verilog Procedural Interface) to Icarus Verilog will be build. The result of this is a file called avr.vpi. This file, in essence a shared library, can then be used as an externally loaded module after compilation:

$ iverilog [...]          # compile verilog .v into .vvp

$ vvp -M<path-to-avr.vpi> -mavr [...] # run compiled verilog
                                      # with additional
                                      # avr.vpi module

In principle, it would also be possible to implement the AVR completely in verilog (and there are several existing models, see e.g. opencores.org), but this would result in decreased performance and duplicated effort, as not only the core needs to be implemented, but also the complex on-board periphery.

Usage

The Verilog interface comes with glue code on the verilog side, for which the main file is avr.v in src/verilog. This is a thin wrapper in Verilog around the exported methods from the core of Simulavr, consisting of the AVRCORE module encapsulating one AVR core and avr_pin for I/O through any AVR pin. On top of this, files named avr_*.v exist in the same directory which contain verilog modules reflecting particular AVR models from Simulavr. The modules in these files are meant to be the interface to be used to connect to simulavr by the user, they have a very simple signature:

module AVRxyz(CLK, port1, port2, ...);

where port1, port2, … are simple arrays of inout wires representing the various ports of the selected AVR. Note that the width of the arrays as visible from the Verilog side is always eight; this does not mean that all bits are connected on the simulavr side!

Clock generation and distribution to the AVR cores is done from the verilog side. Simply connect a clock source with the preferred frequency to the CLK input of the AVR code.

The more complete, low level interface to simulavr in avr.vpi can be accessed directly. For documentation of the available functions, see either src/vpi.cpp or look into the implementation of the high level modules in avr_*.v.

Example iverilog command line

A simple run with the avr.vpi interface could look like this:

$ iverilog -s test -v -I. $(AVRS)/avr.v $(AVRS)/avr_ATtiny15.v \
    $(AVRS)/avr_ATtiny2313.v -o test.vvp

Here for a model having both an ATtiny15 and an ATtiny2313 in the simulation, and the top module test and the environment variable $AVRS pointing to the right directory.

A set of a few simple examples has been put into the verilog/examples subdirectory of the Simulavr source distribution. This directory also contains a Makefile which can be used as an example of command sequences for compiling verilog, running it and producing .vcd output files to be viewed with gtkwave.

Bugs and particularities

  • No problems have been found when instantiating multiple AVR instances inside verilog.

  • Analog pins have not been tested and will probably need some changes in the verilog-side wrapper code.