How to access generate block elements hierarchically - system-verilog

Consider code in SV interface:
genvar i;
generate
for (i = 0; i < 2; i++) begin : g1
task ab ();
///< something here
endtask
end
endgenerate
According to LRM 1800-2012 section 27.6 I should technically be able to access this task by (consider in monitor vif is a virtual instance of interface):
vif.g1[i].ab();
Is this correct? If yes then simulators have issue supporting it since it reports vif.g1 can't be found (elaboration time)
I've tried it without named block as well it just suppose to be:
vif.genblk1[i].ab();
but no luck.
What is the issue here? I think monitor or any other classes have handles created run time, however interface still should be static time compiled and all elements of interface should be available.

You cannot use a variable inside the []'s to reference the task.
A generate loop gets flattened out at elaboration before simulation starts. So you would need to call the task with
vif.g1[0].ab;
Here is a complete self contained example. Please try posting your questions with the same.
interface itf;
for (genvar ii = 0; ii < 2; ii++) begin : g1
task ab ();
$display("%m");
endtask // ab
end : g1
endinterface : itf
module top;
itf i1();
virtual itf vif;
initial begin
vif = i1;
vif.g1[0].ab;
end
endmodule : top

Related

System Verilog: randomization per instance at initial

I want to simulate a multiple latches with random starting conditions, but I want each instance to have its own initial condition
This is a simplified version of the code. I would like the value to be different in both of the instances, without changing the interface
module random_usage();
integer addr1;
real data;
initial begin
addr1 = $urandom();
data = $urandom();
$display("addr1=%0d, data=%0d",addr1,data);
end
endmodule
module tb();
integer seed = 1;
random_usage a();
random_usage b();
initial
begin
#5;
seed = $get_initial_random_seed();
$display("seed=%0d", seed);
end
endmodule
What I have seen so far:
Instance specific $urandom in system-verilog
solution doesn't work in initial condition, or even when you feed the same clock
https://www.systemverilog.io/randomization
I have modules, so i don't know how to apply the solutions, or even if it will work here
https://www.reddit.com/r/FPGA/comments/jd0dmu/system_verilog_force_randomization_different_per/
seems to be the same question, and there is no straight solution, but the last person gave a VCS flag. I am using VCS, but i have not been able to get the flag to work
The IEEE 1800-2017 SystemVerilog LRM section 18.14.1 Random stability properties says rather naively that each instances gets seeded with the same initialization seed.
Most tools now have a switch changing that behavior by using the hierarchical path name to seed each instance. Some tools have even made that the default. If you want tool independent behavior, you can use this package:
package seed_instance;
int initial_seed = $urandom;
function automatic void srandom(string path);
static int hash[int];
int hash_value = initial_seed;
process p = process::self();
for(int i=0;i<path.len();i++)
hash_value+=path[i]*(i*7);
if (!hash.exists(hash_value))
hash[hash_value] = hash_value;
else
hash[hash_value]+=$urandom; // next seed
p.srandom(hash[hash_value]);
endfunction
endpackage
module random_usage();
integer addr1;
real data;
initial begin
seed_instance::srandom($sformatf("%m"));
addr1 = $urandom();
data = $urandom();
$display("1: addr1=%0d, data=%0d",addr1,data);
end
initial begin
seed_instance::srandom($sformatf("%m"));
addr1 = $urandom();
data = $urandom();
$display("2: addr1=%0d, data=%0d",addr1,data);
end
endmodule
module tb();
integer seed = 1;
random_usage a();
random_usage b();
endmodule

fork join within for loop in system verilog

Problem: What will be the output of this code? and why?
module tb;
int i;
initial begin
for(i=0; i<10; i++)
begin
fork
#1 $display("Value = %d", i);
join_none
end
end
endmodule
To spawn the fork threads with all the possible index values, you can use automatic variable inside for loop,
module tb;
int i;
initial begin
for(i=0; i<10; i++)
begin
automatic int j = i;
fork
#1 $display("Value = %d", **j**);
join_none
end
end
endmodule
Output:
Value = 0
Value = 1
Value = 2
Value = 3
Value = 4
Value = 5
Value = 6
Value = 7
Value = 8
Value = 9
EDA Playground link
To understand the automatic variable lifetime concept including 'fork inside for', please refer to SV LRM "6.21 Scope and lifetime" or you can find many threads on this topic such as: fork join_none inside for loop
The example starts 10 parallel threads of $display and schedules each #1 in the future. They print the value 10 because there is no time to block (join_none does not block at all) the loop so the loop executes all its iterations at t=0.
Added some printing of the execution time so that its easier to see what is happening. The thread of execution does not wait for any of them to finish (join_none) so the final print executes at t=0;
The simulation output is here
If you need further research see IEEE 1800-2017 section 9.3.2 parallel blocks.
https://standards.ieee.org/standard/1800-2017.html
If you want to run it go to www.edaplayground.com,and you can run it with the industry standard tools almost free (need to register with an email).

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.

Way to have a function like urandom_range(); which will return unique values?

I want to have a urandom_range(); which will not repeat a value once its picked in a simulation ? If it has exhausted its supply of 'available' numbers, then perhaps it can repeat .
Is there any keyword in systemverilog which will help quickly to get around this ?
Not a SV expert here so an example would really help! Thanks
randc does exactly this. (cyclic randomization)
class A;
randc bit[7:0] m;
endclass
Each time you call randomize() on the same object, it will not repeat value for m until all possible values have been given.
Simulators have limits on how large the cyclic value can be, but the standard requires a minimum of 8-bits. If you have a larger value, then you can use the inside operator.
class A;
rand bit[23:0] r;
bit [23:0] list[$];
constraint c { !(r inside {list}); }
function void post_randomize();
list.push_back(r);
endfunction
endclass
If you really expect to cycle through the list, it might be simpler to build the list first, and then shuffle through the list.
bit [7:0] list[20];
for(int i=0;i<20;i++) list[i] = i+10; // range 10-29
list.shuffle();
// cycle through list[0] ... list[29]
list.shuffle();
// cycle through list[0] ... list[29]
You can declare a variable with randc identifier. This is called 'cyclical random' and will ensure exactly what you are requiring.
Note: This requires a license that supports randomization and random variables. Most commercial simulators do provide this but at a higher cost. If you are constrained by this and need to only use the system calls - $urandom or $urandom_range, I would implement something like a queue that tracks all the values returned.
function automatic void find_unique_num();
int c;
int vals[$];
bit found;
do begin
c = $urandom_range(10, 1);
foreach(vals[i])
if (c == vals[i]) found = 1;
end
while (!found);
vals.push_back(c);
return c
endfunction

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.