Instantiating a module:
- Module declarations are templates and their actual objects (instances) are created (instantiations) and they are actually instantiated.
- Instantiating all modules in the design is a must except the top level module which creates its own instance for simulation and synthesis.
- If the design is complex, the whole design is sub-divided into sub-blocks, and different modules are defined for those sub-blocks. Then all the sub-blocks are instantiated in the main/top module, and the top module is created automatically when we are synthesizing.
- Syntax: module_name instance_name ( port_connection_list );
Different styles of instantiating a module:
- SV Code Examples:
module adder (sum, d1, d2);
output logic [7:0] sum;
input logic [7:0] d1, d2;
//module functionality//
endmodule: adder
------------------------Instantiation of 'adder' module---------------------------
output logic [7:0] sum;
input logic [7:0] d1, d2;
//module functionality//
endmodule: adder
------------------------Instantiation of 'adder' module---------------------------
module alu(result, data1,data2,opcode);
output logic [16:0] result;
input logic [16:0] data1, data2;
input logic [1:0] opcode;
logic [7:0] tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
logic [7:0] sum1, sum2, sum3, sum4;
logic [7:0] sum, d1, d2;
adder add1 (sum1, tmp1, tmp2);
adder add2 (sum2, tmp3, tmp4);
adder add3 (.d1(tmp5), .sum(sum3), .d2(tmp6));
adder add4 (.*); //only instantiated once
adder add5 (.sum(sum4), .*); //since the above has already been instatiated, only for reference
// module functionality
endmodule: alu
- When instantiating, remember to connect the same signals with the same width in the instance.
- Don't connect two signals in two different instances of a module.
Parameterized Modules:
- Modules can use parameters internal to them and get their values while instantiating.
- Syntax: module_name #() instance_name (port_connection_list);
module memory (addr,data,cntl);
parameter ADDR_WIDTH = 8;
parameter DATA_WIDTH = 16;
input logic [ADDR_WIDTH - 1 :0] addr;
input logic [DATA_WIDTH - 1 :0] data;
input logic [5:0] cntl;
//Module funtionality
endmodule: memory
----------------instance------------------
module cpu_fun();
//variable declarations
//Instantiating memory
//No parameter values are given. Parameter gets their default values ADDR_WIDTH=8, DATA_WIDTH=16
memory mem1(.addr(a1), .data(d1), .cntl(c1));
//setting parameter values ADDR_WIDTH=12, DATA_WIDTH=24
memory #(12,24) mem2 (a1,d1,c1);
//Explicitly passing parameters. Setting parameter values as ADDR_WIDTH=16, DATAWIDTH=32
memory #(.ADDR_WIDTH(16), .DATA_WIDTH(32) )
mem2( .addr(a1), .data(d1), .cntl(c1) );
endmodule: cpu_fun
- This is a very useful and powerful way. The same module can be instantiated with different values.
Functions & Tasks: Examples
- Categorized into two types: Functions or a task
- Functions: Don't consume time. Very similar to a module.
- Tasks: Consume time. They aren't synthesizable for RTL design. Very useful in creating Testbenches but we will never use them in design/synthesis coding.
Function definition with an example:
function logic [31:0] find_sum (input logic [31:0] a, b);
logic [31:0] temp;
temp = a+b;
return temp;
endfunction: find_sum
---------------------------
function logic [31:0] find_sum (input logic [31:0] a,b);
find_sum = a+b;
endfunction: find_sum
Task function: Not used for synthesizable RTL design - task task_name(followed by the argument list);
task my_task(input logic [31:0] a,b,output int x );
//Description
endtask: my_task
Comments
Post a Comment