How to "publish" a module property in Verilog? - verilog

Verilog beginner's question: Is there a way a module can publish its static/constant property such as width of the address bus slice or number of internal registers? It it not a parameter, rather information inherent to the module being instantiated. Neither it is module output data.
Something like the (improper) .addr( addr[amod.AMOD_ADDR_W-1:0] ) below
module top_mod #(parameter ADDR_W = 32)
(input [ADDR_W-1:0] addr);
amod amod( .addr( addr[amod.AMOD_ADDR_W-1:0] ) );
endmodule
// ---
module amod(
input [AMOD_ADDR_W-1:0] addr
);
// AMOD_ADDR_W is amod's intrinsic property
localparam AMOD_ADDR_W = 2;
endmodule
Global defines don't seem the way to go to me.
I'd also appreciate links to some useful Verilog coding hints.
Thank you.

Verilog's elaboration process prevents parameter values from flowing up the hierarchy. In this case, there is no need to match the port width; Verilog will truncate or pad the connection as needed. So there is no need for you to do this.
In SystemVerilog, a package is the way to share parameter values between modules.
package amod_pkg;
parameter ADDR_W=2;
endpackage
module amod import amod_pkg::*; (
input [ADDR_W-1:0] addr
);
// ADDR_W is amod's intrinsic property
endmodule
// ---
module top_mod #(parameter ADDR_W = 32)
(input [ADDR_W-1:0] addr);
amod amod( .addr( addr[amod_pkg::ADDR_W-1:0] ) );
endmodule

Related

Verilog [dot] meaning?

What does this " .depth_log2(7) " and .i_wclk mean in Verilog code?
asynch_fifo #(.depth_log2(7),
.data_width(22),
.rd_flop1_megedge(1'b1),
) USB2_ASYNCH_FIFO (
.i_wclk(i_usb2_sieclockin_ip),
);
I'm not able to understand what that .depth_log2 and .rd_flop1_megedge means
When you instantiate a module, such module might have some parameters. You can leave them at default, or you can initialize them at the values you prefer. In your example you are setting the depth at 7, the data width at 22 etc..
In general, if you have a verilog module like this:
module my_module
#( parameter P1 = 2,
parameter P2 = 0)
( input clk,
output reg [P1-1:0] out);
// Module logic
endmodule
You can instantiate it with the dot notation
wire wire_clk;
wire [2-1:0] wire_out;
my_module #(.P1(2),
.P2(3) ) u0
( .clk(wire_clk),
.out(wire_out);
This is called instantiation. Using this "." notation you are basically saying that you want to connect a constant 7 to depth_log2 parameter of your component asynch_fifo.

How to pass a parameter in such scenario

Say tp0 is the lowest hierarchy, all real code omitted just leave a parameter
module tp0;
parameter num=0;
endmodule
Where it is instanced
module tp
(
input id
);
//what I want to do is below code, but this will not pass compile since parameter need this is a constant!
tp0 #(id) tp_i();
endmodule
id is an input but this is actually be assign as fixed value in tp's instance.
module tb
.....
tp tp_0
(
.id(0)
);
tp tp_1
(
.id(1)
);
....
endmodule
How to resolve this if the pass of id is such a way and need to be passed into a parameterized module tp0?
Thanks
Verilog is a RTL language, which means that you are describing hardware that will be eventually synthesized.
When you use a parametrized instance, the parameter is analyzed at compile time and that affects how in synthesis the code will be transformed. The parameter NUM (capital letters suggested for params) usually refers to number of bits or instances, thus it needs to be known to calculate for example how many flip-flops should be instanced.
An input is something that dynamically changes while the application is running (ASIC or FPGA), thus it cannot be defined at compile time by connecting it to a parameter.
In your case, the best solution is to add a parameter also to tp module and then connect it to tp0.NUM, but it is not clear from this example what is your target or if this code is for simulation only (various quick alternatives) or if needs to be synthesized.
An elaborate alternative might be that in tp module you instance two submodules with each value of the parameter (0 and 1) and then mux the outputs depending on the value of id.
module tb();
tp tp0 (.id('0));
tp tp1 (.id('1));
endmodule
module tp(
input logic id
);
logic out0, out1, out_f;
tp_sub #(0) tp_0(.out(out0));
tp_sub #(1) tp_1(.out(out1));
always_comb begin
if (id) begin
out_f = out1;
//or other things
end
else begin
out_f = out0;
//or other things
end
end
endmodule

Masking input unpacked array

I want to "mask" an input unpacked array given a specific signal. If that signal is 1, I want the input to be all zeroes instead of the given array.
module thing (
input clk,
input rst,
input packedBits[`PB_SIZE]
);
// ...
endmodule
module top (
input clk,
input rst
);
logic packedBits[`PB_SIZE];
mod_i thing (
.clk(clk),
.rst(rst),
// I can manually put `PB_SIZE zeroes, but I want the compiler to do it for me
.packedBits(rst ? {0,...,0} : packedBits)
)
endmodule
Putting just {0,0,0,0} when `PB_SIZE is 4 works, but how could I do it in a more generic way?
You can use the replication operator:
.packedBits(rst ? '{`PB_SIZE{0}} : packedBits)
Refer to IEEE Std 1800-2017, section 5.11 Array literals.
Here is a complete example on EDA playground. It runs on Cadence and Synopsys, but there are errors on Mentor. It seems Mentor does not support this syntax yet.
Simulators sometimes struggle with complex expressions connected to module ports. It is usually a good idea to simplify the connection using a separate signal.
`define PB_SIZE 5
module thing (input packedBits [`PB_SIZE]);
initial #1 $display("%m %p", packedBits);
endmodule
module tb;
bit rst = 1;
logic packedBits [`PB_SIZE];
logic packedBitsGated [`PB_SIZE] = rst ? '{`PB_SIZE{0}} : packedBits;
thing mod_i (.packedBits(packedBitsGated));
initial begin
packedBits = '{`PB_SIZE{1}};
#1 $display("%m %p", packedBits);
end
endmodule
This works on all 3 simulators on EDA playground.
You can use a default in an assignment patterns. Then there is no need to know its size.
.packedBits(rst ? '{default:0} : packedBits)

When should I put the "dot" while instantiating a module?

In the example, there is an error when I put a dot as shown in "enc_en", is there anything wrong with my implementation?
module some_top_module();
....
logic [NOF_PORTS-1:0] wr_en_vec;
logic [NOF_PORTS-1:0] rd_en_vec;
logic enc_en;
encoder #(.IN_W(ADDR_WIDTH)) enc(avalon_aligned_if.slave.ext, .enc_en, .wr_en_vec);
...
endmodule
module encoder #(parameter IN_W = 2)(enc_in, enc_en, enc_out);
function integer expb2 (input [31:0] value);
for (expb2 = 1; value > 0; expb2 = expb2 << 1) begin
value = value -1;
end
endfunction
localparam OUT_W = expb2(IN_W);
input logic [IN_W-1:0] enc_in;
input logic enc_en;
output logic [OUT_W-1:0] enc_out;
...
...
endmodule
Your syntax is illegal. VCS produces a helpful error:
The two types of module port connections, by ordered list and by name, shall
not be mixed.
Without a leading ., you are using ordered port list, and with the leading ., you're using port list by name.
encoder #(.IN_W(ADDR_WIDTH)) enc(avalon_aligned_if.slave.ext, .enc_en, .wr_en_vec);
// by-order by-name
Refer to IEEE Std 1800-2017, section 23.3.2 Module instantiation syntax.

Declare vector ports without specifying their size in Verilog

When declaring a module in Verilog (2001?), is it possible to tell that some ports are vectors without indicating their size? The goal here is to handle vector ports of any size, without having to specify the sizes through parameters.
I know I can write something like what follows in Verilog, but I'd like to know if there's a way to get rid of the extra WIDTH_DATA parameter:
module my_module
#(
parameter WIDTH_DATA = 48
)
(
input Clk, En,
input [WIDTH_DATA-1:0] Data_in,
output Ready,
output reg [WIDTH_DATA-1:0] Data_out
);
This is possible in VHDL, using a declaration like that:
entity my_module is
port (
Clk : in std_ulogic;
En : in std_ulogic;
Data_in : in std_ulogic_vector;
Ready : out std_ulogic;
Data_out : out std_ulogic_vector
);
end entity;
The module implementation can then know the size of Data_in at compile time using Data_in'length (same for Data_out).
This is not possible in Verilog.
You can do something close to what you want in SystemVerilog using the interface construct. You can parameterize an interface, and connect that interface (or set of interfaces) to my_module.
interface my_intf #(int WIDTH);
logic [WIDTH-1:0] data;
endinterface
module my_module(input clk, en,
my_intf in, out,
output ready);
// $bits(in.data) - gives you the WIDTH
// typedef type(out.data) out_type // local typedef
endmodule
module top;
my_intf #(8) I1;
my_intf #(16) I2;
bit clk, en, ready;
my_module M1 (.clk,.en, .in(I1), .out(I2), .ready);
endmodule

Resources