Parameterize parameters? - system-verilog

I would like to parameterize localparam parameters.
My module definition:
module native #(
parameter SIM_ONLY = 0,
parameter FREQ = 500
)(
...
);
I have lots of instantiations using the same localparam parameter A.
if (FREQ == 550) begin
localparam A = 987;
end else begin
localparam A = 122;
end
AA #(
.A_VALUE (A),
) AA_inst (
...
);
But that isn't allowed in the specification, is there a different proper way to do it?
/!\ The A value is a magic number, not something that can be calculated from FREQ.
I've tried:
if (FREQ == 550) begin
shortreal A = 987;
end else begin
shortreal A = 122;
end
but I get The expression for a parameter actual associated with the parameter name... must be constant.

Use the conditional operator ?:
localparam A = (FREQ==550) 987 : 122;
You can also put more complicated expressions into a constant function
localparam A = some_function(FREQ);
function int some_function(int F);
case(F)
550: return 987;
123: return 456;
default: return 122;
endcase
endfunction

Related

How to make this expressions dynamic?

I'm trying to make the following expression dynamic with respect to size:
localparam MAX_ALLOWED_RD = 32'b1 << WIDTH_min;
The problem here is that if WIDTH_min becomes 32, the param becomes 0. What I'm trying to replace 32`b1 with something similar to "sizeof (WIDTH_min)"
How do I write this in SystemVerilog?
I have tried the following but get "'A_SIZE' is not a constant"
logic [WIDTH_min : 0] A_SIZE = 'b1;
localparam MAX_ALLOWED_RD = A_SIZE << WIDTH_min ;
The problem here is that the localparam is, by default, an integer, so its width is 32 bit [31:0].
So when you do this assignment:
localparam MAX_ALLOWED_RD = 32'b1 << WIDTH_min;
you would need 33 bits to assign that.
You could solve this by using the width as parameter:
localparam WIDTH_min = 33;
localparam [WIDTH_min:0] MAX_ALLOWED_RD = 32'b1 << WIDTH_min;
A_SIZE must be a parameter or localparam, not logic array.
I was able to achieve it by doing the following:
localparam [WIDTH_min : 0] WIDTH_min_size = '1;
localparam MAX_ALLOWED_RD = WIDTH_min_size << ID_WIDTH_min ;
(I probably should have framed the question better.)

System Verilog Generate - Unable to access local busses in previous loops using $size

enter image description here
I am trying to implement a OR tree using specific cell type CKOR2 in stages.
The stage is in a generate loop. I need to access the previous loops output bus width in the current loop to determine the width and define the output bus of the current stage.
I get errors on the line using $size
module test ( A, o );
parameter WIDTH = 9 ;
input [WIDTH-1:0] A;
output o;
localparam NUM_OR_STAGES = $clog2(WIDTH) ;
genvar i;
for (i=0; i < NUM_OR_STAGES; i=i+1) begin: OR
localparam j=i-1;
if ( i == 0 ) begin
localparam width = WIDTH;
wire [WIDTH-1:0] stgout;
assign stgout = A;
end
else begin
localparam width = $size( OR[i-1].stgout ) ;
localparam width_div2 = width/2;
localparam offset = ( width % 2);
wire [width_div2-1:0] stgo;
wire [width_div2+offset-1:0] stgout;
CKOR2 u_ckor[width_div2-1:0] ( .o(stgo), .i0(OR[i-1].stgout[width-1:width-width_div2]), .i1(OR[i-1].stgout[width-width_div2-1:width-2*width_div2]));
if ( offset )
assign stgout = { stgo,OR[i-1].stgout[0] };
else
assign stgout = stgo;
end
end
assign o = OR[NUM_OR_STAGES -1].stgout;
endmodule
Your problem is stgout[0] is declared inside an unnamed begin/end block, and you can't access it from outside the block. This is also a problem for the CKOR2 port connections. Naming the blocks would not solve your problem because you would have to switch between referencing the i==0 branch when i is 1, and the other branch when i!=1. Better to move the declarations outside the if/else branches. I didn't test the math, but this should get you close:
module test ( A, o );
parameter WIDTH = 9 ;
input [WIDTH-1:0] A;
output o;
localparam NUM_OR_STAGES = $clog2(WIDTH) ;
genvar i;
for (i=0; i < NUM_OR_STAGES; i=i+1) begin: OR
localparam width = WIDTH*2/(i+1);
localparam width_div2 = width/2;
localparam offset = ( width % 2);
wire [width_div2+offset-1:0] stgout;
if ( i == 0 ) begin
assign stgout = A;
end else begin
wire [width_div2-1:0] stgo;
CKOR2 u_ckor[width_div2-1:0] ( .o(stgo), .i0(OR[i-1].stgout[width-1:width-width_div2]), .i1(OR[i-1].stgout[width-width_div2-1:width-2*width_div2]));
if ( offset )
assign stgout = { stgo,OR[i-1].stgout[0] };
else
assign stgout = stgo;
end
end
assign o = OR[NUM_OR_STAGES -1].stgout;
endmodule

Questa dont detect warning concerning always_comb

I have a simple module:
module always_comb_error_ex
(
input logic a, b,
output logic y, z
);
// Error (10166): SystemVerilog RTL Coding error at always_comb_error_ex.sv(13): always_comb
// construct does not infer purely combinational logic
// Info (10041): Inferred latch for "z" at always_comb_error_ex.sv(17)
// Info (10041): Inferred latch for "y" at always_comb_error_ex.sv(17)
always_comb begin
if (a > b) begin
y = 1;
z = 0;
end
else if (a < b) begin
// y = 0; // missing output will create latch
z = 1;
end
// else begin // missing 'else' block will create latch
// y = 1;
// z = 1;
// end
end
endmodule
Since I'm using always_comb I should have some warning about latches.. but there is no warning by using Questa 10.7b
The tcl sctipt for compilation:
set work work
vlib -type directory $work
vlog -work $work +acc -sv -vopt -O5 +incdir+./ ../src/sv_test.sv
exit
Not all errors can be caught by simple parsing of the code, which is what vlog does. Some errors/warning will not show up until elaboration, which is vsim

SystemVerilog error in multiplexing channels : nonconstant index into instance array

I'm designing a module that accepts multiple channels and outputs one channel.
Each channel consists of valid signal and data of some widths.
If a channel has valid data, the module should output that channel. If multiple channels have valid data, the module should output one of them (in my case, channel with highest index) and rests are dropped.
My simple implementation looks like this:
module test1 #(
parameter NUM_CHANNEL = 8,
parameter DATA_WIDTH = 512
) (
input logic [DATA_WIDTH - 1 : 0] data_in [NUM_CHANNEL],
input logic valid_in [NUM_CHANNEL],
output logic [DATA_WIDTH - 1 : 0] data_out,
output logic valid_out
);
always_comb begin
valid_out = 0;
for (int i = 0; i < NUM_CHANNEL; ++i) begin
if (valid_in[i]) begin
valid_out = 1;
data_out = data_in[i];
end
end
end
endmodule
This works perfectly in both simulation and real circuit (FPGA).
However, channel can be complex type so I used interface like this:
interface channel #(
parameter DATA_WIDTH = 512
);
logic valid;
logic [DATA_WIDTH - 1 : 0] data;
modport in (
input valid,
input data
);
modport out (
output valid,
output data
);
endinterface // sub_csr_if
module test #(
parameter NUM_CHANNEL = 8,
parameter DATA_WIDTH = 512
) (
channel.in in[NUM_CHANNEL],
channel.out out
);
always_comb begin
out.valid = 0;
for (int i = 0; i < NUM_CHANNEL; ++i) begin
if (in[i].valid) begin
out.valid = 1;
out.data = in[i].data;
end
end
end
endmodule
Then, this code gets Nonconstant index into instance array 'sub_port'. error in ModelSim, and i is not a constant error in Quartus.
If I unroll the loop, it works but it becomes non-parametric code. (only works for fixed NUM_CHANNEL)
Why the latter one does not work, while the first one works flawlessly?
An array of instances (module or interface) is not a true array type. As your error message indicates, you cannot select a particular instance with a variable index. With a true array, every element is identical. Because of the way parameterization, defparam, and port connections work, each instance element could have differences. The elaboration process essentially flattens all hierarchy before simulation begins.
What you can do is use a generate construct to select your instance as follows
;
module test #(
parameter NUM_CHANNEL = 8,
parameter DATA_WIDTH = 512
) (
channel.in in[NUM_CHANNEL],
channel.out out
);
logic _valid[NUM_CHANNEL];
logic [DATA_WIDTH - 1 : 0] _data[NUM_CHANNEL];
for (genvar ii=0;ii<NUM_CHANNEL;ii++) begin
assign _valid[ii] = in[ii].valid;
assign _data[ii] = in[ii].data;
end
always_comb begin
out.valid = 0;
for (int i = 0; i < NUM_CHANNEL; ++i) begin
if (_valid[i]) begin
out.valid = 1;
out.data = _data[i];
end
end
end
endmodule

Count number of ones in an array of bits

I want to count the number of ones in a packed array. I came up with the following code:
https://www.edaplayground.com/x/2Va6
I think it can be done easier. Any suggestion?
typedef bit bit6_t[5:0];
module test_rand;
bit [5:0] mask_packed;
bit mask_packed_bit[5:0];
int mask_unpacked[5:0];
initial begin
mask_packed = $urandom_range(((2**6)-1),0);
mask_packed_bit = bit6_t'(mask_packed);
foreach (mask_packed_bit[i]) begin mask_unpacked[i] = int'(mask_packed_bit[i]); end
$display("*********************************");
$display("mask_packed = %p",mask_packed);
$display("mask_unpacked = %p",mask_unpacked);
$display("mask_unpacked.sum = %p",mask_unpacked.sum());
$display("*********************************");
end
endmodule
1) For plain verilog code:
Your last implicit $cast to 'int is unnecessary. Since you only want the sum, you can:
typedef bit bit6_t[5:0];
module test_rand;
bit [5:0] mask_packed;
bit mask_packed_bit[5:0];
int sum = 0;
initial begin
mask_packed = $urandom_range(((2**6)-1),0);
mask_packed_bit = bit6_t'(mask_packed);
foreach (mask_packed_bit[i]) begin sum += mask_packed_bit[i]; end
$display("*********************************");
$display("mask_packed = %p",mask_packed);
$display("mask_packed_bit = %p",mask_packed_bit);
$display("sum = %p",sum);
$display("*********************************");
end
endmodule
Working example: https://www.edaplayground.com/x/5ZTW
2) If you are using systemverilog, you can use the simple $countones function.
module test_rand;
bit [5:0] mask_packed;
initial begin
mask_packed = $urandom_range(((2**6)-1),0);
$display("*********************************");
$display("mask_packed = %p",mask_packed);
$display("countones = %p", $countones(mask_packed));
$display("*********************************");
end
endmodule
Working example: https://www.edaplayground.com/x/2Nsd
You can try the following
typedef bit bit6_t[5:0];
module test_rand;
bit [5:0] mask_packed;
bit6_t mask_unpacked;
initial begin
mask_packed = $urandom_range(((2**6)-1),0);
mask_unpacked = bit6_t'(mask_packed);
$display("*********************************");
$display("mask_packed = %p",mask_packed);
$display("mask_unpacked = %p",mask_unpacked);
$display("mask_unpacked.sum = %p",mask_unpacked.sum() with (int'(item)));
$display("*********************************");
end
endmodule
Working example: https://www.edaplayground.com/x/5cXx