sudo apt install make
sudo apt install iverilog
sudo apt install gtkwave
$ make # compile
$ make DUMP=1 # compile and generate dump file for wave
$ make wave # open generated dump vcd file using GTKWAVE
$ make clean # remove all build up files.
- Line terminator: Semicolon
;
- Single line comment:
//
- Multiple line comment:
/* ... */
- Identifier: the name of the object
- Keyword: The word cannot be used as identifier since it is reserved for Verilog HDL.
Value | Logic | Detail |
---|---|---|
0 | Logic LOW | False |
1 | Logic HIGH | True |
X | Don't care | 0,1, or Z |
Z | High Impedence | not connected |
Examples are below.
& | 0 | 1 | X | Z |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
1 | 0 | 1 | X | X |
X | 0 | X | X | X |
Z | 0 | X | X | X |
| | 0 | 1 | X | Z |
---|---|---|---|---|
0 | 0 | 1 | X | X |
1 | 1 | 1 | 1 | 1 |
X | X | 1 | X | X |
Z | X | 1 | X | X |
Signed Number Representation
Usage: <size>'<base_format><number>
-
<size>
: number of bits -
<base_format>
: base format code of following<number>
b
orB
: binaryo
orO
: octald
orD
: decimalh
orH
: hexadecimal
-
<number>
: value of number represented in format specified as<base_format>
-
_
(underscore): it has no grammatical meaning, but used for separation. -
?
(question mark): imply casex or casez syntax
eg)
4'b1111 // 4bit number 1111
12'habc // 12bit number 101010111100
16'd255 // 16bit number 1111111111111111
12'b1010_1011_1100 // 12bit number 101010111100
4'b10?? // 4bit number 10zz
12'h13x // 12bit number 00010011xxxx
6'hx // 6bit number xxxxxx
8'bz // 8bit number zzzzzzzz
- keyword:
wire
- connection between hardware elements or module
- net is continuously driven by other signal
- default value: 'z' (high impedence)
- keyword:
reg
- Data storage elements to retain value until another value is stored
- default value: 'x' (don't care)
Integer, Real, Time may not be realized as Hardware (for simulating stimulus block)
Nets or Registers can be declared as vector (multiple bit widths)
Usage: <data_type>[left_range:right_range]<variable_name>
eg)
wire[7:0] bus; // 8bit bus
$display(bus[3:0]); // part selection (only lower 4bit)
Note that descending index convention is commonly used, such that [(N-1):0] for N-bit vector
Usage: <data_type><array_name>[<subscript>]
Array allows the data types of <reg>
,<ingeger>
, <time>
, <vector reg>
.
Vector form is preferred more, and array form is used especially for memory.
eg)
reg[7:0] membyte [0:1023] // Memory of 1K(1024) of byte words
membyte[511] // 1 byte word whose address is 511
performs certain routine operations.
Usage: $<keyword>;
$display(<list_of_arguments>);
prints the argument given, only when it is called.- accepts 'Verilog Format Specifiers' listed below.
$monitor(<list_of_arguments>);
prints the argument given, whenever the given arguments are changed.- accepts 'Verilog Format Specifiers' listed below.
- needs to be invoked only once unlike
$display
$stop;
suspends the simulation in an interactive mode.$finish;
terminates the simulation.
In order to print variables inside display functions, appropriate format specifiers have to be given for each variable.
Argument | Description |
---|---|
%h, %H | Display in hexadecimal format |
%d, %D | Display in decimal format |
%b, %B | Display in binary format |
%m, %M | Display hierarchical name |
%s, %S | Display as a string |
%t, %T | Display in time format |
%f, %F | Display 'real' in a decimal format |
%e, %E | Display 'real' in an exponential format |
Compiler Directives are annotated by starting with grave accent ```````. It operates pre-processing during compilation
Usage: \`<keyword>
\`define <macro_name> <macro_value>
: text macro in Verilog (similar with#define
in C)- use macro by
\`<macro_name>
- eg)
`define WORD_SIZE 32 // 'WORD_SIZE' implies 32 `define WORD_REG reg[(`WORD_SIZE-1):0] // 'WORD_REG' implies reg[31:0] ... `WORD_REG reg32; // reg32 declared in type of WORD_REG
- use macro by
\`include <verilog_source_file>
: include Verilog Source file in another Verilog file during compliation. (similar with#include
in C)- eg)
`include header.v
- eg)
Module is Basic building blocks that provide the necessary functionality to the higher-level block, and the port interfaces (input&output) while hiding internal implementation. Module may be defined as the form of below.
module <module_name>(<port_list>);
<port_declaration> // if port present
<intermediate_data_definition> // if wire, reg and other variables are needed
<lower_level_module_instantiation> // instantiation of implemented module or primitive gates.
<dataflow_statement> // 'assign'
<behavioral_statement> // 'initial' and 'always' block
<system_task_and_functions> // system task and function if needed.
endmodule
module
, <module_name>
, endmodule
are mandatory for module, while others are optional (used if needed).
Note that the semicolon ;
locates at the end of first line of module definition.
Module is a templete, and instance is actual object created by the templete 'module'.
Instance can be created by module instantiation as follows:
Usage: <module_name> <instance_name> (<list_of_mapped_variable_with_ports>);
eg) D_FF DFF1 (Q,D,CLK,RESET);
- provides the interface by which a module can communicate with its environment.
Verilog Keyword | Type of Port |
---|---|
input | Input port |
output | Output port |
inout | Bidirectional port |
eg) port declaration
module Full_Adder_4bit(sum,cout,a,b,cin);
output wire[3:0] sum; // (output) port declaration
output wire cout; // (output) port declaration
input wire[3:0] a, b; // (output) port declaration
input wire cin; // (output) port declaration
/*Module Instatiation placed here*/
endmodule
module D_FF(q,d,clk,reset);
output reg q; // (output) port declaration
input d, clk, reset; // (input) port declaration
/*Module Instatiation placed here*/
endmodule
Characteristic of two data type mentioned above are followed:
net is continuously driven by other signal
register is data storage elements to retain value until another value is stored
These derives following rules:
- recipient must be declared as 'net' type so that its value can be driven by sender.
- sender can be declared as either 'register' or 'net'.
- if sender is driven by another signal, then it must be 'net' type.
- if sender has its own state and retain its value until modification, then it must be 'reg' type.
Therefore, connection rule should be as follows
Internal | External | |
---|---|---|
input | wire |
wire or reg |
output | wire or reg |
wire |
inout | wire |
wire |
- mapping variables with each corresponding port by order
- eg)
D_FF DFF1 (Q,D,CLK,RESET);
- mapping variables with each correponding port by name
- eg)
D_FF DFF1 (.clk(CLK), .reset(RESET), .d(D), .q(Q))
Recommendation: Ordered connection by name (for readability)
- basically connecting by name, but list in order for easier debugging
- eg)
D_FF DFF1 (.q(Q), .d(D), .clk(CLK), .reset(RESET))
- The block that required to be designed.
- The design block may targets the Hardware.
- It is also called DUT(design under testblock).
- The stimulus block is not included in design requirement.
- It is implemented for only testing the design block.
- It may not be implemented as hardware, but software.
- It is commonly called 'testbench'.
- Intuitive for user with knowledge of digital logic design
- One-to-one correspondence between the logic circuit and Verilog
Note that the following gate types (called 'primitives') are defined in Verilog already. These can be instantiated without gate module definition. Note that the name of primitives does not need to be specified. (But recommend to specify in order to reduce ambiguity)
- AND/OR Gate type
- Multiple scalar input
- Single scalar output
- the first port -> output port
- other ports -> input ports
- BUF/NOT Gate type
- Single scalar input
- Multiple scalar output
- the last port -> input port
- other ports -> output ports
eg)
and a1 (OUT,IN1,IN2); // OUT = IN1 * IN2
nand (OUT,IN1,IN2,IN3); // OUT = ~(IN1 * IN2 * IN3)
buf b1 (OUT1,IN); // OUT1 = IN
not n1 (OUT1,OUT2,IN); // OUT1 = OUT2 = ~IN
Ideal gate may not have the transition delay, but practical does. Verilog simulate the gate delays as follows.
- Rise Delay: transition delay from 0 to 1
- Fall Delay: transition delay from 1 to 0
- Turn Off Delay: transition to high impedence 'Z'
Usage example
and #(5) a1 (out,i1,i2); // Delay time = 5
or #(3,4) o1 (out,i1,i2); // Rise Delay = 3, Fall Delay = 4
buf #(3,4,5) b1 (out,in); // Rise = 3, Fall = 4, Turn-off = 5
Also, delay time may not be consistant. Verilog implements the delay variation using multiple values as follows
variation: (<minimum_value>:<typical_value>:<maximum_value>)
Usage example
and #(3:4:5) a1 (out,i1,i2); // Delay time: min=3, typ=4, max=5
or #(2:3:4,3:4:5) o1 (out,i1,i2); // Rise Delay: min=2, typ=3, max=4
// Fall Delay: min=3, typ=4, max=5
Gate delay is commonly determined or measured by fabricator.
Dataflow modeling focuses on data flow between registers and how a design processes data rather than instantiation of individual gates.
- Logic Synthensis: create a gate-level circuit from a dataflow design description using EDA (Electronic Design Automation) tool.
- RTL Design: combination of dataflow modeling and behavioral modeling.
Dataflow modeling is done by 'continuous assignment' using keyword assign
.
assign
is used to drive a value onto a net such as : assign LHS=RHS;
Continuous assignment means that LHS(left-hand side) changes as soon as RHS(right-hand side) changes
Note that LHS must be 'assignable' variable and the value of LHS is driven continuously by RHS, which may be an expression. This fact gives a following constraint:
side | possible type |
---|---|
LHS | net or concatenation of net (either scalar or vector) |
RHS | expression consists of operator and operand (that is either registers or nets) |
Delay values can be specified by inserting #<delay_time>
after keyword assign
.
eg)
assign out=i1&i2; // dataflow modeling of and gate
assign #10 out=i1&i2; // and gate with delay of 10 time unit
assign addr[15:0]=addr1[15:0]^addr2[15:0]; // some address calculation using xor bitwise operation between addr1 and addr2
assign {cout,sum[3:0]}=a[3:0]+b[3:0]+cin; // dataflow modeling of 4 bit full adder.
- Can be any one of data types (
reg
,wire
,integer
,real
,time
) - may be restricted by operator (operator takes only certain types of operands)
Verilog has three types of operator.
- Unary: eg)
a=~b;
- Binary: eg)
a=b&&c;
- ternary: eg)
a=b?c:d;
Operator can be classified as various type as below
These binary operations take two operands
A=4'b0100; B=4'b0011;
wire[3:0] C;
assign C=A*B; // multiplication: C==4'b1100
assign C=A/B; // Division: C==4'b0001
assign C=A+B; // Addition: C==4'b0111
assign C=A-B; // Subtraction: C==4'b0001
assign C=A**B; // Power: overflow
assign C=A%B; // Modulus: C==4'b0001
Logical operators always evaluate to a 1-bit 0 or 1 or x.
Note that all the non-zero operand considered as logical 1.
A=3; B=0; D=2'b0x; E==2'b10;
wire C;
assign C=A&&B; // logical-and: C==0
assign C=A||B; // logical-or: C==1
assign C=!A; // logical-not: C==0
assign C=!B; // logical-not: C==1
assign C=D&&E; // C=(2'b0x)&&(2'b10): either 0 or 1 => C==X (don't care)
It works exactly same as C. Relational operators return a logical true 1 if the expression is true.
A=4; B=3;
X=4'b1010; Y=4'b1101; Z=4'b1xxx;
wire C;
assign C=A<=B; // C==0 (less than or equal)
assign C=A>B; // C==1 (greater than)
assign C=Y>=X; // C==1 (greater than or equal)
assign C=Y<Z; // C==x (less than)
logical equality ==
and logical inequality !=
returns logical evaluation result. It returns 'don't care' x
if result varies with x
in operand.
Case equality ===
and Case inequality !==
evaluates equality same as above, but it checks even casex and casez bits are identical or not and returns only 0 or 1.
A=4; B=3;
X=4'b1010; Y=4'b1101; Z=4'b1xxz; M=4'b1xxz; N=4'b1xxx;
wire C;
assign C=A==B; // C==0 (logical equality)
assign C=X!=Y; // C==1 (logical inequality)
assign C=X==z; // C==x (logical equality; result depends on don't care bits in Z)
assign C=Z===M; // C==1 (case equality; all bits match)
assign C=Z===N; // C==0 (case equality; least significant bit does not match)
assign C=M!==N; // C==1 (case inequality; least significant bit does not match)
Note that bitwise operators performs a bit-by-bit operation (bitwise logical operation) on two operands, and it returns same size of bits.
symbol | operation |
---|---|
~ | negation |
& | and |
| | or |
^ | xor |
xnor |
X=4'b1010; Y=4'b1101; Z=4'b10x1;
wire[3:0] W;
assign W=~X; // W==4'b0101 (negation)
assign W=X&Y; // W==4'b1000 (bitwise and)
assign W=X|Y; // W==4'b1111 (bitwise or)
assign W=X^Y; // W==4'b0111 (bitwise xor)
assign W=X~^Y; // W==4'b1000 (bitwise xnor)
assign W=X&Z; // W==4'b10x0 (bitwise and with x)
Reduction operator is unary operator. It performs a bitwise operation on a single vector operand and yield a 1bit result. Refer the example below.
symbol | operation |
---|---|
& | and |
~& | nand |
| | or |
~| | nor |
^ | xor |
xnor |
X=4'b1010;
wire Y;
assign Y=&X; // Y==1'b0 (equivalent to 1 & 0 & 1 & 0)
assign Y=~&X; // Y==1'b1 (equivalent to ~(1&0&1&0))
assign Y=|X; // Y==1'b1 (equivalent to 1 | 0 | 1 | 0)
assign Y=~|X; // Y==1'b0 (equivalent to ~(1|0|1|0))
assign Y=^X; // Y==1'b0 (equivalent to 1 ^ 0 ^ 1 ^ 0) even parity checker
assign Y=~^X; // Y==1'b1 (equivalent to ~(1^0^1^0)) odd parity checker
symbol | operation |
---|---|
>> | shift right logical |
<< | shift left logical |
>>> | shift right arithmetic |
<<< | shift left arithmetic |
Arithmetic shift may consider sign-extension. Thus sra may fill MSB with previous MSB while srl just fill with 0. Note that sll and sla may result same.
X=4'b1100;
wire[3:0] Y;
assign Y=X>>1; // Y==4'b0110 (shift right logical by 1)
assign Y=X<<1; // Y==4'b1000 (shift left logical by 1)
assign Y=X<<2; // Y==4'b0000 (shift left logical by 2)
assign Y=X>>>1; // Y==4'b1110 (shift right arithmetic by 1; MSB filled with 1 (sign-extended))
Concatenation operator appends multiple operator, and result an appended single vector (in order)
A=1'b1; B=2'b00; C=2'b10; D=3'b110;
assign Y={B,C}; // Y==4'b0010 (4'b00_10)
assign Y={A,B,C,D,3'b011}; // Y==11'b10010110001 (11'b1_00_10_110_001)
assign Y={A,B[0],C[1]}; // Y==3'b101 (3'b1_0_1)
Replication operator replicate the operands and concatenate as many as the specified number.
reg A;
reg[1:0] B,C;
reg[2:0] D;
A=1'b1; B=2'b00; C=2'b10; D=3'b110;
assign Y={4{A}}; // Y==4'b1111 (4'b1_1_1_1)
assign Y={4{A},2{B}}; // Y==8'b11110000 (8'b1_1_1_1_00_00)
assign Y={4{A},2{B},C}; // Y==11'b11110000110 (11'b1_1_1_1_00_00_110)
Conditional operator is also known as ternary operator.
Usage: <condition_expression>?<true_expression>:<false_expression>
The condition is evaluated first, then returns corresponding expression. Note that conditional operator can be nested as below.
assign out=(control==1'b1)?in1:in0; // 2-to-1 MUX
assign out=(control[1]==1'b1)?((control[0]==1'b1)?in3:in2):((control[0]==1'b1)?in1:in0); // 4-to-1 MUX
Behavioral Modeling can be done by two basic statement of procedure block: initial
and always
Multiple behavioral statements must be grouped in order to be used by initial
and always
.
It can be grouped by using keywords begin
and end
.
If #<delay_time>
is seen before a statement, then the statement is executed <delay_time>
time unit after the current simulation time.
initial
block starts at time 0 and executes only once during a simulation.
Multiple initial block start to execute concurrently at time 0, but finishes execution in various time.
always
block starts at time 0 and executes the statement continuously in a looping fashion.
Multiple always block starts to execute concurrently at time 0, and operates independently in a parallel manner.
always statement can be triggered by a particular event if always @ (<trigger_signal_list>)
keyword posedge
or negedge
can be used to make sensitive to transition edge.
eg)
module stimulus
reg x,y,clk;
initial
clk=1'b0;
initial begin
x=1'b0;
#5 y=1'b1;
end
always #10
clk=~clk;
always @ (posedge clk) begin
x=~x;
y=~y;
end
always @(*)
$display(x,y);
endmodule
The values should remain unchanged until another procedural assignment update the variable with a different value. (unlike dataflow modeling)
Thus left-hand side value must be reg
type in behavioral modeling, while wire
in dataflow modeling.
Blocking assignment statements are executed in the order they are specified in a sequential block.
Non-blocking assignment allow scheduling of assignments without blocking execution of the statements. In other words, non-blocking assignment statement in the block without waiting for the non-blocking statement to complete execution.
initial begin
A=4'h0; B=4'h0; C=4'h0; D=4'h0;
end
always @(posedge CLK) // B is ahead of A by 1
begin
A=A+1;
B=A+1; // executed after A=A+1; is done.
end
always @(posedge CLK) // D is the same as C
begin
C<=C+1;
D<=C+1; // executed concurrently with C<=C+1;
end
Similar with if statement in C.
if(<expression1>) <true_statement1>;
else if(<expression2>) <true_statement2>;
else if(<expression3>) <true_statement3>;
else <default_statement>;
Similar with switch-case statement in C.
Case statement is alternative of if-elseif-else statement in Verilog.
case(<expression1>)
<alternative1>: <statement1>;
<alternative2>: <statement2>;
<alternative3>: <statement3>;
default: <default_statement>;
endcase
keyword casex
allows all x and z values to be considered as don't care. (Only Non-x and Non-z positions in the case expression are compared.)
keyword casez
allows all z values to be considered as don't care.
reg[3:0] encoding;
reg next_state;
casex(encoding)
4'b1xxx: next_state=3;
4'bx1xx: next_state=2;
4'bxx1x: next_state=1;
4'bxxx1: next_state=0;
default: next_state=0;
endcase
Note that case statement is alternative representation of if statement in Verilog. If encoding==4'b0110, then next_state will be 2 (not 1) because case statement above will check 4'bx1xx prior than 4'bxx1x.
Usage: <file_handle> = $fopen("<filename>");
Usage: $fdisplay(<file_handle>,<arguments>);
Usage: $fclose(<file_handle>);
Initializing memeory from file: $readmemb
to read a file as binary / $readmemh
to read a file as hexadecimal
Usage: $readmemb("<file_name>",<mem_name>,<start_addr>,<end_addr>);
(<start_addr>
and <end_addr>
are optional)
eg)
module test;
reg[7:0] memory[0:7]; // 8 byte memeory
integer i;
reg CLK;
initial begin
CLK=1'b0;
$readmemb("init.dat",memory);
end
always #5
CLK=~CLK;
always @(posedge CLK)
$display("Memory[%0h]=%b",i,memory[i]);
endmodule