Same sequence to multiple sequencers in UVM - system-verilog

I have a DUT with 2 Interfaces of the same type. I have created 2 agents to drive the two interfaces. My idea is to drive the same signals on the interface ports to test a specific scenario. Hence, I thought of creating a sequence and driving it to the two sequencers of the agents. But I get an error. The code is something as follows:
my_sequencer m_seqr[2];
my_sequence m_seq;
for(int i=0; i<2; i++) begin
fork
int idx = i;
m_seq.start(p_sequencer.m_seqr[i];
join_none
end
I haven't shown the complete code for keeping the post short. I think my declarations and initializations are correct because I have a similar test with 2 sequences feeding into 2 sequencers working correctly.
My question is how can I achieve my objective of driving the same sequence into 2 or more sequencers?
Error is as follows(Haven't added the complete line of error):
uvm_test_top.m_env.m_my_agent_env.m_my_agent[1].m_seqr##m_in_seq%0d[SEQ_NOT_DONE] Sequuence .... already started

You need to construct a new object for each sequence you want to start. Also, you need to reference [idx] not [i].
my_sequencer m_seqr[2];
...
for(int i=0; i<2; i++)
fork
int idx = i;
my_sequence m_seq = my_sequence::type_id::create(...);
m_seq.start(p_sequencer.m_seqr[idx];
join_none

Related

How to end all outstanding objections in OVM

I am in run phase and lets say I have raised 20 objections. I want to end all these 20 objections already raised and raise 20 new objections in the same phase without jumping to the next phase. Can someone please suggest how to achieve this?
Here is first method(you don't know how many objections were raised):
phase.raise_objection(this);
phase.raise_objection(this);
//your code here
m_phase.drop_objection(this, "", m_phase.get_objection_count(this));
Here is same method (assuming you know how many objections were raised):
phase.raise_objection(this, "raise 3 objections", 3);
//your code here
m_phase.drop_objection(this, "drop 3 objections", 3);
end
Less clever method, but worth mentioning:
`uvm_info(get_type_name(), $sformatf("Dropping all objections now"), UVM_MEDIUM)
for (int i=0 ; m_phase.get_objection_count(this) > 0; i++) begin
`uvm_info(get_type_name(), $sformatf("Dropping objection #%d", i), UVM_MEDIUM)
m_phase.drop_objection(this);
end
You can find more information about uvm_phase class here:
https://verificationacademy.com/verification-methodology-reference/uvm/docs_1.2/html/files/base/uvm_phase-svh.html
I also coded these examples for you to try here:
https://www.edaplayground.com/x/2KLd

UVM sequences producing related numbers

In the UVM test I declare and start the sequences, but the output from separate sequences with the same parameters are "related" somehow(see example at the bottom), so when I do cross coverage I only coverage 12.5% of the cases, what is causing this? How can I make the output of the two sequences independent and random?
//declare
ve_master_sequence#( 8,`num_inputs) x_agent_sequence_inst;
ve_master_sequence#( 8,`num_inputs) y_agent_sequence_inst;
//build_phase
x_agent_sequence_inst = ve_master_sequence#( 8,`num_inputs)::type_id::create("x_seq");
y_agent_sequence_inst = ve_master_sequence#( 8,`num_inputs)::type_id::create("y_seq");
//run_phase
x_agent_sequence_inst.start(multadd_env_inst.ve_x_agent_inst.sequencer);
y_agent_sequence_inst.start(multadd_env_inst.ve_y_agent_inst.sequencer);
The environment contains 4 master agents, two 32 bit, two 8 bit. The same parameterized sequence is run on all the agents
// within the sequence
virtual task body();
`uvm_info("ve_master_sequence", $sformatf("begin body()"), UVM_MEDIUM);
for(int i=0; i<length; i++) begin
req = ve_seq_item#(data_width)::type_id::create("req");
start_item(req);
while(!req.randomize() with {
data <= (2**data_width)-1;
delay dist { [0:1] := 2, [2:6] := 1};
});
finish_item(req);
get_response(req);
end
#1000;
endtask
I replaced the req.randomize() with $urandom_range, which worked but it means losing all the constrained random abilities of systemverilog.
When I run the code, and do cross coverage there is a relationship between the output of the sequencers that are the same size,
when y = 0 is always x = 79 or 80
when y = 1 is always x = 80 or 81
when y = 2 is always x = 81 or 82
....
when y = 51 is always x = 130 or 131
when y = 52 is always x = 131 or 132
etc..
Apparently UVM uses its parent Random Number Generator and the sequence name to create a new RNG for the sequence. This is to give good random stability.
Try changing the names for the sequences to make them more unique. I am assuming that longer unique strings give a higher degree of randomization.
Inside the sequence class was this loop creating sequence items. The explanation is (as already said above) UVM uses the class hierarchy for to create the random seed, which gives good random stability
for(int i=0; i<1000; i++) begin
//this caused the error
req = ve_seq_item#(data_width)::type_id::create("req");
//this fixed it
req = ve_seq_item#(data_width)::type_id::create($sformatf("req_%1d", i));
//randomizing the sequence item with the loop variable

Connect different agent type Anylogic

I have 5 agents - bus, transformer , generator, load , line. I have a requirement where i need dynamically connect the above agents.
I have written the following code, where i am trying to connect for example bus [2] and generator[5]. The connections are not random but based on a circuit, which i am dynamically reading through a text file.
for (int l = 0; l < busList.size(); l++) {
for (int k = 0; k < generatorList.size(); k++) {
if (generatorList.get(k).getBusNumber()==busList.get(l).getBusNumber()) {
busList.get(l).getBusID().connectTo(generatorList.get(k).getGenID());
}
}
}
Can someone help with the connection part. I cannot have a generic list because I need the agent attributes for other functionalities as well.
Assuming that busList and generatorList are collections containing entries of type Bus and Generator respectively, which both are derived of type Agent, the following code should work for connecting:
busList.get(l).connectTo(generatorList.get(k));
I don't know why you used getBusID and getGenID which I assume return an integer. If they really return a Bus or a Generator object it should work as you already wrote. In this case you would need to provide us the error message or the exact problem that you have.

Creating and managing two independent random number sequences

I'm having trouble generating two independent random sequences using the rand and srand functions. The details are below, any help would be most appreciated.
I'm working on a puzzle game for the iPhone, and usually for the random number generation I use the arc4 function. However for the multiplayer mode I want both players to have the same pieces throughout the game, and the only way I can control it is to have two repeatable random sequences. If I then send the seeds to the other device, the games will be identical. However when I use rand and srand and try to switch to the other seed, the sequence starts from scratch, I somehow have to initialize two independent sequences generated with a seed.
Thank you for your responses
Cryptographically bad PRNGs like rand() operate by feeding the previous result back into a certain mathematical procedure.
In order to continue a sequence from where it left off, all you have to do is store the last-generated number and use it as the seed:
srand(time(0));
int player1_rand_num = rand();
NSLog(#"Player 1: %d, %d, %d", rand(), rand(), rand());
srand(7);
int player2_rand_num = rand();
NSLog(#"Player 2: %d, %d, %d", rand(), rand(), rand());
// Re-seed Player 1 sequence
srand(player1_rand_num);
// Displays the same "random" numbers as the first NSLog
NSLog(#"Player 1 again: %ld, %ld, %ld", rand(), rand(), rand());
// and so on...
The random() function generates better random numbers, and has a separate pair of functions, initstate() and setstate() which will give you the state of the generator. You can store the state and pass it into setstate() to resume the sequence from where you left off. I direct you to man 3 random for the details.
First off, as others have pointed out already, you should use random() instead of rand(). Secondly, while your singleton approach may work for you, you could solve your problem more easily and IMHO more elgantly by using setstate(3). See Use of setstate(3) doesn't produce expected sequence of random numbers for an example on how to switch between two random number states.
Thank you for the suggestions, this is how I implemented the whole thing. I created a singleton class with 2 instance variables - seed1 and seed2 - anytime I want to get a number from the first generator I use the method generator1, same for generator2 method. The seed1/2 is instantly set to a newly generated number every time so I can just continue where I left off. In conlusion, Josh Caswell gave me all the information I needed. Check out the code if you ever need something like this. The object inits with seeds 1 and 1 but during the game they get replaced with some other numbers that both devices share.
#implementation RandomNumberGenerator
#synthesize seed1,seed2;
static RandomNumberGenerator *sharedGenerator = nil;
+(RandomNumberGenerator *) sharedInstance
{
if(!sharedGenerator) {
sharedGenerator = [[RandomNumberGenerator alloc] initWithSeed1:1 andSeed2:1];
}
return sharedGenerator;
}
-(id) initWithSeed1:(int) seedOne andSeed2:(int) seedTwo{
self = [super init];
if (self)
{
seed1 = seedOne;
seed2 = seedTwo;
}
return self;
}
-(int) generator1{
srand(seed1);
int j = rand();
seed1 = j;
return abs(j);
}
-(int) generator2 {
srand(seed2);
int k = rand();
seed2 = k;
return abs(k);
}
-(int) giveRandom {
//return abs(arc4random());
return abs(arc4random());
}
#end
Did you seed your random number generator?
srand( myIdenticalSeedValueForBothPartners );
See this question or here [C++ reference].
In case you don't need to call rand() many thousand times:
int nthRandBasedOnSeed( int seed, int count ) {
srand( seed );
int result;
while( 0 < count-- ) {
result = rand();
}
return result;
}
Alternately, you might consider sending with the seed a "count". This count would simply indicate where in the seeded-series you are and would get incretented each time you generate a random number with that seed. This approach gives you the flexibility of using any random generator you like and keeps communication to a minimum.
int playerSeed = 12345;
int playerRndCount = 0;
int generateRandomNumber() {
playerRndCount++;
return rand();
}
void synchSeed(seed, count) {
srand(seed);
for (int i=0; i<count; i++)
generateRandumNumber();
}
Some random number generator libraries allow you to save the state of the generator. This way, you can restore it later, and continue with a sequence already in progress. One I know of is called RandomLib, and it can be found on SourceForge.
Another option is save the seed, and count how many times you've pulled a value from the generator after seeding. Later on when you want to continue, reseed with the original seed, and pull off the same quantity. This probably isn't the best method, but should work fine if not done a lot.

Which costs more while looping; assignment or an if-statement?

Consider the following 2 scenarios:
boolean b = false;
int i = 0;
while(i++ < 5) {
b = true;
}
OR
boolean b = false;
int i = 0;
while(i++ < 5) {
if(!b) {
b = true;
}
}
Which is more "costly" to do? If the answer depends on used language/compiler, please provide. My main programming language is Java.
Please do not ask questions like why would I want to do either.. They're just barebone examples that point out the relevant: should a variable be set the same value in a loop over and over again or should it be tested on every loop that it holds a value needed to change?
Please do not forget the rules of Optimization Club.
The first rule of Optimization Club is, you do not Optimize.
The second rule of Optimization Club is, you do not Optimize without measuring.
If your app is running faster than the underlying transport protocol, the optimization is over.
One factor at a time.
No marketroids, no marketroid schedules.
Testing will go on as long as it has to.
If this is your first night at Optimization Club, you have to write a test case.
It seems that you have broken rule 2. You have no measurement. If you really want to know, you'll answer the question yourself by setting up a test that runs scenario A against scenario B and finds the answer. There are so many differences between different environments, we can't answer.
Have you tested this? Working on a Linux system, I put your first example in a file called LoopTestNoIf.java and your second in a file called LoopTestWithIf.java, wrapped a main function and class around each of them, compiled, and then ran with this bash script:
#!/bin/bash
function run_test {
iter=0
while [ $iter -lt 100 ]
do
java $1
let iter=iter+1
done
}
time run_test LoopTestNoIf
time run_test LoopTestWithIf
The results were:
real 0m10.358s
user 0m4.349s
sys 0m1.159s
real 0m10.339s
user 0m4.299s
sys 0m1.178s
Showing that having the if makes it slight faster on my system.
Are you trying to find out if doing the assignment each loop is faster in total run time than doing a check each loop and only assigning once on satisfaction of the test condition?
In the above example I would guess that the first is faster. You perform 5 assignments. In the latter you perform 5 test and then an assignment.
But you'll need to up the iteration count and throw in some stopwatch timers to know for sure.
Actually, this is the question I was interested in… (I hoped that I’ll find the answer somewhere to avoid own testing. Well, I didn’t…)
To be sure that your (mine) test is valid, you (I) have to do enough iterations to get enough data. Each iteration must be “long” enough (I mean the time scale) to show the true difference. I’ve found out that even one billion iterations are not enough to fit to time interval that would be long enough… So I wrote this test:
for (int k = 0; k < 1000; ++k)
{
{
long stopwatch = System.nanoTime();
boolean b = false;
int i = 0, j = 0;
while (i++ < 1000000)
while (j++ < 1000000)
{
int a = i * j; // to slow down a bit
b = true;
a /= 2; // to slow down a bit more
}
long time = System.nanoTime() - stopwatch;
System.out.println("\\tasgn\t" + time);
}
{
long stopwatch = System.nanoTime();
boolean b = false;
int i = 0, j = 0;
while (i++ < 1000000)
while (j++ < 1000000)
{
int a = i * j; // the same thing as above
if (!b)
{
b = true;
}
a /= 2;
}
long time = System.nanoTime() - stopwatch;
System.out.println("\\tif\t" + time);
}
}
I ran the test three times storing the data in Excel, then I swapped the first (‘asgn’) and second (‘if’) case and ran it three times again… And the result? Four times “won” the ‘if’ case and two times the ‘asgn’ appeared to be the better case. This shows how sensitive the execution might be. But in general, I hope that this has also proven that the ‘if’ case is better choice.
Thanks, anyway…
Any compiler (except, perhaps, in debug) will optimize both these statements to
bool b = true;
But generally, relative speed of assignment and branch depend on processor architecture, and not on compiler. A modern, super-scalar processor perform horribly on branches. A simple micro-controller uses roughly the same number of cycles per any instruction.
Relative to your barebones example (and perhaps your real application):
boolean b = false;
// .. other stuff, might change b
int i = 0;
// .. other stuff, might change i
b |= i < 5;
while(i++ < 5) {
// .. stuff with i, possibly stuff with b, but no assignment to b
}
problem solved?
But really - it's going to be a question of the cost of your test (generally more than just if (boolean)) and the cost of your assignment (generally more than just primitive = x). If the test/assignment is expensive or your loop is long enough or you have high enough performance demands, you might want to break it into two parts - but all of those criteria require that you test how things perform. Of course, if your requirements are more demanding (say, b can flip back and forth), you might require a more complex solution.