UVMC学习笔记一 :phase同步控制

引言

UVMC 实现了UVM SystemVerilog 环境与SystemC 环境之间的同步控制,在systemC 部分通过特定的API实现对UVM 的phase的精确同步

UVMC 在systemC layer的同步主要通过三个api实现

进程同步

 uvmc_wait_for_phase(const  char *phase_name,  UVM_PHASE_STATE,  uvmc_wait_op)

该api用于在SystemC 的spawn线程/进程中等待UVM执行到对应的phase区间

  • arguement的意义:

    1.  `const char *phase_name` 固定表示特定需要等待进入的phase名称,目前支持的phase 按照先后顺序为:
     **build,  
           connect,   
           end_of_elaboration, 
           start_of_simulation, 
           run, 
           extract, 
           check, 
           report**
    包含与`run phase` 处于同行`uvm phase domain`的13个task phase:
    **pre_reset, reset, post_reset, pre_configure,  configure, post_configure, pre_main, main, post_main, pre_shutdown, shutdown, and post_shutdown**
     在SC模块中进入对应的phase等待,需要将phase 类型转换为名称字符串作为传参
    1. UVM_PHASE_STATE 表示api函数进入phase的状态, 主要状态如下:

    UVM_PHASE_STARTED
    UVM_PHASE_EXECUTING
    UVM_PHASE_READY_TO_END | UVM_PHASE_JUMPING
    UVM_PHASE_ENDED
    UVM_PHASE_DONE

如果一个phase在自己的执行状态中被一个其他phase跳转抢占了,那么则需要使用 UVM_PHASE_JUMPING取代UVM_PHASE_READY_TO_END

 3. `uvmc_wait_op` 围绕`UVM_PHASE_STATE`的等待状态更加精细化的控制,默认是`UVM_EQ`
          ` UVM_LT - Phase is before the given state.`
      `UVM_LTE - Phase is before or at the given state.`
      `UVM_EQ - Phase is at the given state.`
      `UVM_GTE - Phase is at or after the given state.`
      `UVM_GT - Phase is after the given state.`
      `UVM_NE - Phase is not at the given state.`

### objection控制

uvmc_raise_objection("phase_name", name(), "your comment")

在指定的sc process 中增加UVM phase objection ,让objection +1,该操作可以影响到UVM SystemVerilog TestBench
name(), 属于typeinfo 里面用来获取类型名字的函数
`uvmc_drop_objection("phase_name", name(), "your comment")`
在指定的sc process 中释放objection ,让objection 设置-1,该操作可以影响到UVM SystemVerilog TestBench

UVMC 在systemC layer的并行化

SystemC 的内核(kernel)是一种基于C++开发的仿真序列调度器,该调度器实现了类似EDA simulator的多任务进程的仿真同步控制,

  1. sc的模型上存在多个需要并行行动的模块,这些模块一般通过SC_THREAD, SC_METHOD, SC_CTHREAD 或者sc_spawn函数来创建派生自sc_object类的任务线程实例
    其中SC_THREAD, SC_METHOD, SC_CTHREAD产生的是静态任务实例,属于unspawned进程。而由sc_spawn 调用的函数属于动态线程,两种线程创建方式的动态静态区别在函数的调用时刻与end_of_elaboration 之间的先后关系。
  2. 使用sc_spawn函数创建并行执行的spawned函数,其中sc_bind, sc_ref, sc_cref 宏提供了基于boost::C++库对spawned 函数的传参,分别用于传值,传引用,传const 引用,该传参 的方式属于非强制要求

示例如下:

例程可以看到通过sc_spawn调用process的各种形态,包括process的句柄返回

int f();
struct Functor{
    typedef int result_type;
    result_type operator() ();
};
Functor::result_type Functor::operator() (){ 
    return f(); 
}

int h(int a, int& b, const int& c);
struct MyMod: sc_module{
    sc_signal sig;
    void g();
    SC_CTOR(MyMod)
    {
        SC_THREAD(T);
    }
    int ret;
    void T(){
        sc_spawn(&f); // Spawn a function without arguments and discard any return value.
        // Spawn a similar process and create a process handle.
        sc_process_handle handle = sc_spawn(&f);
        Functor fr;
        sc_spawn(&ret, fr); // Spawn a function object and catch the return value.
        sc_spawn_options opt;
        opt.spawn_method();
        opt.set_sensitivity(&sig);
        opt.dont_initialize();
        sc_spawn(f, "f1", &opt); // Spawn a method process named "f1", sensitive to sig, not initialized.
        // Spawn a similar process named "f2" and catch the return value.
        sc_spawn(&ret, fr, "f2", &opt);
        // Spawn a member function using Boost bind.
        sc_spawn(sc_bind(&MyMod::g, this));
        int A = 0, B, C;
        // Spawn a function using Boost bind, pass arguments
        // and catch the return value.
        sc_spawn(&ret, sc_bind(&h, A, sc_ref(B), sc_cref(C)));
    }
};

3 SC_FORK / SC_JOIN 成对出现,用于包含若干sc_spawn任务线程,该方法禁止用于SC_METHOD中, 格式如下:

Example 1:
SC_FORK
    sc_spawn( arguments ) ,
    sc_spawn( arguments ) ,
    sc_spawn( arguments )
SC_JOIN

Example 2:
sc_process_handle h1, h2, h3;
SC_FORK
   h1 = sc_spawn( arguments ) ,
   h2 = sc_spawn( arguments ) ,
   h3 = sc_spawn( arguments )
SC_JOIN
  1. sc_bind使用源于boost::bind传参,格式如下
    sc_bind(&func, this, arg1,arg2, arg3), 其中this用于表示当前模块的实例指针

phase 同步实例

// (begin inline source)
#include "systemc.h"
#include "tlm.h"
#include 
#include 

using namespace std;
using namespace sc_core;
using namespace tlm;

#include "uvmc.h"
#include "uvmc_macros.h"
using namespace uvmc;

#include "consumer.cpp"

SC_MODULE(top)
{
  consumer cons;

  SC_CTOR(top) : cons("consumer") {
    SC_THREAD(show_uvm_phasing);
    uvmc_connect(cons.in,"foo");
    uvmc_connect(cons.analysis_out,"bar");
  }

  void show_uvm_phasing();

  private:
  void spawn_phase_control_proc(const char* phase, bool is_task_phase);
  void wait_phase_started(const char* ph_name, bool is_task_phase);
};
// (end inline source)

// (begin inline source)
void top::show_uvm_phasing()
{
  wait(SC_ZERO_TIME);

  // common phases
  spawn_phase_control_proc("build",0);
  spawn_phase_control_proc("connect",0);
  spawn_phase_control_proc("end_of_elaboration",0);
  spawn_phase_control_proc("start_of_simulation",0);
  spawn_phase_control_proc("run",1);
  spawn_phase_control_proc("extract",0);
  spawn_phase_control_proc("check",0);
  spawn_phase_control_proc("report",0);

  // uvm run-time phases
  spawn_phase_control_proc("pre_reset",1);
  spawn_phase_control_proc("reset",1);
  spawn_phase_control_proc("post_reset",1);
  spawn_phase_control_proc("pre_configure",1);
  spawn_phase_control_proc("configure",1);
  spawn_phase_control_proc("post_configure",1);
  spawn_phase_control_proc("pre_main",1);
  spawn_phase_control_proc("main",1);
  spawn_phase_control_proc("post_main",1);
  spawn_phase_control_proc("pre_shutdown",1);
  spawn_phase_control_proc("shutdown",1);
  spawn_phase_control_proc("post_shutdown",1);
}

void top::spawn_phase_control_proc(const char* phase, bool is_task_phase)
{
  sc_spawn(sc_bind(&top::wait_phase_started,this,phase,
         is_task_phase), (string("wait_for_") + phase).c_str());
}

void top::wait_phase_started(const char* ph_name, bool is_task_phase)
{

  UVMC_INFO("SC_TOP/WAITING",(string("Waiting for phase ") +
            ph_name + " to start...").c_str(),UVM_LOW,"");

  uvmc_wait_for_phase(ph_name, UVM_PHASE_STARTED);

  UVMC_INFO("SC_TOP/PH_STARTED", (string(name()) + ": Phase " +
            ph_name + " has started").c_str(), UVM_MEDIUM,"");

  // if a task, raise and drop objection

  if (is_task_phase)
  {
    UVMC_INFO("SC_TOP/RAISE_OBJ",
              (string(name()) + " raising objection in phase "
              + ph_name).c_str(), UVM_MEDIUM,"");

    // if we're the 'run' phase, wait until post_shutdown phase
    if (!strcmp(ph_name ,"run"))
      uvmc_wait_for_phase("post_shutdown",UVM_PHASE_STARTED);

    uvmc_raise_objection(ph_name, name(), "SC waiting 10ns");

    // wait some delay to prove we are in control...
    wait(sc_time(10,SC_NS));

    UVMC_INFO("SC_TOP/DROP_OBJ",
              (string(name()) + " dropping objection in phase "
              + ph_name).c_str(), UVM_MEDIUM,"");

    uvmc_drop_objection(ph_name, name(), "10ns has passed");
  }
}

int sc_main(int argc, char* argv[]) 
{  
  top t("t");
  sc_start();
  return 0;
}

你可能感兴趣的:(systemverilog)