Thursday, October 27, 2016

UVM Test Analysis.

Analysis Layer

  • Scoreboard / Subscriber / Monitor / Predictor
    • Watch / Observe
    • Recognize transactions
    • Place the transactions to the analysis ports
  • Coverage
  • Reporting
  • Simulation
    • Tests/Transactions -> Drivr -> DUT -> Responder -> TLM models
  • Can connect to multiple objects (unlike uvm_put_port)
  • Analysis Ports, Exports, Imps
  • Port, Export and Imp

Example of Monitor Class
class monitor extends interface_base;
   `uvm_component_utils(monitor)
   uvm_analysis_port #(mem_data) rspa;
   uvm_analysis_port #(mem_req)  reqa;

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

   virtual function void build_phase(uvm_phase phase);
      super.build_phase(phase);
      reqa = new ("reqa", this);
      rspa = new ("rspa", this);
   endfunction: build_phase

   task run_phase(uvm_phase phase);
      mem_req  req = new(), c_req;
      mem_data rsp = new(), c_rsp;

      forever begin : monitor_loop

         @(posedge mif.clk);
         #UNIT_DELAY;
         req.load_data (mif.addr, mif.data, nop);
         rsp.load_data (mif.addr, mif.data);
         if (mif.wr) req.op = write;
         if (mif.rd) req.op = read;
         if (req.op != nop) begin
            $cast(c_req, req.clone());
            reqa.write (c_req);
         end
         if (mif.rd) begin
            $cast (c_rap, rsp.clone());
            rspa.write (c_rsp);
         end

      end : monitor_loop
   endtask
endclass : monitor


Create a Subscriber
  • Instantiate a "uvm_tlm_analysis_fifo"
  • Connect to the analysis_port at the top level
  • Use get() to block and take data out of the analysis fifo



Create a Predictor
  • It gets a request from the analysis_port connected to the monitor.
  • It predicts what response transaction will appear.

class predictor extends uvm_agent;
   `uvm_component_utils (predictor)
   logic [15:0] mem [2**16-1 : 0];

   uvm_tlm_analysis_fifo #(mem_req) reqfifo;
   uvm_put_port #(mem_data) rsp_p; // to connect to comparator
   mem_data rsp = new();

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

   virtual function void build_phase (uvm_phase phase);
      super.build_phase(phase);
      req_fifo = new("req_fifl", this);
      rsp_p = new ("rsp_po", this);
   endfunction : build_phase

   task run_phase (uvm_phase phase);
      mem_data cln;
      mem_req req_txn;
      forever begin : run_loop
         req_fifo.get (req_tx);
         case (req_tx.op)
            write : mem[req_tx.addr] = req_tx.data;
            read  : begin : read_op
               rsp.load_data (req_tx.addr, mem[req_tx.addr]);
               $case (cln, rsp.clong());
               rsp_p.put(cln);
            end : read_op
         endcase
      end : run_loop
   endtask : run_phase

endclass : predictor


Create a Comparator and a Printer to Report
  • It gets a response transaction from the monitor.
  • It compares the actual response transaction to the predicted response transaction.

class comparator extends uvm_agent;

   `uvm_component_utils (comparator)

   uvm_tlm_analysis_fifo #(mem_data) actual_f;
   uvm_get_port #(mem_data) predicted_p;
   mem_data actual_rsp, predicted_rsp;

   function new ...

   virtual function void build_phase (uvm_phase phase);
      super.build_phase (phase);
      actual_f = new ("actual_f", this);
      predicted_p = new ("predicted_p", this);
   endfunction : build_phase

   task run_phase (uvm_phase phase);
      forever begin : run_loop
         actual_f.get (actual_rsp);
         predicted_p.get (predicted_rsp);
         if (actual_rsp.comp(predicted_rsp))
            uvm_report_info ("run",
               $psprintf ("passed: %s", 
                          actual_rsp.convert2string()) );
         else
            uvm_report_info ("run",
               $psprintf ("ERROR: expected: %s does not match actual: %s", 
                          predicted_rsp.convert2string(),
                          actual_rsp.convert2string()) );
      end : run_loop
   endtask : run_phase
endclass : comparator

class printer #(type T = mem_data) extends uvm_agent;
   `uvm_component_utils (printer#(T))

   uvm_tlm_analysis_fifo #(T) a_fifo;

   function new ...

   virtual function void build_phase (uvm_phase phase);
      super.build_phase (phase);
      a_fifo = new ("a_fifo", this);
   endfunction : build_phase

   task run_phase (uvm_phase phase);
      forever begin
         T data;
         a_fifo.get(data);
         uvm_report_info ("run", data.convert2string());
      end
   endtask : run_phase
endclass : printer


class mem_data extends uvm_transaction;
   `uvm_object_utils (mem_data)
   rand logic [15:0] data;
   rand lobic [15:0] addr;

   virtual function bit comp (uvm_object rhs);
      mem_data RHS;
      $cast (RHS, rhs);
      return ((RHS.addr == addr) && (RHS.data == data));
   endfunction : comp
endclass : mem_data

class mem_req extends mem_data;
...
endclass : mem_req


Top Leven Test Environment
class test_env extends uvm_env;
   `uvm_component_utils (test_env)

   tester tst;
   driver drv;
   uvm_tlm_fifo #(mem_req) tester2driv;

   printer #(mem_req)  req_prt;
   printer #(mem_data) rsp_prt;
   monitor mon;
   predictor pred;
   comparator cmp;
   uvm_tlm_fifo #(mem_data) pred2cmp;

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

   virtual function void build_phase (uvm_phase phase);
      super.build_phase (phase);
      tst = tester::type_id::create ("tst", this);
      drv = driver::type_id::create ("drv", this);
      tester2drv = new ("tester2drv");

      req_prt = printer#(mem_req)::type_id::create("req_prt", this);
      rsp_prt = printer#(mem_data)::type_id::create("rsp_prt", this);

      mon = monitor::type_id::create ("mon", this);
      pred = predictor::type_id::create ("pred", this);
      cmp = comparator;:type_id::create ("cmp", this);
      pred2cmp = new("pred2cmp"< this);
   endfunction : build_phase

   virtual function void connect_phase (uvm_phase phase);
      super.connect_phase(phase);
      tst.tb_port.connect (tester2drv.put_export);
      drv.req_f.connect (tester2drv.get_export);
      cmp.predicted_p.connect (pred2cmp.get_export);
      pred.rsp_p.connect(pred2cmp.put_export);
      mon.req_a.connect (pred.req_fifo.analysis_export);
      mon.rsp_a.connect (cmp.req_fifo.analysis_export);
      mon.req_a.connect (req_prt.a_fifo.analysis_export);
      mon.rsp_a.connect (rsp_prt.a_fifo.analysis_export);

   endfunction : connect_phase

endclass : test_env

class bucket #(type T = mem_data) extends printer #(T);

   typedef bit_bucket#(T) thistype;
   `uvm_component_param_utils (thistype)

   function new ...

   task run_phase (uvm_phase phase);
      forever begin
         T data;
         a_fifo.get(data);
      end
   endtask : run_phase

endclass : bucket

class qtest extends uvm_test;
   `uvm_component_utils (qtest)

   test_env t_env;

   function new ...

   virtual function void build_phase (uvm_phase phase);
      super.build_phase (phase);
      printer#(mem_data)::type_id::set_type_override
         (bucket#(mem_data)::get_type());
      printer#(mem_req)::type_id::set_type_override
         (bucket#(mem_data)::get_type());
      t_env = test_env::type_id::create ("t_env", this);
   endfunction : build_phase

endclass : qtest



No comments:

Post a Comment