Jump to content
enchanter

How to drive DUT clock and reset signal in UVM-SystemC?

Recommended Posts

I can't find any example in the uvm-systemc preview package which DUT has clock and reset signals. 

I tried to create clock with sc_clock in sc_main and connected it my dut's clock signal. But it looks the simulation will never finish. 

So would someone let me know what's the right way to handle the clock and reset signals?

Share this post


Link to post
Share on other sites

Hello @enchanter,

Can you try using sc_start with some appropriate time-period?

Update: with sc_clock

e.g.:

// Run the simulation till 100 seconds.
sc_start(100, SC_SEC);
// Stop the simulation.
sc_stop();

Disclaimer: Currently I do-not have experience much with UVM-SystemC.

Regards,

Ameya Vikram Singh

Share this post


Link to post
Share on other sites

Hi,

I addressed this by creating a sc_module to generate clock and reset. Clock is a sc_clock signal and the module had a sc_thread for reset generation. This module was instantiated in sc_main and the clock was connected to the DUT using an sc_signal.

You ca give this a try.

 

Thanks

Akhila

Share this post


Link to post
Share on other sites

Hi.

This seems to be related to SystemC in general and not to UVM.

sc_start() - without argument - starts the simulation until there is no activity anymore. No activity means no more events in the event queue. sc_clock generates new events all the time because the value changes independent from everything else in your design. As a result, the event queue will never be empty and the simulation never stops.

(For completemess: the simulation ends as well when the maximum time is reached, i.e. the maximum time value that can be represented by sc_time).

Normally, there are two ways to stop simulation, either by calling sc_start with a argument or by calling sc_stop.

The first has been mentioned already by AmeyaVS. It runs the simulation for the given time and stops.

The second can be done for instance from a testbench thread, e.g. from a sequencer when all sequences are done.

 

Greetings

Ralph

Share this post


Link to post
Share on other sites

I played with scoreboard/basic example from uvm-systemc package, it finished simulation automatically:

 

Quote

80 ns: my_dut received value 9               
80 ns: my_dut send value 10                  
80 ns: tb.agent1.monitor received 9          
80 ns: tb.scoreboard0.rcv_listener received value 9                                       
80 ns: tb.scoreboard0 rcv_listener in scoreboard received value 9                         
80 ns: tb.agent2.monitor received 10         
80 ns: tb.scoreboard0.rcv_listener received value 10                                      
80 ns: tb.scoreboard0 rcv_listener in scoreboard received value 10                        
UVM_INFO ../src/sequence.h(65) @ 90 ns: reporter [sequence<REQ,RSP>] Finishing sequence   

--- UVM Report Summary ---                   

** Report counts by severity                 
UVM_INFO      :   5                          
UVM_WARNING   :   0                          
UVM_ERROR     :   0                          
UVM_FATAL     :   0                          
** Report counts by id                       
[RNTST]                 1                    
[agent1]                1                    
[agent2]                1                    
[sequence<REQ,RSP>]     2                    
UVM_INFO @ 90 ns: reporter [FINISH] UVM-SystemC phasing completed; simulation finished    
 

But when I try to add clock signal to the DUT and sc_main as below:

dut.h

#ifndef DUT_H_                                                                            
#define DUT_H_                                                                            

#include <systemc>                                                                        

class dut : public sc_core::sc_module                                                     
{                                                                                         
 public:                                                                                  
    sc_core::sc_in<int> in;                                                               
    sc_core::sc_in<bool> clk;                                                             
    sc_core::sc_out<int> out;                                                             

    void func()                                                                           
    {                                                                                     
        int val;                                                                          
        val = in.read();                                                                  
        std::cout << sc_core::sc_time_stamp() << ": " << name() << " received value " << val << std::endl;                                                                           
        std::cout << sc_core::sc_time_stamp() << ": " << name() << " send value " << val+1 << std::endl;                                                                             
        out.write(val+1);                                                                 
    }                                                                                     

    SC_CTOR(dut) : in("in"), out("out")                                                   
    {                                                                                     
        SC_METHOD(func);                                                                  
        sensitive << clk.pos();                                                           
    }                                                                                     

};                                                                                        

#endif /* DUT_H_ */          

sc_main.cpp

#include <systemc>                                                                        
#include <uvm>                                                                            

#include "testbench.h"                                                                    
#include "dut.h"                                                                          
#include "vip_if.h"                                                                       

int sc_main(int, char*[])                                                                 
{                                                                                         
    // instantiate the DUT                                                                
    sc_core::sc_time CLK_PERIOD(10, sc_core::SC_NS);                                      

    sc_core::sc_clock clk("clk", CLK_PERIOD, 0.5);                                        

    dut* my_dut = new dut("my_dut");                                                      
    testbench* tb = new testbench("tb");                                                  

    //uvm_config_db_options::turn_on_tracing();                                           

    vip_if* dut_if_in = new vip_if();                                                     
    vip_if* dut_if_out = new vip_if();                                                    

    uvm::uvm_config_db<vip_if*>::set(0, "tb.agent1.*", "vif", dut_if_in);                 
    uvm::uvm_config_db<vip_if*>::set(0, "tb.agent2.*", "vif", dut_if_out);                

    my_dut->clk(clk);                                                                     
    my_dut->in(dut_if_in->sig_data);                                                      
    my_dut->out(dut_if_out->sig_data);                                                    

    uvm::run_test();                                                                      

    return 0;                                                                             
}               

The simulation will not stop and I have to kill the process. 

Quote

1207770 ns: my_dut send value 10
1207780 ns: my_dut received value 9
1207780 ns: my_dut send value 10
1207790 ns: my_dut received value 9
1207790 ns: my_dut send value 10
1207800 ns: my_dut received value 9
1207800 ns: my_dut send value 10
1207810 ns: my_dut received value 9
1207810 ns: my_dut send value 10
1207820 ns: my_dut received value 9
1207820 ns: my_dut send value 10
1207830 ns: my_dut received value 9
1207830 ns: my_dut send value 10
1207840 ns: my_dut received value 9
1207840 ns: my_dut send value 10
1207850 ns: my_dut received value 9
1207850 ns: my_dut send value 10
1207860 ns: my_dut received value 9
1207860 ns: my_dut send value 10
1207870 ns: my_dut received value 9
1207870 ns: my_dut send value 10
1207880 ns: my_dut received value 9
1207880 ns: my_dut send value 10
1207890 ns: my_dut received value 9
1207890 ns: my_dut send value 10
1207900 ns: my_dut received value 9
1207900 ns: my_dut send value 10
1207910 ns: my_dut received value 9
1207910 ns: my_dut send value 10
1207920 
 

 

scoreboard_basic.tar.gz2

Share this post


Link to post
Share on other sites
13 hours ago, AmeyaVS said:

Hello @enchanter,

Can you try using sc_start with some appropriate time-period?

Update: with sc_clock

e.g.:


// Run the simulation till 100 seconds.
sc_start(100, SC_SEC);
// Stop the simulation.
sc_stop();

Disclaimer: Currently I do-not have experience much with UVM-SystemC.

Regards,

Ameya Vikram Singh

For UVM, it should not start the simulation by directly call sc_start() and sc_stop(). 

Share this post


Link to post
Share on other sites

Hello @enchanter,

After looking into the sources of the UVM-SystemC draft release available here.

In the following file under: src/uvmsc/base/uvm_root.cpp, line number 150.

Internally the UVM-SystemC class calls the sc_start() function without any parameter to actually kick start the SystemC simulation.

Which executes the simulation till events are generated and queued, in your case with clocks the events would always be generated.

You could create your own function which reproduces the same behavior in the run_test() method of the uvm_root class, or better would be to extend the uvm_root class to suite your needs.

Here is the code snippet from the UVM-SytemC sources:

// File: src/uvmsc/base/uvm_root.cpp
// Line number: 127
void uvm_root::run_test( const std::string& test_name )
{
  //disable SystemC messages
  sc_core::sc_report_handler::set_actions("/OSCI/SystemC", sc_core::SC_DO_NOTHING);

  // check and register test object
  m_register_test(test_name);

  // start objection mechanism fired as spawned process
  sc_process_handle m_init_objections_proc =
    sc_spawn(sc_bind(&uvm_objection::m_init_objections),
      "m_init_objections_proc");

  uvm_phase::m_register_phases();
  phases_registered = true;

  // call build and connect phase
  uvm_phase::m_prerun_phases();


  // start simulation (of run-phases) here.
  try
  { /////////////////////////////////
    sc_core::sc_start();   //<<<<<<< Run simulation forever or until events exists.
  } ////////////////////////////////
  catch( const std::exception& e )
  {
    std::cerr << e.what() << std::endl;
    exit(1); // TODO exit program with error code?
  }

  // TODO: move post-run phases to here? Currently they are part of the simulation

  if (m_finish_on_completion)
    sc_core::sc_stop();
}

Hope this helps.

Thanks and Regards,

Ameya Vikram Singh

 

 

Share this post


Link to post
Share on other sites
2 hours ago, AmeyaVS said:

Hello @enchanter,

After looking into the sources of the UVM-SystemC draft release available here.

In the following file under: src/uvmsc/base/uvm_root.cpp, line number 150.

Internally the UVM-SystemC class calls the sc_start() function without any parameter to actually kick start the SystemC simulation.

Which executes the simulation till events are generated and queued, in your case with clocks the events would always be generated.

You could create your own function which reproduces the same behavior in the run_test() method of the uvm_root class, or better would be to extend the uvm_root class to suite your needs.

Here is the code snippet from the UVM-SytemC sources:


// File: src/uvmsc/base/uvm_root.cpp
// Line number: 127
void uvm_root::run_test( const std::string& test_name )
{
  //disable SystemC messages
  sc_core::sc_report_handler::set_actions("/OSCI/SystemC", sc_core::SC_DO_NOTHING);

  // check and register test object
  m_register_test(test_name);

  // start objection mechanism fired as spawned process
  sc_process_handle m_init_objections_proc =
    sc_spawn(sc_bind(&uvm_objection::m_init_objections),
      "m_init_objections_proc");

  uvm_phase::m_register_phases();
  phases_registered = true;

  // call build and connect phase
  uvm_phase::m_prerun_phases();


  // start simulation (of run-phases) here.
  try
  { /////////////////////////////////
    sc_core::sc_start();   //<<<<<<< Run simulation forever or until events exists.
  } ////////////////////////////////
  catch( const std::exception& e )
  {
    std::cerr << e.what() << std::endl;
    exit(1); // TODO exit program with error code?
  }

  // TODO: move post-run phases to here? Currently they are part of the simulation

  if (m_finish_on_completion)
    sc_core::sc_stop();
}

Hope this helps.

Thanks and Regards,

Ameya Vikram Singh

 

 

Thanks for the help. I did some digging too and I also thought it is becaused by the clock events. So I tried to use the set_timeout on that example which should finished in 100 NS. 

When I set the timeout to 30 NS, it killed the simulation at 30 NS as expected. But when I set it to 200 NS, the simulation will not finish. I haven't figure out why. 

 

 

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

×