uvm sequence/sequencer example

命令:
vcs -full64 -sverilog -timescale=1ns/1ps -R -ntb_opts uvm-1.1 uvm_seq_exam.sv

import uvm_pkg::*;
`include "uvm_macro.svh"
typedef seq0;
typedef seq1;

定义xaction

class xaction extends uvm_sequence_item;
  rand  int  rng;
  `uvm_object_utils_begin(xaction)
    `uvm_field_int(rng, UVM_ALL_ON)
  `uvm_object_utils_end
endclass

定义seqr

class seqr extends uvm_sequencer #(xaction);
 `uvm_component_utils(seqr)
 function new(string name, uvm_component parent);
   super.new(name, parent);
 endfunction
endclass

定义drvr

class drvr extends uvm_driver #(xaction);
  `uvm_component_utils(drvr)
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
  virtual task run_phase(uvm_phase phase);
    uvm_objection objection;
    $display("drv begin to work......");
    objection = phase.get_objection();
    objection.set_drain_time(this, 1000);
    forever begin
      seq_item_port.get_next_item(req);
      #10; // drive signals in xaction to bus
      $display("@5 receive a xaction:\t%3d", $realtime, req.rng);
      seq_item_port.item_done();
    end
  endtask  
endclass

定义agent来封装seqr和drvr,启动seq

class agent extends uvm_agent;
  seqr       sqr;
  drvr        dvr;
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
  
  `uvm_component_utils(agent)
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    sqr = seqr::type_id::create("sqr", this);
    dvr = drvr::type_id::create("dvr", this);
    /*
    uvm_config_db#(uvm_object_wrapper)::set(this, "sqr.run_phase", "default_sequence", seq0::type_id::get());
    */
  endfunction
  function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    dvr.seq_item_port.connect(sqr.seq_item_export);
  endfunction
/*  
  task main_phase(uvm_phase phase);
    seq0  seq0_inst;
    seq1  seq1_inst;
    seq0_inst = seq0::type_id::create("seq0_inst");
    seq1_inst = seq0::type_id::create("seq1_inst");
    seq0_inst.starting_phase = phase;
    seq1_inst.starting_phase = phase;
    fork
      seq0_inst.start(this.sqr);
      seq1_inst.start(this.sqr);
    join
  endtask
*/
endclass

定义seq0,seq1
seq0发偶数
seq1发奇数

class seq0 extends uvm_sequence #(xaction);
  `uvm_object_utils(seq0)
  function new(string name="seq0");
    super.new(name);
  endfunction
  virtual task body();
    starting_phase.raise_objection(this);
      repeat(10) begin
        `uvm_do_with(req, {rng inside {[0:100]}; rng[0]==0;})
      end
    starting_phase.drop_objection(this);
  endtask
endclass


class seq1 extends uvm_sequence #(xaction);
  `uvm_object_utils(seq1)
  function new(string name="seq1");
    super.new(name);
  endfunction
  virtual task body();
    starting_phase.raise_objection(this);
      repeat(10) begin
        `uvm_do_with(req, {rng inside {[0:100]}; rng[0]==1;})
      end
    starting_phase.drop_objection(this);
  endtask
endclass

定义program块

program uvm_run_test();
  initial begin
    agent agt_inst;
    $timeformat(-9, 1, "ns", 10);
    agt_inst = agent::type_id::create("agt_inst", null);
    run_test();
  end
endprogram

uvm_sequence, uvm_driver 的源码里声明了req,rsp变量,所以扩展的seq和drv里,
`uvm_do系列宏里和drv的seq_item_port的get_next_item
的参数可以用req。


drv_src.png
seq_src.png

例子中给出了两种启动seq的方式,见两段/* */注释之间的代码
第一种通过uvm_config_db
第二种是通过seq.start(sqr),通过第二种方式在一个seqr上启动了两个seq

仿真log如下:


one_seq.png
two_seq.png

可见,两个seq交替发出了xaction。

上面的代码中在drv里设置了set_drain_time来控制仿真时间。一般的环境中会放到tc里设置,不会放在drv组件中。

你可能感兴趣的:(uvm sequence/sequencer example)