Saturday, April 18, 2020

Verilog Tutorial 5: Modules Instantiation

This is the fifth part of the Verilog Tutorials series. Click here for the first part.

Now we have a fair idea of writing a complete Verilog module from scratch, be it implementing a logic diagram or an FSM. We proceed to how to handle large designs with multiple modules.

It is not practical to have a complete design using just a single module.
For large designs, we may already have part of the design present in small modules. Then we can instantiate these modules and combine them into a single top level module.
Eg. In testbenches, we instantiate our design module in the testbench module and then provide stimulus to the input ports and check the outputs on the output ports.
Instantiation format:
<module name> #(PARAMETERS) <instance name> (.port1(signal1), .port2(signal2), .......) ;

Let us learn about instantiation using our same example, the Sequence Detector.
So my Verilog module will comprise of 2 sub-modules.
1. One is the actual Sequence Detector module.
2. Other is the D Flip-Flop module that we shall instantiate.
(Instead of coding the D Flip-Flop, we will instantiate a pre-defined DFF module)

Verilog Code after instantiating DFFs:
(Changes from old code have been mentioned in comments)

module seq_detector(clk, rst, X, Y);

parameter S0 = 2'b00;
parameter S1 = 2'b01;
parameter S2 = 2'b10;
parameter S3 = 2'b11;

input clk;
input rst;
input X;
output Y;

reg [1:0] next_state;                       
wire [1:0] state;       //reg state becomes wire
wire Y;

assign Y = state[1] & state[0];

DFlipFlop state_1 (.d(next_state[1]),.clk(clk),.rst(rst),.q(state[1]));  //instance 1
DFlipFlop state_0 (.d(next_state[0]),.clk(clk),.rst(rst),.q(state[0]));  //instance 2

always @ (*)
begin
case(state)
 S0:
 next_state = X ? S1 : state;
 S1:
 next_state = X ? S2 : S0;
 S2:
 next_state = X ? S3 : S0;
 S3:
 next_state = X ? S3 : S0;
 default:
 next_state = state;
endcase
end
endmodule

//D Flip-Flop Module
module DFlipFlop(d,clk,rst,q);
input d,clk,rst; 
output q;
reg q;
always @ (posedge clk or negedge rst)
begin
if(!rst)
q <= 1'b0;
else
q <= d;
end
endmodule

Conclusions on Instantiation:
1. Both modules can be present in the same Verilog file also.
2. Two DFlipFlop modules have been instantiated with instance names state_1 and state_0. (n-bit signal requires n DFF module instances)
3. Port names of the instance are given by dot ie., .clk and signal going into/out of the port is given within brackets (clk)
4. In instance_1, the signal next_state[1] goes to the DFlipFlop and output comes out as state[1]. Similarly for instance 2.

Note: The signal 'state' was earlier declared as reg as we modelled the Flip-flop in the same module. But now it becomes wire as the signal 'state' comes out from a separate module and it's value is fixed (cannot be modified in the seq_detector module).


Parameter
(Here we will see how to instantiate a module with parameters)
A parameter is a constant that is local to a module.
However its value can be changed during module instantiation or using defparam statements. 
An enhancement was added in the Verilog-2001 standard called the localparam. Its value cannot be changed during instantiation or using defparam statements. 

Let us look at the 3-bit up counter design.
Here we use 3-bits for the counter variable. However, to create an n-bit counter, we parametrize the number of bits so that the desired value can be given during instantiation of the counter module in the testbench.

Verilog code for n-bit counter:
module counter(cnt,clk,rst);

parameter BITS = 3;  //declare no. of bits as parameter

input clk,rst;
output [BITS-1:0]cnt; //change width 

reg [BITS-1:0]cnt;
wire [BITS-1:0]next_cnt;

assign next_cnt = cnt + 1'b1;  

always @ (posedge clk or negedge rst)   
begin
 if(!rst)
 begin
 cnt <= {BITS{1'b0}};
 end
 else
 begin
 cnt <= next_cnt;
 end
end

endmodule

Testbench:

module counter_tb;
 reg clk;
 reg rst;
 //wire [2:0] cnt;   

 counter #(.BITS(4)) inst_name //syntax
 (
  .cnt(cnt), 
  .clk(clk), 
  .rst(rst)
 );

   always #5 clk = ~clk;
 
 initial begin
   clk = 1'b0;
   rst = 1'b0;
   #20 rst = 1'b1;
   #500 $finish;
 end
      
endmodule

Note:
1. Parameter BITS can be changed in the testbench to any value. Here we have made it 4 in the testbench.
2. Note above the syntax for instantiation of module with parameters.
3. wire cnt has been removed in testbench as we do not know the number of bits of cnt. The
     parameter BITS is not accessible from outside the counter module.

Now let us move on to Verilog Tutorial 6 that deals with some constructs that we have not used till now.

No comments:

Post a Comment