You can find a pretty good overview of Verilog in the Verilog overview & references page at Texas A&M.
Creating a ModelSim project
Go to the command line and execute the following commands to start up ModelSim.
mkdir -p csci/320/lab1 vsim &
In the ModelSim program, use the menu choices
File ⇒
New ⇒
Project.
Next use
/home/username/csci/320/lab1,
where username is your login name,
as the Project Location
and lab1
as the
Project Name .
Allow ModelSim to create the directory.
Do not use the browser to find your home directory.
It takes too long.
Go back go the command line, type the following command to make sure you have files in the right place. You should see six files or directories.
ls -lR ~/csci/320
Adding a Verilog program
Under the Project tab, double-click on fulladder.v . This will allow you to start editing your program
You won’t get much help from ModelSim in getting started, so insert the following into your Verilog program.
// Lab 1 for CSCI 320 module fulladder( input An, // A bit input Bn, // B bit input Cn, // carry-in bit output Cnp1, // carry-out bit output Sn) ; // sum bit // your implementation will go here endmodule
All the modifications you do to this program will be made
after the module header and
before the endmodule
keyword.
Notice that Verilog doesn’t use as many braces and semi-colons as Java. It is a bit old fashioned.
In this lab are going to implement a full-adder circuit. You can find a detailed description of the full-adder circuits in Circuits Today. You can also find an interesting picture of one on Discovery magazine.
A structural implementation
In Verilog the wire
is a path for connecting modules.
Add a declaration for the three wires coming out of the
three AND gates.
wire tAB, tAC, tBC ;
Now implement your module by placing the
the following structural description after the wire
declaration.
All your inputs, output and wires are now used in your program.
xor(Sn, An, Bn, Cn) ; and(tAB, An, Bn) ; and(tAC, An, Cn) ; and(tBC, Bn, Cn) ; or(Cnp1, tAB, tAB, tBC) ;
The and
, or
and xor
are some
of the predefined gates that are provided by Verilog.
If you want to give your gates names, you can use the following syntax.
xor sum(Sn, An, Bn, Cn) ; and abTerm(tAB, An, Bn) ; and acTerm(tAC, An, Cn) ; and bdTerm(tBC, Bn, Cn) ; or carry(Cnp1, tAB, tAC, tBC) ;
Go ahead compile your module with Compile ⇒ Compile All. The result of the compile will appear in the Transcript window. If there are errors, you will need to use View ⇒ Message View window to uncover the messages.
Simulation of the full adder
Text-based simulation
Press
Simulate ⇒
Start Simulation.
This will raise the
Start Simulation window,
where you must expand the work
library to
select the fulladder
module.
Afterwards, there will be a flurry of flashing windows.
Take a minute to look at these windows. The Transcript window the console of a TCL program that controls the simulation. In the real world, designers write TCL scripts to customize the simulation.
In the Objects window,
notice the values of your variables.
For now, consider HiZ
and StX
to be to uninitialized variables.
In the Transcript window, issue the following commands.
force An 0 force Bn 0 force Cn 0 run 100
This will initialize An
, Bn
and
Cn
and
“run” your
circuit for 100 picoseconds.
You should see that all you variables now have the value
St0
, a strong 0.
Now set An
to 1 and run for another 100.
The values of An
and Sn
should change.
Riding the wave
Use your mouse to select the input and output values of your circuit. Right-click and use Add ⇒ To wave ⇒ Selected Signals to add these values to the wave display.
You can always mash Simulate ⇒ Run ⇒ Restart to reinitialize the simulation if things look weird, but then you will then toforce
all your variables.
Set An
back to 0 and run another 100.
You should see your values displayed on the wave.
Now we are going to go through all eight combinations of the input using a Gray code, which does relate to the Karnaugh map. Use these 16 commands to do the checking. Each time you type run 100, make sure the outputs look correct.
force Cn 1 run 100 force Bn 1 run 100 force Cn 0 run 100 force An 1 run 100 force Cn 1 run 100 force Bn 0 run 100 force Cn 0 run 100 force An 0 run 100
Kind of tedious, ain’t it? Go ahead and stop the simulation and we’ll try something better.
A testbench program
Let’s add a testbench module to the project The testbench module will not be synthesized. It is purely for testing.
You’ll need to create a new file. Select the Project tab and follow that with Project ⇒ Add to Project ⇒ New File. Name the new file testbench.v and make sure it is of type Verilog. It will not be added to the library until it is successfully compiled.
In this section of the lab, you will modify only the testbench module.
Do not modify the fulladder
module.
Verilog without a circuit
Here is the code for the testbench
module.
This looks a lot like a C or Java loop to print
from 0 to 7.
Notice the reg
declaration.
In Verilog, a register is a variable for storing values.
module testbench() ; reg[2:0] vin ; integer i ; initial begin for (i=0; i<8; i=i+1) begin vin = i ; #100 ; $display("vin = %h", vin) ; end end endmodule
The #100
is Verilog’s way of delaying for
100 picoseconds.
Start the simulator but choose only
testbench
for the simulation.
Either press the run-all button
or just type
run -all to start the simulation.
(About the only thing the buttons do is talk to TCL.)
You should get a count from 0 to 7.
Testing the full adder
Now we are going to add a “call”
of the fulladder
module from the testbench.
To do this you need a wire vout
for the output of
fulladder
along with a statement that connects the testbench
to the
fulladder
.
The fulladder
will be instantiated as
dut
, for device under test.
This is a common naming convention in Verilog.
To instantiate and connect the fulladder
, place the following two
statements right before the initial begin
keywords.
wire[1:0] vout ; fulladder dut(vin[2], vin[1], vin[0], vout[1], vout[0]) ;
Next go into the initial begin
block
and modify the call to $display
so that
in prints out vout
.
$display("vin = %h, vout = %h", vin, vout) ;
Compile all your programs. Start up the simulation, but select only the testbench. It will include the needed copy of the device under test.
Hopefully, you will get the right answers.
You might want to replace the %h
in the call
to $display
with %b
to get binary output.
Back on the wave
Try out the wave simulator by adding in
vin
and vout
.
You will need to expand them to see the individual bits.
Testbench is complete
At this point, your work on the testbench is complete.
You should never modify the testbench
module again.
A behavioral description
The structural description is a good way to match a circuit, but it doesn’t look like a program.
Go to the fulladder
and comment out
the structural description. Just enclose everything from the
wire
declaration to the or
gate withthe usual Java/C /*
and */
comment delimiters.
Now add in a simple behavioral description.
assign Sn = An ^ Bn ^ Cn ; assign Cnp1 = An & Bn | An & Cn | Bn & Cn ;
Except for the assign
keyword, it looks just like
C or Java. Simulate it to see that it works fine.
If you don’t like those logical C/Java operators, you can just
use the regular addition operator, but you need to add a
two-bit declaration of a variable sum2bit
to do this.
wire[1:0] sum2bit ; assign sum2bit = An + Bn + Cn ; assign Sn = sum2bit[0] ; assign Cnp1 = sum2bit[1] ;
Again, simulate.
You can also take advantage of Verilog’s own special use of braces to write a one-statement implementation.
assign {Cnp1, Sn} = An + Bn + Cn ;
And simulate one more time.
Trying out Quartus
Exit from vsim and start up quartus.
quartus &
Create a project in the same directory you have been using.
Give the project any name you want and specify that the top level
entity will be fulladder
.
Now add fulladder.v
to the project and select
the Cyclone IV FPGA at the top of the list as your device.
(It really doesn’t matter which device you select since
we have none of them.)
After you use the menu choices File ⇒ New Project Wizard and choose the Verilog HDL project, there are five steps to this process.
- Create your project within the directory you used above.
Select
fulladder
as your top-level design entry. - Click on the three dots just to the left of the Add button, and use the browser to select your fulladder.v file. Do not use the testbench program.
- Just choose the first device you see, the EP4CGX15BF14A7.
- Use the default EDA tool settings.
- Use finish.
You should now be able to compile and synthesize, though with lots of warnings.
Now just poke around a little. Under Assignments, look at Pin Planner. Under Tools ⇒ Netlist Viewer look at both the RTL Viewer and Post Mapping.
This is little use to us, but in the real world you can use these displays to see how well your design has been synthesized for the target device.