I don't understand this SV randomization randc behaviour - system-verilog

This is code for transaction class,
class transaction;
//declaring the transaction items
randc bit [3:0] a;
randc bit [3:0] b;
bit [6:0] c;
function void display(string name);
$display("-------------------------");
$display("- %s ",name);
$display("-------------------------");
$display("- a = %0d, b = %0d",a,b);
$display("- c = %0d",c);
$display("-------------------------");
endfunction
endclass
And this is code for generator class,
class generator;
rand transaction trans;
int repeat_count;
mailbox gen2driv;
event ended;
function new(mailbox gen2driv);
this.gen2driv = gen2driv;
endfunction
task main();
repeat(repeat_count) begin
trans = new();
if( !trans.randomize() ) $fatal("Gen:: trans randomization failed");
trans.display("[ Generator ]");
gen2driv.put(trans);
end
-> ended;
endtask
endclass
The value of repeat_count that I passed is 10, and here's the output:
- a = 2, b = 0
- c = 0
- a = 1, b = 9
- c = 0
- a = 9, b = 9
- c = 0
- a = 7, b = 15
- c = 0
- a = 10, b = 15
- c = 0
- a = 3, b = 1
- c = 0
- a = 13, b = 12
- c = 0
- a = 1, b = 9
- c = 0
- a = 7, b = 5
- c = 0
- a = 3, b = 15
- c = 0
But, values during randomization are not showing cyclic repetition. It is repeating itself before all possible value can occur for variables a and b.

Move the transaction constructor out of the repeat loop. Change:
repeat(repeat_count) begin
trans = new();
to:
trans = new();
repeat(repeat_count) begin
It seems new resets the initial random permutation of the range values each time it is called.
Here is a self-contained, runnable example which demonstrates the issue (and the fix):
class transaction;
randc bit [3:0] a; // 16 values: 0-15
function void display;
$display("a=%0d", a);
endfunction
endclass
class generator;
rand transaction trans;
task main;
//trans = new(); // Un-comment this line for fix
repeat (16) begin
trans = new(); // Comment out this line for fix
if (!trans.randomize()) $fatal(1, "trans randomization failed");
trans.display();
end
endtask
endclass
module tb;
generator gen = new();
initial gen.main();
endmodule

Yeah exactly to what #toolic said...initializing with new operator inside the repeat loop would create a new space every time the loop runs and thus the newly created object (transaction in your case) has no trace of the values that has been previously exercised. Thus giving out a random number making randc of no use. It though works normal with ' rand' keyword.

Related

SystemVerilog X propagation issue

I'm having an issue with my SV code. I'm attempting to simulate a carry look ahead adder. However, when I look at my timing results
they show result has having an x propagated, as well as SUM.
Here is my SystemVerilog code
module fulladder (input logic i_bit1, i_bit2, i_carry,
output logic o_sum, o_carry);
assign o_sum = i_bit1 ^ i_bit2 ^ i_carry;
assign o_carry = (i_bit1 & i_bit2) | (i_carry & (i_bit1 ^ i_bit2));
endmodule
module carry_lookahead_adder
#(parameter WIDTH)
(input logic [WIDTH-1:0] i_add1,
input logic [WIDTH-1:0] i_add2,
output logic [WIDTH:0] o_result
);
logic [WIDTH:0] w_C;
logic [WIDTH-1:0] w_G, w_P, w_SUM;
//Generate full adders
genvar i;
generate for (i= 1; i<WIDTH; i++)
begin : f_loop
fulladder fi (
.i_bit1(i_add1[i]),
.i_bit2(i_add2[i]),
.i_carry(w_C[i]),
.o_sum(w_SUM[i]),
.o_carry()
);
end
endgenerate
genvar jj;
generate
for (jj=0; jj<WIDTH; jj++)
begin
assign w_G[jj] = i_add1[jj] & i_add2[jj];
assign w_P[jj] = i_add1[jj] | i_add2[jj];
assign w_C[jj+1] = w_G[jj] | (w_P[jj] & w_C[jj]);
end
endgenerate
assign w_C[0] = 1'b0; //No carry input
assign o_result = {w_C[WIDTH], w_SUM};
endmodule
and the testbench
module carry_lookahead_adder_tb (w_RESULT);
parameter WIDTH = 32;
logic [WIDTH-1:0] r_ADD_1 = 0;
logic [WIDTH-1:0] r_ADD_2 = 0;
output logic [WIDTH:0] w_RESULT;
carry_lookahead_adder #(.WIDTH(WIDTH)) carry_lookahead_inst
(
.i_add1(r_ADD_1),
.i_add2(r_ADD_2),
.o_result(w_RESULT)
);
initial
begin
$dumpfile("dump.vcd");
$dumpvars;
#10;
r_ADD_1 = 32'b00000000000000000000000000000000;
r_ADD_2 = 32'b00000000000000000000000000000001;
#10;
r_ADD_1 = 32'b00000000000000000000000000000010;
r_ADD_2 = 32'b00000000000000000000000000000010;
#10;
r_ADD_1 = 32'b00000000000000000000000000000101;
r_ADD_2 = 32'b00000000000000000000000000000110;
#10;
r_ADD_1 = 32'b00000000100000000000000000000101;
r_ADD_2 = 32'b00000000100000000000000000000110;
#10;
r_ADD_1 = 32'b11111111111111111111111111111111;
r_ADD_2 = 32'b11111111111111111111111111111111;
#10;
r_ADD_1 = 32'b00000000000000000000000000000000;
r_ADD_2 = 32'b00000000000000000000000000000001;
#10;
end
endmodule // carry_lookahead_adder_tb
Can anyone clue me into what may be causing this x? Sorry to post my full code; I'm just lost as to where the problem may be coming from.
Bit [0] of w_SUM is unknown because you are not driving it. Change the generate for loop so that the count starts from 0, not 1. Change:
generate for (i= 1; i<WIDTH; i++)
to:
generate for (i= 0; i<WIDTH; i++)
After this change, the x goes away.
The problem was that the for loop was not generating the right number of fulladder instances: you need 32, but you only got 31. There was no fulladder instance for you to connect w_SUM[0], i_add1[0], etc., to.

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

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

Getting a "... not an elaboration-time constant" ... but haven't I already defined that array?

In the code fragment below I'm getting this error:
Source info:
x.data[theword][thebyteH : thebyteL] =
$urandom_range(0,255) ;
'this' is not an elaboration-time constant. To correct the error you may
convert this const variable to a parameter or a localparam.
The geometry of the data record, just a memory, is declared in the definition_pkg. A data record object is created in the Base_txn and
I can access it directly like so:
x.data[0][7:0] = x.frameID ;
I don't know why am I getting an elaboration time error since all that is happening (I think) in for loop is that I'm indexing an already existing object.
Any suggestions, explanation, or solutions appreciated.
definition_pkg.svh
`define REC_DATAWIDTH 32
`define REC_ROWS 16
typedef bit[`REC_DATAWIDTH-1:0] DataRec [`REC_ROWS] ;
sequences.sv
class Base_txn extends uvm_sequence_item;
rand DataRec data;
...
class sequencethingy extends uvm_sequence#(Base_txn);
...
int byte4val ;
int theword ;
int thebyteH ;
int thebyteL ;
// -----------------------------------------------------------------------
function void build_S (ref Base_txn x);
...
x.data[0][7:0] = x.frameID ;
...
for (int i = 8 ; i <= (byte4val+8) ; i++) // byte8 is the location of S[0]
begin
theword = i/4 ;
thebyteL = 8*(i%4) ;
thebyteH = thebyteL + 7 ;
x.data[theword][thebyteH : thebyteL] = $urandom_range(0,255) ;
end
endfunction
...
task body();
Base_txn wd_tx;
...
build_S(wd_tx) ; // give the processor some data
Write this as
x.data[theword][thebyteL +:8] = $urandom_range(0,255) ;
See Indexing vectors and arrays with +:

Simulation in verilog using $monitor

I've been trying to implement full adder in Verilog. I have implemented it and it is also showing results on Isim. Only problem is that when I try to see the simulation using $monitor command, it is showing me only 1 result, not all simulation results. Here is testbench code:
module Full_adder_s2_testbench;
// Inputs
reg a;
reg b;
reg cin;
// Outputs
wire sum;
wire cout;
// Instantiate the Unit Under Test (UUT)
Full_adder_s2 uut (
.a(a),
.b(b),
.cin(cin),
.sum(sum),
.cout(cout)
);
integer i;
initial begin
// Initialize Inputs
a = 0;
b = 0;
cin = 0;
// Wait 100 ns for global reset to finish
#100;
end
always # ( a, b, cin )
begin
// generate truth table
for ( i = 0; i < 8; i = i + 1 )
// every 10 ns set a, b, and cin to the binary rep. of i
#10 {a, b, cin} = i;
$monitor( "%d ns: a + b + cin = %b + %b + %b = cout sum = %b %b",
$time, a, b, cin, cout, sum );
// stop 10ns after last change of inputs
#10 $stop;
end
endmodule
And here is result in ISIM:
# run 1000 ns
Simulator is doing circuit initialization process.
Finished circuit initialization process.
400 ns: a + b + cin = 1 + 1 + 1 = cout sum = 1 1
Stopped at time : 410 ns : in File "E:/Namal/FYP/My work/XILINX/Full_adder_s2/Full_adder_s2_testbench.v" Line 66
$monitor is only meant to be setup once and will trigger every time a signal changes, try using $display since you already have the statement inside of your always #*.
While learning Verilog I would encourage you to use begin end liberally. The issue is that only 1 line was in the for loop, the $display/$monitor was outside and so only executed once at the start.
always #* begin
// generate truth table
for ( i = 0; i < 8; i = i + 1 ) begin //<-- Added begin
// every 10 ns set a, b, and cin to the binary rep. of i
#10 {a, b, cin} = i;
$display( "%d ns: a + b + cin = %b + %b + %b = cout sum = %b %b", $time, a, b, cin, cout, sum );
end //<--Added end
// stop 10ns after last input
#10 $stop;
end
Full example on EDA Playground.
NB: it is best not to use manual sensitivity lists any more replace always # ( a, b, cin ) with always #*. This will result in quicker refactoring and lowering the chance of RTL to gates simulation mismatch.

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