How to create decimal array parameter with width set by another parameter? - verilog

My module has a configurable width input of signals sensor_line[WIDTH-1:0] where WIDTH is parameter.
For each sensor_line I have a recorder module instantiated with a generate block in a for loop.
I need to pass a decimal number parameter to this recorder which is different for each sensor_line.
I need to create some decimal array parameter to give to my module in the top, which it’s width will be aligned with the WIDTH parameter. I don’t mind if I need to match the given array size myself as long as I can do it from the top when instantiating my module.
Looking for a solution, I found only for passing an array of bits (binary value).
For example, to pass 5 bits for each sensor_line, a code like this can be used:
module my_module #(
parameter WIDTH = 4, // number of input lines
parameter [4:0] CYCELS [WIDTH-1:0] = '{ WIDTH{5'b0}}
)
(
Input clk;
input [WIDTH-1:0] sensor_line;
…
);
logic [WIDTH-1:0] sensor_line_out;
…
genvar i;
generate
for (i=0; i< WIDTH; i=i+1) begin : sensor_sync
recorder #(
. CYCELS(CYCELS [(i+1)*5:i*5])
)
recorder_instance(
.in(sensor_line[i]),
.out(sensor_line_out[i]),
.clk(clk),
…
);
end
endgenerate
…
endmodule
How can I pass decimal values to the recorder module, not bits like in the example, like passing integer array in C and then point to the array at index [i] and at the end instance my module like this:
my_module #(
.WIDTH(4), // number of input lines
.CYCELS([2,3,5,4])
) my_module_1 (
...
)
my_module #(
.WIDTH(3), // number of input lines
.CYCELS([3,2,2])
) my_module_2 (
...
)

The syntax you used to pass an array of decimal values is incorrect. For example, change:
.CYCELS([2,3,5,4])
to:
.CYCELS('{2,3,5,4}) // an assignment pattern
or
.CYCELS({2,3,5,4}) // an unpacked array concatenation
Here is actual code that compiles:
module my_module #(
parameter WIDTH = 4, // number of input lines
parameter [4:0] CYCELS [WIDTH-1:0] = '{default:'0}
);
for (genvar i=0; i< WIDTH; i++) begin : sensor_sync
initial $display("%m CYCELS[%0d]=%0d", i, CYCELS[i]);
end
endmodule
module top;
my_module #(
.WIDTH(4), // number of input lines
.CYCELS('{2,3,5,4})
) my_module_1 (
);
my_module #(
.WIDTH(3), // number of input lines
.CYCELS('{3,2,2})
) my_module_2 (
);
endmodule
Output:
top.my_module_1.sensor_sync[0] CYCELS[0]=4
top.my_module_1.sensor_sync[1] CYCELS[1]=5
top.my_module_1.sensor_sync[2] CYCELS[2]=3
top.my_module_1.sensor_sync[3] CYCELS[3]=2
top.my_module_2.sensor_sync[0] CYCELS[0]=2
top.my_module_2.sensor_sync[1] CYCELS[1]=2
top.my_module_2.sensor_sync[2] CYCELS[2]=3

Related

Expression width 32 does not match width 1 of logic gate array port 1

I have two questions.
No output
Expression width 32 does not match width 1 of logic gate array port 1.
When I write and( OutAnd, a, b);, it shows an error.
Expression width 32 does not match width 1 of logic gate array port 1.
How can I fix it?
By the way. I forbid to use & operator, Procedure Assignment, and always block.
Here's my code:
ALU.v
module ALU(
input [5:0] Signal,
input [31:0] a, b,
output reg[31:0] Output
);
wire[31:0] OutAnd;
and( OutAnd, a, b); // AND <-- error
AluMux alumax0( .Signal(Signal), .in_And( OutAnd ) ); // AND
endmodule
AluMax.v
module AluMux(
input [5:0] Signal,
input [31:0] in_And, in_Or,
output reg[31:0] Output
);
parameter AND = 6'd36;
always # ( * )
begin
case ( Signal )
AND : Output = in_And;
default : Output = 32'd11;
endcase
end
endmodule
The output of the and gate defined to be 1 bit and you want to put 32 bits in it which may cause an error or a warning to solve this you have 2 way either instantiate 32 and gates with the following syntax
and u1 (OutAnd[0], a[0], b[0]);
and u1 (OutAnd[1], a[1], b[1]);
and u1 (OutAnd[2], a[2], b[2]);
.
.
.
and u1 (OutAnd[31], a[31], b[31]);
or use a generate statement here is a sample code
genvar i;
generate
for(i = 0;i < 32;i = i + 1) begin
and u1(OutAnd[i], a[i], b[i]);
end
endgenerate

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.

Calculating a parameter in a loop generate block

I have an array of parameters WIDTHS, and I need to calculate another parameter RIGHT based on some values in WIDTHS in a generate block. Is this possible? If not, is there an alternative way?
Here is an example of what I am trying to do. Suppose we have a predefined register module REG which has inputs d, q, we (write enable), CLK and _RESET. I would like to create a new module called GroupReg, which instantiates N instances of REG. Each instance has a different width (hence the WIDTH parameter array). The d, q, and we of each group are aggregated in arrays with the same name in GroupReg and need to be specified for each instance. Specifying we is easy (we[i]) since it is only one bit. However, specifying d and q with the correct LEFT and RIGHT values is where I have problem with since each group has a different width.
Looks like the only way to assign a value to a parameter is upon its definition, which prevents assigning a value to it in a generate loop.
module GroupReg(d, q, we, CLK, _RESET);
parameter N = 4; //Number of groups
//INDICES has to have N+1 members. Last member should be 0
parameter integer WIDTHS [N:0] = {40, 30, 20, 10, 0};
parameter integer DW_TOTAL = 128;
input logic [DW_TOTAL-1:0] d; // Data Input
input logic [N-1:0] we; // write enable
input logic CLK; // Clock Input
input logic _RESET; // Reset input (active low)
output logic [DW_TOTAL-1:0] q; // Q output
genvar i, j;
for (i=N-1 ; i>=0 ; i--) begin:REGISTERS
localparam WIDTH = WIDTHS[i];
localparam LEFT = RIGHT + WIDTHS[i];;
localparam RIGHT = 0;
for (j = 0 ; j<i ; j++) // <<----- Does not work
RIGHT = RIGHT + WIDTH[j];
REG #(
.DW (WIDTH),
)
reg_i
(
.d(d[LEFT:RIGHT]),
.q(q[LEFT:RIGHT]),
.we(we[i]),
.CLK(CLK),
._RESET(_RESET)
);
end : REGISTERS
endmodule
I tried using the sum() array reduction method on WIDTHS and it worked in Aldec Riviera PRO:
module some_module;
parameter N = 4; //Number of groups
parameter integer WIDTHS [N:0] = '{40, 30, 20, 10, 0};
parameter integer DW_TOTAL = WIDTHS.sum();
initial begin
$display("DW_TOTAL", DW_TOTAL);
end
endmodule
If you're lucky it's going to work in your simulator too.
I anyway don't really get what you're trying to do making N a parameter, seeing as how you're anyway hardcoding a fixed number of values for the widths.
This works in Modelsim:
module some_module;
parameter N = 4; //Number of groups
parameter integer WIDTHS [N:0] = '{40, 30, 20, 10, 0};
genvar i;
for (i=N-1 ; i>=0 ; i--) begin
localparam integer FOO[i:0] = WIDTHS[i:0];
//localparam RIGHT = FOO.sum();
initial begin
foreach (FOO[i])
$display("FOO[%0d] = %h", i, FOO[i]);
end
end
endmodule
The FOO parameter would only store the relevant entries from WIDTH for a specific loop iteration. If sum() would work, you'd be home free. The slicing syntax doesn't work in Riviera, however.
This is a typical example of vendors interpreting the standard differently, basically because it's not specific enough. Still, if you use a simulator from a different EDA company, try combining the two answers; maybe you're lucky and it works.

Setting multiple values in a vector to a single value

Basically, what is the best practice for programmatically specifying fan-out in System Verilog?
module fanout
#(
parameter N = 4
)
(
input i,
output j [N-1:0]
);
always # (*) begin
for (int k = 0; k < N; k++) begin
j[k] = i;
end
end
endmodule
This allows the width of the output vector to be a parameter -- are there any issues with this? Will this synthesize okay?
You can use the replication operator. This allows you to replicate a value a fixed number of times and concatenate them.
Example (Note you need to change the output to a packed data type output [N-1:0] j:
module fanout
#(
parameter N = 4
)
(
input i,
output [N-1:0] j
);
assign j = {N{i}};
endmodule
Runnable example on EDA playground: http://www.edaplayground.com/x/9vn
You can use a default in an assignment pattern
module fanout
#(
parameter N = 4
)
(
input i,
output j[N]
);
assign j = '{default:i};
endmodule

Resources