How to use 2 different instances of the same class intest? - system-verilog

I have the following run_phase task in one of my test:
//run_phase
task run_phase(uvm_phase phase);
tx_big_sml_diff_sequence tx_seq_i;
axi_config_reg_sequence axi_seq_i;
phase.raise_objection(.obj(this));
for (int i = 2; i <= 9; i++) begin
tx_seq_i = tx_big_sml_diff_sequence::type_id::create(.name("tx_seq_i"), .contxt(get_full_name()));
axi_seq_i = axi_config_reg_sequence::type_id::create(.name("axi_seq_i"), .contxt(get_full_name()));
axi_seq_i.transfers[0] = i;
axi_seq_i.addr = `TX_FE_LIN_INT_ADDR;
fork
begin
tx_seq_i.start(grb_env_i.tx_lin_int_agent_i.tx_lin_int_sequencer);
end
begin
axi_seq_i.start(grb_env_i.axi_agent_i.axi_sequencer);
end
join
end
phase.drop_objection(.obj(this));
super.run_phase(phase);
endtask // run_phase
Where axi_config_reg_sequence is sequence which is responsible for config specific reg (according to given address).
I want to config another reg beside TX_FE_LIN_INT_ADDR, how can I use the same sequence for config another?

You are not providing any details about the axi_config_reg_sequence implementation, so I am going to assume that the addr variable automatically takes care of configuring a register at that particular address. If that is the case, you can instantiate the same sequence one more time and then start it on the same sequencer as seen below:
tx_seq_i = tx_big_sml_diff_sequence::type_id::create(.name("tx_seq_i"), .contxt(get_full_name()));
axi_seq1_i = axi_config_reg_sequence::type_id::create(.name("axi_seq1_i"), .contxt(get_full_name()));
axi_seq2_i = axi_config_reg_sequence::type_id::create(.name("axi_seq2_i"), .contxt(get_full_name()));
axi_seq1_i.transfers[0] = i;
axi_seq1_i.addr = `TX_FE_LIN_INT_ADDR;
axi_seq2_i.transfers[0] = `SET_THIS_VARIABLE_AS_NEEDED;
axi_seq2_i.addr = `YOUR_OTHER_ADDRESS_GOES_HERE;
fork
begin
tx_seq_i.start(grb_env_i.tx_lin_int_agent_i.tx_lin_int_sequencer);
end
begin
axi_seq1_i.start(grb_env_i.axi_agent_i.axi_sequencer);
axi_seq2_i.start(grb_env_i.axi_agent_i.axi_sequencer);
end
join

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);

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

how to write function about return data

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

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