Hardware Description

Languages : Verilog

David Nguyen, Duy-Ky Nguyen, PhD

1. Introduction

VHDL was first created by DOD contractors IBM, Texas Intruments and Intermetrics to document a large discrete digital project in 1980. Verilog was created by an engineer named Phil Moorby at a CAE company called Gateway Design Automation to verify a large discrete digital projects in 1981.

VHDL is a Pascal/Ada-like language (case insensitive) while Verilog is C-like language (case sensitive).

VHDL is more programming language than Verilog as it has many data types for signal and variable. Verilog is better to describe hardware and 2 basic data types, 1 for combinatory digital (memory-less like gate, decoder, mux, ...) and 1 for sequential digital (memory like flip-flop). It has only signal, not variable (signal is also variable, anyway).

A Verilog Quick Reference CHM file

Remark

There have been a serious mistake published in HDL books saying the order of sequential statements are important. The reason could be the authors may be confused between regular meaning of sequential where one after another and its digital meaning where clock action.

The Verilog is below where keywords are in bold.

module Ent_Name (
	I,
	O,
	IO
);

input		I;
output	[3:0]	O;	// vector
inout	[7:0]	IO;

-- module body

endmodule

2. Combinatory Digital

2.1. Gates

INV O = ~ I;
AND2 O = I0 & I1;
AND2B1 O = (~ I0) & I1;
OR2 O = I0 | I1;
NAND2 O = ~ (I0 & I1);
XOR O = I0 ^ I1;
BUFE O = E ? I : 1`bZ; // 1`b: 1-bit binary, conditional statement

In Verilog, combinatory digital uses `=` while sequential uses <=.

2.2. Decoder

Below is an implementation for D2_4E (2-bit select, 4-bit output with Enable).

If we have vector interfaces, say S_2x and O_4x, then

O_4x =  (~E) ? 0
	  :	 (S_2x==0) ? 1
 	  :	 (S_2x==1) ? 2
 	  :	 (S_2x==2) ? 4
 	  :	 8;

It`s far more convenient to deal with bits in Verilog than VHDL by using concatenation operator {}.

{D3, D2, D1, D0} =  (~E) ? 0
	  :	 ({S1, S0}==0) ? 1
 	  :	 ({S1, S0}==1) ? 2
 	  :	 ({S1, S0}==2) ? 4
 	  :	 8;

2.3. Mux

Below is an implementation for M4_1E (2-bit select, 4-bit input with Enable)

O <= 	(~E) ? `Z`			// Tri-state
	:	(S_2x==0) ? D0
	:	(S_2x==1) ? D1
	:	(S_2x==2) ? D2
	:	D3;

If we have bitwise select, we use the same method for decoder above.

2.4. Adder

For 4-bit adder, we have

O_4x <= A_4x + B_4x;

3. Sequential Digital

3.1. Flip-Flop

For the simplest D-FF, FD in Xilinx, we have

always @ (posedge C )	// equiv process in VHDL
		Q <= D;

Or for falling edge trigger, FD_1, we have

always @ (negedge C )
		Q <= D;

If async clr required, FDC, we have


always @ ( posedge C or posedge CLR )
	if (CLR)
		Q <= 0;
	else
		Q <= D;

If clk enable required, FDCE, we have

always @ ( posedge C or posedge CLR )
	if (CLR)
		Q <= 0;
	else if (E)
		Q <= D;

Note that always has a sensitive list that trigger its action, like @ ( posedge C ) or @ ( posedge C or posedge CLR) above;

3.2. Shifter

For a 8-bit left shifter S with 1-bit input I clocked by C, we have

always @(posedge C)
	O <= {S[7:1], I};	// uses concat op { }

3.3. Counter

If we need a 10-counter, then

always @ ( posedge C or posedge RST ) begin
	if (RST)
		Q <= 0;
	else
		Q <= (Q==9) ? 0 : (Q + 1);

4. Language

Verilog has only one 2 data types of 1-bit size wire for combinatory digital and reg for sequential digital. It best represents the digital nature. It follows closely C style, like type before signal, index with [ : ]

wire 		sig_bit;	// 1-bit combinatory signal
reg [7:0]	sig_vec;	// 8-bit sequential signal

Signal uses `=` for combinatory and `<=` for sequential assignments, like

Sig_a = sig_b;	-- comb` signals
Sig_c <= sig_d;	-- seq` signals

Signal has value 0, 1 and Z for tri-state. 3-bitvector has value 3`b0 (binary) or 3`h0 (hex) or 3`d0 (decimal). The bit size can even be dropped like `b0, `h0 or `d0.

Verilog follows C style, like signal after type, operators, original function convention, like

Int	add (x, y);
Int	x;
Int	y;
{
	return x+y;
}

4.1. Structure

Verilog object has 2 parts

  1. Declaration: module header with IO list;
  2. Implementation: architecture with signal and variable declarations, with concurrent and sequential assignments (within process);

Verilog block statement is several single statements (concurrent or sequential) embedded between begin - end.

module Name (
	I,
	O,
	IO
);

input 	I;
output	O;
inout	IO;

	// signal declarations
	// concurrent assignments

	always @ (sensitive_list)
		-- sequential assignments (begin  -  end)

endmodule

4.2. Relational Operators: ==(equal) !=(unequal) < (less than) > (greater than)

Relational operators result in 1-bit value where TRUE for non-zero and FALSE for zero value.

For example,

X <= (a==b);	// 1 if a equal to b, else 0

4.3. Logical Operators: ~ ! & `&&` | `||` ^

The 3 operators ! (logical not), &&(logical and) and || (logical or) are for 1-bit boolean logical (with relational operators), while ~(bit-wise inv), & (bit-wize and) and | (bit-wise or) and bit-wise logical (digital circuitry)

X_bool <= (a = b) && !(c = d);		// boolean

X_4x <= A_4x & ~B_8x[3:0];			// bit-wise

4.4. Concatenation Operator { }

Concatenation combines many values into a composite value, regardless sizes. It`s equivalent to both concatenation and aggregate in VHDL.

X_4x <= {x, x_2, x_1, x_0};	// combine 4 bits into 4-bit vector

Or even

X_4x <= {x_3, x_vec[2:0]};		// OK to combine 1 bit and 1 vector !!!

4.5. Replication Operator { { } }

X_16x <= {4{x_4x}};		// Make 16-bit vector from 4-bit ones

4.6. Conditional Statements ? :

X <= condition_1 ? value_1 : condition_2 ? value_2 : value_3;

It can be used in any statement (concurrent or sequential).

4.7. IF Statements

if (condition_1)
	Statement_1;
else if (condition_2)
	Statement_2;
else
	Statement_3;

4.8. CASE Statements

case (expression) is
	value_1 		: statement_1;
	value_2, value3 	: Statement_2;
	default 		: Statement_3;
endcase

4.9. ALWAYS Statement

always @(sensitive_list) // or may be used
		-- sequential assignment

Remark

or must be used in sensitive list, and this is the only case it is used.

Any concurrent statement can be put into always statement whose sensitive list includes all inputs;

The simple concurrent assignment below

a = b;

can be written as

always @ (b)
	a = b;

Or a mux

O = (~E) ? `Z` : (S_2x==0) ? D0 : (S_2==1) ? D1 : (S_2x==2) ? D2 : D3;

can be written as

always ({D3, D2, D1, D0} or S_2x or E)
	O = (~E) ? `Z` : (S_2x==0) ? D0 : (S_2==1) ? D1 : (S_2x==2) ? D2 : D3;

Remark

We will not use always statement for concurrent assignments for clarity and sake of debugging.

4.10. Function

Function must execute in zero time and return only one signal for computational purpose. It therefore does not have timing process statement.

function func_name;
-- input list as arguments
begin
-- function body
end
endfunction

For example,

function [3:0] Decoder;
input	E;
input	[1:0]	S;
begin
Decoder =  (~E) ? 0 : (S_2x==0) ? 1 : (S_2x==1) ? 2 : (S_2x==2) ? 4 : 8;
End
endfunction

4.11. Task

In contrast to function, task can return zero or many signals using IO list for modularisation purpose. It may include timing always statements.

task task_name;
-- IO list
begin
-- procedure body
end
endtask

For example,

task ALU;
	input	[7:0]	A, B;
	input	[1:0]	OP;
	output	[7:0]	Z;
	out 		EQ, LT
begin
case OP
	0 : Z = A + B;	// add
	1 : Z = A - B;	// sub
	2 : EQ = (A == B);
	3 : LT = (A < B);
end case;
endtask;

4.12. Instantiation

To instantiate a module module_name, we have

module_name module_name_i (
	.module_if_1(sig_1),	// interface signal 1
	.module _if_2(sig_2),
	.module _if_3(sig_3)
);

4.13. Simulation Memory Model

module spram_5x8 (
	addr,
	din,
	we,
	clk,
	en,
	dout);

input	[4:0]	addr;
input	[7:0]	din;
input		we,
input		clk;
input		en;
output	[7:0]	dout;

reg	[7:0]	MW, RAMa [0:31;

	always @ (posedge clk) begin
		if (we) begin
			RAMa[addr] <= din;
			MW <= din;
		end;
		dout <= RAMa[addr];
	end if;

end

endmodule

4.14. Test Bench

Below is a complete Verilog code for a counter

module cntr (reset_n, clk,	q);

input    	reset_n, clk;
output	[3:0]	q;

reg	[3:0]	q;

always	@(negedge reset_n or posedge clk)
	if (~reset_n) 	q <= 0;
	else		q <= (q==9) ? 0 : (q + 1);

endmodule

Remark

Unlike VHDL, Verilog Output q can be read too.

Below is test bench for counter above

`timescale	1ns/1ps

module cntr_t;	//();

reg	clk, reset_n;

wire[3:0]	q;

cntr cntr_0 (
	.clk(clk),
	.reset_n(reset_n),
	.q(q));

always #50 clk <= ~clk;	// generate clk

initial begin
	clk = 0;
	reset_n = 0;	#200;	reset_n = 1;	// generate reset
end

endmodule