其他分享
首页 > 其他分享> > (25)UVM 寄存器模型集成

(25)UVM 寄存器模型集成

作者:互联网

UVM 寄存器模型集成

文章目录

总线UVC实现代码

class mcdf_bus_trans extends uvm_sequence_item;
	rand bit [1:0]cmd;
	rand bit [7:0]addr;
	rand bit [31:0]wdata;
	bit [31:0]rdata;
	`uvm_object_utils_begin(mcdf_bus_trans)
	...
	`uvm_object_utils_end
	...
endclass
class mcdf_bus_sequencer extends uvm_sequencer;
	virtual mcdf_if vif;
	`uvm_component_utils(mcdf_bus_sequencer)
	...
	function void build_phase(uvm_phase phase);
		if(!uvm_config_db#(virtual mcdf_if)::get(this,"","vif",vif))begin
			`uvm_error("GETVIF","no virtual interface is assigned")
		end
	endfunction	
endclass

class mcdf_bus_monitor extends uvm_monitor;
	virtual mcdf_vif vif;
	uvm_analysis_port #(mcdf_bus_trans) ap;
	`uvm_component_utils(mcdf_bus_monitor)
	...
	function void build_phase(uvm_phase phase);
		if(!uvm_config_db#(virtual mcdf_if)::get(this,"","vif",vif))begin
			`uvm_error("GETVIF","no virtual interface is assigned")
		end
		ap=new("ap",this);
	endfunction
	task run_phase(uvm_phase phase);
		forever begin
			mon_trans();
		end
	endtask
	task mon_trans();
		mcdf_bus_trans t;
		@(posedge vif.clk);
		if(vif.cmd==`WRITE)begin
			t=new();
			t.cmd=`WRITE;
			t.addr=vif.addr;
			t.wdata=vif.wdata;
			ap.write(t);
		end
		else if(vif.cmd=`READ) begin
			t=new();
			t.cmd=`READ;
			t.addr=vif.addr;
			fork
				begin
					@(posedge vif.clk)
					#10ps;
					t.rdata=vif.rdata;
					ap.write(t);
				end
			join_none
		end
	endtask
endclass:mcdf_bus_monitor

class mcdf_bus_driver extends uvm_driver;
	virtual mcdf_if vif;
	`uvm_component_utils(mcdf_bus_driver)
	...
	function void build_phase(uvm_phase phase);
		if(!uvm_config_db#(virtual mcdf_if)::get(this,"","vif",vif))begin
			`uvm_error("GETVIF","no virtual interface is assigned")
		end
	endfunction
	task run_phase(uvm_phase phase);
		REQ tep;
		mcdf_bus_trans req,rsp;
		reset_listener();
		forever begin
			seq_item_port.get_next_item(tmp);
			void'($cast(req,tmp));
			`uvm_info("DRV",$sformatf("got a item\n %s",req.sprint()),UVM_LOW)
			void'($cast(rsp,req.clone()));
			rsp.set_sequence_id(req.get_sequence_id());
			rsp.set_transcation_id(req.get_transaction_id());
			drive_bus(rsp);
			seq_item_port.item_done(rsp);
			`uvm_info("DRV",$sformatf("sent a item\n %s",rsp.sprint()),UVM_LOW)
		end
	endtask
	task reset_listener();
		fork
			forever begin
				@(negedge vif.rstn)drive_idle();
			end
		join_none
	endtask
	task drive_bus(mcdf_bus_trans t);
		cast(t.cmd)
			`WRITE:drive_write(t);
			`READ:drive_read(t);
			`IDLE:drive_idle(1);
			default:`uvm_error("DRIVE","invalid mcdf command type received!")
		endcase
	endtask
	task drive_write(mcdf_bus_trans t);
		@(posedge vif.clk);
		vif.cmd<=t.cmd;
		vif.addr<=t.addr;
		vif.wdata<=t.wdata;
	endtask
	task drive_read(mcdf_bus_trans t);
		@(posedge vif.clk);
		vif.cmd<=t.cmd;
		vif.addr<=t.addr;
		@(posedge vif.clk);
		#10ps;
		t.rdata=vif.rdata;
	endtask
	task drive_idle(bit is_sync=0);
		if(is_sync)@(posedge vif.clk);
			vif.cmd<='h0;
			vif.addr<='h0;
			vif.wdata<='h0;
	endtask
endclass

class mcdf_bus_agent extends uvm_agent;
	mcdf_bus_driver driver;
	mcdf_bus_sequencer sequencer;
	mcdf_bus_monitor monitor;
	`uvm_component_utils(mcdf_bus_agent)
	...
	function void build_phase(uvm_phase phase);
		driver=mcdf_bus_driver::type_id::create("driver",this);
		sequencer=mcdf_bus_sequencer ::type_id::create("sequencer",this);
		monitor=mcdf_bus_monitor ::type_id::create("monitor",this);
	endfunction
	function void connect_phase(uvm_phase phase);
		driver.seq_item_port.connect(sequencer.seq_item_export);
	endfunction
endclass

实例囊括了mcdf_bus_agent的所有组件:sequence item、sequencer、driver、monitor和agent。我们对这些代码的部分实现给出解释:

MCDF寄存器设计代码

MCDF寄存器设计代码:

param_def.v

`define  ADDR_WIDTH 8
`define  CMD_DATA_WIDTH 32

`define  WRITE 2'b10          //Register operation command
`define  READ  2'b01
`define  IDLE  2'b00

`define SLV0_RW_ADDR 8'h00    //Register address 
`define SLV1_RW_ADDR 8'h04
`define SLV2_RW_ADDR 8'h08
`define SLV0_R_ADDR  8'h10
`define SLV1_R_ADDR  8'h14
`define SLV2_R_ADDR  8'h18


`define SLV0_RW_REG 0
`define SLV1_RW_REG 1
`define SLV2_RW_REG 2
`define SLV0_R_REG  3
`define SLV1_R_REG  4
`define SLV2_R_REG  5

`define FIFO_MARGIN_WIDTH 8

`define PRIO_WIDTH 2
`define PRIO_HIGH 2
`define PRIO_LOW  1

`define PAC_LEN_WIDTH 3
`define PAC_LEN_HIGH 5
`define PAC_LEN_LOW  3    

reg.v

   module ctrl_regs(	clk_i,
						rstn_i,
						cmd_i,
						cmd_addr_i,
						cmd_data_i,
						cmd_data_o,
			      		slv0_pkglen_o,
						slv1_pkglen_o,
						slv2_pkglen_o,
			     		slv0_prio_o,
						slv1_prio_o,
						slv2_prio_o,		
						slv0_margin_i,
						slv1_margin_i,
						slv2_margin_i,
					 	slv0_en_o,
						slv1_en_o,
						slv2_en_o);
						
input clk_i;
input rstn_i;
input [1:0] cmd_i;
input [`ADDR_WIDTH-1:0]  cmd_addr_i; 
input [`CMD_DATA_WIDTH-1:0]  cmd_data_i;
input [`FIFO_MARGIN_WIDTH-1:0] slv0_margin_i;
input [`FIFO_MARGIN_WIDTH-1:0] slv1_margin_i;
input [`FIFO_MARGIN_WIDTH-1:0] slv2_margin_i;

reg [`CMD_DATA_WIDTH-1:0] mem [5:0];
reg [`CMD_DATA_WIDTH-1:0] cmd_data_reg;

output  [`CMD_DATA_WIDTH-1:0] cmd_data_o;
output  [`PAC_LEN_WIDTH-1:0]  slv0_pkglen_o;
output  [`PAC_LEN_WIDTH-1:0]  slv1_pkglen_o;
output  [`PAC_LEN_WIDTH-1:0]  slv2_pkglen_o;
output  [`PRIO_WIDTH-1:0]  slv0_prio_o;
output  [`PRIO_WIDTH-1:0]  slv1_prio_o;
output  [`PRIO_WIDTH-1:0]  slv2_prio_o;
output   slv0_en_o;
output   slv1_en_o;
output   slv2_en_o;

always @ (posedge clk_i or negedge rstn_i) //Trace fifo's margin
begin 
  if (!rstn_i)
    begin
      mem [`SLV0_R_REG] <= 32'h00000020;   //FIFO's depth is 32
      mem [`SLV1_R_REG] <= 32'h00000020;
      mem [`SLV2_R_REG] <= 32'h00000020;
    end
    else 
    begin
      mem [`SLV0_R_REG] <= {24'b0,slv0_margin_i};
      mem [`SLV1_R_REG] <= {24'b0,slv1_margin_i};
      mem [`SLV2_R_REG] <= {24'b0,slv2_margin_i};
    end
end

always @ (posedge clk_i or negedge rstn_i) //write R&W register
begin
	if (!rstn_i)
  begin 
    mem [`SLV0_RW_REG] = 32'h00000007;
    mem [`SLV1_RW_REG] = 32'h00000007;
    mem [`SLV2_RW_REG] = 32'h00000007;
  end
 else if (cmd_i== `WRITE) begin
				case(cmd_addr_i)
				`SLV0_RW_ADDR: mem[`SLV0_RW_REG]<= {26'b0,cmd_data_i[`PAC_LEN_HIGH:0]};				
				`SLV1_RW_ADDR: mem[`SLV1_RW_REG]<= {26'b0,cmd_data_i[`PAC_LEN_HIGH:0]};			
				`SLV2_RW_ADDR: mem[`SLV2_RW_REG]<= {26'b0,cmd_data_i[`PAC_LEN_HIGH:0]};   
				endcase 
			end	
end 

always@ (posedge clk_i or negedge rstn_i) // read R&W, R register
  if(!rstn_i)
  	  cmd_data_reg <= 32'b0;
		else if(cmd_i == `READ)
      begin       
				case(cmd_addr_i)
				`SLV0_RW_ADDR:		cmd_data_reg  <= mem[`SLV0_RW_REG];
				`SLV1_RW_ADDR:		cmd_data_reg  <= mem[`SLV1_RW_REG];
				`SLV2_RW_ADDR:	  cmd_data_reg  <= mem[`SLV2_RW_REG];					
				`SLV0_R_ADDR: 		cmd_data_reg  <= mem[`SLV0_R_REG];
				`SLV1_R_ADDR: 		cmd_data_reg  <= mem[`SLV1_R_REG];
				`SLV2_R_ADDR: 		cmd_data_reg  <= mem[`SLV2_R_REG];
				endcase
     end

assign  cmd_data_o  = cmd_data_reg;
assign  slv0_pkglen_o  = mem[`SLV0_RW_REG][`PAC_LEN_HIGH:`PAC_LEN_LOW];
assign  slv1_pkglen_o  = mem[`SLV1_RW_REG][`PAC_LEN_HIGH:`PAC_LEN_LOW];
assign  slv2_pkglen_o  = mem[`SLV2_RW_REG][`PAC_LEN_HIGH:`PAC_LEN_LOW];

assign  slv0_prio_o  = mem[`SLV0_RW_REG][`PRIO_HIGH:`PRIO_LOW];
assign  slv1_prio_o  = mem[`SLV1_RW_REG][`PRIO_HIGH:`PRIO_LOW];
assign  slv2_prio_o  = mem[`SLV2_RW_REG][`PRIO_HIGH:`PRIO_LOW];
  
assign  slv0_en_o = mem[`SLV0_RW_REG][0];
assign  slv1_en_o = mem[`SLV1_RW_REG][0];
assign  slv2_en_o = mem[`SLV2_RW_REG][0];

endmodule

寄存器模型集成

在这里插入图片描述

class reg2mcdf_adapter extends uvm_reg_adapter;
	`uvm_object_utils(reg2mcdf_adapter)
	function new(string name="mcdf_bus_trans");
		super.new(name);
		provides_responses=1;
	endfunction
	function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);
		mcdf_bus_trans t=mcdf_bus_trans::type_id::create("t");
		t.cmd=(rw.kind==UVM_WRITE)?`WRITE:`READ;
		t.addr=rw.addr;
		t.wdata=rw.data;
		return t;
	endfunction

	function void bus2reg(uvm_sequence_item bus_item,ref uvm_reg_bus_op rw);
		mcdf_bus_trans t;
		if(!$cast(t,bus_item))begin
			`uvm_fatal("NOT_MCDF_BUS_TYPE","Provided bus_item is not of the correct type")
			return;
		end
		rw.kind=(t.cmd==`WRITE)?UVM_WRITE:UVM_READ;
		rw.addr=t.addr;
		rw.data=(t.cmd==`WRITE)?t.wdata:t.rdata;
		rw.status=UVM_IS_OK;
	endfunction
endclass

在这里插入图片描述

寄存器无论读写,都应当知道总线操作后的状态返回,对于读操作时,也需要知道总线返回的读数据,因此uvm_reg_adapter::bus2reg()即是从mcdf_bus_driver()将数据写回至mcdf_bus_sequencer,而一致保持监听的reg2mcdf_adapter一旦从sequencer获取了RSP(mcdf_bus_trans)之后,就将自动调用bus2reg()函数。

bus2reg()函数的功能与reg2bus()相反,完成了从mcdf_bus_trans到uvm_reg_bus_op的内容映射。在完成映射之后,更新的uvm_reg_bus_op数据最终返回至寄存器操作场景层。

对于寄存器操作,无论读操作还是写操作,都需要经历调用reg2bus),继而发起总线事务,而在完成总线事务发回反馈之后,又需要调用bus2reg(),将总线的数据返回至寄存器操作层面。

adapter集成

class mcdf_bus_env extends uvm_env;
	mcdf_bus_agent agent;
	mcdf_rgm rgm;
	reg2mcdf_adapter reg2mcdf;
	`uvm_component_utils(mcdf_bus_env)
	...
	function void build_phase(uvm_phase phase);
		agent=mcdf_bus_agent::type_id::create("agent",this);
		if(!uvm_config_db#(mcdf_rgm)::get(this,"","rgm",rgm))begin
			`uvm_info("GETVIF","no top-down RGM handle is assigned",UVM_LOW)
			rgm=mcdf_rgm::type_id::create("rgm",this);
			`uvm_info("NEWRGM","created rgm instance locally",UVM_LOW)
		end
		rgm.build();
		rgm.map.set_auto_predict();
		reg2mcdf=reg2mcdf_adapter::type_id::create("reg2mcdf");
	endfunction
	function void connect_phase(uvm_phase phase);
		rgm.map.set_sequencer(agent.sequencer,reg2mcdf);
	endfunction
endclass

register model和adapter都是object

class test1 extends uvm_test;
	mcdf_rgm rgm;
	mcdf_bus_env env;
	`uvm_component_utils(test1)
	...
	function void build_phase(uvm_phase phase);
		rgm=mcdf_rgm::type_id::create("rgm",this);
		uvm_config_db#(mcdf_rgm)::set(this,"env*","rgm",rgm);
		env=mcdf_bus_env::type_id::create("env",this);
	endfunction
	task run_phase(uvm_phase phase)
	...
	endtask
endclass

关注作者

标签:25,bus,cmd,uvm,寄存器,phase,mcdf,define,UVM
来源: https://blog.csdn.net/qq_42419590/article/details/121456751