The Verilog Hardware Description Language can be used to model a digital circuit during the design stage. Such a design may be simulated using the Verilog-XL digital simulator in order to make early descisions on the viability of a design. The design may then be further refined at this stage before any circuit is implemented. The final Verilog HDL model may then be used as a base for circuit design or directly synthesized to produce a circuit implementation.
This page describes creation and refinement of Verilog HDL model files. It also touches on their simulataion and synthesis. The details of simulation and synthesis are discussed elsewhere.
The Verilog Hardware Description Language offers many more features than I could hope to cover in these pages. This page attempts to choose the most useful parts of the Verilog HDL and illustrate their use with simple examples.
A definitive description of the Verilog constructs used may be found in the cdsdoc on-line manual.
Verilog HDL supports a number of built in logic gates from which larger systems can be constructed. The basic gates are:
Multi-input gates (two or more inputs) |
and or xor nand nor xnor |
e.g. and inst (output, input1, input2, input3 .....); |
Single-input gates (one or more outputs) |
buf not |
e.g. buf inst (output1, output2 ....., input); |
Tri-state gates | bufif1 bufif0 notif1 notif0 |
e.g. bufif1 inst (output, input, enable); |
A simple strucural model is a netlist describing the interconnection of gates to create a module definition.
The following file, dtype.v, is a structural model for the D type flip-flop:
`timescale 100ps / 10ps // structural model of edge triggered D type module dtype(Q, nQ, D, Clk, nRst); output Q, nQ; input D, Clk, nRst; wire Q, nQ, D, Clk, nRst, net1, net2, net3, net4; nand nand1 ( net1, net3, D, nRst ); nand nand2 ( net2, net1, net4 ); nand nand3 ( net3, Clk, net1, net4 ); nand nand4 ( net4, Clk, net2, nRst ); nand nand5 ( nQ, nRst, net3, Q ); nand nand6 ( Q, nQ, net4 ); endmodule
This should exist at the top of each Verilog file. It declares the units for time delays within the file and also the maximum resolution for such delays.
The module...endmodule construct delimits the module definition.
The module line defines the name of the module and gives an ordered port list of the inputs and ouptuts. By convention the outputs are listed first.
Subsequent input and output statements are used to distiguish inputs from outputs.
Here all signals which will be used are declared as single bit wires. This section is optional since an undeclared signal is assumed to be a single bit wire.
Each gate instance line consists of a gate type, a unique instance name by which we can distiguish the different gates and an ordered list of wires to be connected to the gate instance. The ordering of these wires should correspond exactly with the ordering of the ports of the gate; for all these gates the only requirement is that the output is listed before the inputs.
The stimulus file for this HDL model is dtype_stim.v.
To simulate this design, copy the relevant files to a suitable directory and type the following at the unix command prompt:
verilog_xl dtype_stim.v dtype.v
The following file, count.v, is a structural model for the counter:
`timescale 100ps / 10ps // structural model of an "up only" counter module count(count, up, clock, not_reset); output [3:0] count; input up, clock, not_reset; dtype dtype0 (count[0], nq0, d0, clock, not_reset); dtype dtype1 (count[1], nq1, d1, clock, not_reset); dtype dtype2 (count[2], nq2, d2, clock, not_reset); dtype dtype3 (count[3], nq3, d3, clock, not_reset); xor xor0 (d0, count[0], up); xor xor1 (d1, count[1], en1); and and1 (en1, count[0], up); xor xor2 (d2, count[2], en2); and and2 (en2, count[1], en1); xor xor3 (d3, count[3], en3); and and3 (en3, count[2], en2); endmodule
More complex designs employ a hierarchy of structural models. This design defines a counter module in terms of basic gates and the d-type flipflop, which is a sub-module defined in the file dtype.v.
Thus we can redefine the stuctural model as a netlist describing the interconnection of gates and sub-modules to create a module definition.
The stimulus file for this HDL model is count_stim.v.
Type the following at the unix command prompt:
verilog_xl count_stim.v count.v dtype.v
Verilog HDL supports a number of operators from which expressions can be constructed. The basic operators are:
binary | unary | example | ||
Logical | single bit inputs single bit output |
&& || | ! | Logical AND True && False = False |
Relational | multi-bit inputs single bit output |
== != >= <= | Greater or Equal 9 >= 7 = True |
|
Bit-wise Boolean | multi-bit inputs multi-bit output |
& | ^ ~^ | ~ | Bit-wise XOR 1012 ^ 1102 = 0112 |
Arithmetic | multi-bit inputs multi-bit output |
+ - * / % | - | Modulus 9 % 4 = 1 |
Shift | multi-bit inputs multi-bit output |
>> << | Right Shift 101102 >> 2 = 1012 |
Expressions can be used along with continuous assignment statements to provide behavioural models of combinational logic circuits.
More complex behavioural models, in particular those describing sequential circuits, will employ procedural assignments and more complex procedural statements. Such statements include descision statements such as if...else and case and even looping statements such as while and for.
The following file, window.v, is a behavioural model of a digital window comparator:
`timescale 100ps / 10ps // behavioural model of a digital window comparator module window(Too_High, OK, Too_Low, Top_Limit, Value, Bottom_Limit); output Too_High, OK, Too_Low; input [3:0] Top_Limit, Value, Bottom_Limit; wire Too_High, OK, Too_Low; wire [3:0] Top_Limit, Value, Bottom_Limit; assign Too_High = Value >= Top_Limit; assign Too_Low = Value <= Bottom_Limit; assign OK = !Too_High && !Too_Low; endmodule
A single or multi-bit wire may have its value determined as the output of an expression using a continuous assignment statement. The assignment is described as continuous since the expression on the right hand side is continuously monitored allowing any changes to be propagated to the wire on the left hand side of the assignment.
The stimulus file for this HDL model is window_stim.v.
Type the following at the unix command prompt:
verilog_xl window_stim.v window.v
The following file, dff.v, is a behavioural model of a D type flip-flop:
`timescale 100ps / 10ps // behavioural model of edge triggered D type module dff(Q, D, Clk); output Q; input D, Clk; reg Q; // action on clock rising edge always @(posedge Clk) Q = D; endmodule
Q is defined as a register. A register is assigned values at regular or irregular intervals. The register will remember the value assigned until the next time an assignment takes place.
All assignments to registers are procedural and hence must occur within an always or an initial procedure.
@(posedge Clk) is a event control. In this example we see that every time we have a rising edge on the Clk signal we will assign the value of D to the register Q. Between rising clock edges, Q remains unchanged regardless of any changes in the value of D.
This is the normal method for the description of a synchronous sequential system.
The stimulus file for this HDL model is dff_stim.v.
Type the following at the unix command prompt:
verilog_xl dff_stim.v dff.v
The following file, up_down_count.v, is a behavioural model of a 4-bit up/down counter:
`timescale 100ps / 10ps // behavioural model of an up/down counter module up_down_count(count, up, down, clock, not_reset); output [3:0] count; input up, down, clock, not_reset; reg [3:0] count; always @(posedge clock or negedge not_reset) if (!not_reset) // asynchronous reset overrides synchronous action begin count = 0; end else // action on clock rising edge begin if (up & ~down) count <= count + 1; if (down & ~up) count <= count - 1; if (up & down) count <= 0; end endmodule
The begin...end construct groups a number of statements that will be evaluated in sequence.
Note that an alternative construct fork...join which groups statements that will be evaluated in parallel is seldom used since it is unsynthesizable.
Note that it is usual to use a non-blocking procedural assignment, X <= Y, rather than a blocking procedural assignment, X = Y within a clock controlled begin...end construct (synthesis is of the former is much simpler). The non-blocking version evaluates all right hand side expressions in the sequence before assigning values to any of the left hand side registers.
The difference is indicated by the following piece of code which swaps the values of A and B:
begin A <= B; B <= A; endRather than the alternative which leaves A and B both equal to the old value of B:
begin A = B; B = A; end
Here we see that the event control, @(posedge clock or negedge not_reset), will wait for either a rising edge on clock or a falling edge on not_reset.
The subsequent code gives reset priority such that when reset is active, count is held at zero regardless of the clock or other inputs.
This is the normal strategy for the description of an asynchronous reset within a synchronous sequential system.
The following Verilog fragment shows an alternative strategy for describing the asynchronous reset action.
// action on clock rising edge always @(posedge clock) begin if (up & ~down) count = count + 1; if (down & ~up) count = count - 1; if (up & down) count = 0; end // asynchronous "assign" overrides synchronous action always @(not_reset) if (!not_reset) begin assign count = 0; end else begin deassign count; end
The full code can be found in the file, alt_up_down_count.v.
This reset strategy employs the strange hybrid known as the continuous procedural assignment. On the falling edge of not_reset, the register value is forced to zero and will remain at zero regardless of any procedural assignments to the register until the rising edge of not_reset releases the register value for subsequent procedural assignment.
Although this strategy results in a faster simulation and greater flexibility in the layout of code, it is not recognized by many synthesis systems making it of little use for portable code.
The stimulus file for this HDL model is up_down_count_stim.v.
Type the following at the unix command prompt:
verilog_xl up_down_count_stim.v up_down_count.v
The microprocessor is described in the following verilog files:
Most complex behavioural models are constructed as a hierarchy of simpler behavioural models.
The Processor module instances the Control, Datapath and Memory modules. It is in fact merely a structural descrition of their interconnection:
control Control ( Data_bus, Address, Function, Mem_Write, ZFlag, Clock, notReset ); datapath Datapath ( Data_bus, ZFlag, Function, Clock, notReset ); memory Memory ( Data_bus, Address, Mem_Write, Clock );
The Datapath module instances the ALU module but also contains the behavioural description of the Accumulator:
alu ALU ( zflag, ALU_output, Accumulator, data, opcode);
The following construct describes a multiplexor which selects input1 if select is `1' and input0 if select is `0':
The Control module includes an address multiplexor based on this construct:
assign address = (state == `fetch_cycle) ? Program_Counter : operand;
A procedural block with an event control of the form @(input1 or input2 or ...) can be used to describe a combinational logic block provided that:
The ALU module uses such a construct to evaluate result:
reg [15:0] result; always @(inputA or inputB or func) case (func) `LDA : result = inputB; `ADD : result = inputA + inputB; `SUB : result = inputA - inputB; `AND : result = inputA & inputB; `OR : result = inputA | inputB; `NOT : result = ~inputA; `LSL : result = inputA << 1; `LSR : result = inputA >> 1; default : result = inputA; endcase
Note that including a default case covers requirement 3 above.
The Datapath module may drive the Data_bus, locally known as data, from the Accumulator:
inout [15:0] data; assign data = ( func == `STA ) ? Accumulator : 16'bz;
Note the inout declaration for data indicating that it is both an input and an output for the module.
The Memory module may also drive the Data_bus:
inout [15:0] data; assign data = (!write) ? Data_stored [address] : 16'bz;
The opcodes.v file declares constants to be used in other modules:
`define AND 4'd7 `define OR 4'd8 `define NOT 4'd9
The alu.v file includes the opcodes.v file and then uses the constants within the alu module:
`include "opcodes.v" `timescale 100ps / 10ps module alu( zflag, result, inputA, inputB, func); `AND : result = inputA & inputB; `OR : result = inputA | inputB; `NOT : result = ~inputA; endmodule
The stimulus file for this HDL model is system.v.
Before simulating this design, first copy the stimulus file to a suitable directory and then create a sub directory called library into which you should copy the model files. The appropiate simulation command lists only the stimulus file and the name of the directory in which the other files are located:
verilog_xl -y library +libext+.v +incdir+library system.v
All Verilog documentation is available on-line via cdsdoc. Type the following at the unix command prompt in order to invoke cdsdoc:
cdsdoc &
On-line manuals of particular interest to this tutorial are:
1The verilog program runs on the SUCS Sun workstations in the Shackleton building and on the ECS CAD server (salvador). If you are logged into one of these machines you can check the availability of verilog by typing:
which verilog_xl
If you get a "verilog_xl: Command not found." message you should check your account configuration.
If you need only the non-graphics implementation of the simulator you can run
verilog on a verilog capable machine when remotely logged in from any
other machine using telnet.
If you need graphical output, then you must be sitting at a machine with X-windows
running and correctly configured. The best way to be sure of X-windows capability
is to sit at a verilog capable machine.
Iain McNally
22-12-2003