Pages

Thursday, 22 March 2012

Parameterized Modules and Function

Parametrized modules and function: goes a long way

Often functions are very important and using them will make parametrized generic code creation in HDL trivial. If you had ever wondered how to find the number of bits required to hold a count in a parametrized generic counter then this tutorial will be a nice read and resource for you.

Consider a scenario where you have designed a rigid counter that counts from 0 to 31 that is, mod 32 counter. For this counter 5 bits are enough to hold the count from 0 to 31 (number of bits=log2(count)).

You would write the code something like this:

//counter with synchronous reset:

module counter(

clk,

rst,

count

);

input clk,rst;

output [4:0] count; //now 4:0 is 5 bits to hold 32 counts //<-------change here
reg [4:0] count; //<-------change here

always @( posedge clk)

begin

if (rst)

count<=0;

else begin

if (count<31) //<-------change here

count<=count+1;

else

count<=0;

end

endmodule

//counter test bench:
module counter_tb();

reg clk,rst;
wire [31:0] count; //<----------
change here

counter cnt1(.clk(clk),

.rst(rst),
.count(count)
);

always #1 clk=~clk;

initial begin

clk=0; rst=0;

#2 rst=1;

#2 rst=0;
end

endmodule

Fair enough! What if you need a counter that can count to 100 and yet, later, after some days you want a counter that can count to 1000? This goes on and you will have to change each place where you have those constant values in the above example every time over and over again. In this particular example you will have to change at four places in the code (including the testbench) and will have to calculate the number of bits that can hold the count using a calculator.

To start with, it would have been better if you had thought to design a parametrized generic counter instead.

How would you do that? You need to make a function to find the log and use variables at the placed where constant are required. Let us see this with help of an example.

First of all create a function in a text file as given here and save the file as maths.fn:

function integer logb2;

input [31:0] Depth;

integer i;

begin

i = Depth;

for(logb2 = 0; i > 0; logb2 = logb2 + 1)

i = i >> 1;

end

endfunction

Now you have a text file maths.fn that contains the function that we are going to use

Let's create the parametrized counter module and its testbench as given here:

Try to look at it and understand:
module counter_parameterized(

clk,

rst,

count

);

//Note this change:

`include " maths.fn"

Parameter count_max = 32;

parameter count_width= logb2 (count_max);

input clk,rst;

output [count_width-1:0] count; //variable
reg
[count_width-1:0] count;

always @( posedge clk)

begin

if (rst)

count<=0;

else begin

if (count< count_max-1)

count<=count+1;

else

count<=0;

end

endmodule



Now, look at its testbench as well:

//counter test bench:
module counter__parameterized _tb();

parameter val=32 // <------change just here!!

reg clk,rst;
wire [val-1:0] count;

counter_parameterized #(
. count_max(val)
)
cnt1(.clk(clk),
.rst(rst),
.count(count)
);

always #1 clk=~clk;

initial begin

clk=0; rst=0;

#2 rst=1;

#2 rst=0;
end

endmodule


See? This way you have to change the code at just one place and that is, where the code has been instantiated ONLY!! Moreover, the effort of finding out the number of bits required for the counter has been saved. This little effort goes a long way in the long run and saves lots of effort as the code gets bigger.

NB. Make sure that the math.fn file that you created is in the root directory of the project you are working in and is added to the project.




No comments:

Post a Comment