Monday, July 17, 2017

cast p_sequencer m_sequencer details

We can use p_sequencer as a handle to the sequencer and through that we can access other sequencers or environment hierarchy in the sequence where uvm_declare_p_sequencer macro has been used.
Below is my understanding and relevant information. You may please correct if required.
`define uvm_declare_p_sequencer(SEQUENCER) \
SEQUENCER p_sequencer;\
virtual function void m_set_p_sequencer();\
super.m_set_p_sequencer(); \
if( !$cast(p_sequencer, m_sequencer)) \
`uvm_fatal("DCLPSQ", \
$sformatf("%m %s Error casting p_sequencer, please verify that this sequence/sequence item is intended to execute on this type of sequencer", get_full_name())) \
endfunction

p_sequencer type is specified in the argument(SEQUENCER) of `uvm_declare_p_sequencer macro.
When we call `uvm_declare_p_sequencer from sequence, it calls super.m_set_p_sequencer function, which internally will call m_set_sequencer of uvm_base_sequencer. 
When we call start task of sequence, it internally calls for set_item_context, set_item_context calls set_sequencer, set_sequencer assigns handle of sequencer (which we have passed in start task of sequence) to m_sequencer using static cast (***This is first casting or down casting)
virtual function void set_sequencer(uvm_sequencer_base sequencer);
m_sequencer = sequencer;
m_set_p_sequencer();
endfunction

set_sequencer also calls m_set_p_sequencer(declaring `uvm_declare_p_sequencer macro should override the m_set_p_sequencer hence m_set_p_sequencer defined in macro should be executed) which will cast m_sequencer back into p_sequencer using dynamic $cast. (***This is reverse casting or up casting)

MY QUESTIONs:
1. Why do we need this reverse/up casting? what is intended and achieved with this step?
2. Can we pass virtual sequencer as an argument to uvm_declare_p_sequencer inside both virtual sequence and non-virtual sequence? 
3. In case when we are using virtual sequence, and passed virtual sequencer as an argument to uvm_declare_p_sequencer inside it , when we call this virtual sequence from test , we pass null in the start task of the virtual sequence. In this case what will happen? m_sequencer = null and then , m_sequencer = p_sequencer and p_sequencer = m_sequencer , is that correct understanding? OR m_sequencer = p_sequencer and then m_sequencer = null and p_sequencer = m_sequencer , is that correct understanding?

Saturday, July 15, 2017

conc_cast_dynamic_up_vs_down

class Base;
endclass

class Exten extends Base;
endclass

program main;
  initial begin
    Base B;
    Exten E;
    B = new();
    //##E = new();          //##DEBUG: MASTER: doing this will also not allow us to down cast
    if(!$cast(E,B)) begin   //##DEBUG: MASTER: NOTE: as this unsuccessful cast will return '0' value
      $display("\n");
      $display(" Base class object B can'T be assigned to Extended class Handle.");
      $display(" So this implies 'down casting is not possible'\n");
    end
    // Deallocate object B
    //##DEBUG: MASTER: NOTICE: even if we do not include below null assignment, result will be same
    B = null;
    E = new();
    if($cast(B,E)) begin    //##DEBUG: MASTER: NOTE: as this successful cast will return '1' value
      $display(" Extended class object E can be assigned to Base class Handle.");
      $display(" So this implies 'up casting is only possible'\n");
    end
  end
endprogram

//##DEBUG: MASTER: run results
/*
ncsim> run

 Base class object B can'T be assigned to Extended class Handle.
 So this implies 'down casting is not possible'

 Extended class object E can be assigned to Base class Handle.
 So this implies 'up casting is only possible'

Simulation complete via implicit call to $finish(1) at time 0 FS + 1
*/

conc_cast_cases_updown_null_static_dynamic

class Parent ;
virtual task disp ();
    $display(" This is class Parent ");
  endtask
endclass

class Child extends Parent ;
  task disp ();
    $display(" This is class Child ");
  endtask
endclass

program main ;
  Parent P;
  Child C;

  initial
    begin
      C = new();
      $display(" DEBUG: MASTER: step1: doing P = C ");
      P=C;
      $display(" DEBUG: MASTER: step2: calling P.disp() ");
      P.disp();
      $display(" DEBUG: MASTER: step3: calling C.disp() ");
      C.disp();
      $display(" DEBUG: MASTER: step4: doing C=null ");
      C=null;
      $display(" DEBUG: MASTER: step5: doing $cast(C,P) ");
      $display(" $cast(C,P) = %b ",$cast(C,P));
      //##C=P;          //##static cast is not working !!!???
      $cast(C,P);       //##dynamic cast is working
      //##C=P;          //##static cast is not working !!!???
      $display(" DEBUG: MASTER: step6: calling C.disp() ");
      C.disp();
    end
endprogram

//## DEBUG: MASTER: run results
/*
ncsim> run
 DEBUG: MASTER: step1: doing P = C 
 DEBUG: MASTER: step2: calling P.disp() 
 This is class Child 
 DEBUG: MASTER: step3: calling C.disp() 
 This is class Child 
 DEBUG: MASTER: step4: doing C=null 
 DEBUG: MASTER: step5: doing $cast(C,P) 
 $cast(C,P) = 00000000000000000000000000000001 
 DEBUG: MASTER: step6: calling C.disp() 
 This is class Child 
Simulation complete via implicit call to $finish(1) at time 0 FS + 1
./conc_cast_updown_null_static_dynamic.sv:13 program main ; 
ncsim> exit
*/

conc_cast_p_then_null_c_then_use_casted_p

class Parent ;
virtual task disp ();
    $display(" This is class Parent ");
  endtask
endclass

class Child extends Parent ;
  task disp ();
    $display(" This is class Child ");
  endtask
endclass

program main ;
  Parent P;
  Child C;

  initial
    begin
      C = new();
      P=C;
      C = null;
      P.disp();
    end
endprogram

//##run results: DEBUG: MASTER
/*
ncsim> run
 This is class Child 
Simulation complete via implicit call to $finish(1) at time 0 FS + 1
./conc_cast_then_null_then_use_casted.sv:13 program main ; 
ncsim> exit
*/

conc_cast_staticcompile_vs_dynamicrun



class parent_;
  virtual function foo_();
     $display("I am parent with member of values ");
  endfunction
endclass

class child_ extends parent_;
   bit foo_mem;
   function foo_();
     //##void'(super.foo_());           //##DEBUG: MASTER: regardless of casting/virtual, you may want to uncomment this to see the super effect, when function returns nothing , you should use with void
     $display("I am child with member of values %d",foo_mem);
   endfunction
endclass

module foo_foo;
  parent_ parent_handle;
  parent_ parent_handle_1;
  child_ child_handle;

  initial begin
    child_handle = new();
    $cast(parent_handle,child_handle);  //##DEBUG: MASTER: This is dynamic cast and it can be called as task or func. It will return 0 at RUNTIME if not proper valid casting.
    parent_handle_1 = child_handle;     //##DEBUG: MASTER: This is static cast and will give COMPILETIME error if not proper
    void'(parent_handle_1.foo_());      //##DEBUG: MASTER: when function returns nothing , you should use with void
    void'(parent_handle.foo_());        //##DEBUG: MASTER: when function returns nothing , you should use with void
    $display("BOTH DYNAMIC AND STATIC CASTING GAVE SAME RESULT");
  end
endmodule

//##run results:
/*
ncsim> run
I am child with member of values 0      //##DEBUG: MASTER: --> function called from parent_handle_1, but after casting with child_handle
I am child with member of values 0      //##DEBUG: MASTER: --> function called from parent_handle, but after casting with child_handle
BOTH DYNAMIC AND STATIC CASTING GAVE SAME RESULT
ncsim: *W,RNQUIE: Simulation is complete.
ncsim> exit
*/

conc_cast_up_good_down_bad_parallel_not_possible

Case 1:

class B;
  virtual task print();
  $display(" CLASS B ");
  endtask
  virtual task print_master();
  $display(" MASTER ");
  endtask
endclass

class E_1 extends B;
  virtual task print();
  super.print();
  $display(" CLASS E_1 ");
  endtask
endclass

class E_2 extends B;
  virtual task print();
  $display(" CLASS E_2 ");
  endtask
endclass

program main;
  bit g1=0,g2=0,g3=0,g4=0;
  initial
  begin
    B b;
    E_1 e1;
    E_2 e2;
    e1 = new();
    g1 = $cast(b,e1);            //##DEBUG: MASTER: useful when b is not newed
    g2 = $cast(e1,b);            //##down casting is not allowed and not useful
    //##g3 = $cast(e1,e2);    //##DEBUG: MASTER: gives an error
    g4 = $cast(e2,e1);
    $display("DEBUG: g1=%0b and g2=%0b",g1,g2);
    $display("DEBUG: g3=%0b and g4=%0b",g3,g4);
    b.print();                        //DEBUG: MASTER: thus we can call any method which exists in class b
    b.print_master();           //DEBUG: MASTER: thus we can call any method which exists in class b
    e1.print();
    //##e2.print();                //DEBUG: MASTER: will give null error as its object is not created and also casting is not possible at parallel level
  end
endprogram

//##run results:
/*
ncsim> run
DEBUG: g1=1 and g2=1
DEBUG: g3=0 and g4=0
 CLASS B 
 CLASS E_1    --> this print is due to virtual effect tasks, basically parent class task get override with child class task 
 MASTER 
 CLASS B 
 CLASS E_1 
Simulation complete via implicit call to $finish(1) at time 0 FS + 1
*/

Case 2:

class B;
  task print();
  $display(" CLASS B ");
  endtask
  task print_master();
  $display(" MASTER ");
  endtask
endclass

class E_1 extends B;
  task print();
  super.print();
  $display(" CLASS E_1 ");
  endtask
endclass

class E_2 extends B;
  task print();
  $display(" CLASS E_2 ");
  endtask
endclass

program main;
  bit g1=0,g2=0,g3=0,g4=0;
  initial
  begin
    B b;
    E_1 e1;
    E_2 e2;
    e1 = new();
    g1 = $cast(b,e1);          //##DEBUG: MASTER: useful when b is not newed
    g2 = $cast(e1,b);          //##down casting is not allowed and not useful
    //##g3 = $cast(e1,e2);  //##DEBUG: MASTER: gives an error
    g4 = $cast(e2,e1);
    $display("DEBUG: g1=%0b and g2=%0b",g1,g2);
    $display("DEBUG: g3=%0b and g4=%0b",g3,g4);
    b.print(); //DEBUG: MASTER: thus we can call any method which exists in class b
    b.print_master();          //DEBUG: MASTER: thus we can call any method which exists in class b
    e1.print();
    //##e2.print();               //DEBUG: MASTER: will give null error as its object is not created and also casting is not possible at parallel level
  end
endprogram

//##run results:
/*
ncsim> run
DEBUG: g1=1 and g2=1
DEBUG: g3=0 and g4=0
 CLASS B 
 MASTER 
 CLASS B 
 CLASS E_1 
Simulation complete via implicit call to $finish(1) at time 0 FS + 1
*/

//##THUMB RULE -->  PC and C has to be new()ed, virtual will have different effect, super will have as usual effect, P=parent, C=child