UVMA Implementation - Help Needed!

Guys,

I’m implementing a simple protocol based interface UVMA-UVC.

Basically, UVC sends req_length to the DUT and DUT should respond back with res_lengths and UVC needs to compare the request and response.

Lets consider the request and responses as follows.
req_len = 10;
res_len = 3; last = 0;
after few clocks;
req_len = 7;
res_len = 5; last = 0;
after few clocks;
res_len = 2; last = 1;
after few clocks;
req_len = 8;
after few clocks;
res_len = 7; last = 1;
after few clocks;
res_len = 4; last = 0;
after few clocks;
res_len = 4; last = 1;

Here is my implementation for the above UVC…


interface simple_if (input logic clk, rst);

import simple_pkg::simple_seq_item;
import simple_pkg::simple_mon;
import simple_pkg::simple_drv;

logic[31:0] req_length;
logic abort;
logic req_valid;
logic [31:0] res_length;
logic res_valid;
logic last;

simple_drv drv_proxy;
simple_mon mon_proxy;

clocking cb_simple_if @(posedge clk)
input res_length;
input last;
input res_valid;
output  rst;
output req_length;
output abort;
output req_valid;
endclocking


task send_request (simple_seq_item item);

      simple_seq_item cloned_item;
      wait_n_clkcycles(item.delay);
      @(posedge clk);

      // Drive signals
      if (item.abort) begin
         abort     = item.abort;
         req_valid = 1'b0;
      end
      else begin
         req_len              = item.req_len;
         req_valid            = 1'b1;
         $cast(cloned_item, item.clone());
         drv_proxy.simple_drv_analysis_port.write(cloned_item);
      end
endtask


task collect_response (simple_seq_item item);

     simple_seq_item mon_item;
       int   length;
      @(posedge clk);

      //Update Signals 
      item.req_valid = req_valid;
      item.req_length = req_length;
      item.abort = abort;

      item.res_valid = res_valid;
      item.res_length = res_length;
      item.last = last;

      if (req_valid || res_valid) begin
         if (res_valid) begin
            length = res_length + length;
            if (last) begin
               item.total_res_length = length;
               length = 0;
            end
         end
         else begin
         length = 0;
         end
      $cast(mon_item, item.clone());
      mon_proxy.mon_analysis_port.write(mon_item);
      end
endtask

endinterface

class simple_seq_item extends uvm_sequence_item;

   rand int delay;
   rand logic[31:0] req_length;
   rand logic abort;
   logic[31:0] res_length;
   logic last;
   logic [31:0] total_res_length;
endclass

class simple_drv extends uvm_driver #(simple_seq_item);
..
endclass

task simple_drv::run_phase(uvm_phase phase);

   //Set proxy path   
   simple_if.drv_proxy = this;

   forever begin
      seq_item_port.get_next_item(simple_seq_item);
      simple_if.send_request(simple_seq_item);
      seq_item_port.item_done(simple_seq_item);
   end
endtask

class simple_mon extends uvm_monitor;
..
endclass

task simple_mon::run_phase(uvm_phase phase);

   //Set proxy path   
   simple_if.mon_proxy = this;

    forever begin
      simple_if.collect_responses(simple_trans_collected);
    end
endtask : run_phase

class simple_cov extends uvm_subscriber #(simple_seq_item);
..
endclass

class simple_sbd extends uvm_scoreboard;
...
   simple_seq_item request_queue[$];

   function void write_drv (simple_seq_item item);
      request_queue.push_back(item);
   endfunction: write_drv

   function void write_mon (simple_seq_item t);
      if (t.abort) begin
         simple_trans_mon_sbd = request_queue.pop_front();
      end
      else begin
         if (t.total_res_length) begin
            simple_trans_mon_sbd = request_queue.pop_front();
            if (t.total_res_length != simple_trans_mon_sbd.request_length) begin
               `uvm_error("ScoreBoard:", $sformatf("Length Mismatch ! : Expected: 0x%0x Actual: 0x%0x",simple_trans_mon_sbd.request_length,t.total_res_length))
            end
         end
      end
   endfunction: write_mon

endclass

class simple_agent extends uvm_agent;
..
endclass

function void simple_agent::build_phase   (uvm_phase phase);
...
    simple_cov = simple_cov::type_id::create("simple_cov",this);

    simple_mon = simple_mon::type_id::create("simple_mon",this);

    simple_drv = simple_drv::type_id::create("simple_drv",this);

    simple_seqr = simple_seqr::type_id::create("simple_seqr",this);
endfunction

 
function void simple_agent::connect_phase (uvm_phase phase);
    super.connect_phase(phase);
    simple_drv.seq_item_port.connect(simple_seqr.seq_item_export);
    simple_mon.simple_mon_analysis_port.connect(simple_cov.analysis_export);
endfunction

class simple_env extends uvm_env;
..
endclass

function void simple_env::build_phase   (uvm_phase phase);
    super.build_phase(phase); 
    simple_agent = simple_agent::type_id::create("simple_agent",this);
    simple_sbd = simple_sbd::type_id::create("simple_sbd",this);
endfunction
 
function void simple_env::connect_phase (uvm_phase phase);
    super.connect_phase(phase);
    simple_agent.simple_drv.simple_drv_analysis_port.connect(simple_sbd.drv_sbd);
    simple_agent.simple_mon.simple_mon_analysis_port.connect(simple_sbd.mon_sbd);
endfunction

class simple_request_seq extends uvm_sequence#(simple_seq_item);
..
    virtual task body();
        simple_seq_item = simple_seq_item::type_id::create("simple_seq_item");
        start_item (simple_seq_item);
        if (!simple_seq_item.randomize() with {simple_seq_item.abort == 1'b0;})
            `uvm_fatal(get_type_name(), "Randomization Failed !")
        finish_item(simple_seq_item);
    endtask
endclass

class simple_abort_seq extends uvm_sequence#(simple_seq_item);
..
    virtual task body();
        simple_seq_item = simple_seq_item::type_id::create("simple_seq_item");
        start_item (simple_seq_item);
        if (!simple_seq_item.randomize() with {simple_seq_item.abort == 1'b1;})
            `uvm_fatal(get_type_name(), "Randomization Failed !")
        finish_item(simple_seq_item);
    endtask
endclass

class simple_test extends uvm_test;
..

task simple_test::run_phase (uvm_phase phase);
..
    phase.raise_objection(this);
   `uvm_info(get_type_name(), $sformatf(" Test Starting.."), UVM_LOW)
      simple_req_seq.start(simple_env.simple_agent.simple_seqr);
      simple_abort_seq.start(simple_env.simple_agent.simple_seqr);
      simple_req_seq.start(simple_env.simple_agent.simple_seqr);
   phase.drop_objection(this);
   `uvm_info(get_type_name(), $sformatf(" Test Ending.."), UVM_LOW)
endtask

endclass

Questions:

  1. Is my implementation right? Both Driver and Monitor sending seq_item to Scoreboard. Is there any better approach?
  2. Is UVMA compliance? If not, please advise.

Note: this is my first implementation on UVMA*

Thanks
John