Skip to content
Rain Hu's Workspace
Go back

[VHDL] HDLbits 2 - Verilog Language

Rain Hu

1. Getting Started
2. Verilog Language
3. Circuits
4. Verification: Reading Simulations
5. Verification: Writing Testbenches
6. CS450

2 Verilog Language

2.1 Basics

wire

module top_module( input in, output out);
    
    assign out = in;

endmodule

multi-in-out

module top_module( 
    input a,b,c, 
    output w,x,y,z );

    assign w = a;
    assign x = b;
    assign y = b;
    assign z = c;

endmodule

not gate

module top_module( input in, output out );

    assign out = ~in;

endmodule

and gate

module top_module( 
    input a,b,
    output out );

    assign out = a & b;

endmodule

nor gate

module top_module(
    input a,b,
    output out );

    assign out = ~(a|b);

endmodule

xnor gate

module top_module(
    input a, b,
    output out );

    assign out = ~(a^b);

endmodule

wire declaration

module top_module(
    input a,b,c,d,
    output out, out_n );

    wire w1, w2;
    assign w1 = a & b;
    assign w2 = c & d;
    assign out = w1 | w2;
    assign out_n = ~out;

endmodule

7458

module top_module(
    input p1a, p1b, p1c, p1d, p1e, p1f,
    output p1y,
    intput p2a, p2b, p2c, p2d,
    output p2y );

    wire w1a, w1b;
    wire w2a, w2b;

    assign w1a = p1a & p1b & p1c;
    assign w1b = p1d & p1e & p1f;
    assign p1y = w1a | w1b;
    assign w2a = p2a & p2b;
    assign w2b = p2c & p2d;
    assign p2y = w2a | w2b;

endmodule

2.2 Vectors

vector

module top_module (
    input wire [2:0] vec,
    output wire [2:0] outv,
    output wire o2,
    output wire o1,
    output wire o0  );

    assign outv = vec;
    assign o0 = vec[0];
    assign o1 = vec[1];
    assign o2 = vec[2];

endmodule

vector select

module top_module (
    input [15:0] in,
    output [7:0] out_hi,
    output [7:0] out_lo );

    assign out_hi = in[15:8];
    assign out_lo = in[7:0];

endmodule

vector swap

module top_module (
    input [31:0] in,
    output [31:0] out 
);
    assign out[31:24] = in[ 7: 0];
    assign out[23:16] = in[15: 8];
    assign out[15: 8] = in[23:16];
    assign out[ 7: 0] = in[31:24];

endmodule

vector gates

module top_module (
    input [2:0] a,
    input [2:0] b,
    output [2:0] out_or_bitwise,
    output out_or_logical,
    output [5:0] out_not
);

    assign out_or_bitwise = a | b;
    assign out_or_logical = a || b;
    assign out_not[2:0] = ~a;
    assign out_not[5:3] = ~b;

endmodule

gate-prefix vector

module top_module (
    input [3:0] in,
    output out_and,
    output out_or,
    output out_xor );

    assign out_and = & in;
    assign out_or = | in;
    assign out_xor = ^ in;

endmodule

vector concatenate

module top_module (
    input [4:0] a, b, c, d, e, f,
    output [7:0] w, x, y, z );

    assign {w, x, y, z} = {a, b, c, d, e, f, 2'b11};

endmodule

vector reverse

module top_module(
    input [7:0] in,
    output [7:0] out 
);

    assign {out[0], out[1], out[2], out[3], out[4], out[5], out[6], out[7]} = in

endmodule
module top_module(
    input [7:0] in,
    output [7:0] out 
);

    always @(*) begin
        for (int i=0; i<8; i++)
            out[i] = in[8-i-1];
    end

endmodule
module top_module(
    input [7:0] in,
    output [7:0] out 
);

	generate
		genvar i;
		for (i=0; i<8; i = i+1) begin: my_block_name
			assign out[i] = in[8-i-1];
		end
	endgenerate

endmodule

vector replication

module top_module (
    input [7:0] in,
    output [31:0] out );

    assign out = {{24{in[7]}}, in};

endmodule

vector replication2

module top_module (
    input a, b, c, d, e,
    output [24:0] out );

    assign out = ~{{5{a}}, {5{b}}, {5{c}}, {5{d}}, {5{e}}} ^ {5{a,b,c,d,e}};

endmodule

2.3 Modules: Hierarchy

By now, you’re familiar with a module, which is a circuit that interacts with its outside through input and output ports. Larger, more complex circuits are built by composing bigger modules out of smaller modules and other pieces (such as assign statements and always blocks) connected together. This forms a hierarchy, as modules can contain instances of other modules.

The figure below shows a very simple circuit with a sub-module. In this exercise, create one instance of module mod_a, then connect the module’s three pins (in1, in2, and out) to your top-level module’s three ports (wires a, b, and out). The module mod_a is provided for you — you must instantiate it.

When connecting modules, only the ports on the module are important. You do not need to know the code inside the module. The code for module mod_a looks like this:

module mod_a ( input in1, input in2, output out );
    // Module body
endmodule

The hierarchy of modules is created by instantiating one module inside another, as long as all of the modules used belong to the same project (so the compiler knows where to find the module). The code for one module is not written inside another module’s body (Code for different modules are not nested).

You may connect signals to the module by port name or port position. For extra practice, try both methods.

Connecting Signals to Module Ports
There are two commonly-used methods to connect a wire to a port: by position or by name.

By position
The syntax to connect wires to ports by position should be familiar, as it uses a C-like syntax. When instantiating a module, ports are connected left to right according to the module’s declaration. For example:

mod_a instance1 ( wa, wb, wc );

This instantiates a module of type mod_a and gives it an instance name of “instance1”, then connects signal wa (outside the new module) to the first port (in1) of the new module, wb to the second port (in2), and wc to the third port (out). One drawback of this syntax is that if the module’s port list changes, all instantiations of the module will also need to be found and changed to match the new module.

By name
Connecting signals to a module’s ports by name allows wires to remain correctly connected even if the port list changes. This syntax is more verbose, however.

mod_a instance2 ( .out(wc), .in1(wa), .in2(wb) );

The above line instantiates a module of type mod_a named “instance2”, then connects signal wa (outside the module) to the port named in1, wb to the port named in2, and wc to the port named out. Notice how the ordering of ports is irrelevant here because the connection will be made to the correct name, regardless of its position in the sub-module’s port list. Also notice the period immediately preceding the port name in this syntax.


module

module

module top_module ( input a, input b, output out );

    mod_a u_mod_a (
        .in1 (a),
        .in2 (b),
        .out (out)
    );
    
endmodule

module_pos

module top_module (
    input a, b, c, d,
    output out1, out2 );

    mod_a u_mod_a(out1, out2, a, b, c, d);

endmodule

module_name

module top_module ( 
    input a, 
    input b, 
    input c,
    input d,
    output out1,
    output out2
);
    
    mod_a u_mod_a(
        .out1 (out1),
        .out2 (out2),
        .in1  (a),
        .in2  (b),
        .in3  (c),
        .in4  (d)
    );

endmodule

module_shift

module top_module ( input clk, input d, output q );
    
    wire q1;
    wire q2;
    
    my_dff(clk, d, q1);
    my_dff(clk, q1, q2);
    my_dff(clk, q2, q);
	
endmodule

module_shift8

module top_module ( 
    input clk, 
    input [7:0] d, 
    input [1:0] sel, 
    output [7:0] q 
);
    wire [7:0] q1;
    wire [7:0] q2;
    wire [7:0] q3;
    my_dff8 (clk, d, q1);
    my_dff8 (clk, q1, q2);
    my_dff8 (clk, q2, q3);
    
    // multiplexer: mux9to1v
    always@(*) begin
        case(sel)
            2'd0: q = d;
            2'd1: q = q1;
            2'd2: q = q2;
            2'd3: q = q3;
        endcase
    end
    
endmodule

module_Half Adder

module top_module(
    input [31:0] a,
    input [31:0] b,
    output [31:0] sum
);
    wire [15:0] sum1;
    wire [15:0] sum2;
    wire cout1;
    wire cout2;

    add16 (a[15:0], b[15:0], 1'b0, sum1, cout1);
    add16 (a[31:16], b[31:16], cout1, sum2, cout2);
    
    assign sum = {sum2, sum1};
    
endmodule

module_Full Adder

module top_module (
    input [31:0] a,
    input [31:0] b,
    output [31:0] sum
);

    wire [15:0] sum1;
    wire [15:0] sum2;
    wire cout1;
    wire cout2;
    
    add16 (a[15:0], b[15:0], 1'b0, sum1, cout1);
    add16 (a[31:16], b[31:16], cout1, sum2, cout2);
    assign sum = {sum2, sum1};
    
endmodule

module add1 ( input a, input b, input cin,   output sum, output cout );
    assign sum = a ^ b ^ cin;
    assign cout = (a&b)|(b&cin)|(cin&a);
    // assign {cout, sum} = a + b + cin;
endmodule

module_Carry Select Adder

module top_module(
    input [31:0] a,
    input [31:0] b,
    output [31:0] sum
);
    
    wire sel;
    wire [15:0] wire0, wire1;
    add16 (a[15: 0], b[15: 0], 1'b0, sum[15:0], sel);
    add16 (a[31:16], b[31:16], 1'b0, wire0, );
    add16 (a[31:16], b[31:16], 1'b1, wire1, );
    
    // selector
    always@(*) begin
        case(sel)
            1'b0: sum[31:16] = wire0;
            1'b1: sum[31:16] = wire1;
        endcase
    end

    // ternary operator
    // assign sum[31:16] = sel ? wire1 : wire0;

endmodule

module_Adder-Subtractor

module top_module(
    input [31:0] a,
    input [31:0] b,
    input sub,
    output [31:0] sum
);
    wire cout;
    wire [31:0] bin;
    
    assign bin = {32{sub}} ^ b;
    
    add16 (a[15: 0], bin[15: 0], sub,  sum[15: 0], cout);
    add16 (a[31:16], bin[31:16], cout, sum[31:16],     );
    
endmodule

2.4 Procedures

Alwaysblock

module top_module(
    input a, 
    input b,
    output wire out_assign,
    output reg out_alwaysblock
);

	assign out_assign = a & b;
    
    always @(*) begin
    	out_alwaysblock = a & b;
    end
    
endmodule

Clocked

module top_module(
    input clk,
    input a,
    input b,
    output wire out_assign,
    output reg out_always_comb,
    output reg out_always_ff   );
    
    assign out_assign = a ^ b;
    always @(*) begin
    	out_always_comb = a ^ b;
    end
    always @(posedge clk) begin
		out_always_ff <= a ^ b;
    end
    
endmodule

If statement

always @(*) begin
    if (condition) begin
        out = x;
    end
    else begin
        out = y;
    end
end
module top_module(
    input a,
    input b,
    input sel_b1,
    input sel_b2,
    output wire out_assign,
    output reg out_always   ); 

    assign out_assign = sel_b1 & sel_b2 ? b : a;
    
    always @(*) begin
        if (sel_b1 & sel_b2) begin
        	out_always = b;
        end
        else begin
        	out_always = a;        
        end
    end

    // always @(*) begin
    //    case ({sel_b1, sel_b2})
	//		2'd0:begin
	//			out_always = a;
    //        end
    //        2'd1:begin
	//			out_always = a;                
    //        end
    //        2'd2:begin
	//			out_always = a;                
    //        end
    //        2'd3:begin
	//			out_always = b;                
    //        end
    //    endcase
    // end
    
endmodule

If statement latches

Demonstration

always @(*) begin
    if (cpu_overheated)
        shut_off_computer = 1;
end
always @(*) begin
    if (~arrived)
        keep_driving = ~gas_tank_empty;
end

always_if2

module top_module (
    input      cpu_overheated,
    output reg shut_off_computer,
    input      arrived,
    input      gas_tank_empty,
    output reg keep_driving  ); //

    always @(*) begin
        if (cpu_overheated)
            shut_off_computer = 1;
        else
            shut_off_computer = 0;
    end

    always @(*) begin
        if (~arrived)
            keep_driving = ~gas_tank_empty;
        else
            keep_driving = 0;
    end

endmodule

Case statement

always @(*) begin     // This is a combinational circuit
    case (in)
      1'b1: begin 
               out = 1'b1;  // begin-end if >1 statement
            end
      1'b0: out = 1'b0;
      default: out = 1'bx;
    endcase
end
// synthesis verilog_input_version verilog_2001
module top_module ( 
    input [2:0] sel, 
    input [3:0] data0,
    input [3:0] data1,
    input [3:0] data2,
    input [3:0] data3,
    input [3:0] data4,
    input [3:0] data5,
    output reg [3:0] out   );

    always @(*) begin
        case(sel)
            0: out = data0;
			1: out = data1;
            2: out = data2;
            3: out = data3;
            4: out = data4;
            5: out = data5;
            default: out = 0;
        endcase
    end

endmodule

Priority encoder

module top_module (
	input [3:0] in,
	output reg [1:0] pos
);

	always @(*) begin
		case (in)
			4'h0: pos = 2'h0;  //0000
			4'h1: pos = 2'h0;  //0001
			4'h2: pos = 2'h1;  //0010
			4'h3: pos = 2'h0;  //0011
			4'h4: pos = 2'h2;  //0100
			4'h5: pos = 2'h0;  //0101
			4'h6: pos = 2'h1;  //0110
			4'h7: pos = 2'h0;  //0111
			4'h8: pos = 2'h3;  //1000
			4'h9: pos = 2'h0;  //1001
			4'ha: pos = 2'h1;  //1010
			4'hb: pos = 2'h0;  //1011
			4'hc: pos = 2'h2;  //1100
			4'hd: pos = 2'h0;  //1101
			4'he: pos = 2'h1;  //1110
			4'hf: pos = 2'h0;  //1111
			default: pos = 2'b0;
		endcase
	end
endmodule

Priority encoder with casez

module top_module (
    input [7:0] in,
    output reg [2:0] pos  );

    always @(*) begin
        casez(in)
            8'bzzzzzzz1: pos = 3'd0;
            8'bzzzzzz10: pos = 3'd1;
            8'bzzzzz100: pos = 3'd2;
            8'bzzzz1000: pos = 3'd3;
            8'bzzz10000: pos = 3'd4;
            8'bzz100000: pos = 3'd5;
            8'bz1000000: pos = 3'd6;
            8'b10000000: pos = 3'd7;
            default: pos = 2'd0;
        endcase
    end
    
endmodule

Avoiding latches

always @(*) begin
    up = 1'b0; down = 1'b0; left = 1'b0; right = 1'b0;
    case (scancode)
        ... // Set to 1 as necessary.
    endcase
end
module top_module (
    input [15:0] scancode,
    output reg left,
    output reg down,
    output reg right,
    output reg up  ); 

    always @(*) begin
        left = 0;
        down = 0;
        right = 0;
        up = 0;
        case(scancode)
			16'he06b: left = 1;
			16'he072: down = 1;
			16'he074: right = 1;
			16'he075: up = 1;
        endcase
    end
endmodule

2.5 More Verilog Features

Conditional ternary operator

module top_module (
    input [7:0] a, b, c, d,
    output [7:0] min);//

    wire [7:0] wire1;
    wire [7:0] wire2;
    
    assign wire1 = a > b ? b : a;
    assign wire2 = c > d ? d : c;
    assign min = wire1 > wire2 ? wire2 : wire1;

endmodule

Reduction operators

& a[3:0]    // AND: a[3] & a[2] & a[1] & a[0]. Equivalent to (a[3:0] == 4'hf)
| b[3:0]    // OR: b[3] | b[2] | b[1] | b[0]. Equivalent to (b[3:0] != 4'h0)
^ c[2:0]    // XOR: c[2] ^ c[1] ^ c[0]
module top_module (
    input [7:0] in,
    output parity); 

    assign parity = ^ in;
    
endmodule

Reduction: Even wider gates

module top_module( 
    input [99:0] in,
    output out_and,
    output out_or,
    output out_xor );

    assign out_and = & in;
    assign out_or = | in;
    assign out_xor = ^ in;
    
endmodule

Combinational for-loop: Vector reversal

module top_module( 
    input [99:0] in,
    output [99:0] out
);

    always @(*) begin
        for (int i = 0; i < 100; i++) begin
            out[i] = in[99 - i];
        end
    end
    
endmodule

Combinational for-loop: 255-bit population count

module top_module( 
    input [254:0] in,
    output [7:0] out );

    always @(*) begin
        out = 0;
        for (int i = 0; i < 255; i++) begin
            out += in[i];
        end
    end
    
endmodule

Generate for-loop: 100-bit binary adder

module top_module( 
    input [99:0] a, b,
    input cin,
    output [99:0] cout,
    output [99:0] sum );

    always @(*) begin
        {cout[0], sum[0]} = a[0] + b[0] + cin;
        for (int i = 1; i < 100; i++) begin
            {cout[i], sum[i]} = a[i] + b[i] + cout[i-1];
        end
    end
    
endmodule

Generate for-loop: 100-digit BCD adder

module bcd_fadd (
    input [3:0] a,
    input [3:0] b,
    input     cin,
    output   cout,
    output [3:0] sum );
module top_module( 
    input [399:0] a, b,
    input cin,
    output cout,
    output [399:0] sum );

    wire[99:0] carryin;
    
    generate
        genvar i;
        bcd_fadd(a[3:0], b[3:0], cin, carryin[0], sum[3:0]);
        for (i = 4; i < 400; i += 4) begin:adder
            bcd_fadd(a[i+3:i], b[i+3:i], carryin[i/4-1], carryin[i/4], sum[i+3:i]);
        end
        assign cout = carryin[99];
    endgenerate    
endmodule

Share this post on:

Previous
[VHDL] HDLbits 3 - Circuits
Next
[TCAD] 模擬收斂問題