UVM - 12(driver and monitor 练习)

uvm exercise-1

  • 实现apb_sequencer.sv,传输数据类型式abp_trans
  • 实现virtual sequencer.sv,定义两个sub sequencer:mst_sqr,slv_sqr
class abp_sequencer extends uvm_sequencer #(apb_trans);
  `uvm_component_utils(apb_sequencer);
  
  function new(string name,uvm_component parent);
    super.new(name,parent);
  endfunction

  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
  endfunction

endclass
class virtual_sequencer extends uvm_sequencer;

  `uvm_component_utils(virtual_sequencer);

  apb_sequencer mst_sqr;
  apb_sequnecer slv_sqr;
    
  function new(string name,uvm_component parent);
    super.new(name,parent);
  endfunction

endclass

driver的写法


  • sequencer将数据传递给driver
  • driver通过接口将数据传递给dut
  • driver和sequencer的连接通过driver中的seq_item_port和sequencer的seq_item_export连接
  • env --> agent --> driver/sequencer/monitor
  • 在env中例化agent之后,可以通过uvm_config_db设置默认的sequence及执行位置
  • 在agent中例化driver和sequencer之后可以在connect phase中调用driver.seq_item_port.connect(seqr.seq_item_export)进行连接
class  gpio_driver extends uvm_driver #(gpio_transfer);
  // 注册
  `uvm_component_utils(gpio_driver);
  // driver需要将接口信号传给dut,所以要用虚接口
  virtual gpio_if gpio_if;
  

  // 构造函数
  function new(string name,uvm_component parent);
    super.new(name,parent);
  endfunction
  
  // connect_phase中得到gpio_if接口
  function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    if(!uvm_config_db #(virtual gpio_if)::get(this,"","gpio_if",gpio_if))
    `uvm_error("NOVIF",{"virtual interface must be set for:"},get_full_name(),".gpio_if");
  endfunction

  // 获取sequencer发送的数据,并将其传递给dut
  virtual task run_phase(uvm_phase phase);
    get_and_drive();
  endtask

  virtual protected task get_and_drive();
    gpio_transfer this_trans; // 事务句柄
    @(posedge gpio_if.n_p_reset); // 复位信号释放之后
    forever begin  // 用一个循环
      @(posedge gpio_if.clk); // 等到时钟有效沿
      seq.item_port.get_next_item(req); // 将得到的req转换为this_trans
      if(!$cast(this_trans,req))
        `uvm_fatal("CASTFL","Failed to cast req to this_trans in get_and_drive");
      driver_data(this_trans); // 传递数据
      seq_item_port.item_done(); // 传输完成
    end
  endtask

  virtual protected task drive_data(gpio_transfer gpio_tr);
     .............
     // 将传入的tr的数据驱动到对应的接口上
  endtask

endclass

driver的功能:
<1> 在connect_phase中通过uvm_config_db获取接口
<2> 在run_phase中获取数据和驱动接口
a>获取数据通过driver中的seq_item_port.get_next_item(req)
req就是获取出来的transaction对象
b>获取出来req对象之后,将其cast为对应的transaction对象
c>驱动接口,将transaction对象中的信号驱动给接口
d>完成数据传输

monitor写法

  • monitor需要采集接口信号传输给scoreboard,需要将接口信号转换为transaction中的数据进行传递
class my_monitor extends uvm_monitor;
  `uvm_component_utils(my_monitor);

  // 需要采集接口信号,所以要使用虚接口
  virtual dut_if vif;
  
  // monitor可以对采集到的信号进行check,所以定义使能信号
  bit enable_check = 1;
    
  // monitor信号传递给scoreboard需要用到事务传输
  // 例化一个uvm事务传输接口句柄,uvm_analysis_port
  umv_analysis_port #(my_data) mon_analysis_port;

  function new(string name,uvm_component parent);
    super.new(name,parent);
  endfunction
  
  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    // 创建事务传输接口
    mon_analysis_port = new("mon_analysis_port",this);
  endfunction
  
  virtual function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    if(!uvm_config_db #(virtual dut_if)::get(this,"","vif",vif)) begin
      `uvm_error(get_type_name(),"DUT interface not found");
    end
  endfunction
  
  virtual task run_phase(uvm_phase phase);
    // 需要将接口数据传递出去,所以定义transaction对象
    my_data data_object = my_data::type_id::create("data_object",this);

    forever begin
      // 数据有效的时候,采样
      @[Some event when data at DUT port is valid];
      // 将接口信号给到transaction
      data_object.data = vif.data;
      data_object.addr = vif.addr;
      
      // check使能,就调用检查协议的函数
      if(check_enable) check_protocol();  
      
      // 采样功能概率
      data.object.cg_trans.sample()
      
      // 通过analysis_port发送数据
      mon_analysis_port.write(data_object);
    end
  endtask
  
  virtual function void check_protocol();
    // Function to check basic protocol specs
  endfunction 

endclass

定义虚接口,在connectphase中获取接口
例化uvm_analysis_port对象
创建transaction对象,将接口数据给到transaction对象发送出去
定义check_protocol()函数
调用transaction中covergroup的sample()函数

uvm_exercise_2

  • 实现apb_driver.sv,apb_monitor.sv
  • drv:发送apb_trans事务给dut
  • mon:将监控接口得到的事务通过apb_mon_port的analysis_port发送出去
  • 符合apb接口协议

APB总线协议

  • pclk
  • presetn
  • paddr[31:0]
  • pselx
  • pnable
  • pwrite
  • prdata [31:0]
  • pwdata [31:0]

apb_driver

class apb_driver extends uvm_driver #(apb_trans)
  virtual apb_interface apb_ifc;
  `uvm_component_utils(apb_driver);
  
  function new(string name,uvm_component parent);
    super.new(name,parent);
  endfunction
  
  extern virtual function void connect_phase(uvm_phase phase);
  extern virtual task run_phase(uvm_phase phase);
  extern virtual task reset_phase(uvm_phase phase);
  extern virtual task get_and_drive();
  extern virtual task drive_data(apb_trans tr);

endclass

  function void apb_driver::connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    if(!uvm_config_db #(apb_interface)::get(this,"","vif",apb_ifc)) 
      `uvm_error("NOAPB_IFC",{"virtual interface must be set for:",get_full_name(),"apb_ifc"});
  endfunction

  task apb_driver::reset_phase(uvm_phase phase);
    phase.raise_objection(this);
    @(negedge apb_ifc.rst_n);
    // 复位信号有效的时候,接口中的信号进行复位
    apb_ifc.psel <= 1'b0;
    apb_ifc.penable <= 1'b0;
    apb_ifc.pwrite <= 1'b0;
    apb_ifc.pwdata <= 32'b0;
    apb_ifc.paddr <= 32'b0;
    phase.drop_objection(this);
  endtask

  task apb_driver::run_phase(uvm_phase phase);
    get_and_drive();
  endtask

  task apb_driver::get_and_drive();
    apb_trans tr;
    @(posedge apb_ifc.rst_n);
    forever begin
      @(posedge apb_ifc.clk);
      seq_item_port.get_next_item(req);
      if(!$cast(tr,req))
        `uvm_fatal("CASTFL","Failed to cast req to apb_trans in get_and_drive");
      // drive_data(apb_trans);
      drive_data(req)
      seq_item_port.item_done(); 
    end
  endfunction;

  task apb_driver::drive_data(apb_trans tr);
    if(tr.dir == apb_trans::WR)
      // 写信号为高的时候
      begin
        @(posedge apb_ifc.clk);
        apb_ifc.psel <= 1'b1;
        apb_ifc.penable <= 1'b0;
        apb_ifc.pwrite <= 1'b1;
        apb_ifc.pwdata <= tr.data;
        apb_ifc.paddr <= tr.addr;
        @(posedge apb_ifc.clk);
        apb_ifc.penable <= 1'b1;
        @(posedge apb_ifc.clk);
        apb_ifc.psel <= 1'b0;
        apb_ifc.penable <= 1'b0;
      end 
      else begin
        @(posedge apb_ifc.clk);
        apb_ifc.psel <= 1'b1;
        apb_ifc.penable <= 1'b0;
        apb_ifc.pwrite <= 1'b0;
        apb_ifc.paddr <= tr.addr;
        @(posedge apb_ifc.clk);
        apb_ifc.penable <= 1'b1;
        @(posedge apb_ifc.clk);
        tr.data <= apb_ifc.prdata;
        apb_ifc.psel <= 1'b0;
        apb_ifc.penable <= 1'b0;
      end
  endtask
  

apb_monitor

class apb_monitor extends uvm_monitor #(apb_trans)
  `uvm_component_utils(apb_monitor);
  virtual apb_interface apb_ifc;

  bit check_enable = 1;  

  uvm_analysis_port #(apb_trans) mon_analysis_port;

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

  extern virtual function void build_phase(uvm_phase phase);
  extern virtual task run_phase(uvm_phase phase);
  extern virtual check_protocol();
endclass

  function void apb_monitor::build_phase(uvm_phase phase);
    super.build_phase(phase);
    if(!uvm_config_db #(apb_interface)::get(this,"","vif",apb_ifc)) 
      `uvm_error("NOAPB_IFC","No apb_ifc for monitor");
      apb_mon_port = new("apb_mon_port",this);
  endfunction

  task apb_monitor::run_phase(uvm_phase phase);
    super.run_phase(phase);
    apb_trans tr = apb_trans::type_id::create("tr",this);
    forever begin
      @(posedge apb_ifc.clk);
      if(apb_ifc.psel = 1'b1 && apb_ifc.penable == 1'b1) begin
        tr.dir = (apb_ifc.pwrite) ? apb_trans::WR : apb_trans::RD;
        tr.addr = apb_ifc.paddr;
        tr.data = (apb_ifc.pwrite) ? apb_ifc.pwdata :apb_ifc.prdata;
      end
      mon_analysis_port.write(tr);
    end
  endtask

posted @ 2024-03-16 01:13  Icer_Newer  阅读(104)  评论(0编辑  收藏  举报