Akhila

UVM-SC Sequence getting stuck at wait_for_grant()

7 posts in this topic

Hi Guys,

I have a simple framework for an IP level testbench, written using UVM-SC libraries. The intent is to be able to pump basic AHB write/read request to the DUT(in System C) using this BFM. I have created all basic components, snippet for which are pasted below. 

I have an ahb_sequencer, which is just an extension oh uvm_sequencer with specific ahb_transaction type.

In ahb_driver run_phase is as under:

void run_phase(uvm::uvm_phase phase) 
        {
            REQ req, rsp;
            for(;;)
            { 

               UVM_INFO(this->get_name(), "run_phase Entered", UVM_LOW);
                this->seq_item_port->get_next_item(req);

                 rsp.set_id_info(req);
                 this->seq_item_port->item_done();
                 this->seq_item_port->put_response(rsp);

             }

         }

In ahb_env, driver and seqr are connected and sequences are started.

class ahb_basic_env : public uvm::uvm_env
{
    public:
        ahb_driver<ahb_transaction>* ahb_driver_inst;
        ahb_sequencer<ahb_transaction>* ahb_sequencer_inst;
        ahb_basic_write_sequence* ahb_wr_seq[NUM_SEQS];

        UVM_COMPONENT_UTILS(ahb_basic_env);
        ahb_basic_env( uvm::uvm_component_name name) : uvm::uvm_env(name)
        {
         std::cout << sc_core::sc_time_stamp() << ": constructor " << name << std::endl;
        }

        void build_phase(uvm::uvm_phase& phase)
        {
          std::cout << sc_core::sc_time_stamp() << ": build_phase " << name() << std::endl;

          uvm::uvm_env::build_phase(phase);
          
                UVM_INFO(this->get_name(), " is ACTIVE", UVM_LOW);

                ahb_sequencer_inst = ahb_sequencer<ahb_transaction>::type_id::create("ahb_sequencer_inst",this);
                assert(ahb_sequencer_inst);

                ahb_driver_inst = ahb_driver<ahb_transaction>::type_id::create("ahb_driver_inst",this);
                assert(ahb_driver_inst);

          for (int i = 0; i < NUM_SEQS; i++)
          {
              std::ostringstream str;
              str << "ahb_basic_write_sequence" << i;
              ahb_wr_seq = new ahb_basic_write_sequence(str.str());
          }
        }

        void connect_phase(uvm::uvm_phase& phase)
        {
          std::cout << sc_core::sc_time_stamp() << ": connect_phase " << name() << std::endl;
          uvm::uvm_component::connect_phase(phase);
          ahb_driver_inst->seq_item_port(ahb_sequencer_inst->seq_item_export);
        }

        void run_phase(uvm::uvm_phase& phase) 
        {
          phase.raise_objection(this);
          std::cout << sc_core::sc_time_stamp() << ": run_phase Entered " << name() << std::endl;
 
          SC_FORK
              sc_core::sc_spawn(sc_bind(&ahb_basic_env::start_sequence, this, 0)),
              sc_core::sc_spawn(sc_bind(&ahb_basic_env::start_sequence, this, 1)),
          SC_JOIN
          std::cout << sc_core::sc_time_stamp() << ": run_phase Exited " << name() << std::endl;
          phase.drop_objection(this);
        }
        void start_sequence(int n)
        {
          ahb_wr_seq[n]->start(ahb_sequencer_inst, NULL);
        }


};

 

The sequence uses wait_for_grant() and start_item() calls to initiate the transaction:


class ahb_basic_write_sequence : public uvm::uvm_sequence<ahb_transaction,ahb_transaction>
{
    public:
        ahb_basic_write_sequence( const std::string& name = "ahb_basic_write_sequence") : uvm::uvm_sequence< ahb_transaction,ahb_transaction > ( name )
        {
            std::cout << sc_core::sc_time_stamp() << ": constructor " << name << std::endl;
            
        }
        UVM_OBJECT_UTILS(ahb_basic_write_sequence);
  
        void pre_body()
        {
          // raise objection if started as a root sequence
          if(this->starting_phase != NULL)
            this->starting_phase->raise_objection(this);
        }

        void body() 
        {

            ahb_transaction* req_pkt;
            ahb_transaction* rsp;
            unsigned transaction_numb;

            UVM_INFO(this->get_name(), "Starting sequence ahb_basic_write_sequence", uvm::UVM_INFO);
            
            transaction_numb = 10;

            for(unsigned int i = 0; i < transaction_numb; i++) {
                req_pkt = new ahb_transaction();
                rsp     = new ahb_transaction();

                UVM_INFO(this->get_name(), "Sending transaction from sequence ahb_basic_write_sequence", uvm::UVM_INFO);
                req_pkt->haddr  = 0x100000 + 4*i;
                req_pkt->hwrite = 1;
                //req_pkt->hwrite = ahbConfig::WRITE_XACT;
                req_pkt->htrans = 2;
                //req_pkt->htrans = ahbConfig::HTRANS_NONSEQ;
                req_pkt->hwdata = (sc_uint<32>)(0xAAAABBBB + 4*i);
                req_pkt->hsize  = ahbConfig::HSIZE_WORD;
                this->wait_for_grant();
                UVM_INFO(this->get_name(), "Calling send_request from sequence ahb_basic_write_sequence", uvm::UVM_INFO);
                this->send_request(req_pkt);
                UVM_INFO(this->get_name(), "Getting response from sequence ahb_basic_write_sequence", uvm::UVM_INFO);
                this->get_response(rsp);
            }
            UVM_INFO(this->get_name(), "Finishing sequence", uvm::UVM_INFO);
        }
        
        void post_body()
        {
          // drop objection if started as a root sequence
          if(this->starting_phase != NULL)
            this->starting_phase->drop_objection(this);
        }

};

But when i run the code, it gets stuck at wait_for_grant() call and also I don't see the run_phase prints from the driver class.

The output looks something like this:

Starting SC tests ...                                                                                                  
Running AHB tests                                                                                                      
0 sIn dut
UVM_INFO @ 0 s: reporter [RNTST] Running test ...
0 s: build_phase tb
UVM_INFO ahb_basic_env.h(65) @ 0 s: tb [tb]  is ACTIVE
0 s: constructor ahb_sequencer_inst
0 s: constructor ahb_driver_inst
0 s: constructor ahb_basic_write_sequence0
0 s: constructor ahb_basic_write_sequence1
UVM_INFO ahb_driver.h(53) @ 0 s: reporter [ahb_driver_inst] build_phase Entered
0 s: connect_phase tb

Info: (I804) /IEEE_Std_1666/deprecated: all waits except wait() and wait(N)
             are deprecated for SC_CTHREAD, use an SC_THREAD instead
0 s: run_phase Entered tb
UVM_INFO ahb_basic_write_sequence.h(66) @ 0 s: reporter [ahb_basic_write_sequence0] Starting sequence ahb_basic_write_sequence
UVM_INFO ahb_basic_write_sequence.h(76) @ 0 s: reporter [ahb_basic_write_sequence0] Sending transaction from sequence ahb_basic_write_sequence
UVM_INFO ahb_basic_write_sequence.h(66) @ 0 s: reporter [ahb_basic_write_sequence1] Starting sequence ahb_basic_write_sequence
UVM_INFO ahb_basic_write_sequence.h(76) @ 0 s: reporter [ahb_basic_write_sequence1] Sending transaction from sequence ahb_basic_write_sequence

 

 

Any idea why is this happening? wait_for_grant() should unblock when driver takes the request right? Not sure why isnt the driver getting the request.

Appreciate your help here!

TIA

PS: Attached the files for reference.

Akhila
                
                
               

ahb_basic_write_sequence.h

ahb_basic_env.h

ahb_driver.h

ahb_sequencer.h

Share this post


Link to post
Share on other sites

Hi Guys,

 

Not sure if someone else has faced similar issue. After little more debug the issue seems to be with the simulator not entering into driver's run_phase at all. Ideally all run phases should be executed in parallel. Currently it gets stuck after the sequence raises objection and times out.

Please let me know if I can try some alternatives.

Thanks

Akhila

Share this post


Link to post
Share on other sites

Hi All,

I found one basic issue with the run phase method in driver. There was a typo. I used run_phase(uvm_phase phase), instead of run_phase(uvm_phase& phase).

So the phase was not passed by reference, hence I think the phases in driver class were not in sync with other classes. 

Sorry about that, i too spent a lot of time in figuring this out :(.

Now I can see that the simulation enters all run_phases (i.e. of test and driver) and exits after the sequence is over. But even though all phases are exited, the simulation is getting stuck. 

I believe in UVM-SC also we look for objections and exit if there is none after the run phase? Is there a way to query for raised objections? Tried using get_obejctions method, but faced some error.

Thanks

Akhila

Share this post


Link to post
Share on other sites

Hello All,

Another update from my side here:

I could query the objections in final_phase of my test and saw that there were no pending ones. I had to explicitly call sc_stop() and only then end_of_simulation method was called by the simulator. is it the expected behavior?

Pasted the updated methods in my test:

virtual void final_phase(uvm::uvm_phase& phase)
        {
          std::cout << sc_core::sc_time_stamp() << ": Final phase of test entered " << name() << std::endl;
          uvm_objection* uvm_obj;
          uvm_obj = new uvm_objection("obj_cnt");
          uvm_obj->display_objections();
          std::cout << sc_core::sc_time_stamp() << ": Final phase of test happened " << name() << std::endl;
          sc_stop();
        }
        
        virtual void end_of_simulation()
        {
          std::cout << sc_core::sc_time_stamp() << ": end_of_simulation phase of test happened " << name() << std::endl;
        }
 

The output message from simulator looks like as under:. Just wanted to know if this is the recommended way of exiting from simulation.

UVM_INFO ahb_driver.h(65) @ 0 s: tb.top_env_inst.agent.ahb_driver_inst [ahb_driver_inst] CHICKY:run_phase Entered
UVM_INFO ahb_driver.h(70) @ 0 s: tb.top_env_inst.agent.ahb_driver_inst [ahb_driver_inst] AKHILA:run_phase FOR Entered
0 s: run_phase Entered tb.top_env_inst                                                                               
0 s: UVM test started tb
UVM_INFO ahb_basic_write_sequence.h(62) @ 0 s: reporter [ahb_wr_seq] Starting sequence ahb_basic_write_sequence
UVM_INFO ahb_basic_write_sequence.h(68) @ 0 s: reporter [ahb_wr_seq] Starting sequence ahb_basic_write_sequence
UVM_INFO ahb_basic_write_sequence.h(76) @ 0 s: reporter [ahb_wr_seq] Sending transaction from sequence ahb_basic_write_sequence
UVM_INFO ahb_basic_write_sequence.h(87) @ 0 s: reporter [ahb_wr_seq] Calling start_item from sequence ahb_basic_write_sequence
UVM_INFO ahb_driver.h(72) @ 0 s: tb.top_env_inst.agent.ahb_driver_inst [ahb_driver_inst] AKHILA:run_phase after get_next_item Entered
UVM_INFO ahb_driver.h(78) @ 0 s: tb.top_env_inst.agent.ahb_driver_inst [ahb_driver_inst] AKHILA:write trans Entered
UVM_INFO ahb_basic_write_sequence.h(89) @ 10 ns: reporter [ahb_wr_seq] Getting response from sequence ahb_basic_write_sequence
UVM_INFO ahb_basic_write_sequence.h(93) @ 10 ns: reporter [ahb_wr_seq] Finishing sequence
UVM_INFO ahb_driver.h(93) @ 10 ns: tb.top_env_inst.agent.ahb_driver_inst [ahb_driver_inst] AKHILA:run_phase finished
20 ns: run_phase Exited tb.top_env_inst
20 ns: Final phase of test entered tb

The total objection count is 0
20 ns: Final phase of test happened tb
UVM_INFO @ 20 ns: reporter [FINISH] UVM-SystemC phasing completed; simulation finished
20 ns: end_of_simulation phase of test happened tb

Warning: (W545) sc_stop has already been called
In file: ../../../../src/sysc/kernel/sc_simcontext.cpp:1045
=====================================================
||              All tests passed OK                ||
=====================================================

Info: (I804) /IEEE_Std_1666/deprecated: You can turn off warnings about
             IEEE 1666 deprecated features by placing this method call
             as the first statement in your sc_main() function:

  sc_core::sc_report_handler::set_actions( "/IEEE_Std_1666/deprecated",
                                           sc_core::SC_DO_NOTHING );
 

 

Thanks

Akhila

Share this post


Link to post
Share on other sites

UVM-SystemC simulation will automatically finish if all UVM phases have been executed (without any pending objections). You can look in the examples/simple/objections/basic example how to get the objection count. I expect somewhere you raise an objection, but you do not drop it.

The SystemC sc_stop will trigger end_of_simulation. So this is expected behaviour. However, in UVM-SystemC you should not call sc_stop yourself (in a similar way, as a user you do not start the simulation with sc_start)

 

Share this post


Link to post
Share on other sites

Thanks Martin. I looked at the example you mentioned. I will add call to get_objection() in my test's run_phase and check. But if i call display_objections() in final_phase and find the count to be 0, wouldn't this imply there are no pending objections? Also, will the simulation enter into subsequent phases (viz. final, report), if there is a pending objection in previous phase( viz. run_phase) ?

Thanks

Akhila

Share this post


Link to post
Share on other sites

Hi Martin,

I tried adding callback dropped to my top level test. I can that objection->get_objection_total(this) is returning 0 whereas objection->get_objection_total(uvm_root::get()) is returning 1. So this tells that there is some objection pending.

Now when I added all_dropped callback to the test, its also executing. This implies that there is no pending objection for this class and its children correct? 

And the pending one is from uvm_top as shown by display_objections() method(pasted the output below). Any idea from where is this getting generated? 

0 s: UVM test started ahb_basic_test
UVM_INFO ahb_basic_write_sequence.h(62) @ 0 s: reporter [ahb_wr_seq] Starting sequence ahb_basic_write_sequence
[SEQCHECK]: start_item called at 0 s
UVM_INFO ahb_basic_write_sequence.h(94) @ 0 s: reporter [ahb_wr_seq] Finishing sequence
UVM_INFO @ 0 s: ahb_basic_test [dropped] 1 objection(s) dropped from ahb_basic_test, total count is now 0 top: 1

--> This is the result of display_obejctions()

The total objection count is 1
---------------------------------------------------------
 Source  Total
 Count   Count   Object
---------------------------------------------------------
      0      0   ahb_basic_test
      0      1   uvm_top
---------------------------------------------------------
0 s: Stopping simulation as objection count is 0
0 s: UVM test finished ahb_basic_test
UVM_INFO @ 0 s: ahb_basic_test [all_dropped] ALL OBEJCTIONS DROPPED

--- UVM Report Summary ---

** Report counts by severity
UVM_INFO      :   9
UVM_WARNING   :   0
UVM_ERROR     :   0
UVM_FATAL     :   0
** Report counts by id
[RNTST]                 1
[agent]                 1
[ahb_driver_inst]       3
[ahb_wr_seq]            2
[all_dropped]           1
[dropped]               1

------------------SIM HANGS HERE-------------

I have only one test which is then called in sc_main(which looks something like this)

/**
 * SC main function
 */
int sc_main(int, char*[])
{
    run_test("ahb_basic_test");
    
    cout << "=====================================================" << endl;
    cout << "||              All tests passed OK                ||" << endl;
    cout << "=====================================================" << endl;

    return 0;
}
 

Appreciate any suggestions here.

Thanks

Akhila

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now