Verilog COding
In a typical design flow, the design team will first create an RTL level model of their design and write behavioral test benches that model the other systems that surround their design. They will then perform a series of simulations, fixing problems found during simulation, until they decide that the RTL design has been sufficiently tested. The RTL is then synthesized into a gate-level Verilog netlist which can fed into a place-and-route tool to produce a final chip layout or to generate an FPGA programming file.
Let’s use a real-world example to see how this works in practice. Assume you’re tasked with building a PCI-based board that performs optical-character-recognition on data from a scanner and communicates with software running on a PC. If it’s a low-volume application, most of the logic for the board will probably be implemented in an FPGA. You’ll probably also need a little glue logic to buffer the input/output (IO) signals that communicate with the PC and the scanner.
Step 1: Create RTL Design Models and Behavioral Test Bench Code
To program the FPGA, you’ll need to write RTL-level modules that describe the logic for processing image data from the scanner and model the ports that can be read and written to by the PC via the PCI bus. At the end of this process, let’s assume you have generated 3 Verilog files that model your FPGA design:
pci_interface.v (models ports and communication across PCI bus)
ocr_processor.v (communicates with scanner and performs character recognition)
fpga.v (top-level module of fpga design that instantiates modules defined in pci_interface.v and ocr_processor.v)
To test your design code, you’ll need to write a behavioral model that generates data in the format provided by the scanner (e.g. models IO from scanner). And you’ll need to write a bus-functional model (behavioral model that models the bus level IO) of the PC that to test the PCI interface of your board. Let’s assume you create the following testbench files:
pci_stimulator.v (bus-functional IO model of the PC that reads/writes FPGA ports)
scanner.v (generates scanner input to feed the FPGA)
testbench.v (top level test bench that instantiates the pci_stimulator, the scanner, and the FPGA top level module, plus any glue logic we’ve included in the design)
Step 2: Functionally Simulate your Register-Transfer-Level Design
Now that you’ve got something to test and some basic tests written, it’s time to simulate the system. During this phase of the design, you’ll be constantly running simulations, examining the results, and then making changes to your Verilog code to fix bugs you find. This phase is called “functional simulation”, because it’s only testing whether the logical (functional) design of the system is correct, but it doesn’t test whether the system meets speed requirements.
If you’re using a command line simulator, you would compile these files with a command line such as the one below. For the purposes of this tutorial, we’re assuming you’re using SynaptiCAD’s Verilog simulator, simx, but the syntax would be very similar for most verilog simulators. To compile the code and run the simulation from the command line, type:
simx testbench.v scanner.v pci_stimulator.v pci_interface.v ocr_processor.v fpga.v
If you’re using a graphical debugger with your simulator, all these files should be placed into the source file folder of your Verilog simulator’s project file, then you would press the Build button to compile the files, followed by the Run button to simulate the design. After the design has finished simulating (or when you encounter a breakpoint), you can look at the simulation log file and waveforms captured during the simulation run to see if there were any problems. Most simulators provide various ways to examine the internal signals of your design to trace down the cause of any errors, so that you make appropriate corrections to your Verilog source files and re-simulate the design. During debug of your design, a graphical debugger is highly recommended, as it’s much easier to locate and fix bugs using these tools.
Steps 1 and 2 are essentially an iterative process and typically most of the design is spent in these two phases. These two steps are fairly high level and are somewhat independent of the target FPGA or ASIC you’ve decided to use. The exact syntax of commands for the next couple of steps will generally depend more on your choice of FPGA vendor, however.
Step 3: Convert RTL-level files to a Gate-level model with a Synthesizer
After you’ve successfully fixed all the bugs you can find during functional testing, it’s time to synthesize your RTL design. You do not need to synthesize your testbench code, only your RTL design code (in fact, most test bench code uses Verilog features that synthesis tools cannot handle). Synthesis is a mostly automated process using a “synthesizer” tool that converts your RTL-level design source code (pci_interface.v, ocr_processor.v, and fpga.v) into a single gate-level Verilog file (this file is often called timingsim.v) that can be fed into a place-and-route (P&R) tool to create a programming file for your FPGA. The generated gate-level Verilog file will consist of one big module filled with gates connected by wires. This is often referred to as a “flattened” design, because all the individual modules from your original RTL design has been flattened out into one big module and all hierarchical information is gone.
Step 4: Perform Gate Level simulations with FPGA or ASIC libraries
Now that we’ve synthesized the design, it’s time to simulate the gate-level code generated by the synthesizer to check if the synthesizer misunderstood anything we told it to do (generally this occurs if we write some form of improper code that simulates properly at RTL level, but violates a synthesis coding convention). These errors are relatively rare nowadays as there are many good books that cover proper coding techniques for writing synthesizable code and synthesizers have also gotten very good at their job.
Gate-level simulations take longer to run than RTL level simulations (especially when SDF timing is included), but fortunately you don’t typically need to run many gate-level simulations since most bugs are logic errors that should have already been caught during the functional simulation phase. You should be able to reuse the same test benches during your gate level simulation that you created for testing the RTL design, with some minor modifications to handle things like expansion of buses into individual bits and possibly some changes to the stimulus to check stressful timing conditions.
You will need to add some additional command line options to your simulator to compile a gate-level design. Instead of true Verilog gate level primitives, the gates in the synthesized design file will be “vendor gates”. These vendor gates are defined in a Verilog library file or directory provided by the FPGA vendor. These gates are mostly just “wrappers” around the Verilog gate primitives that also include “specify blocks” where standard delay file (SDF) data can be incorporated to model the timing of the gates. So, to compile the synthesized design file, you will need to tell your simulator where to find the vendor library gate models.
FPGA vendor libraries typically come in one of two forms: a single big file that contains all the gate models or a directory with one file per gate model, where the filename matches the name of the gate model.
If it’s a single big file, you can just include this file into the compile options for your simulator with a -v option to specify the vendor library file. For example, assume the vendor’s library file is calledfpga_models.v, you would perform a gate level simulation using a command like:
simx testbench.v scanner.v pci_stimulator. timingsim.v –v c:\fpga\fpga_models.v
(Note we’re using timingsim.v, the flattened gate-level model, rather than the three RTL level source files now, but we’re still using the original test bench files to test the design)
On the other hand, if your FPGA vendor ships its library models as individual files in a directory called fpga_models_dir, then you would use the -y to specify the vendor library directory. In this case, you would use a simulation command like:
simx testbench.v scanner.v pci_stimulator. timingsim.v –y c:\fpga\fpga_models_dir
Optional Step: Gate-level simulation with SDF timing information
Gate level simulations can optionally be performed with timing information from an SDF file. The FPGA vendor’s Place-and-Route tool will generate a separate SDF file that contains estimates of the delay times for the gates in your design based on the way the FPGA was routed (most of the delays in FPGAs are interconnect routing delays rather than delays through the logic gates themselves).
The SDF file generated by the Place-and-Route tool can be used along with the synthesized gate-level model file to perform time-based simulations with your Verilog simulator. An $sdf_annotate command can be placed into the gate-level verilog file to incorporate the timing from the SDF file. These timing simulations are used to detect bugs such as flip flop setup and hold violations.
You generally don’t need to do exhaustive timing simulations, as your design will probably also be getting checked by a timing analyzer tool. A timing analyzer scans for timing paths in your Verilog gate-level netlist that would cause a timing error in your design. A timing analyzer performs a min-max analysis, so it checks more thoroughly for timing problems than a timing simulation does. In theory, you could even skip gate-level simulations and just use the timing analyzer results to verify your design meets timing requirements, but in practice it’s a very good idea to perform a timing simulation as an extra check.
No comments:
Post a Comment