Verilog Intro

Wires

wire input a,b;  
wire output y;  
wire input a2[1:0],b2[1:0];  
wire output y2[1:0];  
wire output y3[2:0];  

Assignment

An assign statement is used for modeling only combinational logic and it is executed continuously. So the assign statement is called 'continuous assignment statement' as there is no sensitive list (see always blocks later).

assign y = a;  

Logic bitwise primitives

Negation

assign y = ~a;  

AND Gate

assign y = a & b;  

OR Gate

assign y = a | b;  

Exclusive OR Gate

assign y = a ^ b;  

Reduction

assign y = | a2;  

is equivalent to:

assign y = a2[1] | a2[0];  

Concatenation and Replication

assign y2 = {a,b};  
assign y2 = {a,1'b0};  
assign y3 = {a,b,1'b1};  
assign y3 = {a,2'b10};  
assign y3 = {a,a2};  
assign y3 = {a,a2[0],1'b1};  
assign {y2,y} = {y3[1:0],a};  
assign y3 = {a,2{1'b1}};  

Shifting

// a         a >> 2    a >>> 2   a << 2    a << 3
// 01001111  00010011  00010011  00111100  01111000
// 11001111  00110011  11110011  00111100  01111000
assign y2 = a2 >> 1; // Logical 0's shifted in  
assign y2 = a2 >>> 1; // Arithemtic MSB sign bit shifted in  
assign y2 = a2 << 1; // Logical shift left same result as  
assign y2 = a2 <<< 1; // Arithmetic shift left  

Rotation

Rotate right 1 bit

assign y3r = {y3[0],y3[2:1]};  

Rotate right 2 bit

assign y3r = {y3[1:0],y3[2]};  

Operator precedence

!,~,+,-(uni),**,*,/,%,+,-(bin),>>,<<,>>>,<<<,==,!=,===,!==,&,^,|,&&,||,?: */

Conditionals

Tertiary

assign max = (a > b) ? a : b;  

If/Else

if(a < b)  
    assign min = a;
else  
    assign min = b;
if(boolean)  
    // if code
else if (boolean)  
    // if else 1 code
else  
    // else code
if(boolean)  
    begin
        // begin code
    end
else  
    begin
        // else code
    end

Synthesis of Z and X Values

Z values can only be synthesised by tristate bufferes and thus infer them
these have output enable inputs to control their output state for example here
is a single bit tristate buffer with an output enable

assign y = (oen) ? a : 1'bz;  

This sort of construuct is useful for biderectional ports or buses.

The synthesis of X is don't care, the value may be either 0 or 1, this can
improve the efficiency or optimisation of combinational circuits

assign y = (a == 2'b00) ? 1'b0:  
                     (a == 2'b01) ? 1'b1:
                     (a == 2'b10) ? 1'b1:
                     1'bx; // i == 2'b11

Behavioural Blocks

Procedural blocks using always block, these black box sections describe
behaviour using procedural statements, always behavioural blocks are defined
with an event control expression or sensitivity list

always @(sensitivity list)  
    begin [Optional label]
        [optional local variable declarations];

        [procedural statements];
    end [optional label]

Procedual Assignment

[variable] = [expression];  // blocking, assigned before next statement
                            // like normal C
[variable] <= [expression]; // non blocking, assigned at end of always
                            // block

Blocking tends to be used for combinational circuits, non-blocking for
sequential

In a procedural assignment, an expression can only be assigned to an output
with one of the variable data types, which are reg, integer, real, time, and
realtime. The reg data type is like the wire data type but used with a
procedural output. The integer data type represents a fixed-size (usually 32
bits) signed number in 2's-complement format. Since its size is fixed, we
usually don't use it in synthesis. The other data types are for modeling and
simulation and cannot be synthesized.

Registers

A register is simple memory wire to hold state, normally implemented as
D-Types

output reg  

Conditional Examples

binary encoder

en      a1      a2      y  
0       -       -       0000  
1       0       0       0001  
1       0       1       0010  
1       1       0       0100  
1       1       1       1000  
module pri_encoder  
    (
        input wire [3:0] r,
        output wire en
        output wire [1:0] y
    )

    always @*
        if(r[3])
            {en,y} = 3'b111;
        else if(r[2])
            {en,y} = 3'b110;
        else if(r[1])
            {en,y} = 3'b101;
        else if(r[0])
            {en,y} = 3'b100;
        else
            {en,y} = 3'b000;

endmodule  
module decoder_1  
    (
        input wire [1:0] a,
        input wire en,
        output reg [3:0] y
    )
    always @*
        if(~en)
            y = 4'b0000;
        else if(a == 2'b00)
            y = 4'b0001;
        else if(a == 2'b01)
            y = 4'b0010;
        else if(a == 2'b10)
            y = 4'b0100;
        else
            y = 4'b1000;

endmodule  

Case

module decoder_2  
    (
        input wire [1:0] a,
        input wire en,
        output reg [3:0] y
    )

    always @*
        case ({en,a})
            3'b000, 3'b001,3'b010,3'b011: y = 4'b0000;
            3'b100: y = 4'b0001;
            3'b101: y = 4'b0010;
            3'b110: y = 4'b0100;
            3'b111: y = 4'b1000;
        endcase // {en,a}

endmodule  
module decoder_3  
    (
        input wire [1:0] a,
        input wire en,
        output reg [3:0] y
    )

    always @*
        case ({en,a})
            3'b100: y = 4'b0001;
            3'b101: y = 4'b0010;
            3'b110: y = 4'b0100;
            3'b111: y = 4'b1000;
            default: y = 4'b0000;
        endcase // {en,a}

endmodule  

Casex

module decoder_4  
    (
        input wire [1:0] a,
        input wire en,
        output reg [3:0] y
    )

    always @*
        casex ({en,a})
            3'b0xx: y = 4'b0000;
            3'b100: y = 4'b0001;
            3'b101: y = 4'b0010;
            3'b110: y = 4'b0100;
            3'b111: y = 4'b1000;
        endcase // {en,a}

endmodule  

When the values in the item expressions are mutually exclusive (i.e., a value
appears in only one item expression), the statement is known as a parallel
case statement. When synthesized, a parallel case statement usually infers a
multiplexing routing network and a non-parallel case statement usually infers
a priority routing network. Unlike C where conditional constructs are executed
serially using branches and jumps, with HDL these are realised by routing
netowrks.

Casez

module decoder_4  
    (
        input wire [1:0] a,
        input wire en,
        output reg [3:0] y
    )

    always @*
        casez ({en,a})
            3'b0??: y = 4'b0000;
            3'b100: y = 4'b0001;
            3'b101: y = 4'b0010;
            3'b110: y = 4'b0100;
            3'b111: y = 4'b1000;
        endcase // {en,a}

endmodule  

In casez, the ? is used to indicate either X or Z state.

Tasks & Functions

Tasks and Functions are used when a set of operations are commonly repeated and used, this save you writing the same thing out over and over a gain. Functions can only be used for modelling combinational logic cannot drive more than one output and cannot contain delays, unlike tasks which can. Tasks also can not return a value unlike functions which can.

Below shows a function for calculating parity, something that may be used frequently in digital logic design.

function parity;  
    input [31:0] data;
    integer i;
    begin
        parity = 0;
        for (i= 0; i < 32; i = i + 1) begin
            parity = parity ^ data[i];
        end
    end
endfunction  

Common Errors

  • Variable assigned in multiple always blocks
  • Incomplete sensitivity list
  • Incomplete branch and incomplete output assignment

Multiple assignment

always @*  
    if(en) y = 1'b0;

always @*  
    y = a & b;

y is the output of two circuits which could be contridictary, this is not synthesiseable. Below is how this should have been writtten:

always @*  
    if(en)
        y = 1'b0;
    else
        y = a & b;

Incomplete sensitivity list

Incomplete sensitivity list (missing b). b could change but the y output
would not, causing unexpected behavior againg this is not synthesiseable.

always @(a)  
    y = a & b;
/* Fixed versions */
always @(a,b)  
    y = a & b;
/* or simple cure all */
always @*  
    y = a & b;

incomplete branch or output assignment

Incomplete branch or output assignment, do not infer state in combinational
circuits.

always @*  
    if(a > b)
        gt = 1'b1; // no eq assignment in branch
    else if(a == b)
        eq = 1'b1; // no gt assignment in branch
    // final else branch omiitted

Here we break both incomplete output assinment rules and branch According to
Verilog definition gt and eq keep their previous values when not assigned
which implies internal state, unintended latches are inferred, these sort of
issues cause endless hair pulling avoid such things. Here is how we could
correct this:

always @*  
    if(a > b)
        begin
            gt = 1'b1;
            eq = 1'b0;
        end
    else if (a == b)
        begin
            gt = 1'b0;
            eq = 1'b1;
        end
    else
        begin
            gt = 1'b0;
            eq = 1'b0;
        end

Or easier still assign default values to variables at the beginning of the
always block

always @*  
    begin
        gt = 1'b0;
        eq = 1'b0;
        if(a > b)
            gt = 1'b1;
        else if (a==b);
            eq = 1'b1;
    end

Similar errors can creep into case statements

case(a)  
    2'b00: y =1'b1;
    2'b10: y =1'b0;
    2'b11: y =1'b1;
endcase  

Here the case 2'b01 is not handled, is a has this value y gets it's previous
value and a latch is assumed, the solution is to include missing case, assign
y a value before the case or add a default clause.

case(a)  
    2'b00: y =1'b1;
    2'b10: y =1'b0;
    2'b11: y =1'b1;
    default : y = 1'b1;
endcase  

Adder with carry

module adder #(parameter N=4)  
    (
    input wire [N-1:0] a,b,
    output wire [N-1:0] sum,
    output wire cout
    );

    /* Constant Declaration */
    localparam N1 = N-1;

    /* Signal Declaration */
    wire [N:0] sum_ext;

    /* module body */
    assign sum_ext = {1'b0, a} + {1'b0, b};
    assign sum = sum_ext[N1:0];
    assign cout = sum_ext[N];

endmodule

module adder_example  
    (
        input wire [3:0] a4,b4,
        output wire [3:0] sum4,
        output wire c4
        )
    // Instantiate a 4 bit adder
    adder #(.N(4)) four_bit_adder (.a(a4), .b(b4), .sum(sum4), .cout(c4));

endmodule  

LocalParams

localparam N = 4