引言
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 类型转换为名称字符串作为传参
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的多任务进程的仿真同步控制,
- sc的模型上存在多个需要并行行动的模块,这些模块一般通过
SC_THREAD, SC_METHOD, SC_CTHREAD
或者sc_spawn
函数来创建派生自sc_object
类的任务线程实例
其中SC_THREAD, SC_METHOD, SC_CTHREAD
产生的是静态任务实例,属于unspawned进程。而由sc_spawn 调用的函数属于动态线程,两种线程创建方式的动态静态区别在函数的调用时刻与end_of_elaboration
之间的先后关系。 - 使用
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
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;
}