One IMP_PORT connected to multiple EXPORTS - system-verilog

I am creating a scoreboard which has a single implication port. I want to connect multiple exports from a parent class to the same imp port of the scoreboard class I am writing. Essentially (in pseudo-code):
class parent_class extends uvm_scoreboard;
uvm_analysis_export #(my_type) export0;
uvm_analysis_export #(my_type) export1;
uvm_analysis_export #(my_type) export2;
uvm_analysis_export #(my_type) export3;
my_scoreboard m_scb;
function void connect_phase(uvm_phase phase);
export0.connect(m_scb.my_imp);
export1.connect(m_scb.my_imp);
export2.connect(m_scb.my_imp);
export3.connect(m_scb.my_imp);
endfunction
endclass
class my_scoreboard extends uvm_scoreboard;
uvm_analysis_imp#(my_type) my_imp;
function void write (my_type);
// do something here
endfunction
endclass
This works fine but I am wondering now, if we get 2 or 3 or 4 transactions broadcasted from their ports on the same clock cycle, will the write function be called twice/thrice/4times? This is the behaviour I would want.
I don't have a dependency on the order in which they are called but don't want to miss a broadcast because of my setup.

Yes, you can have multiple write()s called in an indeterminate order. If the scoreboard needs to know which port it came from, you will have to put that information in the transaction.

Related

Understanding virtual interfaces with classes

I am studying SystemVerilog for verification purposes and stumbled upon virtual interfaces and classes. I am trying to set up an example where I define a virtual interface attribute in a class to be initialized through a method. It looks like this:
class myclass;
virtual interface my_intf val;
...
function void configure(virtual interface my_intf input_intf);
val = input_intf;
endfunction
...
endclass
An object of this class is instantiated in a testbench that has the interface I intend to pass on to the object as an input.
module mytb(my_intf bus);
...
myclass c1;
initial
begin
c1 = new;
c1.configure(bus);
...
endmodule
What I am encountering is a warning at elaboration time that says [related to c1.configure(bus)] formal and actual do not have assignment compatible data types (expecting datatype compatible with 'virtual interface my_intf' but found 'my_intf' instance instead. Nevertheless, the simulation ends with success, and I made sure to follow the code presented in the course I am attending. Is there anything I am still missing or can I neglect this warning?
Thanks!
I have looked more into my code and found out that it had to do with the fact that the testbench uses a specific configuration of the interface defined through a modport and I had to make sure that I extended that to the class too. In short, the testbench receives a my_intf.intf1 bus interface and this caused the tool to complain as it was expecting my_intf but got my_intf.intf1 instead.
Thanks everyone
You missing a lot of code, so it it difficult to figure out what is going one.
However, for references the following code works:
class myclass;
virtual interface my_intf val;
function void configure(virtual interface my_intf input_intf);
val = input_intf;
endfunction
endclass
module mytb(my_intf bus);
myclass c1;
initial
begin
c1 = new;
c1.configure(bus);
end
endmodule
interface my_intf;
endinterface
module top;
my_intf intf();
mytb mytb(intf);
endmodule
Few rules of thumb:
an interface must be defined as intercface..endinterface and it must be visible in all parts of compilation (can be declared after it is used, similarly to moduels). See code example.
the interface must be instantiated in a module, e.g. in module top of the example.
Note, similar issues as you described can happen if you incorrectly use compilation units.
I'm not familiar with SystemVerilog, but I've just RFTM around and the right syntax is:
virtual interface_name instance_name;
So maybe you should try something like this:
virtual my_intf val;
function void configure(virtual my_intf val);
this.val = val;
endfunction
...
endclass
See https://verificationguide.com/systemverilog/systemverilog-virtual-interface/#What_is_the_need_for_a_virtual_interface_in_SystemVerilog

Define order of "Parallelizable" in NUnit

Im having 4 test classes inside one project (Lets call them Class A, Class B, Class C, Class D)
Each of these 3 classes have two [TestFixture("string")], which makes it to 8 tests in total.
All classes are having the [Parallelizable] parameter.
When i start the test all at once by clicking inside the Test Explorer on the name of the project and "Run", then it will start all 8 tests at the same time.
The problem here is, that it consumes a lot RAM and the tests fail because it takes too long to load and i get a timeout error (Im doing automation tests with selenium in chrome)
Now i want to define a order.
For example:
Class A and Class B should start parallel
Class C and Class D should start parallel when Class A and Class B is done
Is it possible?
I tried the parameter [Order(1)] for Class A and Class B and Order(2)] for Class C and Class D
But when i run the tests, all 8 tests start to load.
Example from my code:
[TestFixture("normalUser")]
[TestFixture("adminUser")]
[Parallelizable]
public class ImportTest
{
private IWebDriver webDriver;
private const int waitTimer = 60;
public WebDriverWait w;
public string userRole;
// Constructor
public ImportTest(string userRole)
{
this.userRole = userRole;
Console.WriteLine(userRole);
}
////-----------------------------
[SetUp]
{
}
//-------------------------------
[Test]
public void Test1()
{
Do Test
}
[Test]
public void Test2()
{
Do Test
}
//--------------------------
[TearDown]
public void CloseBrowser()
{
webDriver.Quit();
}
}
First, I'll describe what's happening...
The OrderAttribute was created in NUnit V2, before parallel tests existed. It defines the order in which tests are started. Since there was no parallelism at the time, one test had to finish before the next one started.
When parallel execution was introduced in NUnit 3, Order was not exactly broken, because it continued to start tests in the specified order. But many users perceptions were "broken", because they thought that one test would not start until the prior one finished.
Order could, of course, be changed to work like that. However, at this point, that would be a breaking change for some people, so you most likely won't see it happen until there's an NUnit 4.
So... what can you do as a workaround? I can see three options...
The simplest approach would be to make each fixture [NonParallelizable]. Then they would all run separately. You should try that first and see if the performance is acceptable to you. If you want the tests within each fixture to run in parallel, you could use [Parallelizable(ParallelScope.Children)] instead but that might break things if the tests change the state of the fixture or of any common references found in the fixture.
Alternatively, you could pick only some fixtures to mark as [NonParallelizable]. In that case, I'd do it for the ones that consume a lot of memory.
For the most effort required, you could implement ordering yourself for these classes. I'd do that by creating some sort of shared token... e.g. a lock... which each class had to acquire on startup. I'd grab the lock in the OneTimeSetUp for a fixture and release it in the onetime teardown. The locking code should be before any setup code, which acquires resources and should be released after your teardown releases those resources.
I made option 3 rather sketchy because (a) I don't know precisely how your application works and (b) I presume that you won't do it unless it's absolutely necessary.
Final advice: don't make any assumptions about the performance impact of any of these options, even the first. Measure first!

What causes 'interface resolution' compilation error when working with classes and virtual interfaces

I have declared in a design file following interfaces:
interface t_clocks;
ckrs_t ClkRs125MHz_ix;
ckrs_t ClkRs160MHz_ix;
ckrs_t [3:0] ClkRsLink_ixb;
ckrs_t ClkRsLinkx2_ixb;
logic tdclk_sampling;
modport producer(output ClkRs125MHz_ix,
output ClkRs160MHz_ix,
output ClkRsLink_ixb,
output tdclk_sampling);
modport consumer(input ClkRs125MHz_ix,
input ClkRs160MHz_ix,
input ClkRsLink_ixb,
input tdclk_sampling);
endinterface // clocks
interface t_bst(input ckrs_t ClkRs_ix);
tb_t mark;
modport consumer(input ClkRs_ix, input mark);
modport producer(output ClkRs_ix, output mark);
endinterface // t_bst
and in a package classes working with those interfaces:
package clspkg;
import DefinitionsPkg::*;
class bst_generator;
virtual t_bst.producer bst_master;
....
endclass // bst_generator
class clock_generator;
virtual t_clocks.producer clk_tree;
....
endclass // clock_generator
endpackage // clspkg
I have glued all together in the testbench, using only clock_generator class from the package:
module tb_turn_emulator;
import clspkg::*;
t_clocks clk_tree();
clock_generator cgen;
// ???????????????
//t_bst blast_radius(clk_tree.ClkRs160MHz_ix);
default clocking cb #(posedge clk_tree.ClkRs160MHz_ix.clk); endclocking
`TEST_SUITE begin
`TEST_SUITE_SETUP begin
cgen = new;
cgen.clk_tree = clk_tree;
cgen.run();
##10;
end
....
endmodule
Now, when I try to compile such example, it FAILS with Virtual interface resolution cannot find a matching instance for 'virtual t_bst.producer'
It took me quite some time to find out, that if I instantiate as well the t_bst interface in the testbench module (uncommenting the t_bst line in the code above), everything goes smoothly, no compilation error and the testbench passes as usual.
I don't understand why the t_bst interface has to be instantiated as it is not at all used in code. It is true that I am importing the entire clspkg package, but nothing changes when I cherry pick by importing only the clock_generator by import clspkg::clock_generator.
What is wrong? I'm using Mentor Modelsim
First about using packages:
Once you import one identifier or every identifier from a package in a design, the entire package exists in your design. That means all the static variables get allocated and initialized, as well as all the code for tasks and functions get generated. If static variable initializations call functions like class constructors, that implies executing procedural code without ever referencing it directly. (For those of you familiar with the factory design pattern and UVM, this is exactly how factory registration works.)
Next about using interfaces:
Like a module, an interface is a design element containing definitions of lots of different things. They can define variables, routines, import other packages, and have port connections. But nothing inside an interface exists or generates any code in a design until other design unit instantiates it, or in the case of a module, gets established as a top-level instance.
Now about using virtual interfaces:
Virtual interface are the primary method used to bridge the two kingdoms of the dynamic class based testbench world with the static instance based design world. Virtual interfaces behave much like a class type, except that there is no rule to have seen a definition of the interface before using it in your code. Hierarchical reference also have this capability of referencing something that does not exist at the point of compilation, but must be resolved later in the elaboration phase of compilation.
To summarize, the compiler generates code for a virtual interface once it sees a reference to it whether you actually think you are using it or not. I would try to align packages with specific interfaces they are associated with.
From SV LRM (25.9 Virtual interfaces):
A virtual interface is a variable that represents an interface instance.
A virtual interface shall be initialized before referencing a component of the virtual interface; it has the value null before it is initialized. Attempting to use a null virtual interface shall result in a fatal run-time error.
I hope it answers to your question.

UVM- run test() in top block and Macros

I'm reading the following guide:
https://colorlesscube.com/uvm-guide-for-beginners/chapter-3-top-block/
In Code 3.2 line 24- run_test();
I realized that it supposed to execute the test, but how it know which test, and how, and why should I write it in the top block.
In Code 4.1 lines 11-14 (https://colorlesscube.com/uvm-guide-for-beginners/chapter-4-transactions-sequences-and-sequencers/):
`uvm_object_utils_begin(simpleadder_transaction)
`uvm_field_int(ina, UVM_ALL_ON)
`uvm_field_int(inb, UVM_ALL_ON)
`uvm_field_int(out, UVM_ALL_ON)
`uvm_object_utils_end
Why should I add the "uvm_field_int" , what would happend if i didn't add them, and what is "UVM_ALL_ON"?
run_test is a helper global function , it calls the run_test function of the uvm_root class to run the test case. There are two ways by which you can pass the test name to the function.The first is via the function argument and the second is via a command line argument. The command line argument takes precedence over the test name passed via the function argument.
+UVM_TESTNAME=YOUR_TEST_NAME
run_test("YOUR_TEST_NAME");
run_test function in the uvm_root uses the factory mechanism to create the appropriate instance of the umm_test class and so the test case must register itself with the factory using the macro `uvm_component_utils for the factory mechanism (create_component_by_name) to function.
class YOUR_TEST_NAME extends umm_test ;
// register the class with the factory
// so that run_test can find this class when the
// string test_name is passed to it.
`uvm_component_utils(YOUR_TEST_NAME)
.....
endclass
The run_test function then kicks of the uvm_phases (..,build_phase,connect_phase,...) starting the uvm portion of the simulation. There should be no time ticks consumed before the run_phase starts , so it is essential that run_test case is called in the initial block itself. Also we want the uvm and test bench to be ready to drive and receive data as soon as the RTL is ready for which it is essential that we start the run_test at the earliest. Any delay in doing so will generate an error.
`uvm_field_int/uvm_field_object/.. are called field automation macros. They are not mandatory in the class definition and are provided as a helper macros to ease the use of many common/routine functions of the uvm_object. Examples of thse functions in uvm_object are - copy,compare,pack,unpack,print, etc and these macros generate code to automatically use these functions.
If you are not using the uvm_object common functions leaving out these macros from the class definition will not produce any errors.
In case you implement you own version of the common operations you can also leave out these macros from the class.
UVM_ALL_ON - enables all functions like compare/copy/... to be implemented for the particular field.
link with examples -
http://www.testbench.in/UT_04_UVM_TRANSACTION.html
For example the uvm_object has a compare function which compare two instances of the same class and return true if all the variables in the class are equal.
virtual function bit do_compare( uvm_object rhs, uvm_comparer comparer );
.....
// return 1 if all the variables match
return ( super.do_compare( rhs, comparer ) &&
this.var_1 == rhs.var_1 &&
this.var_2 == rhs.var_2 &&
......
this.var_n == rhs.var_n );
endfunction: do_compare
// use in main code
if ( new_class.compare(old_classs) )
...
//instead of
if ( new_class.var1 == old_class.var1 && new_class.var2 == old_class.var2 && ... new_class.varn == old_class.varn )
...
The above compare has to be written for each class and updated and maintained for every new variable that is added to the class. This could become error prone as newer variables are added. A similar process has to be followed for all the standard functions uvm_object provides.
The field automation macro generates function to address all these functionality automatically. So doing a do_print for a class with the macros will print out all the fields without explicitly writing any code for it.
// compare/print/.. functions for class simpleadder_transaction are provided by using `uvm_field_int macro.
`uvm_object_utils_begin(simpleadder_transaction)
`uvm_field_int(ina, UVM_ALL_ON)
`uvm_object_utils_end
BUT a word of caution , the use of these macros are discouraged as they add a significant amount of code into the class.. Most of these functions may not be needed by the class yet they get generated by default.
run_test is defined in the documentation (link) as:
virtual task run_test (
string test_name = ""
)
So, in principle, you can state there the test name as a string. But what's usually done is to pass it in the command line of your simulator using the argument: +UVM_TESTNAME=TEST_NAME
The uvm_object macros are a bit more complicated. They generate several methods and more importantly they register the object in the UVM factory, which is what makes them necessary (at least if you are using, as you should, the factory to create them). Citing from the UVM Class Reference documentation (Section 20.2 Component and Object Macros):
Simple (non-parameterized) objects use the uvm_object_utils* versions,
which do the following:
Implements get_type_name, which returns TYPE as a string
Implements create, which allocates an object of type TYPE by calling its constructor with no arguments. TYPE’s constructor, if
defined, must have default values on all it arguments.
Registers the TYPE with the factory, using the string TYPE as the factory lookup string for the type.
Implements the static get_type() method which returns a factory proxy object for the type.
Implements the virtual get_object_type() method which works just like the static get_type() method, but operates on an already
allocated object.

Passing variables across classes with objects

Alright so I've been continuing to learn about classes and oop languages. And am a bit confused.
If I was to have a separate class for player stats. And in that class I have some private ints and then some functions to change them publicly.
Say I want to change and get those ints From my main class. I make an object and assign them to local variables then I can call the local variables in my main script. Then update the variable in the stat class.
It seems a little silly that I have to make a local variable as well as a separate variable in a different class.
To me it would make sense to just be able to call the separate class in a new object whenever I wanted to access the variables in the stat class but I can't...
Let me know if this isn't clear as I can try to expand more.
Thanks
Ben
You do not have to make new variables in the "main" class ....
you can just use the getters and setters through the object that you created.
Also copying variables from player stats to main class is not a good idea because now you have to maintain two copies of same data, at least until you are in scope of main class. If not handled correctly it can also cause data inconsistencies.
Assuming you are using Java, you can do this.
public class PlayerStats{
private int var1=20;
public void setVar1(int var1){
this.var1=var1
}
public int getVar1(){
return var1
}
}
public class mainClass{
PlayerStats pStats = new PlayerStats();
pStats.getVar1();
pStats.setVar1(14);
System.out.println(pStats.getVar1());
}
Thanks for that answer definately cleared things up however, in the object created in mainClass if I create the object in one function how do I use it in another function in the same class?
Depends on how and if the two functions are connected and how central that object is to your class.
If the object is very central to class :
That is, you are using it almost in all the function, your class revolves around playing with that object, then you can create it at class level something along these lines
public class mainClass{
PlayerStats pStats = new PlayerStats();
public void function1() {
pStats.setVar1(14);
System.out.println(pStats.getVar1());
}
public void function2(int x) {
pStats.setVar1(x);
System.out.println(pStats.getVar1());
}
}
If two functions are not connected :
Just make a new object inside the function scope, if possible.
This is better than creating an object at class level, because the object becomes eligible for garbage collection after the function is finished executing. Whereas, the object created at class level stays in the memory as long as the object (instance of main class) is in the memory.
If two functions are connected, i.e you are calling one function from inside the second function :
you can just pass the object as an argument, something along these lines
public class mainClass{
public void function1() {
PlayerStats pStats = new PlayerStats();
pStats.setVar1(14);
function2(pStats)
}
public void function2(PlayerStats x) {
System.out.println(pStats.getVar1());
}
}
Also google dependency injection, it is an important concept, try to use it as often as possible. It produces good decoupled and testable design
There is so much more to say, people have written books on this topic, OO Design is an art in itself.