搭建文件框架
ahb_gpio_config
`ifndef AHB_GPIO_CONFIG_SV`define AHB_GPIO_CONFIG_SVclass ahb_gpio_config extends uvm_object;int seq_check_count;int seq_check_error;int scb_check_count;int scb_check_error;bit scb_enable = 1;bit cov_enable = 1;ahb_agent_configuration ahb_cfg;virtual ahb_gpio_if vif;ahb_gpio_rgm rgm;`uvm_object_utils(ahb_gpio_config)// USER to specify the config itemsfunction new (string name = "ahb_gpio_config");super.new(name);ahb_cfg = ahb_agent_configuration::type_id::create("ahb_cfg");endfunction : newendclass`endif // AHB_GPIO_CONFIG_SV
ahb_gpio_cov
`ifndef AHB_GPIO_COV_SV`define AHB_GPIO_COV_SVclass ahb_gpio_cov extends ahb_gpio_subscriber;`uvm_component_utils(ahb_gpio_cov)function new (string name = "ahb_gpio_cov", uvm_component parent);super.new(name, parent);endfunctionfunction void build_phase(uvm_phase phase);super.build_phase(phase);endfunctiontask do_listen_events();endtaskvirtual function void write(ahb_transaction tr);endfunctionendclass`endif // AHB_GPIO_COV_SV
env
ahb_gpio_env
`ifndef AHB_GPIO_ENV_SV`define AHB_GPIO_ENV_SVclass ahb_gpio_env extends uvm_env;ahb_master_agent ahb_mst;ahb_gpio_config cfg;ahb_gpio_virtual_sequencer virt_sqr;ahb_gpio_rgm rgm;ahb_gpio_adapter adapter;uvm_reg_predictor #(ahb_transaction) predictor;ahb_gpio_cov cov;ahb_gpio_scoreboard scb;`uvm_component_utils(ahb_gpio_env)function new (string name = "ahb_gpio_env", uvm_component parent);super.new(name, parent);endfunctionfunction void build_phase(uvm_phase phase);super.build_phase(phase);// Get configuration from test layerif(!uvm_config_db#(ahb_gpio_config)::get(this,"","cfg", cfg)) begin`uvm_fatal("GETCFG","cannot get config object from config DB")enduvm_config_db#(ahb_gpio_config)::set(this, "virt_sqr", "cfg", cfg);uvm_config_db#(ahb_gpio_config)::set(this, "cov", "cfg", cfg);uvm_config_db#(ahb_gpio_config)::set(this, "scb", "cfg", cfg);uvm_config_db#(ahb_agent_configuration)::set(this, "ahb_mst", "cfg", cfg.ahb_cfg);ahb_mst = ahb_master_agent::type_id::create("ahb_mst", this);virt_sqr = ahb_gpio_virtual_sequencer::type_id::create("virt_sqr", this);if(!uvm_config_db#(ahb_gpio_rgm)::get(this,"","rgm", rgm)) beginrgm = ahb_gpio_rgm::type_id::create("rgm", this);rgm.build();enduvm_config_db#(ahb_gpio_rgm)::set(this, "*", "rgm", rgm);adapter = ahb_gpio_adapter::type_id::create("adapter");predictor = uvm_reg_predictor#(ahb_transaction)::type_id::create("predictor", this);scb = ahb_gpio_scoreboard::type_id::create("scb", this);cov = ahb_gpio_cov::type_id::create("cov", this);endfunctionfunction void connect_phase(uvm_phase phase);super.connect_phase(phase);virt_sqr.ahb_mst_sqr = ahb_mst.sequencer;rgm.map.set_sequencer(ahb_mst.sequencer, adapter);ahb_mst.monitor.item_observed_port.connect(predictor.bus_in);predictor.map = rgm.map;predictor.adapter = adapter;ahb_mst.monitor.item_observed_port.connect(cov.ahb_trans_observed_imp);ahb_mst.monitor.item_observed_port.connect(scb.ahb_trans_observed_imp);endfunctionfunction void report_phase(uvm_phase phase);string reports = "\n";super.report_phase(phase);reports = {reports, $sformatf("================================================= \n")};reports = {reports, $sformatf("CURRENT TEST SUMMARY \n")};reports = {reports, $sformatf("SEQUENCE CHECK COUNT : %0d \n", cfg.seq_check_count)};reports = {reports, $sformatf("SEQUENCE CHECK ERROR : %0d \n", cfg.seq_check_error)};reports = {reports, $sformatf("SCOREBOARD CHECK COUNT : %0d \n", cfg.scb_check_count)};reports = {reports, $sformatf("SCOREBOARD CHECK COUNT : %0d \n", cfg.scb_check_error)};reports = {reports, $sformatf("================================================= \n")};`uvm_info("TEST_SUMMARY",reports, UVM_LOW);endfunctionendclass`endif // AHB_GPIO_ENV_SV
ahb_gpio_pkg
`ifndef AHB_GPIO_PKG_SV`define AHB_GPIO_PKG_SVpackage ahb_gpio_pkg;import uvm_pkg::*;`include "uvm_macros.svh"import ahb_pkg::*;`include "ahb_gpio_reg.sv"`include "ahb_gpio_config.sv"`include "ahb_gpio_adapter.sv"`include "ahb_gpio_subscriber.sv"`include "ahb_gpio_cov.sv"`include "ahb_gpio_scoreboard.sv"`include "ahb_gpio_virtual_sequencer.sv"`include "ahb_gpio_env.sv"`include "ahb_gpio_seq_lib.svh"`include "ahb_gpio_tests.svh"endpackage`endif // AHB_GPIO_PKG_SV
ahb_gpio_adapter
`ifndef AHB_GPIO_ADAPTER_SV`define AHB_GPIO_ADAPTER_SVclass ahb_gpio_adapter extends uvm_reg_adapter;`uvm_object_utils(ahb_gpio_adapter)function new(string name = "ahb_gpio_adapter");super.new(name);endfunctionfunction uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);endfunctionfunction void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);endfunctionendclass`endif //AHB_GPIO_ADAPTER_SV
ahb_gpio_subsriber
`ifndef AHB_GPIO_SUBSCRIBER_SV`define AHB_GPIO_SUBSCRIBER_SV`uvm_analysis_imp_decl(_apb)class ahb_gpio_subscriber extends uvm_component;// analysis importuvm_analysis_imp #(ahb_transaction, ahb_gpio_subscriber) ahb_trans_observed_imp;// Declare eventsahb_gpio_config cfg;virtual ahb_gpio_if vif;`uvm_component_utils(ahb_gpio_subscriber)function new(string name = "ahb_gpio_subscriber", uvm_component parent);super.new(name, parent);endfunctionfunction void build_phase(uvm_phase phase);super.build_phase(phase);ahb_trans_observed_imp = new("ahb_trans_observed_imp", this);// Get configuration from test layerif(!uvm_config_db#(ahb_gpio_config)::get(this, "", "cfg", cfg)) begin`uvm_fatal("GETCFG", "cannot get conifg object from config db")endvif = cfg.vif;endfunctiontask run_phase(uvm_phase phase);super.run_phase(phase);do_events_trigger();do_listen_events();endtaskvirtual function void write(ahb_transaction tr);endfunctionvirtual task do_events_trigger();endtaskvirtual task do_listen_events();endtaskendclass`endif // AHB_GPIO_SUBSCRIBER_SV
ahb_gpio_scoreboard
`ifndef AHB_GPIO_SCOREBOARD_SV`define AHB_GPIO_SCOREBOARD_SVclass ahb_gpio_scoreboard extends ahb_gpio_subscriber;bit [31:0] mem [int unsigned];// Events of scoreboard`uvm_component_utils(ahb_gpio_scoreboard)function new (string name = "ahb_gpio_scoreboard", uvm_component parent);super.new(name, parent);endfunctionfunction void build_phase(uvm_phase phase);super.build_phase(phase);endfunctiontask run_phase(uvm_phase phase);super.run_phase(phase);do_data_check();endtaskvirtual function void write(ahb_transaction tr);endfunctiontask do_listen_events();endtaskvirtual task do_data_check();endtaskendclass`endif // AHB_GPIO_SCOREBOARD_SV
reg
ahb_gpio_reg
`ifndef AHB_GPIO_REG_SV`define AHB_GPIO_REG_SVclass ahb_gpio_rgm extends uvm_reg_block;`uvm_object_utils(ahb_gpio_rgm)uvm_reg_map map;function new (string name = "ahb_gpio_rgm");super.new(name, UVM_NO_COVERAGE);endfunctionvirtual function build();map = create_map("map", 'h0, 4, UVM_LITTLE_ENDIAN);lock_model();endfunctionendclass`endif // AHB_GPIO_REG_SV
seq_lib
elem_seqs
ahb_element_sequences
`ifndef AHB_GPIO_ELEMENT_SEQUENCES_SVH`define AHB_GPIO_ELEMENT_SEQUENCES_SVH`include "ahb_gpio_element_base_seq.sv"`include "ahb_gpio_single_write_seq.sv"`include "ahb_gpio_single_read_seq.sv"`endif // AHB_GPIO_ELEMENT_SEQUENCES_SVH
ahb_gpio_element_base_seq
`ifndef AHB_GPIO_ELEMENT_BASE_SEQ_SV`define AHB_GPIO_ELEMENT_BASE_SEQ_SVclass ahb_gpio_element_base_seq extends uvm_sequence;ahb_gpio_config cfg;virtual ahb_gpio_if vif;ahb_gpio_rgm rgm;bit [31:0] rd_val, wr_val;uvm_status_e status;`uvm_object_utils(ahb_gpio_element_base_seq)`uvm_declare_p_sequencer(ahb_gpio_virtual_sequencer)function new(string name = "ahb_gpio_element_base_seq");super.new(name);endfunctionvirtual task body();`uvm_info("body","Entered...",UVM_LOW)//Get cfg from p_sequencercfg = p_sequencer.cfg;vif = cfg.vif;rgm = cfg.rgm;`uvm_info("body","Exiting...",UVM_LOW)endtaskvirtual function void compare_data(logic[31:0] val1, logic[31:0] val2);cfg.seq_check_count++;if(val1 === val2)`uvm_info("CMPSUC", $sformatf("val1 'h%0x === val2 'h%0x", val1, val2), UVM_LOW)else begincfg.seq_check_error++;`uvm_error("CMPSUC", $sformatf("val1 'h%0x !== val2 'h%0x", val1, val2))endendfunctionendclass`endif //AHB_GPIO_ELEMENT_BASE_SEQ_SV
ahb_gpio_seq_lib.svh
`ifndef AHB_GPIO_SEQ_LIB_SVH`define AHB_GPIO_SEQ_LIB_SVH`include "ahb_gpio_element_sequences.svh"`include "ahb_gpio_base_virt_seq.sv"`include "ahb_gpio_portout_set_virt_seq.sv"`endif // AHB_GPIO_SEQ_LIB_SVH
ahb_gpio_base_virt_seq
`ifndef AHB_GPIO_BASE_VIRT_SEQ_SV`define AHB_GPIO_BASE_VIRT_SEQ_SVclass ahb_gpio_base_virt_seq extends uvm_sequence;ahb_gpio_config cfg;virtual ahb_gpio_if vif;ahb_gpio_rgm rgm;bit [31:0] rd_val, wr_val;uvm_status_e status;// declaration of element sequenceahb_gpio_single_write_seq single_write;ahb_gpio_single_read_seq single_read;`uvm_object_utils(ahb_gpio_base_virt_seq)`uvm_declare_p_sequencer(ahb_gpio_virtual_sequencer)function new(string name = "ahb_gpio_base_virt_seq");super.new(name);endfunctionvirtual task body();`uvm_info("body","Entered...",UVM_LOW)//Get cfg from p_sequencercfg = p_sequencer.cfg;vif = cfg.vif;rgm = cfg.rgm;wait_ready_for_stim();// TO do in sub_class`uvm_info("body","Exiting...",UVM_LOW)endtaskvirtual function void compare_data(logic[31:0] val1, logic[31:0] val2);cfg.seq_check_count++;if(val1 === val2)`uvm_info("CMPSUC", $sformatf("val1 'h%0x === val2 'h%0x", val1, val2), UVM_LOW)else begincfg.seq_check_error++;`uvm_error("CMPSUC", $sformatf("val1 'h%0x !== val2 'h%0x", val1, val2))endendfunctiontask wait_reset_asserted();@(posedge vif.rst_n);endtasktask wait_reset_released();@(negedge vif.rst_n);endtasktask wait_cycles(int n = 1);repeat(n) @(posedge vif.clk);endtasktask wait_ready_for_stim();wait_reset_released();wait_cycles(10);endtaskendclass`endif //AHB_GPIO_BASE_VIRT_SEQ
test
ahb_gpio_base_test
`ifndef AHB_GPIO_BASE_TEST_SV`define AHB_GPIO_BASE_TEST_SVvirtual class ahb_gpio_base_test extends uvm_test;ahb_gpio_config cfg;ahb_gpio_env env;ahb_gpio_rgm rgm;function new(string name = "ahb_gpio_base_test", uvm_component parent);super.new(name, parent);endfunctionfunction void build_phase(uvm_phase phase);super.build_phase(phase);rgm = ahb_gpio_rgm::type_id::create("rgm");rgm.build();uvm_config_db#(ahb_gpio_rgm)::set(this, "env", "rgm", rgm);cfg = ahb_gpio_config::type_id::create("cfg");cfg.rgm = rgm;// do pagpioeter configurationcfg.addr_start = 32'h0;cfg.addr_end = 32'h0000_FFFF;if(!uvm_config_db#(virtual ahb_gpio_if)::get(this,"","vif", cfg.vif)) begin`uvm_fatal("GETCFG","cannot get virtual interface from config DB")enduvm_config_db#(ahb_gpio_config)::set(this, "env", "cfg", cfg);env = ahb_gpio_env::type_id::create("env", this);endfunctionfunction void connect_phase(uvm_phase phase);super.connect_phase(phase);endfunctiontask run_phase(uvm_phase phase);super.run_phase(phase);phase.phase_done.set_drain_time(this, 1us);phase.raise_objection(this);phase.drop_objection(this);endtaskendclass`endif //AHB_GPIO_BASE_TEST
ahb_gpio_portout_set_test
`ifndef AHB_RAM_SMOKE_TEST_SV`define AHB_RAM_SMOKE_TEST_SVclass ahb_ram_smoke_test extends ahb_ram_base_test;`uvm_component_utils(ahb_ram_smoke_test)function new(string name = "ahb_ram_smoke_test", uvm_component parent);super.new(name, parent);endfunctionfunction void build_phase(uvm_phase phase);super.build_phase(phase);endfunctiontask run_phase(uvm_phase phase);ahb_ram_smoke_virt_seq seq = ahb_ram_smoke_virt_seq::type_id::create("this");super.run_phase(phase);phase.raise_objection(this);seq.start(env.virt_sqr);phase.drop_objection(this);endtaskendclass`endif //AHB_RAM_SMOKE_TEST_SV
tb
ahb_gpio_if
`ifndef AHB_GPIO_IF_SV`define AHB_GPIO_IF_SVinterface ahb_gpio_if;logic clk;logic rst_n;initial begin : rst_n_genassert_reset(10);endtask automatic assert_reset(int nclks = 1, int delay = 0);#(delay * 1ns);repeat(nclks) @(posedge clk);rst_n <= 0;repeat(5) @(posedge clk);rst_n <= 1;endtaskendinterface`endif // AHB_GPIO_IF_SV
ahb_gpio_tb
当我们完成了上述的这些步骤以后,接下来就需要搭建编辑tb文件了,完成tb和DUT端口的连接:
`ifndef AHB_RAM_TB_SV`define AHB_RAM_TB_SVmodule ahb_ram_tb;import uvm_pkg::*;`include "uvm_macros.svh"import ahb_ram_pkg::*;logic clk;logic rst_n;initial begin : generate_clkclk = 0;forever #2ns clk = !clk;end// AHB_RAM -> AHB_GPIOahb_blockram_32 #(.ADDRESSWIDTH(16)) dut(.HCLK (ahb_if.hclk),.HRESETn (ahb_if.hreset_n),.HSELBRAM (1'b1),.HREADY (ahb_if.hready),.HTRANS (ahb_if.htrans),.HSIZE (ahb_if.hsize),.HWRITE (ahb_if.hwrite),.HADDR (ahb_if.haddr),.HWDATA (ahb_if.hwdata),.HREADYOUT (ahb_if.hready),.HRESP (ahb_if.hresp),.HRDATA (ahb_if.hrdata));module cmsdk_ahb_gpio#(// Parameter to define valid bit pattern for Alternate functions// If an I/O pin does not have alternate function its function mask// can be set to 0 to reduce gate count.//// By default every bit can have alternate functionparameter ALTERNATE_FUNC_MASK = 16'hFFFF,// Default alternate function settingsparameter ALTERNATE_FUNC_DEFAULT = 16'h0000,// By default use little endianparameter BE = 0)// ----------------------------------------------------------------------------// Port Definitions// ----------------------------------------------------------------------------(// AHB Inputs.HCLK, (ahb_if.hclk) // system bus clock.HRESETn, (ahb_if.hreset_n) // system bus reset.FCLK, (ahb_if.hclk) // system bus clock.HSEL, (1'b1) // AHB peripheral select.HREADY, (ahb_if.hready) // AHB ready input.HTRANS, (ahb_if.htrans) // AHB transfer type.HSIZE, (ahb_if.hsize) // AHB hsize.HWRITE, (ahb_if.hwrite) // AHB hwrite.HADDR, (ahb_if.haddr) // AHB address bus.HWDATA, (ahb_if.hwdata) // AHB write data bus.ECOREVNUM, (4'b0110) // Engineering-change-order revision bits.PORTIN, (ahb_gpio_if.portin) // GPIO Interface input.HREADYOUT, (ahb_if.hready) // AHB ready output to S->M mux.HRESP, (ahb_if.hresp) // AHB response.HRDATA, (ahb_if.hrdata).PORTOUT, (ahb_gpio_if.portout) // GPIO output.PORTEN, (ahb_gpio_if.porten) // GPIO output enable.PORTFUNC, (ahb_gpio_if.portfunc) // Alternate function control.GPIOINT, (ahb_gpio_if.gpioint) // Interrupt output for each pin.COMBINT (ahb_gpio_if.combint) // Combined interrupt);// ----------------------------------------------------------------------------// Internal wires// ----------------------------------------------------------------------------wire [31:0] IORDATA; // I/0 read data buswire IOSEL; // Decode for peripheralwire [11:0] IOADDR; // I/O transfer addresswire IOWRITE; // I/O transfer directionwire [1:0] IOSIZE; // I/O transfer sizewire IOTRANS; // I/O transactionwire [31:0] IOWDATA; // I/O write data busahb_if ahb_if();assign ahb_if.hclk = clk;assign ahb_if.hreset_n = rst_n;assign ahb_if.hgrant = 1'b1;ahb_ram_if ahb_ram_if();assign ahb_ram_if.hclk = clk;assign ahb_ram_if.fclk = clk;assign rst_n = ahb_ram_if.rst_n;initial beginuvm_config_db #(virtual ahb_if)::set(uvm_root::get(), "uvm_test_top.env.ahb_mst", "vif", ahb_if);uvm_config_db #(virtual ahb_ram_if)::set(uvm_root::get(), "uvm_test_top", "vif", ahb_ram_if);uvm_config_db #(virtual ahb_ram_if)::set(uvm_root::get(), "uvm_test_top.env", "vif", ahb_ram_if);uvm_config_db #(virtual ahb_ram_if)::set(uvm_root::get(), "uvm_test_top.env.virt_sqr", "vif", ahb_ram_if);run_test();endendmodule`endif // AHB_RAM_TB_SV
- 在连接的过程中,我们可以将DUT中左边与AHB相关的,将他们的信号连接到ahb_if中的信号中,DUT右边的信号与AHB协议没有关系,因此我们需要在当前这个模块的if中声明这些信号并将他们进行连接;
- 另外我们需要注意的就是:
在整个GPIO的模块中是有hclk和fclk两个时钟的,所以我们需要在ahb_gpio_if中声明这两个信号并将他们与tb中的时钟信号进行连接。
后面的括号中放置的一些我们用于端口中的典型的特征值,因此我们不需要修改,直接使用设计代码中的默认值即可
Makefile & 查看波形文件
最后我们重新编辑一下makefile文件,并在sim_run.do文件中放入该波形文件的名称:
############################## User variables#############################TB = ahb_gpio_tbSEED = 1GUI ?= 0COV ?= 0DOTCL ?= 1VERB ?= UVM_HIGHOUT ?= outTESTNAME ?= ahb_gpio_portout_set_testDFILES = ../../verilog/{cmsdk_ahb_gpio.v,cmsdk_ahb_to_iop.v,cmsdk_iop_gpio.v}VFILES += ../vip_lib/ahb_pkg/ahb_pkg.sv \../vip_lib/ahb_pkg/ahb_if.sv \../env/ahb_gpio_pkg.sv \../tb/ahb_gpio_if.sv \../tb/ahb_gpio_tb.sv############################## Environment variables#############################VCOMP_INC = +incdir+../../verilog \+incdir+../vip_lib/ahb_pkg/{.,sequence_lib} \+incdir+../{cfg,cov,reg,env,seq_lib,seq_lib/elem_seqs,test}VCOMP = vlogan -full64 -ntb_opts uvm-1.2 -sverilog -timescale=1ps/1ps -nc -l $(OUT)/log/comp.log $(VCOMP_INC)ELAB = vcs -full64 -ntb_opts uvm-1.2 -debug_acc+all -l $(OUT)/log/elab.log -sim_res=1psRUN = $(OUT)/obj/$(TB).simv -l run.log -sml +ntb_random_seed=$(SEED) +UVM_TESTNAME=$(TESTNAME) +UVM_VERBOSITY=$(VERB) -cm_dir $(CM_DIR) -cm_name $(CM_NAME)COV_OPTS = -full64 -dir $(CM_DIR)CM_DIR ?= $(OUT)/cov.vdbCM_NAME ?= $(TESTNAME)_$(SEED)SIMRUNFILE = ahb_gpio_sim_run.doifeq ($(GUI),1)RUN += -guiendififeq ($(DOTCL),1)RUN += -ucli -do $(SIMRUNFILE)endififeq ($(COV),1)ELAB += -cm line+cond+fsm+tgl+branch+assert -cm_dir $(CM_DIR)RUN += -cm line+cond+fsm+tgl+branch+assert -covg_cont_on_errorendifprepare:mkdir -p $(OUT)/workmkdir -p $(OUT)/logmkdir -p $(OUT)/simmkdir -p $(OUT)/objmkdir -p .shadowcomp: prepare$(VCOMP)$(VCOMP) $(DFILES) $(VFILES)elab: comp$(ELAB) -top $(TB) -o $(OUT)/obj/$(TB).simvrun:$(RUN)mergecov:urg -format both $(COV_OPTS)dvecov:dve $(COV_OPTS)verdicov:verdi -cov -covdir $(CM_DIR)htmlcov:firefox urgReport/dashboard.htmlclean:rm -rf $(OUT) 64 AN.DB DVEfiles csrc *.simv *.simv.daidir *.simv.vdb ucli.keyrm -rf *.log* *.vpd *.h urgReport
【调试及结果】


我们运行默认的ahb_gpio_portout_set_test,运行之后打打开uvm_debug,可以发现没有错误出现且所有phase均正常运行。
