apb_watchdog验证模块搭建(一)文章目录
文章目录
前言
本文介绍了apb_watchdog验证模块的搭建过程与其具体代码,主要包括其中验证环境的构建,测试序列的发送与回归测试收集。主要运用systemvorilog与uvm在已有apb2总线vip(来源路科验证)的基础上进行验证测试,仿真验证工具为vcs。本项目的设计代码由路科验证提供。
一、apb_watchdog简单功能介绍
关于apb_watchdog的具体功能可以参考arm提供的设计功能描述文档**《Cortex™-M System Design Kit》**其中第四节component部分对apb_watchdog进行了详细介绍。下文对其主要功能进行简单介绍,具体功能与寄存器描述将在后文验证中提到。
下图为apb_watchdog接口,左侧接口为apb2总线接口(从信号方向可知其为从端),通过总线端的数据传输完成对watchdog的寄存器进行功能配置,右侧为watchdog本身接口。
watchdog为一个32bit逐减计数器,由重载寄存器初始化,WDOGLOAD。当watchdog计数器减少到预计的数值时,输出端WDPGINT将拉高,输出中断信号。
在WDOGCLKEN信号为高时,计数器会在每个WDOGCLK的上升沿减一。计数到0时,若此时WDOGCONCROL寄存器部分的INT域与RES域为高则使能reset与interrupt功能。即输出中断信号并且watchdog会安装WDOGLAOD中预定值进行重置。若WDOGCONTROL域中有未使能的情况则回等待重置或无法输出中断。
二、测试平台环境搭建
1.测试所用模板介绍
利用gvim可以创建与打开文件如下:
vorilog文件夹中存放设计代码。
uvm文件夹中存放验证代码与其环境结构。
cfg为配置文件,由顶层basetest创建,其中包括一些配置信息,也可将interface,regmodel打包传入。
env为验证环境部分,主体为pkg,env与virtual sequencer
reg为寄存器模型
seq_lib为存放测试用例sequence文件夹
sim为仿真文件夹
tb为testbench与interface文件夹
test用以存放不同测试文件
vip_lib中存放了apb2总线的vip
在创建模板时,除vip部分其他基本为空
2.tb与interface
interface代码:
interface rkv_watchdog_if;
logic [3:0] ecorevnum = 4'b1011;
logic wdogint;
logic wdogres;
logic apb_clk;
logic apb_rstn;
logic wdg_clk;
logic wdg_rstn;
endinterface
tb中提供了apb与watchdog的时钟与复位信号,以及wdogint与wdogres。ecorevnum是注册修订号,赋值即可。
tb代码:
module rkv_watchdog_tb;
import uvm_pkg::*;
`include "uvm_macros.svh"
import rkv_watchdog_pkg::*;
bit apb_clk;
bit apb_rstn;
bit wdg_clk;
bit wdg_rstn;
cmsdk_apb_watchdog dut(
.PCLK(apb_clk), // APB clock
.PRESETn(apb_rstn), // APB reset
.PENABLE(apb_if_inst.penable), // APB enable
.PSEL(apb_if_inst.psel), // APB periph select
.PADDR(apb_if_inst.paddr[11:2]), // APB address bus
.PWRITE(apb_if_inst.pwrite), // APB write
.PWDATA(apb_if_inst.pwdata), // APB write data
.WDOGCLK(wdg_clk), // Watchdog clock
.WDOGCLKEN(1'b1), // Watchdog clock enable
.WDOGRESn(wdg_rstn), // Watchdog clock reset
.ECOREVNUM(wdg_if_inst.ecorevnum), // ECO revision number
.PRDATA(apb_if_inst.prdata), // APB read data
.WDOGINT(wdg_if_inst.wdogint), // Watchdog interrupt
.WDOGRES(wdg_if_inst.wdogres) // Watchdog timeout reset
);
apb_if apb_if_inst(apb_clk, apb_rstn);
assign wdg_if_inst.apb_clk = apb_clk;
assign wdg_if_inst.wdg_clk = wdg_clk;
assign wdg_if_inst.apb_rstn = apb_rstn;
assign wdg_if_inst.wdg_rstn = wdg_rstn;
rkv_watchdog_if wdg_if_inst();
initial begin : clk_gen
fork
forever #5ns apb_clk <= !apb_clk; // 100MHz
forever #25ns wdg_clk <= !wdg_clk; // 20MHz
join
end
initial begin : rstn_gen
#2ns;
apb_rstn <= 1;
#20ns;
apb_rstn <= 0;
#20ns;
apb_rstn <= 1;
end
assign wdg_rstn = apb_rstn;
initial begin : vif_assign
uvm_config_db#(virtual apb_if)::set(uvm_root::get(), "uvm_test_top.env.apb_mst", "vif", apb_if_inst);
uvm_config_db#(virtual rkv_watchdog_if)::set(uvm_root::get(), "uvm_test_top.env", "vif", wdg_if_inst);
uvm_config_db#(virtual rkv_watchdog_if)::set(uvm_root::get(), "uvm_test_top.env.virt_sqr", "vif", wdg_if_inst);
run_test("");
end
endmodule
tb中主要包括时钟复位信号的产生,watchdog模块的例化,interface传递于env以及各部分的连接。值得注意的是:总线地址的连接应按照设计文件的使用要求,PADDR(apb_if_inst.paddr[11:2]),以访问得到正确的地址。
2.env与watchdog_pkg
env代码:
class rkv_watchdog_env extends uvm_env;
apb_master_agent apb_mst;
rkv_watchdog_virtual_sequencer virt_sqr;
`uvm_component_utils(rkv_watchdog_env)
function new (string name = "rkv_watchdog_env", uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
apb_mst = apb_master_agent::type_id::create("apb_mst", this);
virt_sqr = rkv_watchdog_virtual_sequencer::type_id::create("virt_sqr", this);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
virt_sqr.apb_mst_sqr = apb_mst.sequencer;
endfunction
endclass
此时env中包括apb_mst_agt与sequencer,并且将apb_mst中的sequencer与watchdog中的sequencer连接起来,这样后期在写sequence时可以通过watchdog的sequence完成对apb总线部分的访问,vip的连接也就完成了。
env代码:
`ifndef RKV_WATCHDOG_PKG_SV
`define RKV_WATCHDOG_PKG_SV
package rkv_watchdog_pkg;
import uvm_pkg::*;
`include "uvm_macros.svh"
import apb_pkg::*;
`include "rkv_watchdog_config.svh"
`include "rkv_watchdog_reg.svh"
`include "rkv_watchdog_cov.svh"
`include "rkv_watchdog_virtual_sequencer.sv"
`include "rkv_watchdog_env.sv"
`include "rkv_watchdog_seq_lib.svh"
`include "rkv_watchdog_tests.svh"
endpackage
`endif
在pkg中包括了仿真时需要编译的文件,后期在添加新文件时需注意是否加入仿真,同时应注意编译文件的顺序:如config等object类型应在env等组件类型之前,否则容易报错。sequencer代码较为简单,只需要声明即可,值得注意的是,需要在sequencer中声明apb_master_sqr以完成对apb部分vip的调用。
3.test与base_sequence
test代码:
`ifndef RKV_WATCHDOG_BASE_TEST_SV
`define RKV_WATCHDOG_BASE_TEST_SV
virtual class rkv_watchdog_base_test extends uvm_test;
rkv_watchdog_env env;
function new (string name = "rkv_watchdog_base_test", uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
env = rkv_watchdog_env::type_id::create("env", this);
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
phase.raise_objection(this);
do_init_clks();
do_init_regs();
phase.drop_objection(this);
endtask
virtual task do_init_clks();
endtask
virtual task do_init_regs();
endtask
endclass
`endif
base test中例化了env,并给出了时钟与寄存器初始化的task,后期在不同test中可以对其进行相应的修改。
base_sequence代码:
`ifndef RKV_WATCHDOG_BASE_VIRTUAL_SEQUENCE_SV
`define RKV_WATCHDOG_BASE_VIRTUAL_SEQUENCE_SV
class rkv_watchdog_base_virtual_sequence extends uvm_sequence;
`uvm_object_utils(rkv_watchdog_base_virtual_sequence)
`uvm_declare_p_sequencer(rkv_watchdog_virtual_sequencer)
function new (string name = "rkv_watchdog_base_virtual_sequence");
super.new(name);
endfunction
virtual task body();
`uvm_info("body", "Entered...", UVM_LOW)
// TODO in sub-class
`uvm_info("body", "Exiting...", UVM_LOW)
endtask
endclass
`endif
base test中完成了声明,并将watchdog sequencer注册为p_sequencer,这一步的目的与uvm中激励发送的driver,sequence和sequencer之间的关系有关。笔者在这里的简单理解是sequence在被挂载至sequencer上时会将当前sqr传递给底层的m_sequencer,由m_sequencer完成driver与sequence之间的桥梁工作,在激励发送时会检查m_sequncer与p_sequncer的指向是否相同,以此保证激励发送符合使用者的理解。当然,这一点理解对此简单项目不构成影响。
4.Makefile
Makefile代码:
#############################
# User variables
#############################
TB = rkv_watchdog_tb
SEED = 1
GUI ?= 0
DOTCL ?= 1
TESTNAME ?= rkv_watchdog_integration_test
DFILES = ../../verilog/{cmsdk_apb_watchdog_frc.v,cmsdk_apb_watchdog.v}
VFILES += ../vip_lib/apb_pkg/apb_pkg.sv \
../vip_lib/apb_pkg/apb_if.sv \
../env/rkv_watchdog_pkg.sv \
../tb/rkv_watchdog_if.sv \
../tb/rkv_watchdog_tb.sv
#############################
# Environment variables
#############################
VCOMP_INC = +incdir+../../verilog \
+incdir+../vip_lib/apb_pkg \
+incdir+../{cfg,cov,reg,env,seq_lib,test}
VCOMP = vlogan -full64 -ntb_opts uvm-1.2 -sverilog -timescale=1ps/1ps -nc -l comp.log $(VCOMP_INC)
ELAB = vcs -full64 -ntb_opts uvm-1.2 -debug_acc+all -l elab.log -sim_res=1ps
RUN = ./$(TB).simv -l run.log -sml +ntb_random_seed=$(SEED) +UVM_TESTNAME=$(TESTNAME)
SIMRUNFILE = rkv_watchdog_sim_run.do
ifeq ($(GUI),1)
RUN += -gui
endif
ifeq ($(DOTCL),1)
RUN += -ucli -do $(SIMRUNFILE)
endif
comp:
$(VCOMP)
$(VCOMP) $(DFILES) $(VFILES)
elab: comp
$(ELAB) -top $(TB) -o $(TB).simv
run:
$(RUN)
clean:
rm -rf 64 AN.DB DVEfiles csrc *.simv *.simv.daidir *.simv.vdb ucli.key
rm -rf *.log* *.vpd *.h urgReport
makefile中将设计与验证代码加入编译队列
总结——当前验证结构
本文介绍了apb watchdog验证的框架搭建,主要是env,sequence,sequencer,test,tb,interface与Makefile脚本的建立,将验证的骨架搭建起来,但是并没有发送任何激励,下一节将更新寄存器激励发送与寄存器模型的融入。目前的验证框图可如下表示:(由viso完成)
本项目来源路科验证,有疑问可私信