APB-UART-2

该文详细阐述了一个UART模块的验证流程,包括理解DUT、制定验证策略、提取验证点转化为testcase、搭建验证平台、执行testcase、收集覆盖率等步骤。文中特别提到了功能类、接口类和异常类的验证点,以及如何通过APB接口和UART接口进行通信。此外,还介绍了如何利用Questasim和VCS进行覆盖率收集。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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_seqapbuart_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_seqapbuart_recdrv_seqclk_rst_default_seq并在run phase中挂起
调用basetest中的固定配置,start apbuart_config_seqapbuart_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
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值