操作VCS:make elab 、 make run GUI=1 TEST=___________ &
questasim:pwd当前路径 、 cd到sim目录下、 do rkv_i2c_sim.do进行编译和仿真
APB master侧:
apb_transfer: extends uvm_sequence_item;
两个自定义枚举:表示读写 apb_trans_kind、表示OKERROR状态apb_trans_status;
定义随机32位addr、32位data、trans_kind、trans_status、软约束为1的idle_cycles;
注册 域的自动化;
`ifndef LVC_APB_TRANSFER_SV
`define LVC_APB_TRANSFER_SV//------------------------------------------------------------------------------
//
// transfer enums, parameters, and events
//
//------------------------------------------------------------------------------
typedef enum {IDLE, WRITE, READ } lvc_apb_trans_kind;
typedef enum {OK, ERROR} lvc_apb_trans_status;//------------------------------------------------------------------------------
//
// CLASS: lvc_apb_transfer
//
//------------------------------------------------------------------------------class lvc_apb_transfer extends uvm_sequence_item;// USER: Add transaction fieldsrand bit [31:0] addr;rand bit [31:0] data;rand lvc_apb_trans_kind trans_kind; rand lvc_apb_trans_status trans_status;rand int idle_cycles;constraint cstr{soft idle_cycles == 1;};// USER: Add constraint blocks`uvm_object_utils_begin(lvc_apb_transfer)`uvm_field_enum (lvc_apb_trans_kind, trans_kind, UVM_ALL_ON)// USER: Register fields here`uvm_field_int (addr, UVM_ALL_ON)`uvm_field_int (data, UVM_ALL_ON)`uvm_field_int (idle_cycles, UVM_ALL_ON)`uvm_object_utils_end// new - constructorfunction new (string name = "lvc_apb_transfer_inst");super.new(name);endfunction : newendclass : lvc_apb_transfer`endif // LVC_APB_TRANSFER_SV
apb_master_driver.svh头文件:参数化类extends uvm_driver #(lvc_apb_transfer);
例化config;注册;virtual vif;
声明函数new (string name, uvm_component parent); 任务run()、get_and_drive()、drive_transfer(lvc_apb_transfer t)、reset_listener()、do_idle()、do_write(lvc_apb_transfer t)、do_read(lvc_apb_transfer t);
`ifndef LVC_APB_MASTER_DRIVER_SVH
`define LVC_APB_MASTER_DRIVER_SVHclass lvc_apb_master_driver extends uvm_driver #(lvc_apb_transfer);////// Public interface (Component users may manipulate these fields/methods)////lvc_apb_config cfg;// USER: Add your fields here// This macro performs UVM object creation, type control manipulation, and // factory registration`uvm_component_utils_begin(lvc_apb_master_driver)// USER: Register fields here`uvm_component_utils_end// new - constructorextern function new (string name, uvm_component parent);// uvm run phaseextern virtual task run();////// Implementation (private) interface////// The virtual interface used to drive and view HDL signals.virtual lvc_apb_if vif;// This is the method that is responsible for getting sequence transactions// and driving the transaction into the DUTextern virtual protected task get_and_drive();// This method drives a sequence trasnaction onto the interfaceextern virtual protected task drive_transfer(lvc_apb_transfer t);// This method reset interface signalsextern virtual protected task reset_listener();// This method that is responsible for sending an idle cycle to the DUTextern protected task do_idle();// This method that is to trigger write transactionextern protected task do_write(lvc_apb_transfer t);// This method that is to trigger read transactionextern protected task do_read(lvc_apb_transfer t);endclass : lvc_apb_master_driver`endif // LVC_APB_MASTER_DRIVER_SVH
apb_master_driver.sv:
实现头文件中各函数任务;run()→get_and_drive()→get_next_item、drive_transfer(req)中判断trans_kind读写(如下),克隆、id、itemdone→reset_listener()
写do_write(t):第一拍给paddr、pwrite=1、psel=1、penable=0,t.data给pwdata;第二拍penable=1传输数据;10ps后等待接口上pready等于1后,1ps判断接口上pslverr如果为1,状态转为ERROR,不为1转为OK;
读do_read(t):第一拍给paddr、pwrite=0、psel=1、penable=0;第二拍penable=1传输数据;10ps后等待接口上pready等于1后,1ps判断接口上pslverr如果为1,状态转为ERROR,不为1转为OK;并将vif上prdata给t.data;
`ifndef LVC_APB_MASTER_DRIVER_SV
`define LVC_APB_MASTER_DRIVER_SVfunction lvc_apb_master_driver::new (string name, uvm_component parent);super.new(name, parent);
endfunction : newtask lvc_apb_master_driver::run();forkget_and_drive();reset_listener();join_none
endtask : runtask lvc_apb_master_driver::get_and_drive();forever beginseq_item_port.get_next_item(req);`uvm_info(get_type_name(), "sequencer got next item", UVM_HIGH)drive_transfer(req);void'($cast(rsp, req.clone()));rsp.set_sequence_id(req.get_sequence_id());rsp.set_transaction_id(req.get_transaction_id());seq_item_port.item_done(rsp);`uvm_info(get_type_name(), "sequencer item_done_triggered", UVM_HIGH)end
endtask : get_and_drivetask lvc_apb_master_driver::drive_transfer (lvc_apb_transfer t);`uvm_info(get_type_name(), "drive_transfer", UVM_HIGH)case(t.trans_kind)IDLE : this.do_idle();WRITE : this.do_write(t);READ : this.do_read(t);default : `uvm_error("ERRTYPE", "unrecognized transaction type")endcase
endtask : drive_transfertask lvc_apb_master_driver::do_write(lvc_apb_transfer t);`uvm_info(get_type_name(), "do_write ...", UVM_HIGH)@(vif.cb_mst);vif.cb_mst.paddr <= t.addr;vif.cb_mst.pwrite <= 1;vif.cb_mst.psel <= 1;vif.cb_mst.penable <= 0;vif.cb_mst.pwdata <= t.data;@(vif.cb_mst);vif.cb_mst.penable <= 1;#10ps;wait(vif.pready === 1);#1ps;if(vif.pslverr === 1) begint.trans_status = ERROR;if(cfg.master_pslverr_status_severity == UVM_ERROR)`uvm_error(get_type_name(), "PSLVERR asserted!")else`uvm_warning(get_type_name(), "PSLVERR asserted!")endelse begint.trans_status = OK;endrepeat(t.idle_cycles) this.do_idle();
endtask: do_writetask lvc_apb_master_driver::do_read(lvc_apb_transfer t);`uvm_info(get_type_name(), "do_write ...", UVM_HIGH)@(vif.cb_mst);vif.cb_mst.paddr <= t.addr;vif.cb_mst.pwrite <= 0;vif.cb_mst.psel <= 1;vif.cb_mst.penable <= 0;@(vif.cb_mst);vif.cb_mst.penable <= 1;#10ps;wait(vif.pready === 1);#1ps;if(vif.pslverr === 1) begint.trans_status = ERROR;if(cfg.master_pslverr_status_severity == UVM_ERROR)`uvm_error(get_type_name(), "PSLVERR asserted!")else`uvm_warning(get_type_name(), "PSLVERR asserted!")endelse begint.trans_status = OK;endt.data = vif.prdata;repeat(t.idle_cycles) this.do_idle();
endtask: do_readtask lvc_apb_master_driver::do_idle();`uvm_info(get_type_name(), "do_idle ...", UVM_HIGH)@(vif.cb_mst);vif.cb_mst.psel <= 0;vif.cb_mst.penable <= 0;vif.cb_mst.pwdata <= 0;
endtask:do_idletask lvc_apb_master_driver::reset_listener();`uvm_info(get_type_name(), "reset_listener ...", UVM_HIGH)forkforever begin@(negedge vif.rstn); // ASYNC resetvif.paddr <= 0;vif.pwrite <= 0;vif.psel <= 0;vif.penable <= 0;vif.pwdata <= 0;endjoin_none
endtask`endif // LVC_APB_MASTER_DRIVER_SV
apb_master_monitor.svh头文件:extends uvm_monitor;
例化config;virtual vif;item_collected_port;定义两个变量checks_enable(控制是否检查)、coverage_enable(控制是否更新覆盖率)默认打开;注册,两个变量域的自动化;
`ifndef LVC_APB_MASTER_MONITOR_SVH
`define LVC_APB_MASTER_MONITOR_SVHclass lvc_apb_master_monitor extends uvm_monitor;////// Public interface (Component users may manipulate these fields/methods)////lvc_apb_config cfg;// This field controls if this monitor has its checkers enabled// (by default checkers are on)bit checks_enable = 1;// This field controls if this monitor has its coverage enabled// (by default coverage is on)bit coverage_enable = 1;// This property is the virtual interface needed for this component to drive// and view HDL signalsvirtual lvc_apb_if vif;// USER: Add your fields here// The following is the analysis port that allows this monitor's transaction// information to be sent to other verification componets such as// scoreboardsuvm_analysis_port #(lvc_apb_transfer) item_collected_port;// This macro performs UVM object creation, type control manipulation, and // factory registration`uvm_component_utils_begin(lvc_apb_master_monitor)`uvm_field_int(checks_enable, UVM_ALL_ON)`uvm_field_int(coverage_enable, UVM_ALL_ON)// USER: Register fields here`uvm_component_utils_end// new - constructor extern function new(string name, uvm_component parent=null);// uvm run phaseextern virtual task run();// Events needed to trigger covergroupsevent lvc_apb_master_cov_transaction;// Transfer collected covergroupcovergroup lvc_apb_master_cov_trans @lvc_apb_master_cov_transaction;// USER implemented coverpointsendgroup : lvc_apb_master_cov_trans////// Implementation (private) interface//////This is the transaction being collected by this monitor protected lvc_apb_transfer trans_collected;// This method is responsible for collecting transactions, checking,// and updating coverage extern virtual protected task monitor_transactions();// This is the methods that collects transactionsextern virtual protected task collect_transfer();// This is the method that performs checks on a transactionextern protected function void perform_transfer_checks();// This is the method that updates coverage based on a transactionextern protected function void perform_transfer_coverage();endclass : lvc_apb_master_monitor`endif // LVC_APB_MASTER_MONITOR_SVH
apb_master_monitor.sv:
实现头文件中各函数任务:new item_collected_port;run()→monitor_transactions()→collect_transfer()中在cb_mon时钟上升沿等psel=1penable=0时,工厂创建一个trans_collected后,判断读写(如下)→perform_transfer_checks(目前没用)→perform_transfer_coverage(目前没用);
写操作:等一上升沿并且接口上pready=1(说明写操作成功传输、mon需要监测);接口上传输paddr、pwdata、WRITE、OKERROR状态到trans_collected;
读操作:等一上升沿并且接口上pready=1(说明读操作成功传输、mon需要监测);接口上传输paddr、prdata、READ、OKERROR状态到trans_collected;
`ifndef LVC_APB_MASTER_MONITOR_SV
`define LVC_APB_MASTER_MONITOR_SVfunction lvc_apb_master_monitor::new(string name, uvm_component parent=null);super.new(name, parent);item_collected_port = new("item_collected_port",this);
endfunction:newtask lvc_apb_master_monitor::monitor_transactions();forever begin// Extract data from interface into transactioncollect_transfer();// Check transactionif (checks_enable)perform_transfer_checks();// Update coverageif (coverage_enable)perform_transfer_coverage();// Publish to subscribersitem_collected_port.write(trans_collected);end
endtask // monitor_transactionstask lvc_apb_master_monitor::run();forkmonitor_transactions();join_none
endtask // runtask lvc_apb_master_monitor::collect_transfer();// Advance clock@(vif.cb_mon iff (vif.cb_mon.psel === 1'b1 && vif.cb_mon.penable === 1'b0));trans_collected = lvc_apb_transfer::type_id::create("trans_collected");case(vif.cb_mon.pwrite)1'b1 : begin@(vif.cb_mon iff vif.cb_mon.pready === 1'b1);trans_collected.addr = vif.cb_mon.paddr;trans_collected.data = vif.cb_mon.pwdata;trans_collected.trans_kind = WRITE;trans_collected.trans_status = vif.cb_mon.pslverr === 1'b0 ? OK : ERROR;end 1'b0 : begin@(vif.cb_mon iff vif.cb_mon.pready === 1'b1);trans_collected.addr = vif.cb_mon.paddr;trans_collected.data = vif.cb_mon.prdata;trans_collected.trans_kind = READ;trans_collected.trans_status = vif.cb_mon.pslverr === 1'b0 ? OK : ERROR;enddefault : `uvm_error(get_type_name(), "ERROR pwrite signal value")endcase
endtask: collect_transfer // perform_transfer_checks
function void lvc_apb_master_monitor::perform_transfer_checks();// USER: do some checks on the transfer hereendfunction : perform_transfer_checks// perform_transfer_coverage
function void lvc_apb_master_monitor::perform_transfer_coverage();// USER: coverage implementation-> lvc_apb_master_cov_transaction; endfunction : perform_transfer_coverage`endif // LVC_APB_MASTER_MONITOR_SV
apb_master_sequencer.svh头文件:参数类 extends uvm_sequencer #(lvc_apb_transfer);
例化config;注册;virtual vif; 声明new();
`ifndef LVC_APB_MASTER_SEQUENCER_SVH
`define LVC_APB_MASTER_SEQUENCER_SVHclass lvc_apb_master_sequencer extends uvm_sequencer #(lvc_apb_transfer);////// Public interface (Component users may manipulate these fields/methods)////lvc_apb_config cfg;// Provide implementations of virtual methods such as get_type_name and create`uvm_component_utils_begin(lvc_apb_master_sequencer)// USER: Register fields `uvm_component_utils_end// new - constructorextern function new (string name, uvm_component parent);////// Implementation (private) interface////// The virtual interface used to drive and view HDL signals.virtual lvc_apb_if vif;endclass : lvc_apb_master_sequencer`endif // LVC_APB_MASTER_SEQUENCER_SVH
apb_master_sequencer.sv: 实现new
`ifndef LVC_APB_MASTER_SEQUENCER_SV
`define LVC_APB_MASTER_SEQUENCER_SVfunction lvc_apb_master_sequencer::new (string name, uvm_component parent);super.new(name, parent);
endfunction : new`endif // LVC_APB_MASTER_SEQUENCER_SV
apb_master_agent.svh头文件:extends uvm_agent;
例化config;例化drv、sqr、mon;注册;virtual vif;
声明函数new()、build()、connect()、assign_vi(分配virtual vif);
`ifndef LVC_APB_MASTER_AGENT_SVH
`define LVC_APB_MASTER_AGENT_SVHclass lvc_apb_master_agent extends uvm_agent;////// Public interface (Component users may manipulate these fields/methods)////lvc_apb_config cfg;// The following are the verification components that make up// this agentlvc_apb_master_driver driver;lvc_apb_master_sequencer sequencer;lvc_apb_master_monitor monitor;virtual lvc_apb_if vif;// USER: Add your fields here// This macro performs UVM object creation, type control manipulation, and // factory registration`uvm_component_utils_begin(lvc_apb_master_agent)// USER: Register your fields here`uvm_component_utils_end// new - constructorextern function new (string name, uvm_component parent);// uvm build phaseextern function void build();// uvm connection phaseextern function void connect();// This method assigns the virtual interfaces to the agent's childrenextern function void assign_vi(virtual lvc_apb_if vif);////// Implementation (private) interface////endclass : lvc_apb_master_agent`endif // LVC_APB_MASTER_AGENT_SVH
apb_master_agent.sv:new();
build()中get config、virtual vif 并 工厂创建mon、cfg传递给mon;判断cfg中is_active是否为1,创建seq、drv并传递cfg;
connect()中调用assign_vi函数传递vif;判断is_active为1,将drv port和seq export连接;
assign_vi函数,vif连接mon的vif;判断is_active为1,vif连接seq和drv的vif;
`ifndef LVC_APB_MASTER_AGENT_SV
`define LVC_APB_MASTER_AGENT_SVfunction lvc_apb_master_agent::new(string name, uvm_component parent);super.new(name, parent);
endfunction : newfunction void lvc_apb_master_agent::build();super.build();// get configif( !uvm_config_db#(lvc_apb_config)::get(this,"","cfg", cfg)) begin`uvm_warning("GETCFG","cannot get config object from config DB")cfg = lvc_apb_config::type_id::create("cfg");end// get virtual interfaceif( !uvm_config_db#(virtual lvc_apb_if)::get(this,"","vif", vif)) begin`uvm_fatal("GETVIF","cannot get vif handle from config DB")endmonitor = lvc_apb_master_monitor::type_id::create("monitor",this);monitor.cfg = cfg;if(cfg.is_active == UVM_ACTIVE) beginsequencer = lvc_apb_master_sequencer::type_id::create("sequencer",this);sequencer.cfg = cfg;driver = lvc_apb_master_driver::type_id::create("driver",this);driver.cfg = cfg;end
endfunction : buildfunction void lvc_apb_master_agent::connect();assign_vi(vif);if(is_active == UVM_ACTIVE) begindriver.seq_item_port.connect(sequencer.seq_item_export); endendfunction : connectfunction void lvc_apb_master_agent::assign_vi(virtual lvc_apb_if vif);monitor.vif = vif;if (is_active == UVM_ACTIVE) beginsequencer.vif = vif; driver.vif = vif; end
endfunction : assign_vi`endif // LVC_APB_MASTER_AGENT_SV