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

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.

Related

Can the width of an input to a module be determined inside the module?

In SystemVerilog IEEE Std 1800-2017 page 328, the following example is shown :
module ram_model (address, write, chip_select, data);
parameter data_width = 8;
parameter ram_depth = 256;
localparam addr_width = clogb2(ram_depth);
input [addr_width - 1:0] address;
input write, chip_select;
inout [data_width - 1:0] data;
//define the clogb2 function
function integer clogb2 (input [31:0] value);
value = value - 1;
for (clogb2 = 0; value > 0; clogb2 = clogb2 + 1)
value = value >> 1;
endfunction
logic [data_width - 1:0] data_store[0:ram_depth - 1];
//the rest of the ram model
endmodule: ram_model
How does it make sense that the "address" input width determined by "addr_width" which is an output of a function inside the module?
That code is from section 13.4.3 Constant functions.
The key here is that clogb2 meets all the criteria of being a constant function.
As the Std states, constant function calls are evaluated at elaboration time. Since this happens before runtime, the returned value is treated as a constant.
Not all functions can be used this way.
Refer also to IEEE Std 1800-2017, section 23.10.4 Elaboration considerations, for further discussion on elaboration time.

what will be a good way to write 10bits decoder?

I am trying to write a 10 bits binary to thermal decoder.
For a 4 bits decoder, it is relative straightforward as shown below. However, for 10 bits, is there a smarter way to do it instead of write 1000 line code.
module decoder(in,out);
input [3:0] in;
output [15:0] out;
// input enable;
reg [15:0] out;
always #(in) begin
casez(in)
4'h1: out=16'b0000000000000001;
4'h2: out=16'b0000000000000011;
4'h3: out=16'b0000000000000111;
4'h4: out=16'b0000000000001111;
4'h5: out=16'b0000000000011111;
4'h6: out=16'b0000000000111111;
4'h7: out=16'b0000000001111111;
4'h8: out=16'b0000000011111111;
4'h9: out=16'b0000000111111111;
4'hA: out=16'b0000001111111111;
4'hB: out=16'b0000011111111111;
4'hC: out=16'b0000111111111111;
4'hD: out=16'b0001111111111111;
4'hE: out=16'b0011111111111111;
4'hF: out=16'b0111111111111111;
default: out=16'h0000;
endcase
end
endmodule
Yes, you could make this module fully parametrizable by using an unrollable for-loop. This loop would check for each bit of the out signal, if the loop-index is still smaller than the binary input signal.
The code would look like this:
module decoder #(
parameter IN_W = 10,
parameter OUT_W = 1 << IN_W
)
(
input [IN_W-1:0] in,
output reg [OUT_W-1:0] out
);
integer i;
always #* begin
// Use an unrollable loop.
for (i = 0; i < OUT_W; i++) begin
// (in < i) returns a 1-bit value
out[i] = (in < i);
end
end
endmodule
As you probably noticed, I also changed the way the ports are declared. In Verilog 2001—and also in more recent (System)Verilog versions—the port list and port declaration may be combined. This newer syntax, also known as ANSI-style, has the benefit that you don't need to add as much boilerplate code.

Verilog: Assigning a named generate loop's wire inside a for-loop

I am getting a syntax error that I do not understand. It seems Verilog is being picky about an index being a variable in some sense, but I'm not sure exactly what is going on here or how to get around it without hardcoding.
Here's my main module:
module mojo_top(
// 50MHz clock input
input clk,
// Input from reset button (active low)
input rst_n,
// cclk input from AVR, high when AVR is ready
input cclk,
// Outputs to the 8 onboard LEDs
output[7:0]led,
// AVR SPI connections
output spi_miso,
input spi_ss,
input spi_mosi,
input spi_sck,
// AVR ADC channel select
output [3:0] spi_channel,
// Serial connections
input avr_tx, // AVR Tx => FPGA Rx
output avr_rx, // AVR Rx => FPGA Tx
input avr_rx_busy // AVR Rx buffer full
);
// these signals should be high-z when not used
assign spi_miso = 1'bz;
assign avr_rx = 1'bz;
assign spi_channel = 4'bzzzz;
wire rst = ~rst_n; // make reset active high
genvar i;
generate
for (i=0; i<4; i=i+1) begin: clocks
wire clk_slow;
slow_clock #(.FREQ(2**i)) clk1 (
.clk(clk),
.rst(rst),
.clk_out(clk_slow)
);
assign led[i] = clk_slow;
end
endgenerate
always #(*) begin
for (k=0; k<4; k=k+1) begin
assign led[4+k] = clocks[k].clk_slow; // Why can't I do this?
end
end
endmodule
I'm generating 4 clocks (1Hz, 2Hz, 4Hz, and 8Hz).In the always block at the end, I have this line: led[4+k] = clocks[k].clk_slow; to try to assign these 4 clocks each to a different led (led[7:4]).
The error is complaining about the . after clocks[k]. I wondered if I'm not allowed to have a variable index on the right hand side, but when I put just led[4+k] = clocks[k], there is no syntax error (though it obviously will get a different error when I build it).
Why can I have led[4+k] = clocks[k] but not led[4+k] = clocks[k].clk_slow? Am I supposed to do this with a different syntax? Is it impossible to do it with a for-loop as I have here?
EDIT:
In case anyone is wondering, here's the specific error I'm getting. Again, it looks like it's just complaining that I did anything once I indexed the specific generate block I wanted.
Line 46, Column 24 : extraneous input '.' expecting {';', '[', '<=', '*', '+', '-', '?', '&', '|', '^', '~^', '^~', '/', '%', '==', '!=', '===', '!==', '&&', '||', '**', '<', '>', '>=', '>>', '<<', '>>>', '<<<'}
I should also mention that led[4+k] = clocks[0].clk_slow is okay. It lets me do led[4+k] = clocks[0].clk_slow, but not led[4+k] = clocks[k].clk_slow.
I should also mention that led[4+k] = clocks[0].clk_slow is okay. It lets me do led[4+k] = clocks[0].clk_slow, but not led[4+k] = clocks[k].clk_slow
clocks name used must be used with the constant variable and cannot be varying inside for loop. so clocks[0] works perfectly fine.
The generate block gets unrolled replacing 'k' with a literal digit. It similar to macro text expansion. You generate block gets expanded into
begin : clocks[0]
wire clock_slow;
assign led[0] = clocks[0].clock_slow;
end
begin : clocks[1]
wire clock_slow;
assign led[1] = clocks[1].clock_slow;
end
begin : clocks[2]
wire clock_slow;
assign led[2] = clocks[2].clock_slow;
end
...
Note the wire clock_slow does not become an array of wires. Instead, it becomes a set of named wires called clocks[0].clock_slow, clocks[1].clock_slow, ... that you can only access by specifying a with a constant index. That is because of an array of scopes in not like a regular array. Each instance can hold different types. For example:
genvar i;
for (i = 0; i < MAX_LIMIT; i++) begin: a
wire [i+1:0] clock_slow;
end
a[0].clock_slow is a 2-bit wire, a[1].clock_slow is a 3-bit wire. So referencing a[i].clock_slow does not compile. But you can use another generate block genvar to index into another generated block instance.
for example:
genvar k;
generate
for( k = 0; k < 4; k=k+1) begin
assign led [ 4 + k ] = clocks[k].clock_slow;
end
endgenerate
Also led is declared as a wire which doesn't hold a value. But you have used led in always block which stores the value. That will also give an error if you run in any other simulator.
Thanks, it was a good question.
You've assigned led[i] to the clk_slow, why can't you also assign led[i] to led[4+i]? Or even led[7:4] to led[3:0] outside the generate block (and ditch clk_slow, do .clk_out(led[i]))? Also, you can't connect wire type in always#(*), use assign.

How to "publish" a module property in 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

How to write a module with variable number of ports in Verilog

I would like to write a module with a variable number of inputs, i.e. depending on some parameter, the result would be:
module my_module #(LENGTH)(
input clk,
input rst_n,
input [LENGTH-1:0] data_1
);
//...
endmodule
or
module my_module #(LENGTH)(
input clk,
input rst_n,
input [LENGTH-1:0] data_1,
input [LENGTH-1:0] data_2,
input [LENGTH-1:0] data_3
);
//...
endmodule
Would it be possible to do this in Verilog or Systemverilog or would I have to write a script, let's say in Python, in order to generate the code for a specific module with fixed number of inputs? (it might be more than 1000 inputs)
There are no variable number of ports in SystemVerilog, but you could use a port that is a parameterized array.
module my_module #(int LENGTH, DEPTH)(
input clk,
input rst_n,
input [LENGTH-1:0] data[DEPTH]
);
//...
endmodule
Otherwise, you would need to use a script to generate the code.
Use a two dimensional input with a parameterized size. Added a generate for loop that can be used to set signals individually. Although many operations can be done with smart array operations.
module my_module #(SIZE, LENGTH)(
input clk,
input rst_n,
input [SIZE-1:0][LENGTH-1:0] data_in_array,
output [SIZE-1:0][LENGTH-1:0] data_out_array
);
genvar N;
generate for (N=0; N<SIZE; N++) begin :la_coolOps
//Do cool operations here. For example instantiate a module for every data_in
end
//...
endmodule
Edit:
As Mehran Torki points out: The syntax above will work for SystemVerilog only. Verilog does not allow for multiple packed arrays. Use input [LENGTH*SIZE-1:0] data_in_array.
I would add to these other answers that ports are just groupings of wires. While having 3, 1-bit wires named a, b, and c might be easier to read and understand, there is no physical/logical difference between a single, 3-bit wire abc, where abc[0] corresponds to a, abc[1] corresponds to b, and abc[2] corresponds to c.
So, you can always just expand or shrink a single (or multiple) signal(s) to get however many bits you need. It may not be as neat, but it will work. In the receiving module, you can then part-select the bus in whatever manner you like. So, you could have one really long wire the shrinks or expands (wire [(SOME_PARAM*8)-1:0] my_input_wire), or with SystemVerilog an array (wire [7:0] my_input_wire[0:SOME_PARAM-1])
If this is just testbench/verification code, the other thing you could do in SystemVerilog is use a dynamic array
As others said, there is no direct way to do this, but another workaround is to use SystemVerilog interfaces, where you define all the inputs that you want in the interface definition and inside the module only use the ones that correspond to the parameter. Below is a sample:
module my_module #(LENGTH)(
input clk;
input rst_n;
output o;
interface i_data;
);
logic outValue;
generate
case (LENGTH) //Based on the value of LENGTH, use corresponding data
1: outValue = i_data.data_1;
2: outValue = i_data.data_1 + i_data.data_2;
3: outValue = i_data.data_1 + i_data.data_2 + i_data.data_3;
endcase
endgenerate
always #(posedge clk) begin
if (~rst_n)
o <= '0;
else
begin
o <= outValue;
end
endmodule
You can still use a parameterized array for data and a for-generate loop if your outputs are similar.
With System verilog we can import a package instead of having parameterization and define types in the package to be used in the portlist.
module mymodule
import mymodule_pkg::*;
(
input portlist_t portlist
);
endmodule
And define multiple copies of the package with different variants of the port list and compile whichever version is required. eg
package mymodule_pkg;
localparam LENGTH=5;
typedef struct packed {
logic [LENGTH-1:0] data_1,
logic [LENGTH-1:0] data_2,
logic [LENGTH-1:0] data_3
} portlist_t;
endpackage
As with the interface solution there will be situations where you run into issues, like having different iterations of the module instantiated together.

Resources