how to write function about return data - system-verilog

all,i need help.i encounter question about array data transaction.Please help me!
code is following.
packet is data class,and there is three queue,R,G,B,and in module "test",arith function 's return_data is no data. why?
question:though "into-arith" function,output tr_out is no data.
class packet # (int bit_depth =16);//packet class
bit [bit_depth-1:0] R[$];
bit [bit_depth-1:0] G[$];
bit [bit_depth-1:0] B[$];
endclass
//packet is data class
module test #(active_num=1920); //
packet in_tr [4];
initial begin
foreach(in_tr[i]) begin
in_tr[i] = new();
end
foreach(in_tr[j]) begin
for(int i=0;i<1920;i++) begin
in_tr[j].R.push_back(i);
end
end
process_in_tr;
end
task process_in_tr();
packet tr_out[4];
foreach(tr_out[i])begin
tr_out[i] = new();
end
tr_out[4] = into_arith(in_tr);
foreach(tr_out[j]) begin
foreach(tr_out[j].R[i]) begin
$display("%h",tr_out[j].R[i]);
end
end
endtask
function packet[4] into_arith(ref packet in_tr[4]);
packet tr_tmp[4];
foreach(tr_tmp[i]) begin
tr_tmp[i] = new();
end
for(int m=0;m<4;m++) begin
foreach(in_tr[m].R[i]) begin
tr_tmp[m].R.push_back(in_tr[m].R[i]);
tr_tmp[m].G.push_back(in_tr[m].G[i]);
tr_tmp[m].B.push_back(in_tr[m].B[i]);
end
end
return tr_tmp[4];
endfunction
endmodule

I couldn't event get this to compile in Questa, there are many syntax errors.
The three main problems are
The declaration of the function is an error. You must use a typedef when returning an aggregate type (in your case an unpacked array of packet#())
the assignment tr_out[4] = into_arith(in_tr); is illegal. You are trying to assign a unpacked array of 4 elements to the 5th element of an array, which doesn't even exist.
The return tr_tmp[4]; is also illegal. You are trying to return the non-existent 5th element of an array as the return value for a function that requires a 4-element array.
See all my corrections below:
class packet # (int bit_depth =16);//packet class
bit [bit_depth-1:0] R[$];
bit [bit_depth-1:0] G[$];
bit [bit_depth-1:0] B[$];
endclass
//packet is data class
module test #(active_num=1920); //
typedef packet#() packet4_t[4];
packet4_t in_tr;
initial begin
foreach(in_tr[j]) begin
in_tr[j] = new();
for(int i=0;i<1920;i++)
in_tr[j].R.push_back(i);
end
process_in_tr;
end
task process_in_tr();
packet4_t tr_out;
tr_out = into_arith(in_tr);
foreach(tr_out[j]) begin
foreach(tr_out[j].R[i]) begin
$display("%h",tr_out[j].R[i]);
end
end
endtask
function automatic packet4_t into_arith(ref packet4_t in_tr);
packet4_t tr_tmp;
foreach(tr_tmp[i]) begin
tr_tmp[i] = new();
tr_tmp[m].R = in_tr[m].R;
tr_tmp[m].G = in_tr[m].G;
tr_tmp[m].B = in_tr[m].B;
/* assigments above are the same as the foreach loop below
foreach(in_tr[m].R[i]) begin
tr_tmp[m].R.push_back(in_tr[m].R[i]);
tr_tmp[m].G.push_back(in_tr[m].G[i]);
tr_tmp[m].B.push_back(in_tr[m].B[i]);
end */
end
return tr_tmp;
endfunction
endmodule

Related

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.

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

Invalid index in cross-module reference

below is the code snippet of my top_file
`define NUM_SENSORS 2;
module test_top();
svt_configuration multiple_top_cfg[`NUM_SENSORS]; // configuration class instance
svt_xmtr_if xmtr_if[`NUM_OF_SENSORS](); // interface instance
svt_rcvr_if rcvr_if[`NUM_OF_SENSORS]();
always begin
fork
change_clock_speed();
join_none
end
task automatic change_clock_speed();
for(i=0; i<`NUM_OF_SENSORS; i++) begin
wait(multiple_top_cfg[i] != null);
#(multiple_new_dphy_ui[i]) begin
if(multiple_top_cfg[i].xmtr_cfg.lane_cfg.clock_type == svt_mipi_lane_configuration::NON_CONTINUOUS) begin
wait({xmtr_if[i].serial_if.serial_tx_clk_if.dp,xmtr_if[i].serial_if.serial_tx_clk_if.dn} === 2'b11);
end
else begin
if(multiple_top_cfg[i].xmtr_cfg.lane_cfg.clock_type == svt_mipi_lane_configuration::CONTINUOUS) begin
wait({xmtr_if[i].serial_if.serial_if[0].dp,xmtr_if[i].serial_if.serial_if[0].dn} === 2'b11);
end
end
multiple_change_dphy_ui[i] = 1; // this is a local reg
multiple_tx_clock_period[i] = multiple_new_dphy_ui[i]; // this is a local reg
multiple_quadrature[i] = multiple_new_dphy_ui[i]; // this is a local reg
end
end
endtask
// ... other lines
endmodule
When i am running my test, i am getting this error :
Error-[IIXMR] Invalid index in cross-module reference
top.serial.sv, 311
Invalid index in cross-module reference due to index is not constant.
Argument: xmtr_if[i].serial_if.serial_tx_clk_if.dp
Source info: : wait (({xmtr_if[i].serial_if.serial_tx_clk_if.dp,
xmtr_if[i].serial_if.serial_tx_clk_if.dn} === 2'b11))
I understand why this error is coming, but i don't have any solution to it... can any one help...
I tried to put the always block inside generate block. But another error is coming.
Any solution to this error please...
Thanks,
Biren
I have found a solution it. What i did is :
genvar i;
generate
for(i=0; i<`NUM_SENSORS; i++) begin
always begin
change_clock_speed();
end
end
endgenerate
Now it's working. :)

randomization in SystemVerilog

I am trying to randomize an address which should be not fall in a previously allocated segment
suppose if I was allocated address 0, 10 ,40 , and the block length is 5,
when I randomized the address , it should not fall in the range of (0-4) ,( 10-14) , (40-44).
how can I constraint this in system verilog.
I tried a method but it is not working.
Here is my code:
constraint con {
foreach(keys[i]){
!(address inside {[keys[i]:keys[i]+BLOCK_SIZE]});
}
}
keys is array of address that were already alloted , generated address should not fall in the above ranges.
thanks
shiva
Your syntax seems correct to me. What issue do you see with it?
I tried the above and it works for me. See below code.
class t_constraints;
randc bit [2:0] addr; //using randc just to make all values appear.
int keys [2] = {0,4}; // Implies addr {0:1 and 4:5 should not assigned}
int BLOCK_SIZE = 1;
constraint con { foreach(keys[i])
{!(addr inside {[keys[i]:keys[i]+BLOCK_SIZE]});}
}
endclass: t_constraints
module tb_con;
t_constraints t_con;
initial begin
t_con = new();
repeat(8) begin
t_con.randomize();
$display("addr = %h",t_con.addr);
end
$finish;
end
endmodule: tb_con
Below is the log, It seems perfect.
addr = 3
addr = 6
addr = 7
addr = 2
addr = 2
addr = 3
addr = 7
addr = 6
$finish called from file "t_constraints.sv", line 26.
Sorry for not formatting properly. I am not able to answer after formatting. It gives me error saying code is not formatted properly.
EDIT:
If you want to consider the addr generated each time for the next randomization, use inline constraints in tb.
See below code
module tb_con;
t_constraints t_con;
int t_keys [$];
int T_BLOCK_SIZE;
initial begin
t_con = new();
repeat(3) begin // constraint solver cannot solve since after 3rd iteration there won't be any legal values.
t_keys = t_con.keys;
T_BLOCK_SIZE = t_con.BLOCK_SIZE;
t_con.randomize() with{
foreach(t_keys[i])
{ !(addr inside {[t_keys[i]:t_keys[i]+T_BLOCK_SIZE]});}
};
$display("addr = %h",t_con.addr);
t_con.keys.push_back(t_con.addr);
end
$finish;
end
endmodule: tb_con
NOTE: You must be careful not to iterate more than the possible values (here 3) else your simulation will exit with constraint inconsistency error.
It worked for me. Please show a complete testcase and the incorrect results you are getting.
class a;
rand bit [5:0] address;
bit [5:0] keys[] = {0,10,40};
int BLOCK_SIZE = 5;
constraint con {
foreach(keys[i]) {
!(address inside {[keys[i]:keys[i]+BLOCK_SIZE-1]}) ; }
}
endclass
module top;
a a_h;
initial begin
a_h = new;
repeat (200) begin
if (!a_h.randomize())
$error("randomize failed");
$display(a_h.address);
assert (!(a_h.address inside {[0:4],[10:14],[40:44]}));
end
end
endmodule // top