2D arrays: A net is not a legal lvalue in this context [duplicate] - system-verilog

This question already has an answer here:
Compilation error: A net is not a legal lvalue in this context
(1 answer)
Closed last year.
The community reviewed whether to reopen this question last year and left it closed:
Original close reason(s) were not resolved
I am looking to create a FIFO using a 2D array (P_MDIM is the width of each vector, P_NDIM is the depth of the array/memory to store these vectors).
I am having trouble with the above error message on many spots in my code (assigning to out, full, and empty).
I don't know why it occurs. I thought my array ("memory") would be a 2D array of reg (not nets). Below is my full code:
module fifo( signal, enqueue, dequeue, clk, out, full, empty );
//depth of the memory
parameter P_NDIM = 16;
//width of each memory cell(in bits)
parameter P_MDIM = 16;
input [P_MDIM - 1:0] signal;
input enqueue;
input dequeue;
input clk;
output [P_MDIM - 1:0] out;
output full;
output empty;
logic [P_MDIM - 1:0] [P_NDIM - 1:0] memory = 0;
integer enqueue_pos = 0;
integer i = 0;
always #(posedge clk) begin
//enqueue data
if(enqueue) begin
//checking if memory is full
if(enqueue_pos == P_NDIM - 1) begin
$display("data not entered, memory full");
end
//add signal into memory
else begin
memory[enqueue_pos][P_MDIM-1:0] = signal;
enqueue_pos <= enqueue_pos + 1;
end//else
end//if enqueue
//dequeue data
if(dequeue) begin
//checking if memory is empty
if(enqueue_pos == 0) begin
$display("no data to dequeue, memory empty");
out[P_MDIM-1:0] = 0;
end
//output signal from memory, shift memory
else begin
out = memory[0][P_MDIM - 1:0];
enqueue_pos <= enqueue_pos - 1;
for(i = 0; i <= P_NDIM - 2; i = i + 1) begin
memory[i][P_MDIM-1:0] = memory[i + 1][P_NDIM-1:0];
end//for
end//else
end//if dequeue
//check full and empty
full = (enqueue_pos == P_NDIM-1 ? 1'b0 : 1'b1);
empty = (enqueue_pos == 0 ? 1'b0 : 1'b1);
end//always
endmodule

You declared out as a net type, but then you assigned to it inside a procedural always block. Signals assigned in a procedural block should be declared as logic:
Change:
output [P_MDIM - 1:0] out;
output full;
output empty;
to:
output logic [P_MDIM - 1:0] out;
output logic full;
output logic empty;
Unrelated to the error, in your always block, you are using a mixture of blocking (=) and nonblocking (<=) assignments. They should all be nonblocking.

Related

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

How to use get function in mailbox systemverilog

I am a beginner in systemverilog and I tried to make a complex code used to compare between two mailboxes
and it gives me these errors in simulation
enter image description here
//the package code
package types;
typedef struct{
int pid;
}packet;
endpackage
//the main code
module mbox;
import types::*;
//Declare two mailboxes here
mailbox exp_mb = new(256);
mailbox act_mb = new(256);
// This task supplies stimulus to the two mailboxes
task stimulus();
packet stim_pkt;
for (int i = 0; i < 256; i++) begin
stim_pkt.pid = i;
//*** Write stim_pkt to both mailboxes here
exp_mb.put(stim_pkt);
act_mb.put(stim_pkt);
$display("Sending pkt: ",i);
end
endtask
// Add task checker here
task check(input mailbox exp_mb ,act_mb);
bit com;
packet x;
packet y;
for (int i = 0; i < 256; i++) begin
x.pid = exp_mb.get(i) ;
y.pid = act_mb.get(i);
com = compare(x,y);
if (com == 1)
$display ("No Error");
else
$display ("Error in %d", i);
end
endtask
// Add function compare here
function bit unsigned compare (packet a ,b);
if (a.pid == b.pid)
return 1;
else
return 0;
endfunction// Add an initial block to run stimulus & checker tasks simultaneously
initial
begin
fork
stimulus();
check(exp_mb ,act_mb);
join_none
end
endmodule
The error message tells you exactly what the problem is. The mailbox get() method does not return a value, it places a value in its argument.
I believe you want
exp_mb.get(x) ;
act_mb.get(y);
Also, A good idea is add types to your mailboxes. Will become very helpful in getting compile errors instead of runtime errors as your code grows and the number of different packet types grow.
mailbox #(packet) exp_mb = new(256);
mailbox #(packet) act_mb = new(256);
...
task check(mailbox #(packet) exp_mb ,act_mb);

NBA assignment of $urandom

Can $urandom be NBA assigned in a for loop to an unpacked array of variables?
module tb();
logic clk [2];
initial clk[0] = 0;
always clk[0] = #1ns !clk[0];
for (genvar i = 1; i < 2; i++)
assign #(1ns/2) clk[i] = clk[i-1];
int tmp [2] [8];
always # (posedge clk[0]) begin
foreach (tmp[0][i]) begin
/*int m;
m = $urandom(); // SECTION 1 - using this code works (commenting out SECTION 2)
tmp[0][i] <= m;*/
tmp[0][i] <= $urandom(); // SECTION 2
end
#1ns;
foreach (tmp[0][i]) begin
$display("%1d", tmp[0][i]);
end
$finish();
end
for (genvar i = 1; i < 2; i++) begin
always_ff # (posedge clk[i]) begin
tmp[i] <= tmp[i-1]; // SECTION 3 (just removing this works too)
end
end
endmodule
Using Cadence tools (xrun 17.09-v002), I get all 8 of tmp[0] ints assigned the same value.
-2147414528
-2147414528
-2147414528
-2147414528
-2147414528
-2147414528
-2147414528
-2147414528
Can someone confirm whether this code is legal?
I have spoken to Cadence and been told this:
R&D’s response.
This use model of having $urandom call inside a non-blocking assignment is wrong.
The scheduling semantics of System Verilog dictates that the RHS is calculated and sampled once in the "inactive region" and then in the "NBA region" it's assigned the ALL of the elements of the foreach at the same time!
There is no difference in calling $urandom in a procedural loop versus serially calling $urandom multiple times. Your code gives the desired results in several tools, including Cadence's on EDAPlayground.com. Perhaps you are not showing is part of your problem. It always helps to show an MCVE, like
module top;
int tmp [2] [8];
bit clk;
initial begin
#1 clk=1;
#1 $display("%p",
tmp[0]);
end
always # (posedge clk) begin
foreach (tmp[,i]) begin
tmp[0][i] <= $urandom();
end
end
endmodule

Assigning value to a specific bit in 2D unpacked array[system-verilog]

I am trying to assign value on a specific bit of a 2D array(code[i][k]). This is a net type. But the value not being assigned.reg [3:0] code[0:3] gets unknown logic value 'X'.
Here is the code snippet
for(k=0;k<len;k++) begin
if (tc[k] == 1'b0) begin
code[i][k]= 1'b0;//----> value is not assigning as expected
end else begin
code[i][k]= 1'b1;// ---> value is not assigning as expected
end
end
codeLen[i] = len;
This for loop belongs to always block.Here, code and codeLen is output type.
output [3:0] code[0:3];
output [3:0] codeLen[0:3];
reg [3:0] code[0:3];
reg [3:0] codeLen[0:3];
codeLen[i] is assigned correctly but not the code[i][k]. I was trying to assign k-th bit of i-th byte.
Details
I have created a module which takes 6 inputs and returns two 2-dimensional arrays as output.
Here is the module:
`timescale 1ns / 1ps
module generate_code(CLK,nRST,nodes,nodeCount,characters,charCount,code,codeLen);
input CLK;
input nRST;
input integer nodeCount;//Total nodes in huffman tree
input integer charCount;//Total unique characters
input [6:0] characters[0:3];
input [23:0] nodes[0:6]; // total characters
output [3:0] code[0:3]; //[2:0] max code length <= total characters
output [3:0] codeLen[0:3];
reg [3:0] code[0:3];
reg [3:0] codeLen[0:3];
reg[3:0] tc;//temprary code reg. Holds a single bit in each byte
integer len=0;//code length
reg [23:0] tNode;
function void FindRoot;
reg [23:0] aNode;//local
integer i;
begin
for (i=0; i<nodeCount;i++) begin // For all nodes
aNode= nodes[i]; // aNode is current node
if (tNode[23:16] == aNode[14:7]) begin
tc[len]= tNode[15];//15th bit of nodes is codebit
len++;
//aNode is parent of tNode. Is it root?
if(aNode[23:16]==8'b0000_0000) begin//or frequency==nodeCount or node_id = 8'b1111_1111
return;
end else begin
tNode=aNode;
FindRoot();
end
end
end
end
endfunction
always#(posedge CLK or negedge nRST)
begin
if(!nRST) begin
// init
end
else begin
// Do code generation
integer i,j,k;
for(i= 0;i < charCount;i++) begin // For all character we are going to find codeword
for(j=0; j<nodeCount; j++) begin
tNode= nodes[j];//current node
if (characters[i] == tNode[6:0]) begin
// Got the character. tNode is a leaf nodes. Lets back track to root.
break;
end
end
len=0;
FindRoot();
for(k=0;k<len;k++) begin
if (tc[k] == 1'b0) begin
code[i][k]= 1'b0;
end else begin
code[i][k]= 1'b1;
end
end
//code[i]=2;
codeLen[i]= len;
end
end
end
endmodule
When I am assigning values to code[][], it is expected that following loop is executed. Though not all the bits of code[][] will be set. During debugging, when I come to assignment, I found that value is not being assigned (code[i][k] =1 or 0). Its getting unknown logic value X.
for(k=0;k<len;k++) begin
if (tc[k] == 1'b0) begin
code[i][k]= 1'b0;
end else begin
code[i][k]= 1'b1;
end
end
Testbench:
`timescale 1ns / 1ps
module generate_code_test;
// Inputs
reg CLK;
reg nRST;
integer nodeCount=7;//Total nodes in huffman tree
integer charCount=4;//Total unique characters
reg [6:0] characters[0:3];
reg [23:0] nodes[0:6]; // total characters
// Outputs
wire [3:0] code[0:3]; //[2:0] max code length <= total characters
wire [3:0] codeLen[0:3];
generate_code uut (
.CLK(CLK),
.nRST(nRST),
.nodes(nodes),
.nodeCount(nodeCount),
.characters(characters),
.charCount(charCount),
.code(code),
.codeLen(codeLen)
);
initial begin
// Initialize Inputs
CLK = 0;
nRST = 0;
nodeCount= 7;
charCount= 4;
characters[0]= 7'b110_0001;
characters[1]= 7'b110_0010;
characters[2]= 7'b110_0011;
characters[3]= 7'b110_0100;
nodes[0] = 24'b0000_0011_0_0000_0001_110_0001;
nodes[1] = 24'b0000_0011_1_0000_0010_110_0011;
nodes[2] = 24'b0000_0101_1_0000_0011_111_1111;
nodes[3] = 24'b0000_0101_0_0000_0100_110_0010;
nodes[4] = 24'b1111_1111_1_0000_0101_111_1111;
nodes[5] = 24'b1111_1111_0_0000_0110_110_0100;
nodes[6] = 24'b0000_0000_0_1111_1111_111_1111;
// Wait 10 ns for global reset to finish
#10;
nRST = 1;
end
parameter DELAY = 1;
always
#DELAY CLK = ~CLK;
endmodule
The code has been compiled in ModelSim 2016
I just started learning verilog. So I would really appreciate your help to show my mistakes.
Regards.
I got a fix for my problem. Not all the bits of code[][] has been set. This leads to unknown logic value in code[][] even after setting the bit. It gets solved after initializing all the bits of code[][] in always block.

Verilog testbench design for my MSB downsampling module

A couple of days ago I asked about a module (here) I wanted to implement which takes the MSB of input samples, accumulates them (by shifting) and combines them into the output sample when the 32 output bit is "filled".
Thanks to the help there, I got this implementation, which doesn't produce any compilation errors and seemed fine with Xilinx 12.1:
module my_rx_dsp0
#(
//frontend bus width
parameter WIDTH = 24
)
(
//control signals
input clock, //dsp clock
input reset, //active high synchronous reset
input clear, //active high on packet control init
input enable, //active high when streaming enabled
//user settings bus, controlled through user setting regs API
input set_stb, input [7:0] set_addr, input [31:0] set_data,
//full rate inputs directly from the RX frontend
input [WIDTH-1:0] frontend_i,
input [WIDTH-1:0] frontend_q,
//full rate outputs directly to the DDC chain
output [WIDTH-1:0] ddc_in_i,
output [WIDTH-1:0] ddc_in_q,
//strobed samples {I16,Q16} from the RX DDC chain
input [31:0] ddc_out_sample,
input ddc_out_strobe, //high on valid sample
output ddc_out_enable, //enables DDC module
//strobbed baseband samples {I16,Q16} from this module
output reg [31:0] bb_sample,
output reg bb_strobe //high on valid sample
);
reg [3:0] i_msb;
reg [3:0] q_msb;
reg [31:0] temp_buff = 0;
reg [1:0] count = 0;
always #(posedge clock) begin
if(ddc_out_strobe) begin
// bit shifter for MSB
temp_buff <= {i_msb,q_msb,temp_buff[31:8]};
// to avoid if-else condition
count <= (count==2'd3) ? 2'd0 : (count+1);
end
end
always #(*) begin
i_msb = ddc_out_sample[31:28];
q_msb = ddc_out_sample[15:12];
// to avoid if-else condition
bb_strobe = (count==2'd3);
bb_sample = bb_strobe ? temp_buff : 32'd0;
end
assign ddc_in_i = frontend_i;
assign ddc_in_q = frontend_q;
assign ddc_out_enable = enable;
endmodule //my_rx_dsp0_custom
Now I wanted to implement a testbench that tests my_rx_dsp0.v with some examples.
I implemented a my_rx_dsp0_tb_2.v, which reads 32 bit samples from a file named my_input.dat to feed to the module as inputs ddc_out_sample.
They are then compared to the correct values stored at my_output.dat.
Note: I did not write this testbench myself, I adapted it from another testbench from an open-source project.
Here is the implementation:
module my_rx_dsp0_tb ( );
reg clk;
reg reset;
reg enable;
reg ddc_out_strobe; //high on valid sample
reg [31:0] ddc_out_sample;
wire [31:0] bb_sample = 32'd0;
wire bb_strobe;
wire ddc_out_enable = 1'b1; //enables DDC module
parameter WIDTH = 24;
parameter clocks = 2; // number of clocks per input
reg endofsim = 0;
integer number_of_errors;
initial number_of_errors = 0;
wire set_stb = 1;
wire [7:0] set_addr;
wire [31:0] set_data;
wire [WIDTH-1:0] frontend_i;
wire [WIDTH-1:0] frontend_q;
wire [WIDTH-1:0] ddc_in_i;
wire [WIDTH-1:0] ddc_in_q;
reg signed [31:0] compare_out;
// Setup the clock
initial clk = 1'b0;
always #5 clk <= ~clk ;
// Come out of reset after a while
initial reset = 1'b1 ;
initial #1000 reset = 1'b0 ;
// Enable the entire system
initial enable = 1'b1 ;
// Instantiate UUT
my_rx_dsp0 #(.WIDTH(WIDTH)) UUT_rx_dsp0
( .clock(clk), .reset(reset), .clear(clear), .enable(enable),
.set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
.frontend_i(frontend_i), .frontend_q(frontend_q),
.ddc_in_i(ddc_in_i), .ddc_in_q(ddc_in_q),
.ddc_out_sample(ddc_out_sample), .ddc_out_strobe(ddc_out_strobe), .ddc_out_enable(ddc_out_enable),
.bb_sample(bb_sample), .bb_strobe(bb_strobe) );
//-------Setup file IO-------//
//
integer i, r_in, r_out, infile, outfile;
initial begin
infile = $fopen("my_input.dat","r");
outfile = $fopen("my_output.dat","r");
$timeformat(-9, 2, " ns", 10) ;
// for n=9,p=2 digits after decimal pointer
//min_field_width=10 number of character positions for %t
end
//-------Get sim values and display errors-------//
//
initial begin
// Initialize inputs
ddc_out_strobe <= 1'd0;
ddc_out_sample <= 32'd0;
// Wait for reset to go away
#(negedge reset) #0;
while(!endofsim) begin
// Write the input from the file or 0 if EndOfFile(EOF)
#(posedge clk) begin
#1
ddc_out_strobe <= 1'b1;
if(!$feof(infile))
r_in = $fscanf(infile,"%b\n",ddc_out_sample);
else
ddc_out_sample <= 32'd0;
end
//
// Clocked in; set the strobe to 0 if the # of clocks/sample
// is greater than 1
if( clocks > 1 ) begin
#(posedge clk) begin
ddc_out_strobe <= 1'b0 ;
end
// Wait for the specified # of cycles
for( i = 0 ; i < (clocks-2) ; i = i + 1 ) begin
#(posedge clk) #1 ;
end
end
//
//
// Print out the number of errors that occured
if(number_of_errors) begin
$display("FAILED: %d errors during simulation",number_of_errors) ;
end else begin
$display("PASSED: Simulation successful") ;
end
//
end
end
//-------Comparison btwn simulated values vs known good values-------//
//
always #(posedge clk) begin
if(reset)
endofsim <= 1'b0 ;
else begin
if(!$feof(outfile)) begin
if(bb_strobe) begin
r_out = $fscanf(outfile,"%b\n",compare_out);
if(compare_out != bb_sample) begin
$display("%t: %b != %b",$realtime,bb_sample,compare_out);
number_of_errors = number_of_errors + 1;
end else begin
$display("%t: %b = %b",$realtime,bb_sample,compare_out);
end
end
end else begin
// Signal end of simulation when no more outputs
endofsim <= 1'b1 ;
end
end
end
endmodule // my_rx_dsp0_tb
When simulating with ISim from Xilinx ISE Suite Edition 12.1 I do not get the desired functionality from the module. I am afraid the output contains several x states (unknown states), instead of 1s or 0s as expected.
Question Is this due to:
1) The way the files are being read with $fscanf?
2) Did I wrong by initializing reg [31:0] temp_buff = 0?
3) Or does someone have an idea on what went wrong?
The error prompts from the testbench are (as an example):
xx000x00xxx00x0xx000x0x000000000 != 10000110111001011100010001101100
The X is from having multiple conflicting drivers on bb_sample and ddc_out_enable. The wire type merges the drivers, conflicting bit values of the same strength resolve as X.
UUT_rx_dsp0 is the intended diver. However you added and additional drivers from the way you declared your wires.
...
wire [31:0] bb_sample = 32'd0; // "= 32'd0" is a continuous driver
wire bb_strobe;
wire ddc_out_enable = 1'b1; // "= 1'd1" is a continuous driver
...
What you want is:
...
wire [31:0] bb_sample;
wire bb_strobe;
wire ddc_out_enable;
...
Correcting the above will resolve the X issue. Based on the example error it looks like are data miss matches. With the provided information, it is hard to tell it if it a test-bench or design issue. Could be just clock or propagation skew.