1.uart 模块验证流程
1.理解dut
2.制定验证策略方法
3.提取验证点(feature list)-> testcase list
4.搭建验证平台(1.验证框架图2.验证环境代码)
5.执行验证
写testcase跑仿真+regression(大批量仿真收集覆盖率(前提是仿真pass)、分析覆盖率+补充case )
1.1理解DUT
1.2 制定验证策略方法
- 验证策略:白盒测试(已知内部代码和结构)
- 验证方法:随机测试(分析覆盖率)+定向测试
code coverage:line/condition/fsm/assertion/toggle
function converage:covergroup/coverpoint/bins/cross/sample
1.3 提取验证点 -> testcase
(1)

(2)

1.3.1 功能类
复位
寄存器
寄存器的检查,可以分为与功能相关和与功能无关两个部分。
- 功能无关:对寄存器的复位值以及读写属性的检查,这些检查与具体的 DUT 设计相独立,具有很强的移植性。
- 功能相关:必须结合具体的 DUT功能,在仿真过程中实现。
DUT中的寄存器一般可分为控制寄存器和状态寄存器:
控制寄存器常见类型为只写、可读可写等,通过对控制寄存器的配置,DUT可以在不同工作模式间切换;
状态寄存器一般为只读或者读后清零等,通过访问状态寄存器可以了解 DUT 当前的工作状态。 - 两个独立的寄存器占用相同的地址
CPU通过左边总线做写操作的时候,写到上面的寄存器,CPU通过左边总线做读操作的时候,读的是下面的寄存器。对CPU来说,这两个寄存器有同一个总线地址。这就是标准的全双工啊。寄存器可以同时通过右边的TXD和RXD接收发送数据。如果只定义一个寄存器的话,不是不可以。但是CPU写了寄存器以后,就只能等寄存器中的数据从TXD发送完以后,才有可能接收RXD的数据,然后CPU才能读。这就是半双工。

1.3.2 接口类
APB-INTERFACE
为了使系统中各个模块之间能够正确无误的传递信息,在信号线上进行数据传输时往往需要遵循一定的协议。由于信号线的数量、工作频率、串并行需求、全半双工等要求的不同,总线协议也是多种多样的。
UART-INTERFACE
1.3.3 异常类
如果在数据逻辑中使用到了 FIFO 结构,就需要对 FIFO 的空满信号等相关特性进行验证
1.4 搭建验证平台
1.4.1 验证框架图

1.4.2 验证环境代码思路
从顶层向下,具体如下:
tb_top层
1.首先最顶层就是tb_top层,tb_top层就是例化了DUT,例化了interface并且通过config_db进行interface的传递,传递到下面env所需要使用的interface的component,并且产生时钟和复位,然后会有个run_test()(UVM启动的入口),以上就是tb_top层做的工作。
还例化了断言(连接vif)
base_test
2.tb_top层下面就是base_test,base_test里面有什么?他是做什么的?
base_test里面例化了一个env以及virtual_sequencer,reg_model、adapter等,base_test也是整个UVM验证平台的树根,即UVM_TEST_TOP。
要去验证UART的功能,肯定要做一些配置,因此基于SPEC去配置了相关的寄存器,比如先把波特率配置起来
在apbuart_base_test中,有一个set_config_params的方法用来实现这些配置,同时,此方法中还有一个flag来决定是使用定向配置还是随机配置设置。
congfig
-
Uart Congfiguration
uart的相关配置主要包括波特率、帧长、奇偶校验以及停止位。 -
APB Congfiguration
APB相关的主要配置包括address以及pselect
class apbuart_base_test extends uvm_test;
...
apbuart_env env_sq;
uart_config cfg;
clk_rst_cfg clk_cfg;
apb_config apb_cfg;
...
extern virtual function void build_phase(uvm_phase phase);
extern virtual function void set_config_params(input [31:0] bd_rate , input [3:0] frm_len , input [1:0] parity , input sb , input flag);
extern virtual function void set_apbconfig_params (input [31:0] addr , input flag);
...
function void apbuart_base_test::build_phase(uvm_phase phase);
clk_cfg = new();
uvm_config_db#(clk_rst_cfg)::set(this,"*","clk_cfg",clk_cfg);
cfg = new();
uvm_config_db#(uart_config)::set(this,"*","cfg",cfg);
set_config_params(9600,8,3,1,0); // 波特率 , 帧长 , 奇偶校验 , 停止位 , Randomize Flag (1 随机配置, 0 定向配置)
apb_cfg = new();
uvm_config_db#(apb_config)::set(this,"*","apb_cfg",apb_cfg);
set_apbconfig_params(2,0); // Slave Bus Address, Randomize flag (1 for random , 0 for directed)
endfunction
//如果flag为1,uart_config实现randomize;否则定向配置波特率 , 帧长 , 奇偶校验等
//调用uart_config的baudRateFunc函数,根据apb agent的波特率配置uart monitor的波特率
function void apbuart_base_test::set_config_params(input [31:0] bd_rate , input [3:0] frm_len , input [1:0] parity , input sb , input flag);
if(flag)
begin
if (!cfg.randomize())
`uvm_error("RNDFAIL", " Config Randomization")
end
else
begin
cfg.frame_len = frm_len;
cfg.n_sb = sb;
cfg.parity = parity;
cfg.bRate = bd_rate;
end
cfg.baudRateFunc();
endfunction
//如果flag为1,apb_config实现randomize;否则定向配置地址
//调用apb_config的AddrCalcFunc函数,根据addr选择psel_Index即选通哪个外设
function void apbuart_base_test::set_apbconfig_params(input [31:0] addr, input flag);
if(flag)
begin
if (!apb_cfg.randomize())
`uvm_error("RNDFAIL", " APB Config Randomization")
end
else
begin
apb_cfg.slave_Addr = addr;
end
apb_cfg.AddrCalcFunc();
//$diplay("Slave Index is ",apb_cfg.AddrCalcFunc());
endfunction
class uart_config extends uvm_object;
...
function void baudRateFunc();
case (bRate)
32'd4800: baud_rate = 32'd10416;
32'd9600: baud_rate = 32'd5208;
32'd14400: baud_rate = 32'd3472;
32'd19200: baud_rate = 32'd2604;
32'd38400: baud_rate = 32'd1302;
32'd57600: baud_rate = 32'd868;
32'd115200: baud_rate = 32'd434;
32'd128000: baud_rate = 32'd392;
default: baud_rate = 32'd5208;
endcase
endfunction
...
`define UART_START_ADDR 32'd0
`define UART_END_ADDR 32'd5
`define I2C_START_ADDR 32'd6
`define I2C_END_ADDR 32'd12
`define SPI_START_ADDR 32'd13
`define SPI_END_ADDR 32'd20
class apb_config extends uvm_object;
...
function void AddrCalcFunc();
if ((slave_Addr >= ` UART_START_ADDR) && (slave_Addr <= ` UART_END_ADDR))
psel_Index = 1;
else if ((slave_Addr >= ` I2C_START_ADDR) && (slave_Addr <= ` I2C_END_ADDR))
psel_Index = 2;
else if ((slave_Addr >= ` SPI_START_ADDR) && (slave_Addr <= ` SPI_END_ADDR))
psel_Index = 4;
else
psel_Index = 0;
endfunction
...
env
3.base_test下面的env,里面有什么?
里面有apb_agent(apb总线这边发并行数据激励给DUT),uart_agent(发串行数据激励给DUT)和以及进行数据的check的scoreboard
scoreboard
数据流主要分2个方向
(1)apb_driver这边发并行数据到interface经过DUT(UART)后输出为串行数据,由uart_monitor抓到
(2)uart_driver发送串行数据到interface经过DUT后由APB总线这边读出(prdata),读出的为经过DUT后由串行数据转化成为并行的数据。
class apbuart_scoreboard extends uvm_scoreboard;
...
// ---------------------------------------
// 所以需要pkt_qu_monapb、pkt_qu_monuart、pkt_qu_uartdrv
// 分别用来存储scoreboard通过analysis_port从apb_monitor、uart_monitor、uart_driver取出的数据
// ---------------------------------------
apb_transaction pkt_qu_monapb[$];
uart_transaction pkt_qu_monuart[$];
uart_transaction pkt_qu_drvuart[$];
// Handle to a cfg class
uart_config cfg;
...
extern virtual function void build_phase(uvm_phase phase);
extern virtual function void write_monapb(apb_transaction pkt);
extern virtual function void write_monuart(uart_transaction pkt);
extern virtual function void write_drvuart(uart_transaction pkt);
extern virtual function void compare_config (apb_transaction apb_pkt);
extern virtual function void compare_transmission (apb_transaction apb_pkt, uart_transaction uart_pkt);
extern virtual function void compare_receive (apb_transaction apb_pkt , uart_transaction uart_pkt);
extern virtual task run_phase(uvm_phase phase);
endclass
// ---------------------------------------
// 获取uart_config 配置好波特率 , 帧长 , 奇偶校验 , 停止位 , Randomize Flag 等
// ---------------------------------------
function void apbuart_scoreboard::build_phase(uvm_phase phase);
...
if(!uvm_config_db#(uart_config)::get(this, "", "cfg", cfg))
`uvm_fatal("No cfg",{"Configuration must be set for: ",get_full_name(),".cfg"});
...
endfunction: build_phase
task apbuart_scoreboard::run_phase(uvm_phase phase);
apb_transaction apb_pkt_mon;
uart_transaction uart_pkt_mon;
apb_transaction apb_pkt_drv;
uart_transaction uart_pkt_drv;
forever
begin
wait(pkt_qu_monapb.size() > 0); // checking the fifo that it contains any valid entry from monitor apb
apb_pkt_mon = pkt_qu_monapb.pop_front(); // getting the entry from the start of fifo
//PWRITE=1写0读
//如果为写的同时,apb_mon的地址和配置的某个寄存器地址相同(写是cpu配置寄存器)
//根据 APB_mon 地址更新SCOREBOARD相应的寄存器值。更新对应的参数值:波特率、帧等等
if(apb_pkt_mon.PWRITE==1 && (apb_pkt_mon.PADDR == cfg.baud_config_addr || apb_pkt_mon.PADDR == cfg.frame_config_addr || apb_pkt_mon.PADDR == cfg.parity_config_addr || apb_pkt_mon.PADDR == cfg.stop_bits_config_addr))
begin
case(apb_pkt_mon.PADDR)
cfg.baud_config_addr : baud_rate_reg = apb_pkt_mon.PWDATA;
cfg.frame_config_addr : frame_len_reg = apb_pkt_mon.PWDATA;
cfg.parity_config_addr : parity_reg = apb_pkt_mon.PWDATA;
cfg.stop_bits_config_addr : stopbit_reg = apb_pkt_mon.PWDATA;
default : `uvm_error(get_type_name(),$sformatf("------ :: Incorrect Config Address :: ------"))
endcase
end
//如果为读的同时,apb_mon的地址和配置的某个寄存器地址相同(读是看cpu是否和配置同步)
//比较apb_mon和config的寄存器值
//将来自apb_monitor的值与配置了configuration后的scoreboard进行比较
//(apb_pkt.PRDATA与baud_rate_reg、frame_len_reg、parity_config_reg、stop_bits_config_reg的比对)
else if(apb_pkt_mon.PWRITE==0 && (apb_pkt_mon.PADDR == cfg.baud_config_addr || apb_pkt_mon.PADDR == cfg.frame_config_addr || apb_pkt_mon.PADDR == cfg.parity_config_addr || apb_pkt_mon.PADDR == cfg.stop_bits_config_addr))
begin
compare_config (apb_pkt_mon) ;
end
//如果apb_mon的地址和配置的发送数据寄存器地址相同
//比较apb和uart的mon数据
//数据流(1)apb_driver这边发并行数据到interface经过DUT(UART)后输出为串行数据,由uart_monitor抓到
//将apb_driver写入到DUT上的PWDATA与uart_monitor在DUT的TX—pin上监控的数据进行比较
//(apb_pkt.PWDATA与uart_pkt.transmitter_reg的比对)
else if (apb_pkt_mon.PADDR == cfg.trans_data_addr)
begin
wait(pkt_qu_monuart.size() > 0); // checking the fifo that it contains any valid entry from monitor apb
uart_pkt_mon = pkt_qu_monuart.pop_front(); // getting the entry from the start of fifo
compare_transmission (apb_pkt_mon,uart_pkt_mon);
end
//如果apb_mon的地址和配置的接收数据寄存器地址相同
//比较uart的dri数据和apb的mon数据
//数据流(2)uart_driver发送串行数据到interface经过DUT后由APB总线这边读出(prdata)
//将uart_driver提供给RX—pin的数据与apb—monitor从DUT接收到的PRDATA进行比较。
//(apb_pkt.PRDATA与uart_pkt.payload的比对)
else if (apb_pkt_mon.PADDR == cfg.receive_data_addr)
begin
wait(pkt_qu_drvuart.size() > 0); // checking the fifo that it contains any valid entry from driver
uart_pkt_drv = pkt_qu_drvuart.pop_front(); // getting the entry from the start of fifo
compare_receive (apb_pkt_mon,uart_pkt_drv);
end
end
endtask : run_phase
其中,三个不同的函数来对数据进行比较
//compare_config (apb_pkt_mon) ;
//将来自apb_monitor的值与配置了configuration后的scoreboard进行比较,用于寄存器测试
function void apbuart_scoreboard::compare_config (apb_transaction apb_pkt);
if(apb_pkt.PADDR == cfg.baud_config_addr)
begin
if(apb_pkt.PRDATA == baud_rate_reg)
`uvm_info(get_type_name(),$sformatf("------ :: Baud Rate Match :: ------"),UVM_LOW)
else
`uvm_error(get_type_name(),$sformatf("------ :: Baud Rate MisMatch :: ------"))
`uvm_info(get_type_name(),$sformatf("Expected Baud Rate: %0d Actual Baud Rate: %0d",baud_rate_reg,apb_pkt.PRDATA),UVM_LOW)
`uvm_info(get_type_name(),"------------------------------------\n",UVM_LOW)
end
if(apb_pkt.PADDR == cfg.frame_config_addr)
begin
if(apb_pkt.PRDATA == frame_len_reg)
`uvm_info(get_type_name(),$sformatf("------ :: Frame Rate Match :: ------"),UVM_LOW)
else
`uvm_error(get_type_name(),$sformatf("------ :: Frame Rate MisMatch :: ------"))
`uvm_info(get_type_name(),$sformatf("Expected Frame Rate: %0h Actual Frame Rate: %0h",frame_len_reg,apb_pkt.PRDATA),UVM_LOW)
`uvm_info(get_type_name(),"------------------------------------\n",UVM_LOW)
end
if(apb_pkt.PADDR == cfg.parity_config_addr)
begin
if(apb_pkt.PRDATA == parity_reg)
`uvm_info(get_type_name(),$sformatf("------ :: Parity Match :: ------"),UVM_LOW)
else
`uvm_error(get_type_name(),$sformatf("------ :: Parity MisMatch :: ------"))
`uvm_info(get_type_name(),$sformatf("Expected Parity Value : %0h Actual Parity Value: %0h",parity_reg,apb_pkt.PRDATA),UVM_LOW)
`uvm_info(get_type_name(),"------------------------------------\n",UVM_LOW)
end
if(apb_pkt.PADDR == cfg.stop_bits_config_addr)
begin
if(apb_pkt.PRDATA == stopbit_reg)
`uvm_info(get_type_name(),$sformatf("------ :: Stop Bit Match :: ------"),UVM_LOW)
else
`uvm_error(get_type_name(),$sformatf("------ :: Stop Bit MisMatch :: ------"))
`uvm_info(get_type_name(),$sformatf("Expected Stop Bit Value : %0h Actual Stop Value: %0h",stopbit_reg,apb_pkt.PRDATA),UVM_LOW)
`uvm_info(get_type_name(),"------------------------------------\n",UVM_LOW)
end
endfunction
//compare_transmission (apb_pkt_mon,uart_pkt_mon);
//如果apb_mon的写数据和uart_mon的发送寄存器数据相同,说明发送数据正确
function void apbuart_scoreboard::compare_transmission (apb_transaction apb_pkt, uart_transaction uart_pkt);
if(apb_pkt.PWDATA == uart_pkt.transmitter_reg)
`uvm_info(get_type_name(),$sformatf("------ :: Transmission Data Packet Match :: ------"),UVM_LOW)
else
`uvm_error(get_type_name(),$sformatf("------ :: Transmission Data Packet MisMatch :: ------"))
`uvm_info(get_type_name(),$sformatf("Expected Transmission Data Value : %0h Actual Transmission Data Value: %0h",apb_pkt.PWDATA,uart_pkt.transmitter_reg),UVM_LOW)
`uvm_info(get_type_name(),"------------------------------------\n",UVM_LOW)
endfunction
//compare_receive (apb_pkt_mon,uart_pkt_drv);
//如果apb_mon的读数据和uart_dri的产生的数据相同,说明接收的数据正确
function void apbuart_scoreboard::compare_receive (apb_transaction apb_pkt , uart_transaction uart_pkt);
if(apb_pkt.PRDATA == uart_pkt.payload)
`uvm_info(get_type_name(),$sformatf("------ :: Reciever Data Packet Match :: ------"),UVM_LOW)
else
`uvm_error(get_type_name(),$sformatf("------ :: Reciever Data Packet MisMatch :: ------"))
`uvm_info(get_type_name(),$sformatf("Expected Reciever Data Value : %0h Actual Reciever Data Value: %0h",uart_pkt.payload,apb_pkt.PRDATA),UVM_LOW)
`uvm_info(get_type_name(),"------------------------------------\n",UVM_LOW)
//$display("uart_pkt.sb_corr::%0b\tuart_pkt.sb_corr_bit[0]::%0b\tcfg.n_sb::%d",uart_pkt.sb_corr,uart_pkt.sb_corr_bit,cfg.parity[1]);
if((uart_pkt.bad_parity && cfg.parity[1]) || (uart_pkt.sb_corr && (cfg.n_sb || uart_pkt.sb_corr_bit[0])))
begin
//$display("uart_pkt.sb_corr::%0b\tuart_pkt.sb_corr_bit[0]::%0b\tcfg.n_sb::%d",uart_pkt.sb_corr,uart_pkt.sb_corr_bit[0],cfg.n_sb[0]);
if(apb_pkt.PSLVERR == 1'b1)
`uvm_info(get_type_name(),$sformatf("------ :: Error Match :: ------"),UVM_LOW)
else
`uvm_error(get_type_name(),$sformatf("------ :: Error MisMatch :: ------"))
`uvm_info(get_type_name(),$sformatf("Expected Error Value : %0h Actual Error Value: %0h",1'b1,apb_pkt.PSLVERR),UVM_LOW)
`uvm_info(get_type_name(),"------------------------------------\n",UVM_LOW)
end
else
begin
if(apb_pkt.PSLVERR == 1'b0)
`uvm_info(get_type_name(),$sformatf("------ :: Error Match :: ------"),UVM_LOW)
else
`uvm_error(get_type_name(),$sformatf("------ :: Error MisMatch :: ------"))
`uvm_info(get_type_name(),$sformatf("Expected Error Value : %0h Actual Error Value: %0h",1'b0,apb_pkt.PSLVERR),UVM_LOW)
`uvm_info(get_type_name(),"------------------------------------\n",UVM_LOW)
end
endfunction
sequence
test调用vseq,vseq调用seq
vsequence
- vseq_base
- apbuart_config_seq
- apbuart_singlebeat_seq
- apbuart_recdrv_seq
- apbuart_recreadreg_seq
- apbuart_frameError_seq
- apbuart_parityError_seq
- apbuart_NoError_seq
sequence
-
apb seq
config_apbuart //apb配置dut
transmit_single_beat //apb发送数据
rec_reg_test //apb接收数据 -
uart seq
recdrv_test_uart //正确的停止位
fe_test_uart //错误的停止位
pe_test_uart //错误的校验位
err_free_test_uart //正确的停止位和校验位
1.5 具体testcase执行验证
1.5.1 apbuart_base_test
1.模块目的
例化了env
配置了 uart_config,clk_rst_cfg,apb_config
分为定向配置和随机配置
1.5.2 apbuart_config_test
寄存器验证点
1.测试目的
通过在配置寄存器中存储特定的值来设置config。配置元素如下:波特率,帧大小,奇偶校验,停止位,可以通过使用APB接口提供的PADDR变量来访问它们的特定配置地址
2.测试思路
(1)例化apbuart_config_seq并在run phase中挂起,调用basetest中的随机配置,start挂载vsqr
(2)apbuart_config_seq是vseq,在 task body中例化config_apbuart,并挂载在apb_sqr
(3)config_apbuart是apb_seq,在task body中随机产生1笔apb_transaction,限制写/读配置寄存器的波特率/帧长/奇偶校验/停止位;同时在task body中create了uart_config,uart_config中设置了循环次数loop_time
3.
调用了scoreboard的compare_config
(Compare_config():此函数在configuration register上有读取操作时调用,将来自apb_monitor的值与配置了configuration后的scoreboard进行比较,这里的配置主要指uart_config中的波特率、帧长、奇偶校验以及停止位这几个参数。
(apb_pkt.PRDATA与baud_rate_reg、frame_len_reg、parity_config_reg、stop_bits_config_reg的比对))
1.5.3 apbuart_data_compare_test
基本数据发送功能检测
1.测试目的:
首先通过运行config sequence将配置设置写入DUT,然后将一些数据写入PWDATA端口,并通过TX-pin串行(逐位)读取数据。输出应该是相同的。加载在PWDATA上的数据应该在TX-pin上串行接收。
2.测试思路
(1)例化apbuart_config_seq和apbuart_singlebeat_seq 并在run phase中挂起,调用basetest中的随机配置,start挂载vsqr
(2) apbuart_config_seq是vseq,在 task body中例化config_apbuart,并挂载在apb_sqr
apbuart_singlebeat_seq 是vseq,在 task body中例化transmit_single_beat,并挂载在apb_sqr
(3)config_apbuart是apb_seq,在task body中随机产生1笔apb_transaction,限制写/读配置寄存器的波特率/帧长/奇偶校验/停止位
transmit_single_beat是apb_seq,在task body中随机产生1笔apb_transaction,将apb_transaction中的PWDATA写入发送寄存器
同时在task body中create了uart_config,uart_config中设置了循环次数loop_time
3.
先调用了scoreboard的compare_config
再调用了scoreboard的compare_transmission
1.5.4 apbuart_free_error_test
1.测试目的:
发送一个帧,其中停止位、校验位正确
2.测试思路
(1)例化apbuart_NoError_seq并在run phase中挂起,调用basetest中的随机配置,start挂载vsqr
(2)apbuart_NoError_seq 是vseq,在 task body中例化err_free_test_uart,并挂载在uart_sqr
(3)err_free_test_uart是uart_seq,在task body中随机产生1笔uart_transaction,将uart_transaction中的bad_parity 设置为0,sb_corr设置为0,即停止位、校验位都没有错误
3.
调用了scoreboard的compare_config
1.5.5 apbuart_frame_error_test
1.测试目的:
发送一个帧,其中包含损坏的停止位。DUT应响应输出PSLVERR位拉高。设置DUT为random config,然后运行此测试。
2.测试思路:
(1)例化apbuart_frameError_seq,并在run phase中挂起,调用basetest中的随机配置,start挂载vsqr
(2)apbuart_frameError_seq 是vseq,在 task body中例化fe_test_uart,并挂载在uart_sqr
(3)fe_test_uart是uart_seq,在task body中随机产生1笔uart_transaction,将uart_transaction中的bad_parity 设置为0,sb_corr设置为1,即停止位发生错误
3.
调用了scoreboard的compare_config
1.5.6 apbuart_parity_error_test
1.测试目的:
发送包含损坏的奇偶校验位的帧。DUT应响应PSLVERR为高。设置DUT为random config,然后运行此测试。
2.测试思路:
(1)例化apbuart_parityError_seq,并在run phase中挂起,调用basetest中的随机配置,start挂载vsqr
(2)apbuart_parityError_seq是vseq,在 task body中例化pe_test_uart,并挂载在uart_sqr
(3)pe_test_uart是uart_seq,在task body中随机产生1笔uart_transaction,将uart_transaction中的bad_parity 设置为1,sb_corr设置为0,即校验位发生错误
3.调用了scoreboard的compare_config
1.5.7 apbuart_rec_drv_test
1.测试目的:
随机奇偶校验错误,使用时钟和复位驱动器序列,时钟会有不同的周期,并会在每次transaction后进行重置。
2.测试思路:
(1)例化apbuart_config_seq、apbuart_recdrv_seq和clk_rst_default_seq并在run phase中挂起
调用basetest中的固定配置,start apbuart_config_seq、apbuart_recdrv_seq挂载vsqr
(2)apbuart_config_seq是vseq,在 task body中例化config_apbuart,并挂载在apb_sqr
apbuart_recdrv_seq是vseq,在 task body中例化recdrv_test_uart,并挂载在uart_sqr
(3)config_apbuart是apb_seq,写/读配置寄存器的波特率/帧长/奇偶校验/停止位固定配置
recdrv_test_uart是uart_seq,在task body中随机产生1笔uart_transaction,将uart_transaction中的sb_corr限制为0,即停止位没有错误,校验位rand错误
1.5.8 apbuart_rec_readreg_test
1.测试目的:
设置random config,随机奇偶校验错误和帧错误。使DUT处于receive模式,包括在RX引脚上逐位发送数据,然后在PREADY时从PRDATA端口读取数据。
2.测试思路:
(1)例化
在run phase中挂起
调用basetest中的随机配置,start挂载vsqr
(2)其中
apbuart_recreadreg_seq是vseq,在 task body中例化rec_reg_test,并挂载在apb_sqr
(3)rec_reg_test是apb_seq,在task body中随机产生1笔apb_transaction,将1笔apb_transaction中从接收寄存器的PRDATA接收读出
3.
先调用了scoreboard的compare_config
后调用了scoreboard的compare_receive
总结测试时数据流
![]()
1.5.9 APB协议检测
assertion断言
apbuart_property.sv中
断言写法
property 名称1
//描述时序行为
@(posedge PCLK) disable iff (!PRESETn)
A |-> B,A为高的时候B也为高
A |=> B,A为高的下一周期B也为高
$rose
$stable
$isunknown
endproperty
assert property(名称1)
else `uvm_error()
1.6 覆盖率收集
1.6.1questasim
1.编译
2.仿真
选择test
vsim -i -novopt -classdebug -solvefaildebug -sv_seed random +UVM_TESTNAME= work.tbench_top
log -r /*
3.run -all
1.6.1vcs
1.编译
make compile
vcs 执行 ./simv -gui时 报错原因:没有生成vpd文件
解决办法:compile加一个-debug_all
2.仿真
make run
生成了simv可执行文件
3.打开dve
./simv -gui
