timer_subscriber实现
思路也是首先实现父类timer_subscriber,实现计分板和覆盖率模型的公用部分逻辑。
timer_subscriber需要实现的逻辑和内容:
- scb和cgm都是与apb的monitor通过analysis port连接,因此需要analysis imp和实现write函数
- 通过monitor发送到管道上的是一次传输的地址数据和读写类型,需要拿一个暂时变量存储这些信息。信息的暂存和初始事件 (timer_regacc_e) 的触发加在一起就构成了write函数
uvm_analysis_imp #(apb_transfer, timer_subscriber) apb_trans_observed_imp;
uvm_reg_bus_op rop; // 暂存信息的结构
virtual function write(apb transfer tr);
uvm_reg r;
r = rgm.map.get_reg_by_offset(tr.addr);
if(r!=null)begin
timer_regacc_e.trigger(r); // 初始事件的触发
// 信息的暂存
rop.addr = tr.addr;
rop.kind = tr.trans_kind == apb_pkg::WRITE ? UVM_WRITE : UVM_READ;
rop.data = tr.data;
rop.status = tr.trans_status == apb_pkg::OK ? UVM_IS_OK : UVM_NOT_OK;
rop.n_bits = 32;
rop.byte_en = 4'b1111;
end
endfunction
- 基本的思路是定义一些事件,每次从analysis port接收到信息后,通过解析信息,判断总线上产生了什么样的事件,进行相应事件的定义和触发。
// 事件定义
uvm_event timer_regacc_e; // 寄存器访问
uvm_event timer_enable_e; // timer被使能
uvm_event timer_intren_e; // 中断被使能
uvm_event timer_reload_e; // 对RELOAD寄存器进行访问
uvm_event timer_value_e; // 对VALUE寄存器进行访问
uvm_event timer_intrclr_e; // 对INTSTAT寄存器进行访问
// timer倒计时到0后加载reload寄存器中的值
// 这里使用static是因为这个事件会由scb监测到timer出现特定行为时触发
// 但cgm会等待这个事件以进行相关的覆盖率采样,只有定义为静态事件变量
// 才能保证scb触发的事件和cgm等待的事件是同一个事件
static uvm_event timer_counter_take_reload_e;
// 事件池
protected uvm_event_pool _ep;
// 其中do_listen_events()由子类实现,subsciber仅实现do_event_trigger()
task run_phase(uvm_phase pphase);
super.run_phase(phase);
fork
do_event_trigger();
do_listen_events();
join
endtask
virtual task do_event_trigger();
uvm_object tmp;
uvm_reg r;
forever begin
// 等待timer_regacc_e事件被触发,只有apb monitor调用analyisis port的write方法时会触发
timer_regacc_e.wait_trigger_data(tmp);
void'($cast(r, tmp));
#1ps;
// 判断访问的是什么寄存器,并触发相应的事件
case(r.get_name())
"CTRL":begin
if(rgm.CTRL.ENABLE.get() == 1'b1) timer_enable_e.trigger();
if(rgm.CTRL.INTREN.get() == 1'b1) timer_intren_e.trigger();
end
"VALUE":begin
if(rgm.VALUE.get() != 0) timer_value_e.trigger();
end
"RELOAD":begin
if(rgm.RELOAD.get() !=0) timer_reload_e.trigger();
end
"INTSTAT":begin
if(rgm.INTSTAT.get == 1'b1) timer_intrclr_e.trigger();
end
endcase
end
endtask
timer scoreboad的实现(参考模型的实现)
- 作为计分板和参考模型,scb首先要做的就是实现父类遗留下来的do_listen_events(),接收各种事件传递过来的消息并进行相应的模拟和处理。
task do_listen_events();
fork
listen_counter_reset();
listen_counter_enable();
listen_counter_intren();
listen_counter_reload();
listen_counter_value();
listen_counter_intrclr();
join_none
endtask
- 另外作为一个简陋的参考模型,我们必须要记录一些数据以进行基本的timer行为模拟,比如需要一个32位的counter记录当前value,比如指示timer和中断是否被使能的flag变量等
bit [31:0] counter; // 计数值
bit [31:0] reload; // reload值
bit intrrupt; // 中断标志
bit timer_enable;
bit timer_intren;
- 有了这些模拟变量,就可