关于axi-slave模块的随机性

关于axi_slave需要考虑如下的随机性:

(1)size,数据长度;

(2)burst length,数据包长度;

(3)4kB地址对齐;

(4)传输类型,wrap,incr;

(5)delay,分为两种,一种是写,这种delay一个burst只包含一个delay;第二种是读,这种delay一个burst包含len长度个delay;

(6)strobe信号,这个信号的随机只存在于写操作中;

(7)时钟和复位的随机性,关于时钟和复位的随机性,具体参考下面代码:

package clk_rst_pkg;
	import uvm_pkg::*;
	`include "uvm_macros.svh"
	
	class clk_rst_trans extends uvm_sequence_item;
		logic 			 	hclk;
		logic 				hrst;
		logic 				pclk;
		logic 				prst;
		rand logic [31:0] 	hclk_high_time;
		rand logic [31:0]	hclk_low_time;
		rand logic [31:0] 	pclk_high_time;
		rand logic [31:0]	pclk_low_time;
		rand logic [31:0]	hrst_time;
		rand logic [31:0]	prst_time;
		rand logic [31:0] 	ahb_transfer_reset_delay;
		rand logic [31:0] 	apb_transfer_reset_delay;
		
		constraint cstr{
			soft hclk_high_time == 5;
			soft hclk_low_time  == 5;
			soft pclk_high_time == 10;
			soft pclk_low_time  == 10;
			soft hrst_time      == 32;
			soft prst_time		== 32;};
		
		`uvm_object_utils_begin(clk_rst_trans)
			`uvm_field_int(hclk_high_time,UVM_ALL_ON)
			`uvm_field_int(hclk_low_time,UVM_ALL_ON)
			`uvm_field_int(pclk_high_time,UVM_ALL_ON)
			`uvm_field_int(pclk_low_time,UVM_ALL_ON)
			`uvm_field_int(hrst_time,UVM_ALL_ON)
			`uvm_field_int(prst_time,UVM_ALL_ON)
			`uvm_field_int(ahb_transfer_reset_delay,UVM_ALL_ON)
			`uvm_field_int(apb_transfer_reset_delay,UVM_ALL_ON)
		`uvm_object_utils_end

		function new (string name = "clk_rst_trans");
			super.new(name);
		endfunction
		
	endclass

仅仅从item上来看有这几个随机的点:(1)时钟为高的时间、为低的时间;(2)一开始复位需要的delay时间(3)传输过程中复位需要的时间。这三点在driver中都有体现。

class clk_rst_driver extends uvm_driver#(clk_rst_trans);
		virtual ahb_clk_rst_if ahb_intf;
		virtual apb_clk_rst_if apb_intf;
		uvm_event transfer_ahb_rst;
		uvm_event transfer_apb_rst;
		
		function new (string name = "clk_rst_driver");
			super.new(name);
		endfunction
		
		virtual function void build_phase(uvm_phase phase);
			super.build_phase(phase);
			if(!uvm_config_db#(virtual ahb_clk_rst_if)::get(this, "", "ahb_intf",ahb_intf))
				`uvm_fatal("driver", "can not get ahb clk interface")
			if(!uvm_config_db#(virtual apb_clk_rst_if)::get(this, "", "apb_intf",apb_intf))
				`uvm_fatal("driver", "can not get apb clk interface")
			transfer_ahb_rst = uvm_event_pool::get_global("transfer_ahb_rst");
			transfer_apb_rst = uvm_event_pool::get_global("transfer_apb_rst");
		endfunction
	
		virtual function void connect_phase(uvm_phase phase);
			super.connect_phase(phase);
		endfunction
	
		virtual task run_phase(uvm_phase phase);
			fork
				run_hclk();
				run_pclk();
				run_hrst();
				run_prst();
			join
		endtask
	
		task run_hclk();
			forever begin
				ahb_intf.drv_ck.clk <= 1'b1;
				#(this.hclk_high_time);
				ahb_intf.drv_ck.clk <= 1'b0;
				#(this.hclk_low_time);
			end
		endtask
		
		task run_pclk();
			forever begin
				apb_intf.drv_ck.clk <= 1'b1;
				#(this.pclk_high_time);
				apb_intf.drv_ck.clk <= 1'b0;
				#(this.pclk_low_time);
			end
		endtask
		
		task run_hrst();
			uvm_object tmp;
			clk_rst_trans trans;
			ahb_intf.drv_ck.rst <= 1'b0;
			#(this.hrst_time);
			ahb_intf.drv_ck.clk <= 1'b1;
			
			forever begin
				transfer_ahb_rst.wait_trigger_data(tmp);
				void'($cast(trans,tmp));
				ahb_intf.drv_ck.rst <= 1'b0;
				#(this.trans.ahb_transfer_reset_delay);
				ahb_intf.drv_ck.clk <= 1'b1;
			end
		endtask
		
		task run_prst();
			uvm_object tmp;
			clk_rst_trans trans;
			apb_intf.drv_ck.rst <= 1'b0;
			#(this.prst_time);
			apb_intf.drv_ck.clk <= 1'b1;
			
			forever begin
				transfer_apb_rst.wait_trigger_data(tmp);
				void'($cast(trans,tmp));
				apb_intf.drv_ck.rst <= 1'b0;
				#(this.trans.apb_transfer_reset_delay);
				ahb_intf.drv_ck.clk <= 1'b1;
			end
		endtask
	
	endclass
	
	class clk_rst_sqr extends uvm_sequencer #(clk_rst_trans);
	
	`uvm_component_utils(ahb_clk_rst_sqr)
		
	
	function new(string name = "clk_rst_sqr", uvm_component parent);
		super.new(name,parent);
	endfunction
	
	virtual function void build_phase(uvm_phase phase);
		super.new(name,parent);
	endclass

	endclass
	
	class clk_rst_agent extends uvm_agent;
		virtual ahb_clk_rst_if ahb_intf;
		virtual apb_clk_rst_if apb_intf;
		
		clk_rst_driver dri;
		clk_rst_sqr	   sqr;
		
		function void build_phase(uvm_phase phase);
			super.build_phase(phase);
			if(!uvm_config_db#(virtual ahb_clk_rst_if)::get(this, "", "ahb_intf", ahb_intf))
				`uvm_fatal("clk_rst_agent", "can not get ahb interface in clk_rst_agent")
		
			if(!uvm_config_db#(virtual apb_clk_rst_if)::get(this, "", "apb_intf", apb_intf))
				`uvm_fatal("clk_rst_agent", "can not get apb interface in clk_rst_agent")
				
			dri = clk_rst_driver::type_id::create("dri",this);
			sqr = clk_rst_sqr::type_id::create("sqr",this);
			
			uvm_config_db#(virtual ahb_clk_rst_if)::set(this, "dri", "ahb_intf", ahb_intf);
			uvm_config_db#(virtual apb_clk_rst_if)::set(this, "dri", "apb_intf", apb_intf);
			
		endfunction
	
		function void connect_phase(uvm_phase phase);
			super.connect_phase(phase);
			dri.seq_item_port.connect(sqr.seq_item_export);
		endfunction
	endclass

endpackage

除此以外还可以考虑时钟抖动问题:

时钟抖动的类型包含高斯分布、周期性抖动、随机分布、占空比失真抖动等。

以下是一个简单的AXI-Full Slave BFM模块的SV代码: ``` module axi_full_slave_bfm ( input logic aclk, input logic aresetn, // AXI4 signals input logic [31:0] araddr, input logic [7:0] arlen, input logic [2:0] arsize, input logic arvalid, output logic arready, input logic [31:0] rdata, input logic [1:0] rresp, input logic rvalid, output logic rready, // Memory interface signals input logic [31:0] mem_addr, input logic [31:0] mem_write_data, input logic [31:0] mem_read_data, input logic mem_write_en, input logic mem_read_en ); // AXI4 slave state machine enum logic [2:0] axi_state; parameter IDLE = 3'h0, ADDR = 3'h1, DATA = 3'h2, RESP = 3'h3; // AXI4 slave registers logic [31:0] addr_reg; logic [31:0] data_reg; logic [1:0] resp_reg; // Initialize the AXI4 slave state machine initial begin axi_state <= IDLE; end always_ff @(posedge aclk) begin if (!aresetn) begin // Reset the AXI4 slave state machine axi_state <= IDLE; addr_reg <= '0; data_reg <= '0; resp_reg <= '0; arready <= '0; rready <= '0; end else begin case (axi_state) IDLE: begin // Wait for a valid AXI4 read request if (arvalid) begin // Save the read address and move to ADDR state addr_reg <= araddr; axi_state <= ADDR; arready <= '1; end else begin arready <= '0; end end ADDR: begin // Wait for the address phase to complete if (mem_read_en) begin // Start the data phase and move to DATA state data_reg <= mem_read_data; axi_state <= DATA; end end DATA: begin // Wait for the data phase to complete if (rready && rvalid) begin // Save the read data and move to RESP state resp_reg <= rresp; axi_state <= RESP; end else begin rready <= '1; end end RESP: begin // Wait for the response phase to complete if (rready && rvalid) begin // Send the read response and move to IDLE state rresp <= resp_reg; rdata <= data_reg; axi_state <= IDLE; end else begin rready <= '1; end end endcase end end // Memory interface always_comb begin // Write data to memory if (mem_write_en) begin $mem_write(mem_addr, mem_write_data); end // Read data from memory if (mem_read_en) begin mem_read_data <= $mem_read(mem_addr); end end endmodule ``` 该模块包含一个AXI4从设备状态机和一个简单的内存接口。当从设备接收到读请求时,它将等待地址阶段完成,然后开始数据阶段,并将读取的数据保存在数据寄存器中。一旦数据阶段完成,从设备将等待响应阶段完成,并将读取的数据和响应发送回主设备。内存接口支持读写操作,并使用了$mem_read和$mem_write系统任务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值