h1. Ruby-VPI user manual This manual was last updated on <%= Time.now %>. It is meant to be read in conjunction with the "reference documentation for Ruby-VPI":../ref/ruby/index.html. In addition, if you are new to "the Ruby language":http://www.ruby-lang.org, you are encouraged to "explore its documentation":http://www.ruby-lang.org/en/documentation/ alongside this manual. You can give feedback about this manual and, in general, any aspect of the Ruby-VPI project on the "project forums":http://rubyforge.org/forum/?group_id=1339. _Happy reading!_ h2(#terms). Terms Copyright (c) 2006 Suraj N. Kurapati. Permission is granted to copy, distribute and/or modify this document under the terms of the "GNU Free Documentation License":http://www.gnu.org/copyleft/fdl.html, Version 1.1 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts and no Back-Cover Texts. A copy of the license is included in the the file named "LICENSE":./LICENSE. The admonition and navigation graphics used in this manual are Copyright (c) 2005, 2006 "Tango Desktop Project":http://tango.freedesktop.org and are licensed under "these terms":./images/LICENSE. h1(#intro). Introduction <%= File.read 'intro.inc' %> h2(#intro.license). License Ruby-VPI is "free software":http://en.wikipedia.org/wiki/Free_software ; you can redistribute it and/or modify it under the terms of the "GNU General Public License":http://www.gnu.org/copyleft/gpl.html as published by the "Free Software Foundation":http://www.fsf.org ; either version 2 of the License, or (at your option) any later version. h2(#intro.related-works). Related works * "JOVE":http://jove.sourceforge.net is a Java interface to VPI. * "Teal":http://teal.sourceforge.net is a C++ interface to VPI. * "ScriptEDA":http://embedded.eecs.berkeley.edu/Alumni/pinhong/scriptEDA/ is a Perl, Python, and Tcl interface to VPI. * "RHDL":http://rhdl.rubyforge.org is a hardware description and verification language based on Ruby. * "MyHDL":http://myhdl.jandecaluwe.com is a hardware description and verification language based on Python, which features conversion to Verilog and co-simulation. h3(#intro.related-works.pli). Ye olde PLI The following projects utilize the archaic *tf* and *acc* PLI interfaces, which have been officially deprecated in IEEE Std 1364-2005. * "ScriptSim":http://www.nelsim.com is a Perl, Python, and Tcl/Tk interface to PLI. * "Verilog::Pli":http://www.veripool.com/verilog-pli.html is a Perl interface to PLI. * "JPLI":http://www.time-rover.com/jpli/ is a proprietary Java interface to PLI. h1(#background). Background h2(#background.methodology). Methodology Ruby-VPI presents an open-ended interface to VPI. Thus, you can use any methodology you wish when writing tests. However, being an agile language, Ruby makes it _very_ easy to use agile development practies such as "TDD":#glossary.TDD and "BDD":#glossary.BDD. h2(#background.vocab). Terminology <% note do %> Have a look at the "glossary":#glossary for definitions of terms used in this manual. <% end %> As a newcomer into the world of Verilog, I often heard the term *test bench*: "I ran the test bench, but it didn't work!" or "Are you crazy?!! You _still_ haven't written the test bench?", for example. I poured through my textbook for a definition of the term, but it was to no avail. Instead, it nonchalantly employed the term _throughout_ its being, as if mocking my ignorance of what seems to be universal knowledge. Defeated, I turned to my inner faculties to determine the answer. Let's see, the term _test bench_ has the word _test_—so it has something to do with testing—and it has the word _bench_—so maybe it's referring to a table where the testing should occur. This reasoning grew increasingly familiar as my mind rummaged through towering stores of obsolescence and ultimately revealed dreaded memories of sleepless anguish: debugging electronics in the robotics laboratory. Aha! I exclaimed, hesitantly, rushing to dismiss the past. The term has its roots in the testing of electronic devices, where an engineer would sit at a bench in an electronics laboratory and verify that an electronic component satisfies some criteria. The bench would be furnished with tools of measurement and manipulation—such as oscilloscopes, voltmeters, soldering irons, and so on—which help the engineer to verify the electronic component or locate the sources of defects in the component. Alright, now I remember what a laboratory bench is, but how does that compare with the term test bench? Surely they cannot have the same meaning, because it doesn't make sense to _run_ a laboratory bench or to _write_ one. Thus, to avoid propagating such confusion into this manual, I have attempted to clarify the terminology by "simplifying and reintroducing it in a new light":#glossary. h2(#background.org). Organization <% figure "Overall organization of a test", "#fig..organization" do %> !figures/organization.png! <% end %> As shows, a "test":#glossary.test is composed of a "bench":#glossary.bench, a "design":#glossary.design, and a "specification":#glossary.specification. To extend the "analogy of an electronics laboratory":#background.vocab, the _bench_ acts as the laboratory bench which provides measurement and manipulation tools. The _design_ acts as the electronic component being verified by the engineer. And the _specification_ acts as the engineer who measures, manipulates, and verifies the electronic component. <% figure "Detailed organization of a test", "#fig..organization.detail" do %> !figures/organization_detailed.png! <% end %> Now, let us take a more detailed look at this organization, as illustrated in . Notice that Ruby-VPI encapsulates all communication between the Ruby interpreter and VPI. This allows the specification, or any Ruby program in general, to access VPI using nothing more than the Ruby language! Thus, Ruby-VPI removes the burden of having to write C programs in order to use VPI. h2(#background.relay). Ruby/Verilog interaction In a typical VPI application written in C, the _Verilog simulator_ is in charge. Verilog code temporarily transfers control to C by invoking C functions, which return control to Verilog when they finish. In contrast, Ruby-VPI puts the _specification_ in charge. The specification temporarily transfers control to the Verilog simulator by invoking the @Vpi::advance_time@ method, which returns control to the specification when it finishes. This process is illustrated in . Ruby-VPI's approach is the same as any software testing framework, where the _specification_ drives the design under test. Whereas, the typical VPI & C approach is literally _backwards_ because the design under test drives the specification. <% figure "Interaction between Ruby and Verilog", "#fig..ruby_relay" do %> !figures/ruby_relay.png! # The current simulation time is _X_. # The specification invokes the @Vpi::advance_time@ method with parameter _Y_, which specifies the number of simulation time steps to be simulated. # The Verilog simulator is now in control (temporarily). # The current simulation time has _not_ changed; it is still _X_. # The Verilog simulator simulates _Y_ simulation time steps. # The current simulation time is now _X + Y_. # The Verilog simulator returns control back to the specification. <% end %> h1(#setup). Setup h2(#setup.manifest). Manifest When you extract a release package, the following is what you would expect to find. * doc contains user documentation in various formats. * ref contains reference API documentation in HTML format. * ext contains source code, written in the C language, for the "core of Ruby-VPI":#background.org. * lib contains Ruby libraries provided by Ruby-VPI. * bin contains various tools. See for more information. * samp contains example tests. See for more information. h2(#setup.reqs). Requirements The following software is necessary in order to use Ruby-VPI. * Verilog simulator - Ruby-VPI is known to work with the following simulators. However, you should be able to use it with any Verilog simulator that supports VPI. ** "GPL Cver":http://www.pragmatic-c.com/gpl-cver/ - version 2.11a or newer is acceptable. ** "Icarus Verilog":http://www.icarus.com/eda/Verilog/ - version 0.8 is _mostly_ acceptable -- you *will not* be able to "access child handles through method calls":#background.org.vpi.util. The reason for this limitation is explained in . ** "Synopsys VCS":http://www.synopsys.com/products/simulation/simulation.html - any version that supports the -load option is acceptable. ** "Mentor Modelsim":http://www.model.com - any version that supports the -pli option is acceptable. <% tip "Add support for your Verilog simulator" do %> Write a "support request":http://rubyforge.org/tracker/?group_id=1339 for your simulator, while providing a sample transcript of the commands you use to run a test with your simulator, and we will add support for your simulator in the next release! <% end %> * *make* - any distribution should be acceptable. * C compiler - the "GNU Compiler Collection (GCC)":http://www.gnu.org/software/gcc/ is preferred, but any C compiler should be acceptable. * "POSIX threads (pthreads)":http://en.wikipedia.org/wiki/Pthreads - header and linkable object files, and operating system support for this library are necessary. * "Ruby":http://www.ruby-lang.org - version 1.8 or newer, including header and linkable object files for building extensions, is necessary. You can install Ruby by following "these instructions":http://www.rubygarden.org/faq/section/show/3. * "RubyGems":http://rubyforge.org/frs/?group_id=126 - any recent version should be acceptable. You can install RubyGems by following "these instructions":http://www.rubygems.org/read/chapter/3. h2(#setup.recom). Recommendations The following software may make your interactions with Ruby-VPI more pleasant. h3(#setup.recom.merger). Text merging tool An _interactive_ text merging tool can greatly simplify the process of transferring wanted changes from one file to another. In particular, such tools are especially beneficial when using the "automated test generator":#usage.tools.generate-test. A handful of the currently available open-source text merging tools are listed below. ** "*kdiff3*":http://kdiff3.sourceforge.net/ is a graphical, three-way merging tool for KDE. ** "*meld*":http://meld.sourceforge.net/ is a graphical, three-way merging tool for GNOME. ** "*tkdiff*":http://tkdiff.sourceforge.net/ is a graphical, two-way merging tool that uses the cross-platform Tk windowing toolkit. ** "*xxdiff*":http://furius.ca/xxdiff/ is a graphical, three-way merging tool. ** "*imediff2*":http://elonen.iki.fi/code/imediff/ is a textual, fullscreen two-way merging tool. It is very useful when you are working remotely via SSH. h2(#setup.installation). Installation Once you have satisfied the "necessary requirements":#setup.reqs, you can install Ruby-VPI by running the
gem install -y ruby-vpi
command. RubyGems will install Ruby-VPI into the system gem directory, whose path can be determined by running the
gem env gemdir
command. Within this directory, there is a gems/ subdirectory which contains the Ruby-VPI installation, as illustrated below.
$ gem env gemdir
/usr/lib/ruby/gems/1.8

$ ls -d /usr/lib/ruby/gems/1.8/gems/ruby-vpi*
/usr/lib/ruby/gems/1.8/gems/ruby-vpi-7.0.0/
h3(#setup.installation.windows). Installing on Windows * Install "Cygwin":http://www.cygwin.com, the Linux-like environment for Windows. <% note "Undefined symbols in Windows" do %> After Ruby-VPI is compiled, it is linked to symbols whose names begin with _vpi. In GNU/Linux and similar operating systems, these symbols are allowed to be undefined. However, one "cannot compile a shared object file with references to undefined symbols in Windows":http://sourceware.org/ml/cygwin/2001-12/msg01293.html. One solution is to supply the Verilog simulator's VPI object file, which contains definitions of all VPI symbols, to the linker. The following steps illustrate this process. <% end %> * Search for object files whose names end with .so, .o, or .dll in your Verilog simulator's installation directory. * Determine which object files, among those found in the previous step, contain symbols whose names begin with "_vpi" by running the
for x in *.{o,so,dll}; do nm $x | grep -q '[Tt] _vpi' && echo $x; done
command in Cygwin. ** If you are using Mentor Modelsim, the desired object file can be found at a path similar to C:\Modeltech\win32\libvsim.dll. ** If you are using GPL Cver, the desired object file can be found at a path similar to C:\gplcver\objs\v_vpi.o. * Assign the path of the object file (determined in the previous step) to the @LDFLAGS@ environment variable. For example, if the object file's path is /foo/bar/vpi.so, then you would run the
export LDFLAGS=/foo/bar/vpi.so
command in Cygwin. * You may now install Ruby-VPI by running the
gem install ruby-vpi
command in Cygwin. h2(#setup.maintenance). Maintenance * You can uninstall Ruby-VPI by running the
gem uninstall ruby-vpi
command. * You can upgrade to the latest release of Ruby-VPI by running the
gem update ruby-vpi
command. <% note do %> Learn more about using and manipulating RubyGems in "the RubyGems user manual":http://www.rubygems.org. <% end %> h1(#usage). Usage h2(#usage.vpi). VPI in Ruby The _entire_ IEEE Std 1364-2005 VPI interface is available in Ruby, but with one minor difference: the names of all VPI types, structures, and constants become _capitalized_ because Ruby requires that the names of constants begin with a capital letter. For example, the @s_vpi_value@ structure becomes the @S_vpi_value@ class in Ruby. Likewise, the @vpiIntVal@ constant becomes the @VpiIntVal@ constant in Ruby. Note that this capitalization rule does *not* apply to VPI functions; their names remain _unchanged_ in Ruby. h3(#usage.vpi.handles). Handles A _handle_ is a reference to an object, such as a module, register, wire, and so on, inside the Verilog simulation. In short, handles allow you to inspect and manipulate the design under test and its components. <% note do %> Handles are instances of the @Vpi::Handle@ class (see "reference documentation":../ref/ruby/classes/Vpi/Handle.html for details) in Ruby-VPI. <% end %> Handles have various _properties_, which provide different kinds of information (see the "Kind of value accessed" column in ) about the underlying Verilog object represented by a handle. These properties are accessed through various functions, which are listed in the "VPI functions used to access the value" column in . Handles are typically obtained through the @vpi_handle_by_name@ and @vpi_handle@ functions. These functions are hierarchical in nature, because they allow you to obtain new handles that are related to existing handles. For example, to obtain a handle to a register inside a module, you would typically write: @some_reg = vpi_handle(VpiReg, some_handle)@. p(title). Shortcuts for productivity Given a handle, Ruby-VPI allows you to access (1) its relatives and (2) its properties by simply invoking its methods. If a handle's relative happens to have the same name as one of the handle's properties, then the relative is given preference. However, if you _really_ need to access a handle's property in such a situation, then you can use the @Vpi::Handle.get_value@ and @Vpi::Handle.put_value@ methods. h4. Accessing a handle's relatives To access a handle's relative (a handle related to it), simply invoke the relative's name as a method on the handle. For example, to access the @reset@ signal of the @counter@ module shown in , you would write the following: counter_module = vpi_handle_by_name("counter", nil) reset_signal = counter_module.reset # <== shortcut! In this code, the shortcut is that you simply wrote @counter_module.reset@ instead of having to write @vpi_handle_by_name("reset", counter_module)@. h4. Accessing a handle's properties To access a handle's properties, invoke the proprty name, using the following format, as a method on the handle. shows how this naming format is used. <% figure "Method naming format for accessing a handle's properties" do %> |_. Operation |_. _ |_. Property |_. _ |_. Accessor |_. Addendum | |\2. optional | required |\3. optional | * *Operation* suggests a method that should be invoked in the context of the Property parameter. All "methods in the Enumerable module":http://www.ruby-doc.org/core/classes/Enumerable.html are valid _operations_. * *Property* suggests a VPI property that should be accessed. The "vpi" prefix, which is common to all VPI properties, can be omitted if you wish. For example, the VPI property "vpiFullName" is considered equivalent to "fullName" and "FullName", but not equivalent "full_name". * *Accessor* suggests a VPI function that should be used in order to access the VPI property. When this parameter is not specified, Ruby-VPI will attempt to _guess_ the value of this parameter. shows a list of valid accessors and how they affect the access to a property. * *Addendum* suggests that the specified VPI property should be queried as a boolean value when it is a question mark @?@. This suggestion is the same as specifying @b@ for the Accessor parameter. Also, when this parameter is an equal sign @=@, it suggests that the specified VPI property should be written to. <% end %> <% table "Possible accessors and their implications", "tbl..accessors" do %> |_. Accessor |_. Kind of value accessed |_. VPI functions used to access the value | | d | delay | @vpi_get_delays@, @vpi_put_delays@ | | l | logic | @vpi_get_value@, @vpi_put_value@ | | i | integer | @vpi_get@ | | b | boolean | @vpi_get@ | | s | string | @vpi_get_str@ | | h | handle | @vpi_handle@ | <% end %> <% example "Examples of accessing a handle's properties", "ex..properties" do %> |_/2. Ruby expression |_\6. Parts of speech |_/2. Description | ||_. Operation |_. _ |_. Property |_. _ |_. Accessor |_. Addendum || | @handle.vpiIntVal@ |   |   | vpiIntVal |   |   |   |/4. These expressions access the logic value of the handle's vpiIntVal property. | | @handle.vpiIntVal_l@ |   |   | vpiIntVal | _ | l |   | | @handle.intVal@ |   |   | intVal |   |   |   | | @handle.intVal_l@ |   |   | intVal | _ | l |   | | @handle.vpiIntVal = 15@ |   |   | vpiIntVal |   |   | = |/4. These expressions assign the number 15 to the logic value of the handle's vpiIntVal property. | | @handle.vpiIntVal_l = 15@ |   |   | vpiIntVal | _ | l | = | | @handle.intVal = 15@ |   |   | intVal |   |   | = | | @handle.intVal_l = 15@ |   |   | intVal | _ | l | = | | @handle.vpiType@ |   |   | vpiType |   |   |   |/4. These expressions access the integer value of the handle's vpiType property. | | @handle.vpiType_i@ |   |   | vpiType | _ | i |   | | @handle.type@ |   |   | type |   |   |   | | @handle.type_i@ |   |   | type | _ | i |   | | @handle.vpiProtected@ |   |   | vpiProtected |   |   |   |/6. These expressions access the boolean value of the handle's vpiProtected property. | | @handle.vpiProtected_b@ |   |   | vpiProtected | _ | b |   | | @handle.vpiProtected?@ |   |   | vpiProtected |   |   | ? | | @handle.protected@ |   |   | protected |   |   |   | | @handle.protected_b@ |   |   | protected | _ | b |   | | @handle.protected?@ |   |   | protected |   |   | ? | | @handle.vpiFullName@ |   |   | vpiFullName |   |   |   |/4. These expressions access the string value of the handle's vpiFullName property. | | @handle.vpiFullName_s@ |   |   | vpiFullName | _ | s |   | | @handle.fullName@ |   |   | fullName |   |   |   | | @handle.fullName_s@ |   |   | fullName | _ | s |   | | @handle.vpiParent@ |   |   | vpiParent |   |   |   |/4. These expressions access the handle value of the handle's vpiParent property. | | @handle.vpiParent_h@ |   |   | vpiParent | _ | h |   | | @handle.parent@ |   |   | parent |   |   |   | | @handle.parent_h@ |   |   | parent | _ | h |   | | handle.each_vpiNet {|net| puts net.fullName} | each | _ | vpiNet |   |   |   |/2. These expressions print the full name of each vpiNet object associated with the handle. | | handle.each_net {|net| puts net.fullName} | each | _ | net |   |   |   | | handle.all_vpiReg? {|reg| reg.size == 1} | all? | _ | vpiReg |   |   |   |/2. These expressions check if all registers associated with the handle are capable of storing only one bit. | | handle.all_reg? {|reg| reg.size == 1} | all? | _ | reg |   |   |   | | handle.select_vpiNet {|net| net.x?} | select | _ | VpiNet |   |   |   |/2. These expressions return a list of nets whose logic value is unknown or "don't care" (x).| | handle.select_net {|net| net.x?} | select | _ | net |   |   |   | <% end %> h3(#usage.vpi.callbacks). Callbacks A _callback_ is a mechanism that makes the Verilog simuluator execute a block of code, which is known as a "callback handler", when some prescribed event occurs in the simulation. They are set up using the @vpi_register_cb@ function and torn down using the @vpi_remove_cb@ function. <% example "Using a callback for value change notification", "ex..callback" do %> This example shows how to use a callback for notification of changes in a handle's @VpiIntVal@ property. When you no longer need this callback, you can tear it down using @vpi_remove_cb(cb_handle)@. In this example, the handle being monitored is the @Counter.count@ signal from . cb_time = S_vpi_time.new cb_time.type = VpiSimTime cb_time.low = 0 cb_time.high = 0 cb_value = S_vpi_value.new cb_value.format = VpiIntVal cb_data = S_cb_data.new cb_data.reason = CbValueChange cb_data.obj = Counter.count cb_data.time = cb_time cb_data.value = cb_value cb_data.index = 0 cb_handle = vpi_register_cb(cb_data) do |data| time = (data.time.high << 32) | data.time.low count = data.value.value.integer puts "hello from callback! time=#{time} count=#{count}" end To see this code in action, append it to the counter_rspec_spec.rb and counter_xunit_spec.rb files, which are provided in and discussed in . <% end %> <% figure "Output from " do %> Shown below is the output from running the "counter_rspec test":#usage.tutorial after appending the code shown in to the counter_rspec_spec.rb file.
$ rake -f counter_rspec_runner.rake cver

(in /home/sun/src/ruby-vpi/samp/counter)
cver +loadvpi=/home/sun/src/ruby-vpi/lib/ruby-vpi/../../obj/ruby-vpi.cver.so:vlog_startup_routines_bootstrap counter.v counter_rspec_bench.v
GPLCVER_2.11a of 07/05/05 (Linux-elf).
Copyright (c) 1991-2005 Pragmatic C Software Corp.
  All Rights reserved.  Licensed under the GNU General Public License (GPL).
  See the 'COPYING' file for details.  NO WARRANTY provided.
Today is Sat Dec 30 09:24:09 2006.
Compiling source file "counter.v"
Compiling source file "counter_rspec_bench.v"
Highest level modules:
counter_rspec_bench


A resetted counter's value
hello from callback! time=1 count=0
- should be zero
hello from callback! time=5 count=1
hello from callback! time=7 count=2
hello from callback! time=9 count=3
hello from callback! time=11 count=4
hello from callback! time=13 count=5
hello from callback! time=15 count=6
hello from callback! time=17 count=7
hello from callback! time=19 count=8
hello from callback! time=21 count=9
hello from callback! time=23 count=10
hello from callback! time=25 count=11
hello from callback! time=27 count=12
hello from callback! time=29 count=13
hello from callback! time=31 count=14
hello from callback! time=33 count=15
hello from callback! time=35 count=16
hello from callback! time=37 count=17
hello from callback! time=39 count=18
hello from callback! time=41 count=19
hello from callback! time=43 count=20
hello from callback! time=45 count=21
hello from callback! time=47 count=22
hello from callback! time=49 count=23
hello from callback! time=51 count=24
hello from callback! time=53 count=25
hello from callback! time=55 count=26
hello from callback! time=57 count=27
hello from callback! time=59 count=28
hello from callback! time=61 count=29
hello from callback! time=63 count=30
hello from callback! time=65 count=31
hello from callback! time=67 count=0
- should increment by one count upon each rising clock edge

A counter with the maximum value
hello from callback! time=71 count=1
hello from callback! time=73 count=2
hello from callback! time=75 count=3
hello from callback! time=77 count=4
hello from callback! time=79 count=5
hello from callback! time=81 count=6
hello from callback! time=83 count=7
hello from callback! time=85 count=8
hello from callback! time=87 count=9
hello from callback! time=89 count=10
hello from callback! time=91 count=11
hello from callback! time=93 count=12
hello from callback! time=95 count=13
hello from callback! time=97 count=14
hello from callback! time=99 count=15
hello from callback! time=101 count=16
hello from callback! time=103 count=17
hello from callback! time=105 count=18
hello from callback! time=107 count=19
hello from callback! time=109 count=20
hello from callback! time=111 count=21
hello from callback! time=113 count=22
hello from callback! time=115 count=23
hello from callback! time=117 count=24
hello from callback! time=119 count=25
hello from callback! time=121 count=26
hello from callback! time=123 count=27
hello from callback! time=125 count=28
hello from callback! time=127 count=29
hello from callback! time=129 count=30
hello from callback! time=131 count=31
hello from callback! time=133 count=0
- should overflow upon increment

Finished in 0.042328 seconds

3 specifications, 0 failures
<% end %> h2(#usage.debugger). Debugging The "ruby-debug project":http://www.datanoise.com/articles/category/ruby-debug serves as the interactive debugger for Ruby-VPI. # Enable the debugger by activating the @DEBUG@ environment variable (see for details). # Put the @debugger@ command in your code -- anywhere you wish to activate an interactive debugging session. These commands are automatically ignored when the debugger is disabled; so you can safely leave them in your code, if you wish. h3(#usage.debugger.init). Advanced initialization By default, Ruby-VPI enables the debugger by invoking the @Debugger.start@ method. If you wish to perform more advanced initialization, such as having the debugger accept remote network connections for interfacing with a remote debugging session or perhaps with an IDE (see "the ruby-debug documentation":http://www.datanoise.com/articles/category/ruby-debug for details), then: # Deactivate the @DEBUG@ environment variable. # Put your own code, which initializes the debugger, above the @RubyVpi.init_bench@ line in your generated spec.rb file. h2(#usage.test-runner). Test runner A test runner is a file, generated by the "automated test generator":#usage.tools.generate-test, whose name ends with .rake. It helps you run generated tests -- you can think of it as a _makefile_ if you are familiar with C programming in a UNIX environment. <% example "Seeing what a test runner can do" do %> When you invoke a test runner without any arguments, it will show you a list of available tasks:
$ rake -f some_test_runner.rake

<%= `rake -f ../samp/counter/counter_rspec_runner.rake` %>
<% end %> <% tip "Running multiple tests at once." do %> Create a file named Rakefile containing the following line. bq. @require 'ruby-vpi/runner_proxy'@ Now you can invoke all test runners in the current directory simply by executing
rake cver
(where _cver_ denotes the "GPL Cver simulator":#setup.reqs). <% end %> h3(#usage.test-runner.env-vars). Environment variables Test runners support the following _environment_ variables, which allow you to easily change the behavior of the test runner. * @COVERAGE@ enables code coverage analysis and generation of code coverage reports. * @DEBUG@ enables the "interactive debugger":#usage.debugger in its "post-mortem debugging mode":http://www.datanoise.com/articles/2006/12/20/post-mortem-debugging. * @PROTOTYPE@ enables the Ruby prototype for the design under test. To activate these variables, simply assign a non-empty value to them. For example, @DEBUG=1@ and @DEBUG=yes@ and @DEBUG=foo_bar_baz@ all activate the @DEBUG@ variable. To deactivate these variables, simply assign an _empty_ value to them, *unset* them in your shell, or do not specify them as command-line arguments to rake. For example, both @DEBUG=@ dectivates the @DEBUG@ variable. In addition, you can specify variable assignments as arguments to the *rake* command. For example,
rake DEBUG=1
is equivalent to
$ DEBUG=1
$ export DEBUG
$ rake
in Bourne shell or
% setenv DEBUG 1
% rake
in C shell. <% example "Running a test with environment variables" do %> Here we enable the prototype and code coverage analysis:
rake -f some_test_runner.rake PROTOTYPE=1 COVERAGE=1
Here we _disable_ the prototype and enable the code coverage analysis. Note that both of these invocations are equivalent:
rake -f some_test_runner.rake PROTOTYPE= COVERAGE=1
rake -f some_test_runner.rake COVERAGE=1
<% end %> h2(#usage.examples). Sample tests The samp directory contains several sample tests which illustrate how Ruby-VPI can be used. Each sample has an associated Rakefile which simplifies the process of running it. Therefore, simply navigate into an example directory and run the
rake
command to get started. h2(#usage.tools). Tools The bin directory contains various utilities which ease the process of writing tests. Each tool provides help and usage information invoked with the --help option. h3(#usage.tools.generate-test). Automated test generation The automated test generator (*generate_test.rb*) generates tests from Verilog 2001 module declarations, as demonstrated "in the tutorial":#usage.tutorial.generate-test. A generated test is composed of the following parts: * Runner - written in "Rake":#glossary.rake, this file builds and runs the test. * Bench - written in Verilog and Ruby, these files define the testing environment. * Design - written in Ruby, this file provides an interface to the design being verified. * Prototype - written in Ruby, this file defines a prototype of the design being verified. * Specification - written in Ruby, this file describes the expected behavior of the design. The reason for dividing a single test into these parts is mainly to decouple the design from the specification. This allows you to focus on writing the specification while the remainder is automatically generated by the tool. For example, when the interface of a Verilog module changes, you would simply re-run this tool and incorporate those changes (using a "text merging tool":#setup.recom.merger) into the test without diverting your focus from the specification. <% tip "Using *kdiff3* with the automated test generator." do %> # Create a file named merge2 with the following content: #!/bin/sh # args: old file, new file kdiff3 --auto --output "$2" "$@" # Make the file executable by running the
chmod +x merge2
command. # Place the file somewhere accessible by your @PATH@ environment variable. # Assign the value "merge2" to the @MERGER@ environment variable using your shell's *export* or *setenv* command. From now on, *kdiff3* will be invoked to help you transfer your changes between generated files. When you are finished transferring changes, simply issue the "save the file" command and quit *kdiff3*. Or, if you do not want to transfer any changes, simply quit *kdiff3* _without_ saving the file. <% end %> h3(#usage.tools.verilog-ruby-conv). Verilog to Ruby conversion The *header_to_ruby.rb* tool can be used to convert Verilog header files into Ruby. You can try it by running the
header_to_ruby.rb --help
command. By converting Verilog header files into Ruby, your "test":#glossary.test can utilize the same @`define@ constants that are used in the Verilog "design":#glossary.design. h2(#usage.tutorial). Tutorial # "Declare the design":#usage.tutorial.declare-design, which is a Verilog module, using Verilog 2001 syntax. # "Generate a test":#usage.tutorial.generate-test for the design using the "automated test generator":#usage.tools.generate-test tool. # "Identify your expectations":#usage.tutorial.specification for the design and implement them in the specification. # (Optional) "Implement the prototype":#usage.tutorial.implement-proto of the design in Ruby. # (Optional) "Verify the prototype":#usage.tutorial.test-proto against the specification. # "Implement the design":#usage.tutorial.implement-design in Verilog once the prototype has been verified. # "Verify the design":#usage.tutorial.test-design against the specification. h3(#usage.tutorial.declare-design). Start with a design First, we need a "design":#glossary.design to verify. In this tutorial, will serve as our design. Its interface is composed of the following parts: * @Size@ defines the number of bits used to represent the counter's value. * @clock@ causes the @count@ register to increment whenever it reaches a positive edge. * @reset@ causes the @count@ register to become zero when asserted. * @count@ is a register that contains the counter's value. <% example "Declaration of a simple up-counter with synchronous reset", "#fig..counter.v_decl" do %> module counter #(parameter Size = 5) ( input clock, input reset, output reg [Size - 1 : 0] count ); endmodule <% end %> <% important "Before we continue..." do %> Save the source code shown in into a file named counter.v. <% end %> h3(#usage.tutorial.generate-test). Generate a test Now that we have a "design":#glossary.design to verify, let us generate a "test":#glossary.test for it using the "automated test generator":#usage.tools.generate-test. This tool allows us to implement our specification in either rSpec, xUnit, or our very own format. Each format represents a different software development methodology: * rSpec represents "BDD":#glossary.BDD * xUnit represents "TDD":#glossary.TDD * our own format can represent another methodology <% note do %> Both rSpec and xUnit formats are presented in this tutorial. <% end %> Once we have decided how we want to implement our specification, we can proceed to generate a test for our design. This process is illustrated by and . <% example "Generating a test with specification in rSpec format", "#fig..generate-test.rspec" do %>
$ generate_test.rb counter.v --rspec --name rspec

  module  counter
  create  counter_rspec_runner.rake
  create  counter_rspec_bench.v
  create  counter_rspec_bench.rb
  create  counter_rspec_design.rb
  create  counter_rspec_proto.rb
  create  counter_rspec_spec.rb
<% end %> <% example "Generating a test with specification in xUnit format", "#fig..generate-test.unit-test" do %>
$ generate_test.rb counter.v --xunit --name xunit

  module  counter
  create  counter_xunit_runner.rake
  create  counter_xunit_bench.v
  create  counter_xunit_bench.rb
  create  counter_xunit_design.rb
  create  counter_xunit_proto.rb
  create  counter_xunit_spec.rb
<% end %> h3(#usage.tutorial.specification). Specify your expectations So far, the test generation tool has created a basic foundation for our "test":#glossary.test. Now we must build upon this foundation by identifying our "expectation":#glossary.expectation of the "design":#glossary.design. That is, how do we expect the design to _behave_ under certain conditions? Here are some reasonable expectations for our simple counter: * A resetted counter's value should be zero. * A resetted counter's value should increment by one count upon each rising clock edge. * A counter with the maximum value should overflow upon increment. Now that we have identified a set of expectations for our design, we are ready to implement them in our specification. This process is illustrated by and . <% example "Specification implemented in rSpec format", "#fig..counter_rspec_spec.rb" do %> <%= File.read '../samp/counter/counter_rspec_spec.rb' %> <% end %> <% example "Specification implemented in xUnit format", "#fig..counter_xunit_spec.rb" do %> <%= File.read '../samp/counter/counter_xunit_spec.rb' %> <% end %> <% important "Before we continue..." do %> # Replace the contents of the file named counter_rspec_spec.rb with the source code shown in . # Replace the contents of the file named counter_xunit_spec.rb with the source code shown in . # Replace the contents of the files named counter_rspec_design.rb and counter_xunit_design.rb with the following code. <%= File.read '../samp/counter/counter_rspec_design.rb' %> <% end %> h3(#usage.tutorial.implement-proto). Implement the prototype Now that we have a "specification":#glossary.specification against which to verify our "design":#glossary.design, let us build a prototype of our design. By doing so, we exercise our specification, experience potential problems that may arise when we later implement our design in Verilog, and gain confidence in our work. The result of this proceess is illustrated by . <% example "Ruby prototype of our Verilog design", "#fig..counter_proto.rb" do %> def Counter.simulate! if reset.intVal == 1 count.intVal = 0 else count.intVal += 1 end end <% end %> <% important "Before we continue..." do %> Replace the contents of the files named counter_rspec_proto.rb and counter_xunit_proto.rb with the source code shown in <% end %> h3(#usage.tutorial.test-proto). Verify the prototype Now that we have implemented our prototype, we are ready to verify it against our "specification":#glossary.specification by running the "test":#glossary.test. This process is illustrated by and . <% example "Running a test with specification in rSpec format", "#fig..test-proto.rspec" do %>
$ rake -f counter_rspec_runner.rake cver PROTOTYPE=1

Ruby-VPI: prototype has been enabled for test "counter_rspec"

A resetted counter's value
- should be zero
- should increment by one count upon each rising clock edge

A counter with the maximum value
- should overflow upon increment

Finished in 0.018199 seconds

3 specifications, 0 failures
<% end %> <% example "Running a test with specification in xUnit format", "#fig..test-proto.unit-test" do %>
$ rake -f counter_xunit_runner.rake cver PROTOTYPE=1

Ruby-VPI: prototype has been enabled for test "counter_xunit"

Loaded suite counter_xunit_bench
Started
...
Finished in 0.040668 seconds.

3 tests, 35 assertions, 0 failures, 0 errors
<% end %> In these examples, the @PROTOTYPE@ environment variable is assigned a non-empty value while running the test so that, instead of our design, our prototype is verified against our specification. You can also assign a value to @PROTOTYPE@ before running the test, by using your shell's *export* or *setenv* command. Finally, the "GPL Cver simulator":#setup.reqs, denoted by _cver_, is used to run the simulation. <% tip "What can the test runner do?" do %> If you invoke the test runner (1) without any arguments or (2) with the --tasks option, it will show you a list of tasks that it can perform for you. <% end %> h3(#usage.tutorial.implement-design). Implement the design Now that we have implemented and verified our prototype, we are ready to implement our "design":#glossary.design. This is often quite simple because we translate _existing_ code from Ruby (our prototype) into Verilog (our design). The result of this process is illustrated by . <% example "Implementation of a simple up-counter with synchronous reset", "#fig..counter.v_impl" do %> <%= File.read '../samp/counter/counter.v' %> <% end %> <% important "Before we continue..." do %> Replace the contents of the file named counter.v with the source code shown in <% end %> h3(#usage.tutorial.test-design). Verify the design Now that we have implemented our "design":#glossary.design, we are ready to verify it against our "specification":#glossary.specification by running the "test":#glossary.test. and illustrate this process. <% example "Running a test with specification in rSpec format", "#fig..test-design.rspec" do %>
$ rake -f counter_rspec_runner.rake cver

A resetted counter's value
- should be zero
- should increment by one count upon each rising clock edge

A counter with the maximum value
- should overflow upon increment

Finished in 0.005628 seconds

3 specifications, 0 failures
<% end %> <% example "Running a test with specification in xUnit format", "#fig..test-design.unit-test" do %>
$ rake -f counter_xunit_runner.rake cver

Loaded suite counter_xunit_bench
Started
...
Finished in 0.006766 seconds.

3 tests, 35 assertions, 0 failures, 0 errors
<% end %> In these examples, the @PROTOTYPE@ environment variable is _not_ specified while running the test, so that our design, instead of our prototype, is verified against our specification. You can also achieve this effect by assigning an empty value to @PROTOTYPE@, or by using your shell's *unset* command. Finally, the "GPL Cver simulator":#setup.reqs, denoted by _cver_, is used to run the simulation. h1(#hacking). Hacking h2(#hacking.release-packages). Building release packages In addition to the "normal requirements":#setup.reqs, you need the following software to build release packages: * "SWIG":http://www.swig.org/ * "RedCloth":http://rubyforge.org/projects/redcloth/ * "CodeRay":http://rubyforge.org/projects/coderay/ Once you have satisfied these requirements, you can run
rake release
to build the release packages. Also, see the output of
rake -T
for more build options. h1(#problems). Known problems This chapter presents known problems and possible solutions. In addition, previously solved problems have been retained for historical reference. h2(#problems.ruby). Ruby h3(#problems.ruby.SystemStackError). SystemStackError <% note "Fixed in 2.0.0." do %> This problem was fixed in release 2.0.0 (2006-04-17). <% end %> If a "stack level too deep (SystemStackError)" error occurs during the simulation, then increase the system-resource limit for stack-size by running the
ulimit -s unlimited
command before starting the simulation. h3(#problems.ruby.xUnit). test/unit <% note "Fixed in 2.0.0." do %> This problem was fixed in release 2.0.0 (2006-04-17). <% end %> If your specification employs Ruby's unit testing framework, then you will encounter an error saying "[BUG] cross-thread violation on rb_gc()". h2(#problem.ivl). Icarus Verilog h3(#problems.ivl.vpi_handle_by_name). Vpi::vpi_handle_by_name h4(#problems.ivl.vpi_handle_by_name.absolute-paths). Give full paths to Verilog objects In version 0.8 and snapshot 20061009 of Icarus Verilog, the @vpi_handle_by_name@ function requires an _absolute_ path (including the name of the bench which instantiates the design) to a Verilog object. In addition, @vpi_handle_by_name@ always returns @nil@ when its second parameter is specified. For example, consider . Here, one must write @vpi_handle_by_name("TestFoo.my_foo.clk", nil)@ instead of @vpi_handle_by_name("my_foo.clk", TestFoo)@ in order to access the @clk@ input of the @my_foo@ module instance. <% example "Part of a bench which instantiates a Verilog design", "#ex..TestFoo" do %> module TestFoo; reg clk_reg; Foo my_foo(.clk(clk_reg)); endmodule <% end %> h4(#problems.ivl.vpi_handle_by_name.connect-registers). Registers must be connected In version 0.8 of Icarus Verilog, if you want to access a register in a design, then it must be connected to something (either assigned to a wire or passed as a parameter to a module instantiation). Otherwise, you will get a @nil@ value as the result of @vpi_handle_by_name@ method. For example, suppose you wanted to access the @clk_reg@ register, from the bench shown in If you execute the statement @clk_reg = vpi_handle_by_name("TestFoo.clk_reg", nil)@ in a specification, then you will discover that the @vpi_handle_by_name@ method returns @nil@ instead of a handle to the @clk_reg@ register. The solution is to change the design such that it appears like the one shown in where the register is connected to a wire, or where the register is connected to a module instantiation. <% example "Bad design with unconnected registers", "#ex..TestFoo_bad" do %> module TestFoo; reg clk_reg; endmodule Here the @clk_reg@ register is not connected to anything. <% end %> <% example "Fixed design with wired registers", "#ex..TestFoo_fix" do %> module TestFoo; reg clk_reg; wire clk_wire; assign clk_wire = clk_reg; endmodule Here the @clk_reg@ register is connected to the @clk_wire@ wire. <% end %> h3(#problems.ivl.vpi_reset). Vpi::reset
The @vpi_control@ method was removed in release 3.0.0 (2006-04-23). Please use @Vpi::vpi_control(VpiReset)@ instead.
In version 0.8 of Icarus Verilog, the @vpi_control(vpiReset)@ VPI function causes an assertion to fail inside the simulator. As a result, the simulation terminates and a core dump is produced. h2(#problems.vsim). Mentor Modelsim h3(#problems.vsim.ruby_run). ruby_run(); <% note "Fixed in 2.0.0." do %> This problem was fixed in release 2.0.0 (2006-04-17). <% end %> Version 6.1b of Mentor Modelsim doesn't play nicely with either an embedded Ruby interpreter or POSIX threads in a PLI application. When Ruby-VPI invokes the ruby_run function (which starts the Ruby interpreter), the simulator terminates immediately with an exit status of 0. h1(#glossary). Glossary h2(#glossary.bench). Bench An environment in which a "design":#glossary.design is verified against a "specification":#glossary.specification. Often, it is used to emulate conditions in which the design will be eventually deployed. h2(#glossary.BDD). Behavior driven development (BDD) An "agile software development methodology":http://agilemanifesto.org/ which emphasizes thinking in terms of behavior when designing, implementing, and verifying software. See the "official wiki":http://behaviour-driven.org/ for more information. h2(#glossary.design). Design A Verilog module that is verified against a "specification":#glossary.specification in order to ensure correctness or soundness of its being. In other words, it is the thing being checked: does it work or not? h2(#glossary.expectation). Expectation The desired response to some stimulus. h2(#glossary.handle). Handle A reference to an object inside the Verilog simulation that was obtained through the @vpi_handle_by_name@ function. h2(#glossary.rake). Rake bq. Rake is a build tool, written in Ruby, using Ruby as a build language. Rake is similar to *make* in scope and purpose. bq>. --"Rake documentation":http://docs.rubyrake.org h2(#glossary.rspec). rSpec The "BDD":#glossary.BDD framework for Ruby. See the "rSpec website":http://rspec.rubyforge.org and "tutorial":http://rspec.rubyforge.org/tutorials/index.html for more information. h2(#glossary.specification). Specification A set of "expectations":#glossary.expectations which define the desired behavior of a "design":#glossary.design when it is subjected to certain stimulus. h2(#glossary.TDD). Test driven development (TDD) An "agile software development methodology":http://agilemanifesto.org/ which emphasizes (1) testing functionality before implementing it and (2) refactoring. See "this introductory article":http://www.agiledata.org/essays/tdd.html for more information. h2(#glossary.test). Test Something that checks if a "design":#glossary.design satisfies a "specification":#glossary.specification. h2(#glossary.test_bench). Test bench An allusion to "a bench in an electronics laboratory":#background.vocab, or so it seems.