core-v-verif系列之lib<63>

UVM环境介绍
HEAD commitID: 1f968ef

lib/uvm_agents/uvma_obi_memory/src/comps

//
// Copyright 2021 OpenHW Group
// Copyright 2021 Datum Technology Corporation
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
//
// Licensed under the Solderpad Hardware License v 2.1 (the "License"); you may
// not use this file except in compliance with the License, or, at your option,
// the Apache License version 2.0. You may obtain a copy of the License at
//
//     https://solderpad.org/licenses/SHL-2.1/
//
// Unless required by applicable law or agreed to in writing, any work
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
//


`ifndef __UVMA_OBI_MEMORY_MON_TRN_LOGGER_SV__
`define __UVMA_OBI_MEMORY_MON_TRN_LOGGER_SV__


/**
 * Component writing Open Bus Interface monitor transactions debug data to disk as plain text.
 */
class uvma_obi_memory_mon_trn_logger_c extends uvml_logs_mon_trn_logger_c#(
   .T_TRN  (uvma_obi_memory_mon_trn_c),
   .T_CFG  (uvma_obi_memory_cfg_c    ),
   .T_CNTXT(uvma_obi_memory_cntxt_c  )
);


   `uvm_component_utils(uvma_obi_memory_mon_trn_logger_c)

   /**
    * Default constructor.
    */
   function new(string name="uvma_obi_memory_mon_trn_logger", uvm_component parent=null);

      super.new(name, parent);

   endfunction : new

   /**
    * Writes contents of t to disk
    */
   virtual function void write(uvma_obi_memory_mon_trn_c t);

      string format_header_str_1p1 = "%15s | %6s | %2s | %8s | %4s | %8s";
      string format_header_str_1p2 = "%15s | %6s | %2s | %8s | %4s | %8s | %2s | %2s | %2s | %2s | %2s | %2s | %2s";
      string log_msg;

      // Log the 1p1 signals
      log_msg = $sformatf("%15s | %6s | %2s | %08x |  %1x | %8s",
                          $sformatf("%t", $time),
                          cfg.mon_logger_name,
                          t.access_type == UVMA_OBI_MEMORY_ACCESS_READ ? "R" : "W",
                          t.address,
                          t.be,
                          t.get_data_str());


      if (cfg.version == UVMA_OBI_MEMORY_VERSION_1P2) begin
         log_msg = $sformatf("%s | %2x |    %1x |   %2x | %3s",
                             log_msg,
                             t.aid,
                             t.prot,
                             t.atop,
                             t.err ? "ERR" : "OK");
         if (cfg.auser_width > 0)
            log_msg = $sformatf("%s |     %1x", log_msg, t.auser);
         if (cfg.wuser_width > 0)
            log_msg = $sformatf("%s |     %1x", log_msg, t.wuser);
         if (cfg.ruser_width > 0)
            log_msg = $sformatf("%s |     %1x", log_msg, t.ruser);
      end

      fwrite(log_msg);

   endfunction : write

   /**
    * Writes log header to disk
    */
   virtual function void print_header();

      if (cfg.version == UVMA_OBI_MEMORY_VERSION_1P1) begin
         string banner_str = {80{"-"}};
         string format_header_str_1p1 = "%15s | %6s | %2s | %8s | %2s | %8s";


         fwrite(banner_str);
         fwrite($sformatf(format_header_str_1p1,
                          "TIME", "OBI", "RW", "ADDR", "BE", "DATA"));
         fwrite(banner_str);
      end
      else begin
         string banner_str = {106{"-"}};
         string format_header_str_1p2 = "%15s | %6s | %2s | %8s | %2s | %8s | %2s | %2s | %2s | %2s";
         string header_str;

         header_str = $sformatf(format_header_str_1p2,
                                "TIME", "OBI", "RW", "ADDR", "BE", "DATA",
                                "ID", "PROT", "ATOP", "ERR");

         if (cfg.auser_width > 0)
            header_str = $sformatf("%s | %2s", header_str, "AUSER");
         if (cfg.ruser_width > 0)
            header_str = $sformatf("%s | %2s", header_str, "RUSER");
         if (cfg.wuser_width > 0)
            header_str = $sformatf("%s | %2s", header_str, "WUSER");

         fwrite(banner_str);
         fwrite(header_str);
         fwrite(banner_str);
      end

   endfunction : print_header

endclass : uvma_obi_memory_mon_trn_logger_c


/**
 * Component writing OBI monitor transactions debug data to disk as JavaScript Object Notation (JSON).
 */
class uvma_obi_memory_mon_trn_logger_json_c extends uvma_obi_memory_mon_trn_logger_c;

   `uvm_component_utils(uvma_obi_memory_mon_trn_logger_json_c)


   /**
    * Set file extension to '.json'.
    */
   function new(string name="uvma_obi_memory_mon_trn_logger_json", uvm_component parent=null);

      super.new(name, parent);
      fextension = "json";

   endfunction : new

   /**
    * Writes contents of t to disk.
    */
   virtual function void write(uvma_obi_memory_mon_trn_c t);

      // TODO Implement uvma_obi_memory_mon_trn_logger_json_c::write()
      // Ex: fwrite({"{",
      //       $sformatf("\"time\":\"%0t\",", $realtime()),
      //       $sformatf("\"a\":%h,"        , t.a        ),
      //       $sformatf("\"b\":%b,"        , t.b        ),
      //       $sformatf("\"c\":%d,"        , t.c        ),
      //       $sformatf("\"d\":%h,"        , t.c        ),
      //     "},"});

   endfunction : write

   /**
    * Empty function.
    */
   virtual function void print_header();

      // Do nothing: JSON files do not use headers.

   endfunction : print_header

endclass : uvma_obi_memory_mon_trn_logger_json_c


`endif // __UVMA_OBI_MEMORY_MON_TRN_LOGGER_SV__

uvma_obi_memory_mon_trn_logger.sv

1. 简要介绍

该文件是OBI内存监控事务日志记录组件,主要功能包括:

  1. 将监控事务数据写入磁盘
  2. 支持文本和JSON两种格式
  3. 根据协议版本动态调整输出格式
  4. 作为验证环境的调试辅助组件

2. 接口介绍

2.1 类定义
class uvma_obi_memory_mon_trn_logger_c extends uvml_logs_mon_trn_logger_c#(
   .T_TRN(uvma_obi_memory_mon_trn_c),
   .T_CFG(uvma_obi_memory_cfg_c)
);
  • 代码介绍:定义OBI监控事务日志记录类
  • 继承关系:继承自参数化基础日志记录类
  • 特点:支持协议特定字段记录

3. 参数介绍

3.1 日志格式定义
string format_header_str_1p1 = "%15s | %6s | %2s | %8s | %4s | %8s";
string format_header_str_1p2 = "%15s | %6s | %2s | %8s | %4s | %8s | %2s | %2s | %2s | %2s";
  • 参数说明
    • 1p1格式:基础协议字段
    • 1p2格式:扩展协议字段

4. 模块实现介绍

4.1 写入函数
function void write(uvma_obi_memory_mon_trn_c t);
   log_msg = $sformatf("%15s | %6s | %2s | %08x |  %1x | %8s",
                       $sformatf("%t", $time),
                       cfg.mon_logger_name,
                       t.access_type == UVMA_OBI_MEMORY_ACCESS_READ ? "R" : "W",
                       t.address,
                       t.be,
                       t.get_data_str());
endfunction
  • 代码分析
    1. 格式化时间戳
    2. 记录操作类型(R/W)
    3. 输出地址和数据
    4. 根据协议版本扩展字段
4.2 JSON日志类
class uvma_obi_memory_mon_trn_logger_json_c extends uvma_obi_memory_mon_trn_logger_c;
   function new();
      fextension = "json";
   endfunction
endclass
  • 代码分析
    1. 继承基础日志类
    2. 设置文件扩展名为json
    3. 预留JSON格式实现

5. 总结

该OBI监控事务日志记录组件具有以下特点:

  1. 灵活的多格式支持
  2. 协议版本自适应
  3. 清晰的输出格式
  4. 可扩展的JSON实现

作为验证环境的调试辅助工具,它为OBI接口的调试和分析提供了直观的事务记录能力,确保能够方便地追踪接口行为。

//
// Copyright 2021 OpenHW Group
// Copyright 2021 Datum Technology Corporation
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
//
// Licensed under the Solderpad Hardware License v 2.1 (the "License"); you may
// not use this file except in compliance with the License, or, at your option,
// the Apache License version 2.0. You may obtain a copy of the License at
//
//     https://solderpad.org/licenses/SHL-2.1/
//
// Unless required by applicable law or agreed to in writing, any work
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
//


`ifndef __UVMA_OBI_MEMORY_MON_SV__
`define __UVMA_OBI_MEMORY_MON_SV__


/**
 * Component sampling transactions from a Open Bus Interface virtual interface
 * (uvma_obi_if).
 */
class uvma_obi_memory_mon_c extends uvm_monitor;

   // Objects
   uvma_obi_memory_cfg_c    cfg;
   uvma_obi_memory_cntxt_c  cntxt;

   // TLM
   uvm_analysis_port#(uvma_obi_memory_mon_trn_c)  ap;
   uvm_analysis_port#(uvma_obi_memory_mon_trn_c)  sequencer_ap;

   // Handles to virtual interface modport
   virtual uvma_obi_memory_if.passive_mp  passive_mp;


   `uvm_component_utils_begin(uvma_obi_memory_mon_c)
      `uvm_field_object(cfg  , UVM_DEFAULT)
      `uvm_field_object(cntxt, UVM_DEFAULT)
   `uvm_component_utils_end

   /**
    * Default constructor.
    */
   extern function new(string name="uvma_obi_memory_mon", uvm_component parent=null);

   /**
    * 1. Ensures cfg & cntxt handles are not null.
    * 2. Builds ap.
    */
   extern virtual function void build_phase(uvm_phase phase);

   /**
    * TODO Describe uvma_obi_memory_mon_c::run_phase()
    */
   extern virtual task run_phase(uvm_phase phase);

   /**
    * Monitors passive_mp for asynchronous reset and updates the context's reset state.
    */
   extern task observe_reset();

   /**
    * TODO Describe uvma_obi_memory_mon_c::mon_chan_a_pre_reset/mon_chan_a_in_reset/mon_chan_a_post_reset()
    */
   extern task mon_chan_a_pre_reset ();
   extern task mon_chan_a_in_reset  ();
   extern task mon_chan_a_post_reset();

   /**
    * TODO Describe uvma_obi_memory_mon_c::mon_chan_r_pre_reset/mon_chan_r_in_reset/mon_chan_r_post_reset()
    */
   extern task mon_chan_r_pre_reset ();
   extern task mon_chan_r_in_reset  ();
   extern task mon_chan_r_post_reset();

   /**
    * TODO Describe uvma_obi_memory_mon_c::mon_chan_a_trn()
    */
   extern task mon_chan_a_trn(output uvma_obi_memory_mon_trn_c trn);

   /**
    * TODO Describe uvma_obi_memory_mon_c::mon_chan_r_trn()
    */
   extern task mon_chan_r_trn(uvma_obi_memory_mon_trn_c trn);

   /**
    * User hooks for modifying transactions after they've been sampled but before they're sent out the analysis port(s).
    */
   extern virtual function void process_a_trn(uvma_obi_memory_mon_trn_c trn);
   extern virtual function void process_r_trn(uvma_obi_memory_mon_trn_c trn);

   /**
    * TODO Describe uvma_obi_memory_mon_c::send_trn_to_sequencer()
    */
   extern task send_trn_to_sequencer(ref uvma_obi_memory_mon_trn_c trn);

   /**
    * TODO Describe uvma_obi_memory_mon_c::sample_trn_a_from_vif()
    */
   extern task sample_trn_a_from_vif(uvma_obi_memory_mon_trn_c trn);
   extern task sample_trn_r_from_vif(uvma_obi_memory_mon_trn_c trn);

endclass : uvma_obi_memory_mon_c


function uvma_obi_memory_mon_c::new(string name="uvma_obi_memory_mon", uvm_component parent=null);

   super.new(name, parent);

endfunction : new


function void uvma_obi_memory_mon_c::build_phase(uvm_phase phase);

   super.build_phase(phase);

   void'(uvm_config_db#(uvma_obi_memory_cfg_c)::get(this, "", "cfg", cfg));
   if (cfg == null) begin
      `uvm_fatal("CFG", "Configuration handle is null")
   end

   void'(uvm_config_db#(uvma_obi_memory_cntxt_c)::get(this, "", "cntxt", cntxt));
   if (cntxt == null) begin
      `uvm_fatal("CNTXT", "Context handle is null")
   end
   passive_mp = cntxt.vif.passive_mp;

   ap           = new("ap"          , this);
   sequencer_ap = new("sequencer_ap", this);

endfunction : build_phase


task uvma_obi_memory_mon_c::run_phase(uvm_phase phase);

   super.run_phase(phase);

   if (cfg.enabled) begin
      fork
         observe_reset();

         begin : chan_a
            forever begin
               case (cntxt.reset_state)
                  UVMA_OBI_MEMORY_RESET_STATE_PRE_RESET : mon_chan_a_pre_reset ();
                  UVMA_OBI_MEMORY_RESET_STATE_IN_RESET  : mon_chan_a_in_reset  ();
                  UVMA_OBI_MEMORY_RESET_STATE_POST_RESET: mon_chan_a_post_reset();
               endcase
            end
         end

         begin : chan_r
            forever begin
               case (cntxt.reset_state)
                  UVMA_OBI_MEMORY_RESET_STATE_PRE_RESET : mon_chan_r_pre_reset ();
                  UVMA_OBI_MEMORY_RESET_STATE_IN_RESET  : mon_chan_r_in_reset  ();
                  UVMA_OBI_MEMORY_RESET_STATE_POST_RESET: mon_chan_r_post_reset();
               endcase
            end
         end
      join_none
   end

endtask : run_phase


task uvma_obi_memory_mon_c::observe_reset();

   forever begin
      wait (cntxt.vif.reset_n === 0);
      cntxt.reset_state = UVMA_OBI_MEMORY_RESET_STATE_IN_RESET;
      `uvm_info("OBI_MEMORY_MON", $sformatf("RESET_STATE_IN_RESET"), UVM_NONE)
      wait (cntxt.vif.reset_n === 1);
      cntxt.reset_state = UVMA_OBI_MEMORY_RESET_STATE_POST_RESET;
      `uvm_info("OBI_MEMORY_MON", $sformatf("RESET_STATE_POST_RESET"), UVM_NONE)
   end

endtask : observe_reset


task uvma_obi_memory_mon_c::mon_chan_a_pre_reset();

   @(passive_mp.mon_cb);

endtask : mon_chan_a_pre_reset


task uvma_obi_memory_mon_c::mon_chan_a_in_reset();

   @(passive_mp.mon_cb);

endtask : mon_chan_a_in_reset


task uvma_obi_memory_mon_c::mon_chan_a_post_reset();

   uvma_obi_memory_mon_trn_c  trn;

   mon_chan_a_trn(trn);
   trn.cfg = cfg;
   cntxt.mon_outstanding_reads_q.push_back(trn);
   `uvm_info("OBI_MEMORY_MON", $sformatf("monitored transaction on channel A:\n%s", trn.sprint()), UVM_HIGH)
   process_a_trn(trn);
   `uvm_info("OBI_MEMORY_MON", $sformatf("monitored transaction on channel A after process_a_trn():\n%s", trn.sprint()), UVM_HIGH)

   if (cfg.enabled && cfg.is_active && (cfg.drv_mode == UVMA_OBI_MEMORY_MODE_SLV)) begin
      send_trn_to_sequencer(trn);
      `uvm_info("OBI_MEMORY_MON", $sformatf("Sent trn to sequencer"), UVM_HIGH)
   end
   `uvml_hrtbt()
   @(passive_mp.mon_cb);

endtask : mon_chan_a_post_reset


task uvma_obi_memory_mon_c::mon_chan_r_pre_reset();

   @(passive_mp.mon_cb);

endtask : mon_chan_r_pre_reset


task uvma_obi_memory_mon_c::mon_chan_r_in_reset();

   @(passive_mp.mon_cb);

endtask : mon_chan_r_in_reset


task uvma_obi_memory_mon_c::mon_chan_r_post_reset();

   uvma_obi_memory_mon_trn_c  trn;

   wait (cntxt.mon_outstanding_reads_q.size());
   trn = cntxt.mon_outstanding_reads_q.pop_front();

   mon_chan_r_trn(trn);
   trn.cfg = cfg;
   `uvm_info("OBI_MEMORY_MON", $sformatf("monitored transaction on channel R:\n%s", trn.sprint()), UVM_HIGH)
   process_r_trn(trn);
   `uvm_info("OBI_MEMORY_MON", $sformatf("monitored transaction on channel R after process_r_trn():\n%s", trn.sprint()), UVM_HIGH)
   ap.write(trn);
   `uvml_hrtbt()
   @(passive_mp.mon_cb);

endtask : mon_chan_r_post_reset


task uvma_obi_memory_mon_c::mon_chan_a_trn(output uvma_obi_memory_mon_trn_c trn);

   trn = uvma_obi_memory_mon_trn_c::type_id::create("trn");

   while((passive_mp.mon_cb.req !== 1'b1) || (passive_mp.mon_cb.gnt !== 1'b1)) begin
      @(passive_mp.mon_cb);
      trn.gnt_latency++;
   end

   sample_trn_a_from_vif(trn);
   trn.__timestamp_start = $realtime();

endtask : mon_chan_a_trn


task uvma_obi_memory_mon_c::mon_chan_r_trn(uvma_obi_memory_mon_trn_c trn);

   // 1.1 only requires rvalid
   // fixme:strichmo:for 1.2 this must take rready into account as well
   while (passive_mp.mon_cb.rvalid !== 1'b1) begin
      @(passive_mp.mon_cb);
      trn.rvalid_latency++;
   end

   sample_trn_r_from_vif(trn);
   trn.__timestamp_end = $realtime();

endtask : mon_chan_r_trn


function void uvma_obi_memory_mon_c::process_a_trn(uvma_obi_memory_mon_trn_c trn);


endfunction : process_a_trn


function void uvma_obi_memory_mon_c::process_r_trn(uvma_obi_memory_mon_trn_c trn);


endfunction : process_r_trn


task uvma_obi_memory_mon_c::send_trn_to_sequencer(ref uvma_obi_memory_mon_trn_c trn);

   sequencer_ap.write(trn);

endtask : send_trn_to_sequencer

task uvma_obi_memory_mon_c::sample_trn_a_from_vif(uvma_obi_memory_mon_trn_c trn);

   trn.__originator = this.get_full_name();

   if (passive_mp.mon_cb.we === 1'b1) begin
      trn.access_type = UVMA_OBI_MEMORY_ACCESS_WRITE;
   end
   else if (passive_mp.mon_cb.we === 1'b0) begin
      trn.access_type = UVMA_OBI_MEMORY_ACCESS_READ;
   end
   else begin
      `uvm_error("OBI_MEMORY_MON", $sformatf("Invalid value for we:%b", passive_mp.mon_cb.we))
      trn.__has_error = 1;
   end

   for (int unsigned ii=0; ii<cfg.addr_width; ii++) begin
      trn.address[ii] = passive_mp.mon_cb.addr[ii];
   end
   for (int unsigned ii=0; ii<(cfg.data_width/8); ii++) begin
      trn.be[ii] = passive_mp.mon_cb.be[ii];
   end
   if (trn.access_type == UVMA_OBI_MEMORY_ACCESS_WRITE) begin
      for (int unsigned ii=0; ii<cfg.data_width; ii++) begin
         trn.data[ii] = passive_mp.mon_cb.wdata[ii];
      end
   end

   // 1P2 signals
   if (cfg.is_1p2_or_higher()) begin
      for (int unsigned ii=0; ii<cfg.auser_width; ii++) begin
         trn.auser[ii] = passive_mp.mon_cb.auser[ii];
      end
      if (trn.access_type == UVMA_OBI_MEMORY_ACCESS_WRITE) begin
         for (int unsigned ii=0; ii<cfg.wuser_width; ii++) begin
            trn.wuser[ii] = passive_mp.mon_cb.wuser[ii];
         end
      end
      // ID: Use zero for aid if id_width is configured to 0
      if (cfg.id_width == 0) begin
         trn.aid = '0;
      end
      else begin
         for (int unsigned ii=0; ii<cfg.id_width; ii++) begin
            trn.aid[ii] = passive_mp.mon_cb.aid[ii];
         end
      end
      trn.atop    = passive_mp.mon_cb.atop;
      trn.memtype = passive_mp.mon_cb.memtype;
      trn.prot    = passive_mp.mon_cb.prot;
      for (int unsigned ii=0; ii<cfg.achk_width; ii++) begin
         trn.achk = passive_mp.mon_cb.achk[ii];
      end
   end

endtask : sample_trn_a_from_vif


task uvma_obi_memory_mon_c::sample_trn_r_from_vif(uvma_obi_memory_mon_trn_c trn);

   trn.__originator = this.get_full_name();

   if (trn.access_type == UVMA_OBI_MEMORY_ACCESS_READ) begin
      for (int unsigned ii=0; ii<cfg.data_width; ii++) begin
         trn.data[ii] = passive_mp.mon_cb.rdata[ii];
      end
   end

   // 1P2 signals
   if (cfg.is_1p2_or_higher()) begin
      trn.err = passive_mp.mon_cb.err;
      for (int unsigned ii=0; ii<cfg.ruser_width; ii++) begin
         trn.ruser[ii] = passive_mp.mon_cb.ruser[ii];
      end
      for (int unsigned ii=0; ii<cfg.id_width; ii++) begin
         trn.rid[ii] = passive_mp.mon_cb.rid[ii];
      end
      trn.exokay     = passive_mp.mon_cb.exokay;
      for (int unsigned ii=0; ii<cfg.rchk_width; ii++) begin
         trn.rchk = passive_mp.mon_cb.rchk[ii];
      end
   end
endtask : sample_trn_r_from_vif


`endif // __UVMA_OBI_MEMORY_MON_SV__

uvma_obi_memory_mon.sv

1. 简要介绍

该文件是OBI内存接口的监控组件,主要功能包括:

  1. 采样OBI接口的事务数据
  2. 跟踪复位状态变化
  3. 处理通道A和通道R的事务
  4. 将监控数据发送给分析端口

2. 接口介绍

2.1 类定义
class uvma_obi_memory_mon_c extends uvm_monitor;
  • 代码介绍:定义OBI内存监控类
  • 继承关系:继承自UVM基础监控类
  • 特点:支持被动模式监控

3. 参数介绍

3.1 分析端口
uvm_analysis_port#(uvma_obi_memory_mon_trn_c) ap;
uvm_analysis_port#(uvma_obi_memory_mon_trn_c) sequencer_ap;
  • 参数说明
    • ap:标准分析端口
    • sequencer_ap:序列发生器分析端口
3.2 虚拟接口
virtual uvma_obi_memory_if.passive_mp passive_mp;
  • 参数说明:被动模式虚拟接口
  • 用途:采样信号不驱动

4. 模块实现介绍

4.1 运行阶段
task run_phase(uvm_phase phase);
   fork
      observe_reset();
      forever begin
         case (cntxt.reset_state)
            UVMA_OBI_MEMORY_RESET_STATE_POST_RESET: mon_chan_a_post_reset();
         endcase
      end
   join_none
endtask
  • 代码分析
    1. 并行运行复位监控
    2. 根据复位状态调用不同监控任务
    3. 使用fork-join_none实现并发
4.2 通道A监控
task mon_chan_a_post_reset();
   mon_chan_a_trn(trn);
   cntxt.mon_outstanding_reads_q.push_back(trn);
   process_a_trn(trn);
   if (cfg.enabled && cfg.is_active) begin
      send_trn_to_sequencer(trn);
   end
endtask
  • 代码分析
    1. 监控通道A事务
    2. 存储未完成读事务
    3. 处理事务数据
    4. 条件化发送给序列发生器

5. 总结

该OBI内存监控组件具有以下特点:

  1. 完整的协议监控能力
  2. 灵活的复位状态处理
  3. 可靠的事务跟踪机制
  4. 标准化的UVM实现

作为验证环境的核心监控组件,它为OBI接口的验证提供了全面的监控能力,确保能够准确捕获接口行为。

// 
// Copyright 2021 OpenHW Group
// Copyright 2021 Datum Technology Corporation
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
// 
// Licensed under the Solderpad Hardware License v 2.1 (the "License"); you may
// not use this file except in compliance with the License, or, at your option,
// the Apache License version 2.0. You may obtain a copy of the License at
// 
//     https://solderpad.org/licenses/SHL-2.1/
// 
// Unless required by applicable law or agreed to in writing, any work
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
// 


`ifndef __UVMA_OBI_MEMORY_SEQ_ITEM_LOGGER_SV__
`define __UVMA_OBI_MEMORY_SEQ_ITEM_LOGGER_SV__


/**
 * Component writing Open Bus Interface sequence items debug data to disk as plain text.
 */
class uvma_obi_memory_seq_item_logger_c extends uvml_logs_seq_item_logger_c#(
   .T_TRN  (uvma_obi_memory_base_seq_item_c),
   .T_CFG  (uvma_obi_memory_cfg_c          ),
   .T_CNTXT(uvma_obi_memory_cntxt_c        )
);
   
   `uvm_component_utils(uvma_obi_memory_seq_item_logger_c)
   
   
   /**
    * Default constructor.
    */
   function new(string name="uvma_obi_memory_seq_item_logger", uvm_component parent=null);
      
      super.new(name, parent);
      
   endfunction : new
   
   /**
    * Writes contents of t to disk.
    */
   virtual function void write(uvma_obi_memory_base_seq_item_c t);
      
      uvma_obi_memory_mstr_seq_item_c  mstr_t;
      uvma_obi_memory_slv_seq_item_c   slv_t;
      
      case (cfg.drv_mode)
         UVMA_OBI_MEMORY_MODE_MSTR: begin
            if (!$cast(mstr_t, t)) begin
               `uvm_fatal("OBI_MEMORY_SEQ_ITEM_LOGGER", $sformatf("Could not cast 't' (%s) to 'mstr_t' (%s)", $typename(t), $typename(mstr_t)))
            end
            write_mstr(mstr_t);
         end
         
         UVMA_OBI_MEMORY_MODE_SLV: begin
            if (!$cast(slv_t, t)) begin
               `uvm_fatal("OBI_MEMORY_SEQ_ITEM_LOGGER", $sformatf("Could not cast 't' (%s) to 'slv_t' (%s)", $typename(t), $typename(slv_t)))
            end
            write_slv(slv_t);
         end
         
         default: `uvm_fatal("OBI_MEMORY_SEQ_ITEM_LOGGER", $sformatf("Invalid drv_mode: %0d", cfg.drv_mode))
      endcase
      
   endfunction : write
   
// A significant chunk of the write_mstr method is common between this
// sequence item logger and the monitor transaction logger.  Given that
// much of this code is template generated, and is not expected to be edited
// further, the duplicated code has a lint waiver.
//
//@DVT_LINTER_WAIVER_START "MT20210901_2" disable SVTB.33.1.0, SVTB.33.2.0
   /**
    * Writes contents of mstr t to disk.
    */
   virtual function void write_mstr(uvma_obi_memory_mstr_seq_item_c t);
      
      string access_str = "";
      string err_str    = "";
      string be_str     = "";
      string data_str   = "";
      string auser_str  = "";
      string wuser_str  = "";
      string ruser_str  = "";
      string id_str     = "";
      
      case (t.access_type)
         UVMA_OBI_MEMORY_ACCESS_READ : access_str = "R  ";
         UVMA_OBI_MEMORY_ACCESS_WRITE: access_str = "  W";
         default              : access_str = " ? ";
      endcase
      
      case (t.__has_error)
         0: err_str = "    ";
         1: err_str = " ERR";
      endcase
      
      case (t.access_type)
         UVMA_OBI_MEMORY_ACCESS_READ : data_str = $sformatf("%b", t.rdata);
         UVMA_OBI_MEMORY_ACCESS_WRITE: data_str = $sformatf("%h", t.wdata);
      endcase
      
      case (t.access_type)
         UVMA_OBI_MEMORY_ACCESS_READ : ruser_str = $sformatf("%h", t.rdata);
         UVMA_OBI_MEMORY_ACCESS_WRITE: wuser_str = $sformatf("%h", t.wdata);
      endcase
      
      auser_str = $sformatf("%h", t.auser);
      be_str    = $sformatf("%b", t.be   );
      id_str    = $sformatf("%b", t.id   );
      
      fwrite($sformatf(" %t | %s | %s | %s | %s | %s | %s | %h | %s | %s ", $realtime(), access_str, id_str, auser_str, wuser_str, ruser_str, err_str, t.address, be_str, data_str));
      
   endfunction : write_mstr
//@DVT_LINTER_WAIVER_END "MT20210901_2"
   
   /**
    * Writes contents of slv t to disk.
    */
   virtual function void write_slv(uvma_obi_memory_slv_seq_item_c t);
      
      string access_str = "";
      string err_str    = "";
      string be_str     = "";
      string data_str   = "";
      string auser_str  = "";
      string wuser_str  = "";
      string ruser_str  = "";
      string id_str     = "";
      
      case (t.access_type)
         UVMA_OBI_MEMORY_ACCESS_READ : access_str = "R  ";
         UVMA_OBI_MEMORY_ACCESS_WRITE: access_str = "  W";
         default              : access_str = " ? ";
      endcase
      
      case (t.err)
         0: err_str = "    ";
         1: err_str = " ERR";
      endcase
      
      case (t.access_type)
         UVMA_OBI_MEMORY_ACCESS_READ : data_str = $sformatf("%h", t.rdata);
         UVMA_OBI_MEMORY_ACCESS_WRITE: data_str = $sformatf("%h", t.orig_trn.data);
      endcase
      
      case (t.access_type)
         UVMA_OBI_MEMORY_ACCESS_READ : ruser_str = $sformatf("%h", t.rdata);
         UVMA_OBI_MEMORY_ACCESS_WRITE: wuser_str = $sformatf("%h", t.orig_trn.data);
      endcase
      
      auser_str = $sformatf("%h", t.orig_trn.auser);
      be_str    = $sformatf("%b", t.orig_trn.be   );
      id_str    = $sformatf("%b", t.orig_trn.aid  );
      
      fwrite($sformatf(" %t | %s | %s | %s | %s | %s | %s | %h | %s | %s ", $realtime(), access_str, id_str, auser_str, wuser_str, ruser_str, err_str, t.orig_trn.address, be_str, data_str));
      
   endfunction : write_slv
   
   /**
    * Writes log header to disk.
    */
   virtual function void print_header();
      
      fwrite("---------------------------------------------------------------------------------");
      fwrite("        TIME        | R/W |  ID  | AUSER | WUSER | RUSER | ERR | ADDRESS  |  BE  | DATA");
      fwrite("---------------------------------------------------------------------------------");
      
   endfunction : print_header
   
endclass : uvma_obi_memory_seq_item_logger_c


/**
 * Component writing Open Bus Interface monitor transactions debug data to disk as JavaScript Object Notation (JSON).
 */
class uvma_obi_memory_seq_item_logger_json_c extends uvma_obi_memory_seq_item_logger_c;
   
   `uvm_component_utils(uvma_obi_memory_seq_item_logger_json_c)
   
   
   /**
    * Set file extension to '.json'.
    */
   function new(string name="uvma_obi_memory_seq_item_logger_json", uvm_component parent=null);
      
      super.new(name, parent);
      fextension = "json";
      
   endfunction : new
   
   /**
    * Writes contents of t to disk.
    */
   virtual function void write(uvma_obi_memory_base_seq_item_c t);
      
      // TODO Implement uvma_obi_memory_seq_item_logger_json_c::write()
      // Ex: fwrite({"{",
      //       $sformatf("\"time\":\"%0t\",", $realtime()),
      //       $sformatf("\"a\":%h,"        , t.a        ),
      //       $sformatf("\"b\":%b,"        , t.b        ),
      //       $sformatf("\"c\":%d,"        , t.c        ),
      //       $sformatf("\"d\":%h,"        , t.c        ),
      //     "},"});
      
   endfunction : write
   
   /**
    * Empty function.
    */
   virtual function void print_header();
      
      // Do nothing: JSON files do not use headers.
      
   endfunction : print_header
   
endclass : uvma_obi_memory_seq_item_logger_json_c


`endif // __UVMA_OBI_MEMORY_SEQ_ITEM_LOGGER_SV__

uvma_obi_memory_seq_item_logger.sv

1. 简要介绍

该文件是OBI内存序列项日志记录组件,主要功能包括:

  1. 将序列项数据写入磁盘
  2. 支持文本和JSON两种格式
  3. 区分主设备和从设备模式
  4. 提供标准化的日志输出格式

2. 接口介绍

2.1 类定义
class uvma_obi_memory_seq_item_logger_c extends uvml_logs_seq_item_logger_c#(
   .T_TRN(uvma_obi_memory_base_seq_item_c),
   .T_CFG(uvma_obi_memory_cfg_c)
);
  • 代码介绍:定义OBI序列项日志记录类
  • 继承关系:继承自参数化基础日志记录类
  • 特点:支持多种驱动模式

3. 参数介绍

3.1 日志写入函数
virtual function void write(uvma_obi_memory_base_seq_item_c t);
   case (cfg.drv_mode)
      UVMA_OBI_MEMORY_MODE_MSTR: write_mstr(mstr_t);
      UVMA_OBI_MEMORY_MODE_SLV: write_slv(slv_t);
   endcase
endfunction
  • 参数说明
    • drv_mode:驱动模式选择
    • mstr_t:主设备事务
    • slv_t:从设备事务

4. 模块实现介绍

4.1 主设备日志写入
virtual function void write_mstr(uvma_obi_memory_mstr_seq_item_c t);
   case (t.access_type)
      UVMA_OBI_MEMORY_ACCESS_READ: access_str = "R  ";
      UVMA_OBI_MEMORY_ACCESS_WRITE: access_str = "  W";
   endcase
   fwrite($sformatf(" %t | %s | ...", $realtime(), access_str));
endfunction
  • 代码分析
    1. 格式化操作类型
    2. 记录时间戳
    3. 输出完整事务信息
4.2 JSON日志类
class uvma_obi_memory_seq_item_logger_json_c extends uvma_obi_memory_seq_item_logger_c;
   function new();
      fextension = "json";
   endfunction
endclass
  • 代码分析
    1. 继承基础日志类
    2. 设置JSON文件扩展名
    3. 预留JSON格式实现

5. 总结

该OBI序列项日志记录组件具有以下特点:

  1. 灵活的多模式支持
  2. 清晰的文本输出格式
  3. 可扩展的JSON实现
  4. 标准化的UVM集成

作为验证环境的调试辅助工具,它为OBI接口的事务分析提供了可靠的日志记录能力,确保能够方便地追踪接口行为。

// 
// Copyright 2021 OpenHW Group
// Copyright 2021 Datum Technology Corporation
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
// 
// Licensed under the Solderpad Hardware License v 2.1 (the "License"); you may
// not use this file except in compliance with the License, or, at your option,
// the Apache License version 2.0. You may obtain a copy of the License at
// 
//     https://solderpad.org/licenses/SHL-2.1/
// 
// Unless required by applicable law or agreed to in writing, any work
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
// 


`ifndef __UVMA_OBI_MEMORY_SQR_SV__
`define __UVMA_OBI_MEMORY_SQR_SV__


/**
 * Component running Open Bus Interface sequences extending uvma_obi_base_seq_c.
 * Provides sequence items for uvma_obi_drv_c.
 */
class uvma_obi_memory_sqr_c extends uvm_sequencer#(
   .REQ(uvma_obi_memory_base_seq_item_c),
   .RSP(uvma_obi_memory_mon_trn_c      )
);
   
   // Objects
   uvma_obi_memory_cfg_c    cfg;
   uvma_obi_memory_cntxt_c  cntxt;
   
   // TLM
   uvm_tlm_analysis_fifo #(uvma_obi_memory_mon_trn_c)  mon_trn_fifo;
   
   
   `uvm_component_utils_begin(uvma_obi_memory_sqr_c)
      `uvm_field_object(cfg  , UVM_DEFAULT)
      `uvm_field_object(cntxt, UVM_DEFAULT)
   `uvm_component_utils_end
   
   
   /**
    * Default constructor.
    */
   extern function new(string name="uvma_obi_memory_sqr", uvm_component parent=null);
   
   /**
    * Ensures cfg & cntxt handles are not null
    */
   extern virtual function void build_phase(uvm_phase phase);
   
endclass : uvma_obi_memory_sqr_c


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


function void uvma_obi_memory_sqr_c::build_phase(uvm_phase phase);
   
   super.build_phase(phase);
   
   void'(uvm_config_db#(uvma_obi_memory_cfg_c)::get(this, "", "cfg", cfg));
   if (cfg == null) begin
      `uvm_fatal("CFG", "Configuration handle is null")
   end
   
   void'(uvm_config_db#(uvma_obi_memory_cntxt_c)::get(this, "", "cntxt", cntxt));
   if (cntxt == null) begin
      `uvm_fatal("CNTXT", "Context handle is null")
   end
   
   mon_trn_fifo = new("mon_trn_fifo", this);
   
endfunction : build_phase


`endif // __UVMA_OBI_MEMORY_SQR_SV__

uvma_obi_memory_sqr.sv

1. 简要介绍

该文件是OBI内存接口的序列发生器组件,主要功能包括:

  1. 运行OBI接口序列
  2. 为驱动组件提供序列项
  3. 管理监控事务FIFO
  4. 作为序列和驱动之间的桥梁

2. 接口介绍

2.1 类定义
class uvma_obi_memory_sqr_c extends uvm_sequencer#(
   .REQ(uvma_obi_memory_base_seq_item_c),
   .RSP(uvma_obi_memory_mon_trn_c)
);
  • 代码介绍:定义OBI内存序列发生器类
  • 继承关系:继承自UVM参数化序列发生器类
  • 特点:支持基础序列项和监控事务响应

3. 参数介绍

3.1 配置对象
uvma_obi_memory_cfg_c cfg;
uvma_obi_memory_cntxt_c cntxt;
  • 参数说明
    • cfg:配置对象
    • cntxt:上下文对象
  • 用途:存储运行时配置和状态
3.2 分析FIFO
uvm_tlm_analysis_fifo #(uvma_obi_memory_mon_trn_c) mon_trn_fifo;
  • 参数说明:监控事务FIFO
  • 用途:存储来自监控组件的事务

4. 模块实现介绍

4.1 构造函数
function new(string name="uvma_obi_memory_sqr", uvm_component parent=null);
   super.new(name, parent);
endfunction
  • 代码分析
    1. 调用父类构造函数
    2. 初始化序列发生器
    3. 无额外初始化逻辑
4.2 构建阶段
function void build_phase(uvm_phase phase);
   void'(uvm_config_db#(uvma_obi_memory_cfg_c)::get(this, "", "cfg", cfg));
   mon_trn_fifo = new("mon_trn_fifo", this);
endfunction
  • 代码分析
    1. 从配置数据库获取配置对象
    2. 创建监控事务FIFO
    3. 检查配置和上下文有效性

5. 总结

该OBI内存序列发生器组件具有以下特点:

  1. 标准化的UVM实现
  2. 灵活的序列项管理
  3. 可靠的监控事务处理
  4. 清晰的接口定义

作为验证环境的核心组件,它为OBI接口的序列执行提供了可靠的基础设施,确保能够高效地执行各类测试场景。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值