Вы находитесь на странице: 1из 15

Chapter1: Introduction to Verilog

This document uses short examples to demonstrate the basic Verilog syntax, time delays, and
concurrent execution features. We have tried to condense all the interesting and hard parts of
Verilog into 15 pages and skip all of the boring stuff like the what is the difference between real
and integer data types. Studying this document will enable you to model circuits using simple
structural and behavioral Verilog code and provide a solid framework for learning all the details
of the language.

If Verilog is a new language for you we recommend getting a copy of "Verilog HDL" by Samir
Plantikar. It is a well organized Verilog textbook that is filled with lots of examples.

1.0 Why Use Verilog?

Most Verilog and VHDL books begin with several chapters describing the language's history and
advantages. But the arguments boil down to these:

 HDL simulators are better then gate level simulators for 2 reasons: portable
model development, and the ability to design complicated test benches that react
to outputs from the model under test. Finding a model for a unique component for
your particular gate level simulator can be a frustrating task, with an HDL
language you can always write your own model. Also most gate level simulators
are limited to simple waveform based test benches which complicates the testing
of bus and microprocessor interface circuits.
 Verilog is a great low level language. Structural models are easy to design and
Behavioral RTL code is pretty good. The syntax is regular and easy to
remember. It is the fastest HDL language to learn and use. However Verilog
lacks user defined data types and lacks the interface-object separation of the
VHDL's entity-architecture model.
 VHDL is good for designing behavioral models and incorporates some of the
modern object oriented techniques. It's syntax is strange and irregular, and the
language is difficult to use. Structural models require a lot of code that interferes
with the readability of the model.
 C++as an hardware modeling language is excellent choice for high-level
behavioral analysis of a system (like evaluating different data flow architectures
in a microprocessor). However C++ lacks the basic hardware concepts like
knowledge of strengths, connections, and concurrent execution which
complicates model generation for lower level simulations.

Choosing Verilog, VHDL, or C++ will be based on availability of tools, models, and in-house
expertise. If you are just learning your first HDL language we recommend Verilog because you
will be able to quickly become comfortable with the syntax and timing issues of the language:
Chapter 2: Verilog Structure
This chapter gives a quick overview of the structural and behavioral elements of
Verilog and discusses the time flow and time control statements. Verilog differs from
regular programming languages (C, Pascal, ...) in 3 main aspects: (1) simulation time
concept, (2) multiple threads, and (3) some basic circuit concepts like network
connections and primitive gates. If you know how to program in C and you
understand basic digital design then learning Verilog will be easy.

If you have VeriLogger Pro installed on your computer you can copy and paste the
following code segments into a text file and simulate the examples.

2.1 Modules

In Verilog, circuit components are designed inside a module. Modules can contain
both structural and behavioral statements. Structural statements represent circuit
components like logic gates, counters, and microprocessors. Behavioral level
statements are programming statements that have no direct mapping to circuit
components like loops, if-then statements, and stimulus vectors which are used to
exercise a circuit.

Figure 1 shows an example of a circuit and a test bench module. A module starts with
the keyword module followed by an optional module name and an optional port list.
The key word endmodule ends a module.
`timescale 1ns / 1ps
//create a NAND gate out of an AND and an Invertor
module some_logic_component (c, a, b);
// declare port signals
output c;
input a, b;
// declare internal wire
wire d;
//instantiate structural logic gates
and a1(d, a, b); //d is output, a and b are inputs
not n1(c, d); //c is output, d is input
endmodule

//test the NAND gate


module test_bench; //module with no ports
reg A, B;
wire C;

//instantiate your circuit


some_logic_component S1(C, A, B);

//Behavioral code block generates stimulus to test circuit


initial
begin
A = 1'b0; B = 1'b0;
#50 $display("A = %b, B = %b, Nand output C = %b \n", A, B, C);
A = 1'b0; B = 1'b1;
#50 $display("A = %b, B = %b, Nand output C = %b \n", A, B, C);
A = 1'b1; B = 1'b0;
#50 $display("A = %b, B = %b, Nand output C = %b \n", A, B, C);
A = 1'b1; B = 1'b1;
#50 $display("A = %b, B = %b, Nand output C = %b \n", A, B, C);
end
endmodule

Figure 1 shows a simple logic circuit and test bench.

2.2 Structural Design with Gate Primitives and the Delay operator

Verilog defines some basic logic gates as part of the language. In Figure 1, module
some_logic_component instantiates two gate primitives: the not gate and the and gate.
The output of the gate is the first parameter, and the inputs are the rest of the
parameters. These primitives are scaleable so you can get multiple input gates just by
adding inputs into the parameter list. For example:
nand a1(out1, in1, in2); //2-input NAND gate
nand a2(out1, in1, in2, in3, in4, in5); //5-input NAND gate

By default the timing delay for the gate primitives is zero time. You can define the
rising delay, falling delay using the #(rise, fall) delay operator. And for tri-state gates
you can also define the turn-off delay (transition to high impedance state Z) by using
the #(rise, fall, off) delay operator. For example
notif0 #(10,11,27) inv2(c,d,control) //rise=10, fall=11, off=27(not if
control=0)
nor #(10,11) nor1(c,a,b); //rise=10, fall=11 (nor gate)
xnor #(10) xnor1(i,g,h); //rise=10, fall=10 (xnor gate)

Also each of the 3 delays can be defined to have minimum, typical, and a maximum
value using the a colon to separate the values like 8:10:12 instead of 10 in the above
examples. At run time, the Verilog simulator looks for to see if
the +mindelay, +typdelay, or +maxdelay option has been defined so that it will
know which of the 3 time values to use. In VeriLogger these options are set using
the Project > Project Preferences menu. If none of the options are specified then the
typical value is used.
// min:typ:max values defined for the (rise, fall) delays
or #(8:10:12, 10:11:13) or1(c,a,b);
The delay operator has one subtle side effect: it swallows narrow input pulses.
Normally, the delay operator causes the output response of a gate to be delayed a
certain amount of time. However if the input pulse width is shorter then the overall
delay of the gate then the change will not be shown on the output.

Here is a list of logic primitives defined for Verilog:

Gate Parameter List Examples


scalable, requires at and a1(C,A,B);nand na1(out1,in1,in2,in3,in4);nor #(5)
nand nor and least 2 inputs(output, n1(D,A,B);//delay = 5 time unitsxor #(3,4,5)
or xor xnor input1, input2, … , x1(E,A,B);//rise,fall,off delaysnor #(3:4:5)
inputx) n2(F,A,B);//min:typ:max of delays
not buf (output, input) not inv1(c,a);
control signal active
notif0bufif0 low(output, input, notif0 inv2(c,a, control);
control)
control signal active
notif1bufif1 high(output, input, not inv1(c,a, control);
control)

2.3 Structural Design with Assignment Statements

If you have a lot of random logic, the gate primitives of the previous section are
tedious to use because all the internal wires must be declared and hooked up correctly.
Sometimes it is easier to just describe a circuit using a single Boolean equation. In
Verilog, Boolean equations which have similar timing properties as the gate
primitives are defined using a continuous assignment statement.

For example, the following code excerpt from Figure 1:


wire d;
and a1(d, a, b);
not n1(c, d);

can be replaced with one statement:


assign c = !(a && b); //notice that wire d was not used here

Assignments can also be made during the declaration of a wire. In this case the assign
keyword is implicitly assumed to be there for example:
wire d;
assign d = a || b; //continuous assignment
wire d = a || b; //implicit continuous assignment

By default the timing delay for assignment statements is zero time. You can define a
propagation delay using the #delay operator just like we did for the gate primitives.
The following examples have the exact same timing.
wire c;
assign #5 c = a && b; //delay in the continuous assignment

wire #5 c = a && b; //delay in the implicit assignment

wire #5 c; //delay in the wire declaration


assign c = a && b;

To demonstrate the pulse swallowing effect of the delays operator, consider the
following senario. In the above examples, if input a changed value at time 10 (and
held its value for at least 5 time units), then the output c would change values at time
15. If input a had a value pulse that was shorter then the propagation delay of the
assignment then the value on a would not be passed to the output.

The delay operator can also use the full rise, fall, and off delays and each delay can
have a minimum:typical: maximum value. The following is a valid line of code.
and #(8:10:12, 10:11:13, 26:27:29) a1(c,a,b); //min:typ:max of (rise,fall,off)

Appendix A defines all of the operators that can be used in an assignment statement.

2.4 Structural Design with using Modules

Verilog supports hierarchical design by allowing modules to instantiate other


modules. For example in Figure1 module test_bench instantiates a component S1 of
type some_logic_component. The code is reprinted here for convince:
module test_bench;
...
some_logic_component S1(C, A, B); //instantiate a some_logic_component
module
...
endmodule

By default the timing inside a module is controlled by the module itself. However,
modules can be defined to have parameterized delays similar to the #(4,5) delay
operator used with gate primitives. In the module definition, use the parameter
keyword to create delay variables. Parameters can also be used to change other scalar
values in the module. When the module is instantiated then you can choose to
override the delay values using the #(parameter) notation. For example:
module some_logic_component (c, a, b);
... //some code
parameter andDelay = 2; //default delays
parameter invDelay = 2;
and #andDelay a1(d, a, b); //using parameter delays
not #invDelay n1(c, d);
endmodule

module test_bench; //module with no ports


...
some_logic_component #(5,4) S3(E, A, B); //override andDelay=5, invDelay=4
some_logic_component #(5) S2(D, A, B); //override andDelay=5, invDelay=2
some_logic_component S1(C, A, B); //uses default delays
....
endmodule

Modules also support a special kind of timing called specify blocks which can be used
in conjunction with SDF analyzers. Specify blocks also support continuous setup and
hold checking.

2.5 Behavioral Design with Initial and Always blocks

Behavioral code is used to describe circuits at a more abstract level then the structural
level statements we have studied. All Behavioral code occurs within either an initial
block or in an always block. A module can contain several initial and always blocks.
These behavioral blocks contain statements that control simulation time, data flow
statements (like if-then and case statements), and blocking and non-blocking
statements.

An initial block executes once during a simulation. Initial blocks are usually used to
initialize variables and to describe stimulus waveforms which exercise which drive
the simulation.

An always block continuously repeats its execution during a simulation. Always


blocks usually contain behavioral code that models the actual circuit operation.

During a simulation each always and each initial block begin to execute at time zero.
Each block executes concurrently with each structural statement and all the other
behavioral blocks. The following example shows a behavioral SRAM model. The
initial block sets the memory cells to zero at startup. The always block executes each
time there is a change on the write control line, the chip select line, or the address bus.
As an exercise, copy and paste this code into a verilog file and write a test bench to
exercise the model. If you are using VeriLogger Pro then you can draw a test bench.
//SRAM Model
module sram(CSB,WRB,ABUS,DATABUS);
input CSB; // active low chip select
input WRB; // active low write control
input [11:0] ABUS; // 12-bit address bus
inout [7:0] DATABUS; // 8-bit data bus
//** internal signals
reg [7:0] DATABUS_driver;
wire [7:0] DATABUS = DATABUS_driver;
reg [7:0] ram[0:4095]; // memory cells
integer i;

initial //initialize all RAM cells to 0 at startup


begin
DATABUS_driver = 8'bzzzzzzzz;
for (i=0; i < 4095; i = i + 1)
ram[i] = 0;
end

always @(CSB or WRB or ABUS)


begin
if (CSB == 1'b0)
begin
if (WRB == 1'b0) //Start: latch Data on rising edge of CSB or WRB
begin
DATABUS_driver <= #10 8'bzzzzzzzz;
@(posedge CSB or posedge WRB);
$display($time," Writing %m ABUS=%b DATA=%b",ABUS,DATABUS);
ram[ABUS] = DATABUS;
end
if (WRB == 1'b1) //Reading from sram (data becomes valid after 10ns)
begin
#10 DATABUS_driver = ram[ABUS];
$display($time," Reading %m ABUS=%b DATA=%b",ABUS,DATABUS_driver);
end
end
else //sram unselected, stop driving bus after 10ns
begin
DATABUS_driver <= #10 8'bzzzzzzzz;
end
end
endmodule
Chapter 3: Verilog Syntax Details
Our goal up to this point has been to teach you how to model some simple circuits
before swamping you with all the details about Verilog types, ports, and numbers. But
as we do more Behavioral design it becomes easier to make mistakes in this area.
Before you begin a big design you might want to get a copy of "Verilog HDL" by
Samir Plantikar and memorize Chapters 3, 4, and 7. What follows is just enough
information in order to understand the subsequent behavioral code examples.

3.1 Structural Data Types: wire and reg

Verilog supports structural data types called nets which model hardware connections
between circuit components. The two most common structural data types
arewire and reg. The wire nets act like real wires in circuits. The reg type hold their
values until another value is put on them, just like a register hardware component. The
declarations for wire and reg signals are inside a module but outside any initial or
always block. The initial state of a reg is x unknown, and the initial state of awire is z.

Ports:Modules communicate with each other through ports, the signals listed in the
parameter list at the top of the module. Ports can be of type in, out, and inout.

Here are 3 simplistic rules for matching the structural data type to the type of port:

1. Use reg as the outputs of Behavioral blocks. If you us a wire then the value will
never be seen by other blocks.
2. Use wire for all inputs, inouts, and most outputs of Structural elements.
3. If you need a special strength type operation use special net keyword wand, wor,
tir, triand, trior, trireg.

3.2 Behavioral Data Types: integer, real, and time

The types in integer and real are convenient data types to use for counting in


behavioral code blocks. These data types act like their counter parts in other
programming languages. If you eventually plan to synthesize your behavioral code
then you would probably want to avoid using these data types because they often
synthesize large circuits.

The data type time can hold a special simulator value called simulation time which is
extracted from the system function $time. The time information can be used to help
you debug your simulations.

..... //code fragment from inside a module


integer i, y;
real a;
real b = 3.5;
real c = 4;
time simulationTime;
initial
begin
y = 4;
i = 5 + y;
c = c + 3.5;
a = 5.3e4;
simulationTime = $time;
$display("integer y = %d, i = %f \n", y, i);
$display("reals c = %f, a = %e, b= %g \n", c, a, b);
$display("time simulationTime = %t \n", simulationTime);
end

3.3 Number Syntax

Numbers in verilog are in the following format


'

The size is always specified as a decimal number. If no is specified then the default
size is at least 32bits and may be larger depending on the machine. Valid base formats
are 'b , 'B , 'h , 'H 'd , 'D , 'o , 'O for binary, hexadecimal, decimal, and octal.
Numbers consist of strings of digits (0-9, A-F, a-f, x, X, z, Z). The X's mean
unknown, and the Z's mean high impedance If no base format is specified the number
is assumed to be a decimal number. Some examples of valid numbers are:
2'b10 // 2 bit binary number
'b10 // at least a 32-bit binary number
3 // at least a 32-bit decimal number
8'hAf // 8-bit hexadecimal
-16'd47 // negative decimal number

3.4 Behavioral Design with blocking and non-blocking statements

There are 2 kinds of assignment statements: blocking using the = operator, and non-
blocking using the <= operator. Blocking assignments act like sequential code
statements and execute when they are called. Non-blocking schedule events to happen
at some time in the future. This can be confusing because lines that appear after a non-
blocking statement execute at the same time as the non-blocking statement. Here are
some examples:
#5 x = 1'b0; // blocks for 5 time units, applies value to x, then next line
goes
y = 1'b1; // blocks, sets y to 1 now, then next statement goes
y <= #3 1'b0; // evaluates now, schedules apply y=0 in 3 time units, and next
line goes
#5 x <= y; // waits for 5 time units, evaluates,
// schedules apply at end of current time, and next line
goes

The following two code blocks are not equivalent:


// Section 1: Blocking statements execute sequentially
#5 a = b; // waits 5 time units, evaluates and applies value to a
c = d; // evaluates and applies value to c

// Section 2: Non-Blocking statements execute concurrently


#5 a <= b; // waits 5 time units, evaluates, schedules apply for end of
current time
c <= d; // evaluate, schedules apply for end of current time
// At end of current time both a and c receive their values

3.6 Arrays, Vectors, and Memories

Verilog supports three similar data structures called Arrays, Vectors, and Memories.
Arrays are used to hold several objects of the same type. Vectors are used to represent
multi-bit busses. And Memories are arrays of vectors which are accessed similar to
hardware memories. Read the following examples to determine how to reference and
use the different data structures.
//*** Arrays for integer, time, reg, and vectors of reg ***************
integer i[3:0]; //integer array with a length of 4
time x[20:1]; //time array with length of 19
reg r[7:0]; //scalar reg array with length of 8

c = r[3]; //the 3rd reg value in array r is assigned to c

//*** Vectors are multi-bit words of type reg or net (wire)************


reg [7:0] MultiBitWord1; // 8-bit reg vector with MSB=7 LSB=0
wire [0:7] MultiBitWord2; // 8-bit wire vector with MSB=0 LSB=7
reg [3:0] bitslice;
reg a; // single bit vector often referred to as a scalar
.... //referencing vectors
a = MultiBitWord1[3]; //applies the 3rd bit of MultiBitWord1 to a
bitslice = MultiBitWord1[3:0]; //applies the 3-0 bits of MultiBitWord1 to
bitslice

//*** Memories are arrays of vector reg ********************************


reg [7:0] ram[0:4095]; // 4096 memory cells that are 8 bits wide

//code excerpt from Chapter 2 SRAM model


input [11:0] ABUS; // 12-bit address bus to access all 4096 memory cells
inout [7:0] DATABUS; // 8-bit data bus to wite into and out of a memory cell
reg [7:0] DATABUS_driver;
wire [7:0] DATABUS = DATABUS_driver; //inout must be driven by a wire
....
for (i=0; i < 4095; i = i + 1) // Setting individual memory cells to 0
ram[i] = 0;
end
....
ram[ABUS] = DATABUS; //writing to a memory cell
....
DATABUS_driver = ram[ABUS]; //reading from a memory cell

3.7 Operators

Here is a small selection of the Verilog Operators which look similar but have
different effects. Logical Operators evaluate to TRUE or FALSE. Bitwise operators
act on each bit of the operands to produce a multi-bit result. Unary Reduction
operators perform the operation on all bits of the operand to produce a single bit
result.

Operator Name Examples


! logical negation
~ bitwise negation
&& logical and
abus =
& bitwise and
bbus&cbus;
& reduction and abit = &bbus;
~& reduction nand
|| logical or
| bitwise or
| reduction or
~| reduction nor
^ bitwise xor
^ reduction xor
~^ ^~ bitwise xnor
~^ ^~ reduction xnor
== logical equality, result may be unknown if x or z in the input if (a == b)
=== logical equality including x and z
!= logical inequality, result may be unknown if x or z in the input
!== logical inequality including x and z
> relational greater than
a = shiftvalue
>> shift right by a number of positions
>> 2;
>= relational greater than or equal
< relational less than
<< shift left by a number of positions
<= relational less than or equal if (a <= b)
non blocking assignment statement, schedules assignment for future
<= #5 b <= b + 2;
and allows next statement to execute
blocking assignment statement, waits until assignment time before
= #5 a = a + 2;
allowing next statement to execute

Verilog also supports arithmetic, replication, and concatenation operators

Chapter 4: Verilog Design Flow


 
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 called fpga_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.

Вам также может понравиться