I2C学习笔记——00apb_mst侧trans、drv、mon、sqr、agt

操作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 fields

  rand 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 - constructor
  function new (string name = "lvc_apb_transfer_inst");
    super.new(name);
  endfunction : new


endclass : 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_SVH

class 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 - constructor
  extern function new (string name, uvm_component parent);

  // uvm run phase
  extern 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 DUT
  extern virtual protected task get_and_drive();
 
  // This method drives a sequence trasnaction onto the interface
  extern virtual protected task drive_transfer(lvc_apb_transfer t);

  // This method reset interface signals
  extern virtual protected task reset_listener();
 
  // This method that is responsible for sending an idle cycle to the DUT
  extern protected task do_idle();
  // This method that is to trigger write transaction
  extern protected task do_write(lvc_apb_transfer t);
  // This method that is to trigger read transaction
  extern 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()将paddr pwrite psel penable pwdata置0;

        写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_SV

function lvc_apb_master_driver::new (string name, uvm_component parent);
  super.new(name, parent);
endfunction : new

task lvc_apb_master_driver::run();
   fork
     get_and_drive();
     reset_listener();
   join_none
endtask : run

task lvc_apb_master_driver::get_and_drive();
  forever begin
    seq_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_drive

task 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_transfer

task 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) begin
    t.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!")
  end
  else begin
    t.trans_status = OK;
  end
  repeat(t.idle_cycles) this.do_idle();
endtask: do_write

task 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) begin
    t.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!")
  end
  else begin
    t.trans_status = OK;
  end
  t.data = vif.prdata;
  repeat(t.idle_cycles) this.do_idle();
endtask: do_read

task 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_idle

task lvc_apb_master_driver::reset_listener();
  `uvm_info(get_type_name(), "reset_listener ...", UVM_HIGH)
  fork
    forever begin
      @(negedge vif.rstn); // ASYNC reset
      vif.paddr <= 0;
      vif.pwrite <= 0;
      vif.psel <= 0;
      vif.penable <= 0;
      vif.pwdata <= 0;
    end
  join_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_SVH

class 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 signals
  virtual 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
  // scoreboards
  uvm_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 phase
   extern virtual task run();

  // Events needed to trigger covergroups
  event lvc_apb_master_cov_transaction;

  // Transfer collected covergroup
  covergroup lvc_apb_master_cov_trans @lvc_apb_master_cov_transaction;
    // USER implemented coverpoints
  endgroup : 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 transactions
  extern virtual protected task collect_transfer();

  // This is the method that performs checks on a transaction
  extern protected function void perform_transfer_checks();

  // This is the method that updates coverage based on a transaction
  extern 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、pwdataWRITE、OKERROR状态到trans_collected;

        读操作:等一上升沿并且接口上pready=1(说明读操作成功传输、mon需要监测);接口上传输paddr、prdataREAD、OKERROR状态到trans_collected;

`ifndef LVC_APB_MASTER_MONITOR_SV
`define LVC_APB_MASTER_MONITOR_SV

function lvc_apb_master_monitor::new(string name, uvm_component parent=null);
  super.new(name, parent);
  item_collected_port = new("item_collected_port",this);
endfunction:new

task lvc_apb_master_monitor::monitor_transactions();
   forever begin
 
      // Extract data from interface into transaction
      collect_transfer();

      // Check transaction
      if (checks_enable)
 	      perform_transfer_checks();

      // Update coverage
      if (coverage_enable)
 	      perform_transfer_coverage();

      // Publish to subscribers
      item_collected_port.write(trans_collected);

   end
endtask // monitor_transactions
   

task lvc_apb_master_monitor::run();
  fork
    monitor_transactions();
  join_none
endtask // run
  
  
task 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;
              end
    default : `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 here

endfunction : 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_SVH

class 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 - constructor
  extern 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_SV

function 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_SVH

class 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 agent
  lvc_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 - constructor
  extern function new (string name, uvm_component parent);

  // uvm build phase
  extern function void build();

  // uvm connection phase
  extern function void connect();
  
  // This method assigns the virtual interfaces to the agent's children
  extern 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_SV

function lvc_apb_master_agent::new(string name, uvm_component parent);
  super.new(name, parent);
endfunction : new


function void lvc_apb_master_agent::build();
  super.build();
  // get config
  if( !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 interface
  if( !uvm_config_db#(virtual lvc_apb_if)::get(this,"","vif", vif)) begin
    `uvm_fatal("GETVIF","cannot get vif handle from config DB")
  end
  monitor = lvc_apb_master_monitor::type_id::create("monitor",this);
  monitor.cfg = cfg;
  if(cfg.is_active == UVM_ACTIVE) begin
    sequencer = 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 : build

function void lvc_apb_master_agent::connect();
  assign_vi(vif);

  if(is_active == UVM_ACTIVE) begin
    driver.seq_item_port.connect(sequencer.seq_item_export);       
  end

endfunction : connect
  
function void lvc_apb_master_agent::assign_vi(virtual lvc_apb_if vif);
   monitor.vif = vif;
   if (is_active == UVM_ACTIVE) begin
      sequencer.vif = vif; 
      driver.vif = vif; 
    end
endfunction : assign_vi



`endif // LVC_APB_MASTER_AGENT_SV

你可能感兴趣的:(学习,笔记)