diff --git a/README.txt b/README.txt index 8edf3f82..2473bec7 100644 --- a/README.txt +++ b/README.txt @@ -18,11 +18,11 @@ recent Python feature, MyHDL requires Python 2.2.2 or higher. MyHDL can be used to experiment with high level modeling, and with verification techniques such as unit testing. The most important -practical applicaton however, is to use it as a hardware verification -language by cosimulation with Verilog and VHDL. +practical application however, is to use it as a hardware verification +language by co-simulation with Verilog and VHDL. The present release, MyHDL 0.2, enables MyHDL for -cosimulation. The MyHDL side is designed to work with any simulator +co-simulation. The MyHDL side is designed to work with any simulator that has a PLI. For each simulator, an appropriate PLI module in C needs to be provided. The release contains such a module for the Icarus Verilog simulator. @@ -54,11 +54,11 @@ You can test the installation as follows: cd test python test.py -To install cosimulation support: +To install co-simulation support: -Go to the directory cosimulation/ for your target platform +Go to the directory co-simulation/ for your target platform and following the instructions in the README.txt file. Currently, the -only supported platfrom is Icarus. +only supported platform is Icarus. DOCUMENTATION diff --git a/doc/MyHDL.tex b/doc/MyHDL.tex index 4a0f5c4c..cf84acb4 100644 --- a/doc/MyHDL.tex +++ b/doc/MyHDL.tex @@ -32,11 +32,11 @@ recent Python feature, \myhdl\ requires Python 2.2.2 or higher. \myhdl\ can be used to experiment with high level modeling, and with verification techniques such as unit testing. The most important -practical applicaton however, is to use it as a hardware verification -language by cosimulation with Verilog and VHDL. +practical application however, is to use it as a hardware verification +language by co-simulation with Verilog and VHDL. The present release, \myhdl\ 0.2, enables \myhdl\ for -cosimulation. The \myhdl\ side is designed to work with any simulator +co-simulation. The \myhdl\ side is designed to work with any simulator that has a PLI. For each simulator, an appropriate PLI module in C needs to be provided. The release contains such a module for the Icarus Verilog simulator. diff --git a/doc/cosimulation.tex b/doc/cosimulation.tex index 37de4de1..a39075d7 100644 --- a/doc/cosimulation.tex +++ b/doc/cosimulation.tex @@ -16,8 +16,8 @@ implementable. Therefore, unlike synthesizable code, there are no constraints on creativity. Technically, verification of a design implemented in -another language requires cosimulation. \myhdl\ is -enabled for cosimulation with any HDL simulator that +another language requires co-simulation. \myhdl\ is +enabled for co-simulation with any HDL simulator that has a procedural language interface (PLI). The \myhdl\ side is designed to be independent of a particular simulator, On the other hand, for each HDL simulator a specific @@ -28,7 +28,7 @@ be used in the examples. \section{The HDL side} -To introduce cosimulation, we will continue to use the Gray encoder +To introduce co-simulation, we will continue to use the Gray encoder example from the previous chapters. Suppose that we want to synthesize it and write it in Verilog for that purpose. Clearly we would like to reuse our unit test verification environment. This is exactly @@ -51,7 +51,7 @@ def bin2gray(B, G, width): \end{verbatim} -To show the cosimulation flow, we don't need the Verilog +To show the co-simulation flow, we don't need the Verilog implementation yet, but only the interface. Our Gray encoder in Verilog would have the following interface: @@ -102,8 +102,8 @@ from C source code. \section{The \myhdl\ side} -\myhdl\ supports cosimulation by a \code{Cosimulation} object. -A \code{Cosimulation} object must know how to run a HDL cosimulation. +\myhdl\ supports co-simulation by a \code{Co-Simulation} object. +A \code{Co-Simulation} object must know how to run a HDL co-simulation. Therefore, the first argument to its constructor is a command string to execute a simulation. The way to generate and run an simulation executable is simulator dependent. @@ -130,28 +130,28 @@ This runs the \code{bin2gray} simulation, and specifies to use the \code{myhdl.vpi} PLI module present in the current directory. (This is just a command line usage example; actually simulating with the \code{myhdl.vpi} module is only meaningful from a -\code{Cosimulation} object.) +\code{Co-Simulation} object.) -We can use a \code{Cosimulation} object to provide a HDL cosimulation +We can use a \code{Co-Simulation} object to provide a HDL co-simulation version of a design to the \myhdl\ simulator. Instead of a generator -function, we write a function that returns a \code{Cosimulation} +function, we write a function that returns a \code{Co-Simulation} object. For our example and the Icarus Verilog simulator, this is done as follows: \begin{verbatim} import os -from myhdl import Cosimulation +from myhdl import Co-Simulation cmd = "iverilog -o bin2gray -Dwidth=%s bin2gray.v dut_bin2gray.v" def bin2gray(B, G, width): os.system(cmd % width) - return Cosimulation("vvp -m ./myhdl.vpi bin2gray", B=B, G=G) + return Co-Simulation("vvp -m ./myhdl.vpi bin2gray", B=B, G=G) \end{verbatim} -After the executable command argument, the \code{Cosimulation} +After the executable command argument, the \code{Co-Simulation} constructor takes an arbitrary number of keyword arguments. Those arguments make the link between \myhdl\ Signals and HDL nets, regs, or signals, by named association. The keyword is the name of the argument @@ -266,24 +266,24 @@ The result is a compromise that places certain restrictions on the HDL code. In this section, these restrictions are presented. -\subsection{Only passive HDL can be cosimulated} +\subsection{Only passive HDL can be co-simulated} -The most important restriction of the \myhdl\ cosimulation solution is -that only ``passive'' HDL can be cosimulated. This means that the HDL +The most important restriction of the \myhdl\ co-simulation solution is +that only ``passive'' HDL can be co-simulated. This means that the HDL code should not contain any statements with time delays. In other words, the \myhdl\ simulator should be the master of time; in particular, any clock signal should be generated at the \myhdl\ side. At first this may seem like an important restriction, but if one -considers the target application for cosimulation, it probably +considers the target application for co-simulation, it probably isn't. -\myhdl\ support cosimulations so that test benches for HDL +\myhdl\ support co-simulations so that test benches for HDL designs can be written in Python. Let's consider the nature of the target HDL designs. For high-level, behavioral models that are not intended for implementation, it should come as no surprise that I would recommend to write them in \myhdl\ -directly; that is exactly the target of the \myhdl\ effort. Likewise, +directly; that is one of the goals of the \myhdl\ effort. Likewise, gate level designs with annotated timing are not the target application: static timing analysis is a much better verification method for such designs. @@ -300,21 +300,21 @@ same time step. For example, when a clock signal triggers some signals may change in the same time step. For race-free operation, an HDL must differentiate between such events within a time step. This is done by the concept of ``delta'' cycles. In a fully general, race free -cosimulation, the cosimulators would communicate at the level of delta -cycles. However, in \myhdl\ cosimulation, this is not entirely the +co-simulation, the co-simulators would communicate at the level of delta +cycles. However, in \myhdl\ co-simulation, this is not entirely the case. -Delta cycles from the \myhdl\ simulator toward the HDL cosimulator are +Delta cycles from the \myhdl\ simulator toward the HDL co-simulator are preserved. However, in the opposite direction, they are not. The signals changes are only returned to the \myhdl\ simulator after all delta -cycles have been performed in the HDL cosimulator. +cycles have been performed in the HDL co-simulator. What does this mean? Let's start with the good news. As explained in -the previous section, the logic of the \myhdl\ cosimulation implies +the previous section, the concept behind \myhdl\ co-simulation implies that clocks are generated at the \myhdl\ side. \emph{When using a \myhdl\ clock and its corresponding HDL signal directly as a clock, -cosimulation operation is race free.} In other words, the case -that most closely reflects the \myhdl\ cosimulation approach, is race free. +co-simulation operation is race free.} In other words, the case +that most closely reflects the \myhdl\ co-simulation approach, is race free. The situation is different when you want to use a signal driven by the HDL (and the corresponding MyHDL signal) as a clock. @@ -334,7 +334,7 @@ edge. This section requires some knowledge of PLI terminology. \end{quote} -Enabling a simulator for cosimulation requires a PLI module +Enabling a simulator for co-simulation requires a PLI module written in C. In Verilog, the PLI is part of the ``standard''. However, different simulators implement different versions and portions of the standard. Worse yet, the behavior of @@ -357,30 +357,68 @@ on future implementations in other simulators. \subsection{Icarus Verilog} -To make cosimulation work, a specific type of PLI callback is +\subsubsection{Delta cycle implementation} +\label{icarus-delta-cycles} + +To make co-simulation work, a specific type of PLI callback is needed. The callback should be run when all pending events have been processed, while allowing the creation of new events in the current -time step (e.g. by the \myhdl\ simulator). In some Verilog simulators, -the \code{cbReadWriteSync} callback does exactly that. However, -in others, including Icarus, it does not. The callback's behavior is -not fully standardized; some simulators run the callback before -non-blocking assignment events have been processed. +time step (e.g. by the \myhdl\ simulator). In some Verilog +simulators, the \code{cbReadWriteSync} callback does exactly +that. However, in others, including Icarus, it does not. The +callback's behavior is not fully standardized; some simulators run the +callback before non-blocking assignment events have been processed. Consequently, I had to look for a workaround. One half of the solution is to use the \code{cbReadOnlySync} callback. This callback runs after all pending events have been processed. However, it does not permit to create new events in the current time step. The second half -of the solution is to map \myhdl\ delta cycles onto Verilog time steps. -Note that there is some freedom here because of the restriction that -only passive HDL code can be cosimulated. +of the solution is to map \myhdl\ delta cycles onto real Verilog time +steps. Note that there is some freedom here because of the +restriction that only passive HDL code can be co-simulated. I chose to make the time granularity in the Verilog simulator a 1000 -times finer than in the \myhdl{} simulator. For each \myhdl\ time step, -1000 Verilog time steps are available for \myhdl\ delta cycles. In practice, -only a few delta cycles per time step should be needed. More than 1000 -almost certainly indicates an error. This limit is checked at -run-time. The factor 1000 also makes it easy to distinguish ``real'' -time from delta cycle time when printing out the Verilog time. +times finer than in the \myhdl{} simulator. For each \myhdl\ time +step, 1000 Verilog time steps are available for \myhdl\ delta +cycles. In practice, only a few delta cycles per time step should be +needed. Exceeding this limit almost certainly indicates a design error +and his limit is checked at run-time. The factor 1000 also makes it +easy to distinguish ``real'' time from delta cycle time when printing +out the Verilog time. + +\subsubsection{Passive Verilog check} + +As explained before, co-simulated Verilog should not contain delay +statements. Ideally, there should be a run-time check to flag +non-compliant code. However, there is currently no such check in the Icarus +module. + +The check can be written using the \code{cbNextSimTime} VPI callback +in Verilog. However, Icarus 0.7 doesn't support this callback. In +the meantime, it has been added to the Icarus development branch. When +Icarus 0.8 is released, a check will be added. + +In the mean time, just don't do this. It may appear to ``work'' but it +really won't as events will be missed over the co-simulation +interface. + +\subsubsection{Interrupted system calls} + +The PLI module uses \code{read} and \code{write} system calls to +communicate between the co-simulators. The implementation assumes that +these calls are restarted automatically by the operating system when +interrupted. This is apparently what happens on my Linux box and on +other operating systems I have used before. + +I know how to handle non-restarted interrupted system calls, but I +cannot test the code! Also, I don't know whether this is still a +relevant issue with modern operating systems. So I left it +at that for the moment, and added assertions that should trigger +when this situation occurs. + +Whenever you see an assertion fire in the PLI module, let me +know. The same holds for Python exceptions that you cannot +easily explain. \subsection{Other Verilog simulators} @@ -391,8 +429,9 @@ module. If the simulator supports VPI, the Icarus module should be reusable to a large extent. However, it may be possible to improve on it. The -workaround described in the previous section may not be necessary. In -some simulators, the \code{cbReadWriteSync} callback occurs after all +workaround to support delta cycles described in +Section~\ref{icarus-delta-cycles} may not be necessary. In some +simulators, the \code{cbReadWriteSync} callback occurs after all events (including non-blocking assignments) have been processed. In that case, the functionality can be supported without a finer time granularity in the Verilog simulator. @@ -405,10 +444,11 @@ required functionality. \subsection{VHDL} -It would be great to have an interface to the Modelsim VHDL -simulator. This will require a redesign from scratch with the -appropriate PLI. One feature which I would like to keep if possible -is the way to declare the communicating signals. In the Verilog -solution, it is not necessary to define and instantiate any special -entity (module). Rather, the participating signals can be declared -directly in the \code{to_myhdl} and \code{from_myhdl} task calls. +It would be great to have an interface to VHDL simulators such as the +Modelsim VHDL simulator. This will require a PLI module using the +PLI of the VHDL simulator. One feature which I would +like to keep if possible is the way to declare the communicating +signals. In the Verilog solution, it is not necessary to define and +instantiate a special HDL module (entity). Rather, the participating +signals can be declared directly in the \code{to_myhdl} and +\code{from_myhdl} task calls. diff --git a/doc/reference.tex b/doc/reference.tex index 56c6c2d8..3e4c7026 100644 --- a/doc/reference.tex +++ b/doc/reference.tex @@ -272,7 +272,7 @@ defined bit width. \label{cosimulation} \begin{classdesc}{Cosimulation}{exe, **kwargs} -Class to construct a new cosimulation object. +Class to construct a new Cosimulation object. The \var{exe} argument is a command string to execute an HDL simulation. The \var{kwargs} keyword diff --git a/doc/unittest.tex b/doc/unittest.tex index 9d616c2d..d2835b13 100644 --- a/doc/unittest.tex +++ b/doc/unittest.tex @@ -136,7 +136,7 @@ def bin2gray(B, G, width): \end{verbatim} -For the first requirement, we will write a testbench that applies all +For the first requirement, we will write a test bench that applies all consecutive input numbers, and compares the current output with the previous one for each input. Then we check that the difference is a single bit. We will test all Gray codes up to a certain order