Difference Between the uvm_analysis ports - uvm

Can you please help to understand the functionality and clear difference between:
uvm_analysis_export
uvm_analysis_port
uvm_analysis_imp
I have searched in internet, there are some explanations, like those:
https://verificationacademy.com/forums/uvm/uvmanalysisimp-and-uvmanalysisexport
https://www.vmmcentral.org/uvm_vmm_ik/files3/tlm1/uvm_analysis_port-svh.html
But still I feel that need more explanation. Can someone help please.

uvm_analysis_port's are the publisher, they broadcast transactions
uvm_analysis_imp's are the subscriber, they receive transactions and call a function named 'write' in the class in which they are defined.
uvm_analysis_export's can be more confusing, they are used to expose 'imp' ports at higher level of the hierarchy. For example if you have an agent which contains a component with an analysis_imp and you want to make that 'imp' available at the agent's interface level. In this situation you declare and instantiate the analysis_export in the agent class, then in the connect_phase connect the agent's analysis_export to your internal component's analysis_imp.
Its worth noting, exports are for the subscribing side, but on the publishing side regular uvm_analysis_port's can be used in the same way. So agent's can instantiate analysis_ports and connect them to an internal component's analysis_port.
This is good because it allows you to avoid reaching down into the hierarchy when you are connecting components (which makes maintenance easier):
bad:
bus_agent.internal_monitor.packet_port.connect(checker.ref_model.packet_imp)
good:
bus_agent.packet_port.connect(checker.packet_export)
Its also good to become familiar with the macro uvm_analysis_imp_decl(). It allows you to use more than one analysis_imp in a component.

Advantage for this analysis port is that a user can transfer data from a single producer to multiple consumers that is not archived with help of uvm_blocking_put_port.
This thing is also explained in the figure.
Here I provides sample code to get more clarity for uvm_analysis_port.
Remember: Port connection is used to connect two or more independent component.
This image gives explanation of uvm_analysis_port
uvm_analysis_port EXAMPLE
class transaction extends uvm_sequence_item;
`uvm_object_utils(transaction);
rand int unsigned a;
rand int unsigned b;
function new(string name ="");
super.new(name);
endfunction
endclass
class producer extends uvm_component;
`uvm_component_utils(producer);
transaction tr_inst;
uvm_analysis_port #(transaction) produce_to_consumer_p;
function new(string name ="",uvm_component parent);
super.new(name,parent);
produce_to_consumer_p = new("produce_to_consumer_p",this);
tr_inst = new("tr_inst");
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
phase.raise_objection(this);
// tr_inst.randomize();
`uvm_info(get_full_name(),"Write the data from PRODUCER",UVM_LOW);
tr_inst.a = 10; tr_inst.b = 20;
produce_to_consumer_p.write(tr_inst);
phase.drop_objection(this);
endtask
endclass
class consumer_1 extends uvm_component;
`uvm_component_utils(consumer_1);
uvm_analysis_imp#(transaction,consumer_1) write_imp_1;
function new(string name ="",uvm_component parent);
super.new(name,parent);
write_imp_1 = new("write_imp_1",this);
endfunction
function void write(transaction tr_inst);
`uvm_info(get_full_name(),"Got the data in CONSUMER_1",UVM_LOW);
`uvm_info(get_full_name(),$sformatf("The value of a = %0d and b = %0d",tr_inst.a,tr_inst.b),UVM_LOW);
endfunction
endclass
class consumer_2 extends uvm_component;
`uvm_component_utils(consumer_2);
uvm_analysis_imp#(transaction,consumer_2) write_imp_2;
function new(string name ="",uvm_component parent);
super.new(name,parent);
write_imp_2 = new("write_imp_2",this);
endfunction
function void write(transaction tr_inst);
`uvm_info(get_full_name(),"Got the data in CONSUMER_2",UVM_LOW);
`uvm_info(get_full_name(),$sformatf("The value of a = %0d and b = %0d",tr_inst.a,tr_inst.b),UVM_LOW);
endfunction
endclass
class consumer_3 extends uvm_component;
`uvm_component_utils(consumer_3);
uvm_analysis_imp#(transaction,consumer_3) write_imp_3;
function new(string name ="",uvm_component parent);
super.new(name,parent);
write_imp_3 = new("write_imp_3",this);
endfunction
function void write(transaction tr_inst);
`uvm_info(get_full_name(),"Got the data in CONSUMER_3",UVM_LOW);
`uvm_info(get_full_name(),$sformatf("The value of a = %0d and b = %0d",tr_inst.a,tr_inst.b),UVM_LOW);
endfunction
endclass
class env extends uvm_component;
`uvm_component_utils(env);
producer p_inst;
consumer_1 c_inst_1;
consumer_2 c_inst_2;
consumer_3 c_inst_3;
function new(string name="",uvm_component parent);
super.new(name,parent);
p_inst = new("p_inst",this);
c_inst_1 = new("c_inst_1",this);
c_inst_2 = new("c_inst_2",this);
c_inst_3 = new("c_inst_3",this);
endfunction
function void connect();
p_inst.produce_to_consumer_p.connect(c_inst_1.write_imp_1);
p_inst.produce_to_consumer_p.connect(c_inst_2.write_imp_2);
p_inst.produce_to_consumer_p.connect(c_inst_3.write_imp_3);
endfunction
endclass
module main();
env env_inst;
initial
begin
env_inst = new("env_inst",null);
run_test();
end
endmodule
Here is link which gives you more clarity for analysis port as well as uvm_port.
Link: http://stackoverflow.com/questions/38085875/where-to-use-uvm-blocking-put-port-and-uvm-analysis-port

Related

ctypes: Minimal type checking in object oriented C API

I am trying to wrap to python3 a very simple Object Oriented C-API. This basically follow the same pattern as:
Developing C wrapper API for Object-Oriented C++ code or,
Wrapping C++ class API for C consumption
So basically my issue is as follow, I have the following input API:
$ cat api.h
/* ns::a */
typedef struct ns_a ns_a;
ns_a* ns_a_create();
void ns_a_delete(ns_a* a);
bool ns_a_execute(ns_a* a);
/* ns::b */
typedef struct ns_b ns_b;
ns_b* ns_b_create();
void ns_b_delete(ns_b* b);
bool ns_b_run(ns_b* b);
Which I then wrap using the following steps:
class _TypeSafeHandle:
def __init__(self, ptr):
self._as_parameter_ = ptr
#classmethod
def from_param(cls, obj):
if obj.__class__ != cls:
raise ValueError(f"Not a {obj.__class__.__name__} reference")
if not obj._as_parameter_:
raise ValueError("Passing undefined instance")
return obj
#final
class _A(_TypeSafeHandle):
""" for library author, not intended to be exposed publicly """
def __init__(self, ptr):
super().__init__(ptr)
#final
class _B(_TypeSafeHandle):
def __init__(self, ptr):
super().__init__(ptr)
Given the type definition I can now expose the C-API as:
# a
ns_a_create = _func('ns_a_create', c_void_p, None, _check_ns_a)
ns_a_delete = _func('ns_a_delete', None, [_A])
ns_a_execute = _func('ns_a_execute', c_bool, [_A])
# b
ns_b_create = _func('ns_b_create', c_void_p, None, _check_ns_b)
ns_b_delete = _func('ns_b_delete', None, [_B])
ns_b_run = _func('ns_b_run', c_bool, [_B])
Using:
def _func(name, restype, argtypes, errcheck):
func = getattr(_lib, name)
func.restype = restype
func.argtypes = argtypes
func.errcheck = errcheck
return func
and:
def _check_ns_a(result, _func, _args):
if result is None:
raise MemoryError("internal memory allocation failure")
if type(result) != int:
raise TypeError("Expecting int value for pointer")
return = _A(c_void_p(result))
and
def _check_ns_b(result, _func, _args):
if result is None:
raise MemoryError("internal memory allocation failure")
if type(result) != int:
raise TypeError("Expecting int value for pointer")
return = _B(c_void_p(result))
At this step, I can now expose the class A to my user:
class A:
def __init__(self):
self._a = ns_a_create()
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
ns_a_delete(self._a)
def execute(self):
ret = ns_a_execute(self._a)
if not ret:
raise ValueError("Could not execute")
I'd like to keep the intermediate _A and _B class as implementation detail for the library author (avoid shooting in the foot passing wrong instance to wrong delete function). I find it more readable than declaring a forward declared class A:
class A: # forward declaration
pass
# _func declaration with type `A` instead of `_A`
class A:
# actual implementation detail
So my question is: is there a way to reduce code redundancy in between _A and _B ? Is there a way to reduce code redundancy in between _check_ns_a and _check_ns_b ?

What's the difference between change input arguments and creating a new object in Vprog of spark graphx

there is my program:
static class Vprog extends AbstractFunction3< Object, OddRange, OddRange, OddRange> implements Serializable {
#Override
public OddRange apply(Object l, OddRange self, OddRange sumOdd) {
System.out.println(self.getS()+self.getI()+" ---> "+sumOdd.getS()+sumOdd.getI());
self.setS(sumOdd.getS() + self.getS());
self.setI(self.getI() + sumOdd.getI());
return new OddRange(self.getS(), self.getI());
}
}
the question is if I use return new OddRange like above in class Vprog,I can change the vertexRDD
But, if I use retuen self, like:
static class Vprog extends AbstractFunction3< Object, OddRange, OddRange, OddRange> implements Serializable {
#Override
public OddRange apply(Object l, OddRange self, OddRange sumOdd) {
System.out.println(self.getS()+self.getI()+" ---> "+sumOdd.getS()+sumOdd.getI());
self.setS(sumOdd.getS() + self.getS());
self.setI(self.getI() + sumOdd.getI());
return self;
}
}
The vertexRDD didn't change.
I know RDD is immutable, but how can I update the vectexRDD in spark.graphx.pregel correctly?Can you give me any advise?
I have found the same question:
Spark Pregel is not working with Java
But I use spark 2.3.0,maybe it have the same problem?
I think I have found the answer:
We must return a new one, if we wanna change the data which will be used in next sendMsg in Vprog.
that's because Vprog changes the vertexRDD, but sendMsg uses the tripletsRDD. And what's more, the verteies in the tripletsRDD are not equels to vertexRDD, it's just a copy of vertexRDD. So,the problem is when to update the verteies in tripletsRDD when vertexRDD is changed.
We can follow the source below to find out the reason:
first part:pregel(in Pregel.scala)->joinVertices(in GraphOps.scala)->outerJoinVertices(in GraphImpl.scala)->diff(in VertexRddImpl.scala)
And then:
second part:pregel(in Pregel.scala)->mapReduceTriplets(in GraphXUtils.scala)->aggregateMessagesWithActiveSet(in GraphImpl.scala).
In first part, I found that Vprog will compare the VertexRDD data before and after execution. SO, if it is modified on the source data, they will be the same. Then a data structure named replicatedVertexView will be generated to store different VertexRDD info. If they are same, nothing will be stored.
In second part, it will update the tripletsRDD with the infomations which stored in the relicatedVertexView. And then, use the tripletsRDD in sendMsg.
So, if we don't return new in Vprog, the tripletsRDD will not be changed with VertexRDD, and the results will be wrong.

Why can't I test that a class's instance is defined

I have a helper class which creates instance of another class
class TestEnv {
val questionsController = new QuestionsController(...)
}
I am unit testing QuestionsController and have created a basic test case
class QuestionsControllerUnitSpec extends PlaySpec with BeforeAndAfterAll with BeforeAndAfterEach with OneAppPerSuiteWithComponents{
override def beforeEach() = {
println("------------new test -----------------")
}
override def components: BuiltInComponents = new BuiltInComponentsFromContext(context) with NoHttpFiltersComponents {
import play.api.mvc.Results
import play.api.routing.Router
import play.api.routing.sird._
lazy val router: Router = Router.from({
case GET(p"/") => defaultActionBuilder {
Results.Ok("success!")
}
})
}
"Question Controller " should {
"be created" in {
val testEnv = new TestEnv(components = components)
val qc:QuestionsController = testEnv.questionsController
qc mustBe defined //I get compilation error
}
}
}
I get the following compilation error
Error:(52, 10) could not find implicit value for parameter definition: org.scalatest.enablers.Definition[controllers.QuestionsController]
qc mustBe defined
Error:(52, 10) not enough arguments for method mustBe: (implicit definition: org.scalatest.enablers.Definition[controllers.QuestionsController])org.scalatest.Assertion.
Unspecified value parameter definition.
qc mustBe defined
I checked the definition of mustBe in MustMatchers.class. It is defined as def mustBe(right : org.scalatest.words.DefinedWord)(implicit definition : org.scalatest.enablers.Definition[T]) : org.scalatest.Assertion = { /* compiled code */ }
Why am I getting the error.
defined matcher syntax can be used with user defined types if we provide implicit implementation of Definition trait. For example, say we have a user defined class
class Foo {
val bar = 3
}
and we provide implicit definition
implicit val fooDefinition = new Definition[Foo] {
override def isDefined(foo: Foo): Boolean = foo.bar != null
}
then we can use defined syntax
(new Foo()) mustBe defined
If similar implicit implementation of Definition[QuestionsController] is provided, then the compiler error should be resolved.
I am happy to accept a different answer if it can provide more accurate answer. I suppose I am testing the wrong thing. What I am doing is similar to declaring an integer and checking if the integer exists! Instead I should be checking the value of the integer.
About matchers, more information is at http://doc.scalatest.org/3.0.1/#org.scalatest.MustMatchers. More information on Definition is on http://doc.scalatest.org/3.0.1/#org.scalatest.enablers.Definition

Where to use uvm_blocking_put_port and uvm_analysis_port?

What is the difference between port and analysis port ?
Where to use uvm_blocking_put_port and where to use uvm_analysis_port ?
What is advantage of uvm_analysis_port over uvm_blocking_put_port ?
Port connection is used to connect two independent blocks(components).
Both uvm_blocking_put_port and uvm_analysis_port used to transfer data from producer to consumer.
(1) uvm_blocking_put_port:
Used for data transfer from a single producer to a single consumer.
(2) uvm_analysis_port:
Used for data transfer from a single producer to a single consumer or multiple consumers.
Advantage for this analysis port is that a user can transfer data from a single producer to multiple consumers that is not archived with help of uvm_blocking_put_port.
This thing is also explained in the figure.
Here I provide sample code to get more clarity for uvm_blocking_put_port and uvm_analysis_port.
This image explain use of uvm_blocking_put_port
Remember: Port connection is used to connect two or more independent component.
(1) uvm_blocking_put_port EXAMPLE.
class transaction extends uvm_sequence_item;
`uvm_object_utils(transaction);
rand int unsigned a;
rand int unsigned b;
function new(string name ="");
super.new(name);
endfunction
endclass
class producer extends uvm_component;
`uvm_component_utils(producer);
transaction tr_inst;
uvm_blocking_put_port #(transaction) produce_to_consumer_p;
function new(string name ="",uvm_component parent);
super.new(name,parent);
produce_to_consumer_p = new("produce_to_consumer_p",this);
tr_inst = new("tr_inst");
endfunction
task run_phase(uvm_phase phase) ;
super.run_phase(phase);
phase.raise_objection(this);
//tr_inst.randomize();
`uvm_info(get_full_name(),"Write the data from PRODUCER",UVM_LOW)
tr_inst.a = 10; tr_inst.b = 20;
produce_to_consumer_p.put(tr_inst);
phase.drop_objection(this);
endtask
endclass
class consumer extends uvm_component;
`uvm_component_utils(consumer);
uvm_blocking_put_imp#(transaction,consumer) put_imp;
//transaction tr_inst;
function new(string name ="",uvm_component parent);
super.new(name,parent);
put_imp = new("put_imp",this);
endfunction
function void put(transaction tr_inst);
`uvm_info(get_full_name(),"Got the data in CONSUMER",UVM_LOW);
`uvm_info(get_full_name(),$sformatf("the value of a %0d and b is %0d",tr_inst.a,tr_inst.b),UVM_LOW);
endfunction
endclass
class env extends uvm_component;
`uvm_component_utils(env);
producer p_inst;
consumer c_inst;
function new(string name="",uvm_component parent);
super.new(name,parent);
p_inst = new("p_inst",this);
c_inst = new("c_inst",this);
endfunction
function void connect();
p_inst.produce_to_consumer_p.connect(c_inst.put_imp);
endfunction
endclass
module main();
env env_inst;
initial
begin
env_inst = new("env_inst",null);
run_test();
end
endmodule
This image gives explanation of uvm_analysis_port
(2) uvm_analysis_port EXAMPLE
class transaction extends uvm_sequence_item;
`uvm_object_utils(transaction);
rand int unsigned a;
rand int unsigned b;
function new(string name ="");
super.new(name);
endfunction
endclass
class producer extends uvm_component;
`uvm_component_utils(producer);
transaction tr_inst;
uvm_analysis_port #(transaction) produce_to_consumer_p;
function new(string name ="",uvm_component parent);
super.new(name,parent);
produce_to_consumer_p = new("produce_to_consumer_p",this);
tr_inst = new("tr_inst");
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
phase.raise_objection(this);
// tr_inst.randomize();
`uvm_info(get_full_name(),"Write the data from PRODUCER",UVM_LOW);
tr_inst.a = 10; tr_inst.b = 20;
produce_to_consumer_p.write(tr_inst);
phase.drop_objection(this);
endtask
endclass
class consumer_1 extends uvm_component;
`uvm_component_utils(consumer_1);
uvm_analysis_imp#(transaction,consumer_1) write_imp_1;
function new(string name ="",uvm_component parent);
super.new(name,parent);
write_imp_1 = new("write_imp_1",this);
endfunction
function void write(transaction tr_inst);
`uvm_info(get_full_name(),"Got the data in CONSUMER_1",UVM_LOW);
`uvm_info(get_full_name(),$sformatf("The value of a = %0d and b = %0d",tr_inst.a,tr_inst.b),UVM_LOW);
endfunction
endclass
class consumer_2 extends uvm_component;
`uvm_component_utils(consumer_2);
uvm_analysis_imp#(transaction,consumer_2) write_imp_2;
function new(string name ="",uvm_component parent);
super.new(name,parent);
write_imp_2 = new("write_imp_2",this);
endfunction
function void write(transaction tr_inst);
`uvm_info(get_full_name(),"Got the data in CONSUMER_2",UVM_LOW);
`uvm_info(get_full_name(),$sformatf("The value of a = %0d and b = %0d",tr_inst.a,tr_inst.b),UVM_LOW);
endfunction
endclass
class consumer_3 extends uvm_component;
`uvm_component_utils(consumer_3);
uvm_analysis_imp#(transaction,consumer_3) write_imp_3;
function new(string name ="",uvm_component parent);
super.new(name,parent);
write_imp_3 = new("write_imp_3",this);
endfunction
function void write(transaction tr_inst);
`uvm_info(get_full_name(),"Got the data in CONSUMER_3",UVM_LOW);
`uvm_info(get_full_name(),$sformatf("The value of a = %0d and b = %0d",tr_inst.a,tr_inst.b),UVM_LOW);
endfunction
endclass
class env extends uvm_component;
`uvm_component_utils(env);
producer p_inst;
consumer_1 c_inst_1;
consumer_2 c_inst_2;
consumer_3 c_inst_3;
function new(string name="",uvm_component parent);
super.new(name,parent);
p_inst = new("p_inst",this);
c_inst_1 = new("c_inst_1",this);
c_inst_2 = new("c_inst_2",this);
c_inst_3 = new("c_inst_3",this);
endfunction
function void connect();
p_inst.produce_to_consumer_p.connect(c_inst_1.write_imp_1);
p_inst.produce_to_consumer_p.connect(c_inst_2.write_imp_2);
p_inst.produce_to_consumer_p.connect(c_inst_3.write_imp_3);
endfunction
endclass
module main();
env env_inst;
initial
begin
env_inst = new("env_inst",null);
run_test();
end
endmodule

How to initialize an Option array to None in Scala

I have defined a class in Scala (2.9.1) as follows:
class A(val neighbors: Array[Option[A]]) {
def this() = this(new Array[Option[A]](6))
// class code here ...
}
My problem is that neighbors is initialized with nulls, when I would like it to be initialized with None. I tried this, but the compiler complains with the error message "not found: type None":
class A(val neighbors: Array[Option[A]]) {
def this() = this(new Array[None](6))
// class code here ...
}
I can do this, which gives the desired behavior, but it doesn't seem very elegant:
class A(val neighbors: Array[Option[A]]) {
def this() = this(Array(None, None, None, None, None, None))
// class code here ...
}
So, my question is, what is the best way to do this?
EDIT: I am referring to the behavior when new A() is called.
The easiest way to do this would be
Array.fill(6)(None:Option[A])
Additionally you can change your class's constructor to take a default parameter like this:
class A(val neighbors: Array[Option[A]] = Array.fill(6)(None))
Maybe like this?
def this() = this(Array.fill(6) {Option.empty})

Resources