How do I implement a Parametrizable Mux in SystemVerilog? - system-verilog

I am getting the following error in System Verilog with VCS synthesizer:
The following access has an invalid number of indices.
bus[i]
I am basically trying to do a parametrizable mux made of interfaces, with the select bus being one-hot:
module myMux
#(int unsigned WIDTH=3)
(
my_interface bus[WIDTH-1:0],
input logic [WIDTH-1:0] select,
output logic [31:0] out_data
)
always_comb begin
out_data = 'x;
for (int unsigned i=0; i < WIDTH; i++) begin
if (select[i]) out_data = bus[i].in_data;
end
end
endmodule
I tried the different methods outlined in this answer here (including using |= ) but I always get the same error. Using a "genvar i" instead of an int does not even compile.
If I replace bus[i] with bus[0], then it compiles (but it is not what I want) . . . also, replacing WIDTH with a number in the for statement (ie i < 1) gives me the same error even though it is less than the value of WIDTH.
Any ideas? the code needs to be synthesizable.

Accessing an instances of an arrayed interface can only be accessed via a simulation constant (parameter, genvar, or hard-coded number). Data types and design elements both use dotted names to access there respected member or hierarchical-name, but the rules for accessing index arrays are different. Best description I can quickly find is in IEEE Std 1800-2012 § 23.6 Hierarchical names and § 23.7 Member selects and hierarchical names.
Here are two possible solutions:
Tri-state solution: floating if select is 0, x on the bit with multiple conflicting drivers.
module myMux
#(int unsigned WIDTH=3)
(
my_interface bus[WIDTH-1:0],
input logic [WIDTH-1:0] select,
output wire [31:0] out_data
);
for (genvar i=0; i < WIDTH; i++) begin : loop
assign out_data = select[i] ? bus[i].in_data : 'z;
end
endmodule
Priority selector: using a local 2D array to map the interface instances. This map can be accessed in an always block. If you are on FPGA, this is the better solution as it doesn't need tri-state.
module myMux
#(int unsigned WIDTH=3)
(
my_interface bus[WIDTH-1:0],
input logic [WIDTH-1:0] select,
output logic [31:0] out_data
);
logic [31:0] map [WIDTH];
for (genvar i=0; i < WIDTH; i++) begin : loop
assign map[i] = bus[i].in_data;
end
always_comb begin
out_data = 'x;
for(int unsigned i=0; i<WIDTH; i++) begin
if (select[i]) out_data = map[i];
end
end
endmodule

Related

How to make randomize redo until get the number I want?

A basic sequence class for randomize reset below:
class random_reset;
rand int rst_period;
constraint rst_range { rst_period inside {[1:100]}; }
task random_system_reset (
ref reg rst,
ref reg clk);
begin
rst = 1;
repeat (rst_period) #(posedge clk);
rst = 0;
end
endtask
endclass
However, I test need at least 6 clocks. Got anyway to make sure when I call this class, will get the random value bigger than 6?
Assuming you want to keep your original constraint as-is, but in some circumstances, you need to enforce the period to be 6 or more, you can use randomize() with:
random_reset rr = new();
initial rr.randomize() with { rst_period >= 6; };
For this rr object, rst_period will be between 6 and 100.
Refer to IEEE Std 1800-2017, section 18.7 In-line constraints—randomize() with.

How to slicing array interface in system verliog

I try to use array interface mapping through always_comb procedure instead of generate a statement.
You can see my test codes is in below(https://www.edaplayground.com/x/5cLt)
interface tintf;
bit valid;
bit data;
bit stall;
endinterface: tintf
module top;
tintf intf_a[0:3]();
bit valid, data, stall;
always_comb begin
loop_for_mapping:
for(int i = 0; i < 4; i++) begin
intf_a[i].valid = valid;
intf_a[i].data = data;
end
end
endmodule
But I see the error message below.
intf_a[i].valid = valid;
| ncelab: *E,NOTPAR (./testbench.sv,18|13): Illegal operand for constant expression [4(IEEE)].
I don't know that is why illegal...As I know 'i' in for-loop is considered constant.
Would you let me know what I missing??
It may be true for synthesis the for loop gets unrolled into a constant set of iterations, but it's not a constant from a language point of view. Simulation tools don't know which portions of your code you plan to synthesize. You need to write this as a generate-for loop.
for(genvar i = 0; i < 4; i++) begin : loop_for_mapping
always_comb begin
intf_a[i].valid = valid;
intf_a[i].data = data;
end
end
instantiating an interface (or a module) as an array (arrayed instance) is a part of the generate feature of verilog. As a result, you can only access those by using literal constants (0,1,2...) or from other generate blocks (see dave_59's answer).
It can be more flexible if you make arrays of the interface variables instead:
interface tintf;
bit [3:0] valid;
bit [3:0] data;
bit [3:0] stall;
endinterface: tintf
module top;
tintf intf_a();
bit valid, data, stall;
always_comb begin
loop_for_mapping:
for(int i = 0; i < 4; i++) begin
intf_a.valid[i] = valid;
intf_a.data[i]= data;
end
end
endmodule

SystemVerilog: How to create an interface which is an array of a simpler interfaces with different inputs?

What is the best way to create the below logic?
interface top_if(input rst_n[NUM_OF_modules],
input clk[NUM_OF_modules]);
simple_if i_simple_if[NUM_OF_modules](.reset_n(rst_n[?]), .clock(clk[?]));
I need to send the rst_n[x] and clk[x] to corresponding i_simple_if[x]? what is the best way to do that. The reset_n and clock are 1 bit input signals of simple_if.
endinterface
How about a generate loop:
interface top_if #(parameter NUM_OF_modules = 1)
(input rst_n[NUM_OF_modules],
input clk[NUM_OF_modules]);
generate
genvar i;
for (i=0; i<NUM_OF_modules; i++)
begin : NAME
simple_if i_simple_if(.reset_n(rst_n[i]), .clock(clk[i]));
end
endgenerate
endinterface
http://www.edaplayground.com/x/3ALC
I tried two different methods:
1) generate loop for the Interface : simple_if inside the top_if.The VCS is not happy about it and throwing Illegally connected interface port, when i pass the generated interface to a module.
2) So i had to try the below method.
interface top_if #(parameter NUM_OF_modules = 1)
(input rst_n[NUM_OF_modules],clk[NUM_OF_modules]);
simple_if i_simple_if[NUM_OF_modules]();
endinterface
top_if i_top_if();
generate
for (genvar i=0; i<NUM_OF_modules; i++) begin
assign i_top_if.i_simple_if[i].rst_n = xxx;
assign i_top_if.i_simple_if[i].clk = yyy;
end
endgenerate

LFSR description right?

I wrote a 32-bit LFSR based on the taps from [1]. I want to ask if the following description is right for the 32-bit LFSR with the taps 32,22,2 and 1.
module lfsr (
input logic clk_i,
input logic rst_i,
output logic [31:0] rand_o
);
logic[31:0] lfsr_value;
assign rand_o = lfsr_value;
always_ff #(posedge clk_i, negedge rst_i) begin
if(~rst_i) begin
lfsr_value <= '0;
end else begin
lfsr_value[31:1] <= lfsr_value[30:0];
lfsr_value[0] <= ~(lfsr_value[31] ^ lfsr_value[21] ^ lfsr_value[1] ^ lfsr_value[0]);
end
end
endmodule
[1] http://www.xilinx.com/support/documentation/application_notes/xapp052.pdf
Looks Ok. you could also use an XOR, instead of an XNOR, as long as you reset to something else (the XOR version locks up at all 0's, the XNOR at all 1's).
For many apps the pseudo-random output is the single bit you shift out (31 in your case), rather than the entire register. It's also (more?) common to shift right, and put the XOR data in the top bit, and use the bit 0 output as your PR data.
Your code is specifically SystemVerilog, and not Verilog, so I've removed the Verilog tag.

How do you join several input wires into one wire in systemverilog (all wires except one hi-Z)

Suppose that all input wires except one is supposed to be in Hi-Z. We want to connect these wires into a single wire (e.g. data bus). How can this be done in SystemVerilog?
If you mean module inputs, the alias construct can do this:
module a(input wire a,b,c);
wire bus; // use if you want a different internal name
alias a = b = c = bus;
endmodule
I'm sure this will not be synthesizable.
Assuming your condition that only one input is not Z holds true then we could just loop through and find the last non-Z input and assign its value to the output. No idea if this would synthesize.
module merge_bus
#(parameter BUSW = 8)
(
input [BUSW-1:0] bus_in,
output wire_out
);
always_comb begin
wire_out = 1'bz;
for(int i = 0; i<BUSW; i++) begin
if(bus_in[i] !== 1'bz) wire_out = bus_in[i];
end
end
endmodule
You can make use of wor/wand data types from verilog.