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

core-v-verif系列之lib<23>
UVM环境介绍
HEAD commitID: 1f968ef

1. core-v-verif/lib/uvm_agents/uvma_axi/src/obj/uvma_axi_cntxt.sv

// Copyright 2022 Thales DIS SAS
//
// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0
// You may obtain a copy of the License at https://solderpad.org/licenses/
//
// Original Author: Alae Eddine EZ ZEJJARI (alae-eddine.ez-zejjari@external.thalesgroup.com)
// Co-Author: Abdelaali Khardazi


`ifndef __UVMA_AXI_CFG_SV__
`define __UVMA_AXI_CFG_SV__

class uvma_axi_cfg_c extends uvm_object;

   rand uvm_active_passive_enum            is_active;
   rand bit                                trn_log_enabled;
   rand uvma_axi_drv_slv_mode_enum         drv_slv_mode;
   rand uvma_axi_drv_slv_err_mode_enum     drv_slv_err_mode;

   rand int unsigned             drv_slv_fixed_latency;
   rand int unsigned             drv_slv_random_latency_min;
   rand int unsigned             drv_slv_random_latency_max;

   rand int unsigned             drv_slv_err_ok;
   rand int unsigned             drv_slv_err_dec;
   rand int unsigned             drv_slv_err_slv;
   rand bit                      drv_slv_err_one_shot_mode;
   rand bit                      drv_slv_err_one_shot_flag;
   bit                           directed_slv_err_valid;
   bit[1:0]                      drv_slv_fixed_resp = 2'b10;

   `uvm_object_utils_begin(uvma_axi_cfg_c)
      `uvm_field_enum(uvm_active_passive_enum, is_active, UVM_DEFAULT);
      `uvm_field_int (directed_slv_err_valid, UVM_DEFAULT)
      `uvm_field_int (drv_slv_fixed_latency, UVM_DEFAULT)
      `uvm_field_int (drv_slv_random_latency_min, UVM_DEFAULT)
      `uvm_field_int (drv_slv_random_latency_max, UVM_DEFAULT)
      `uvm_field_int (drv_slv_err_one_shot_mode, UVM_DEFAULT)
      `uvm_field_int (drv_slv_err_one_shot_flag, UVM_DEFAULT)
      `uvm_field_int (drv_slv_err_ok, UVM_DEFAULT  | UVM_DEC)
      `uvm_field_int (drv_slv_err_dec, UVM_DEFAULT | UVM_DEC)
      `uvm_field_int (drv_slv_err_slv, UVM_DEFAULT | UVM_DEC)
      `uvm_field_int (drv_slv_fixed_resp, UVM_DEFAULT | UVM_DEC)
      `uvm_field_enum(uvma_axi_drv_slv_mode_enum, drv_slv_mode, UVM_DEFAULT)
      `uvm_field_enum(uvma_axi_drv_slv_err_mode_enum, drv_slv_err_mode, UVM_DEFAULT)
   `uvm_object_utils_end

   constraint defaults_config {
      soft is_active                   == UVM_ACTIVE;
      soft drv_slv_err_one_shot_mode   == 0;
      soft drv_slv_mode                == UVMA_AXI_DRV_SLV_MODE_RANDOM_LATENCY;
      soft drv_slv_fixed_latency       == 3;
      soft drv_slv_random_latency_min  == 0;
      soft drv_slv_random_latency_max  == 4;
      soft directed_slv_err_valid      == 0;
      soft drv_slv_err_mode            == UVMA_AXI_DRV_SLV_ERR_MODE_RANDOM;
     }

   constraint err_wgts_cons {
      // Keep the weights for errors within some bounds
      drv_slv_err_ok  inside {[0:1000]};
      drv_slv_err_dec inside {[0:1000]};
      drv_slv_err_slv inside {[0:1000]};
   }

   extern function new(string name = "uvma_axi_cfg");

   extern function int unsigned calc_random_latency();

   extern function bit[1:0] random_err();

endclass : uvma_axi_cfg_c


function uvma_axi_cfg_c::new(string name = "uvma_axi_cfg");

   super.new(name);

endfunction : new

function int unsigned uvma_axi_cfg_c::calc_random_latency();
   int unsigned effective_latency;

   case (drv_slv_mode)
      UVMA_AXI_DRV_SLV_MODE_CONSTANT      : effective_latency = 0;
      UVMA_AXI_DRV_SLV_MODE_FIXED_LATENCY : effective_latency = drv_slv_fixed_latency;
      UVMA_AXI_DRV_SLV_MODE_RANDOM_LATENCY: begin
         effective_latency = $urandom_range(drv_slv_random_latency_min, drv_slv_random_latency_max);
      end
   endcase

   return effective_latency;

endfunction : calc_random_latency

function bit[1:0] uvma_axi_cfg_c::random_err();

   bit[1:0] err;

   // If we are in "one-shot" mode and have already calculated an error,
   // then skip any new errors (until the code resets the flag)
   if (drv_slv_err_one_shot_mode && drv_slv_err_one_shot_flag) begin
      return 0;
   end

   // Check for a directed error reponse first
   if (directed_slv_err_valid) begin

      if (drv_slv_err_one_shot_mode) begin
         drv_slv_err_one_shot_flag = 1;
      end

      return drv_slv_fixed_resp;
   end

   case (drv_slv_err_mode)
      UVMA_AXI_DRV_SLV_ERR_MODE_OK      : err = 2'b00;
      UVMA_AXI_DRV_SLV_ERR_MODE_RANDOM  : begin
         randcase
            drv_slv_err_ok : err = 2'b00;
            drv_slv_err_dec: err = 2'b11;
            drv_slv_err_slv: err = 2'b10;
         endcase
      end
   endcase

   if (err != 0 && drv_slv_err_one_shot_mode) begin
      drv_slv_err_one_shot_flag = 1;
   end

   return err;

endfunction : random_err

`endif //__UVMA_AXI_CFG_SV__

1. 简要介绍

uvma_axi_cfg.sv 文件定义了一个名为 uvma_axi_cfg_c 的类,该类继承自 uvm_object。在 UVM(通用验证方法学)环境里,这个类主要用于存储和配置 AXI(Advanced eXtensible Interface)代理的相关参数。通过随机化成员变量和使用约束条件,可灵活设置 AXI 驱动的工作模式、延迟、错误处理等行为,方便验证人员对不同的 AXI 场景进行测试。

2. 接口介绍

此文件定义的类本身无传统意义上的硬件接口,主要是通过成员变量和方法为外部代码提供配置信息。外部代码可创建 uvma_axi_cfg_c 类的对象,访问和修改其成员变量,调用其方法来获取随机延迟和错误信息。

// 部分成员变量示例
rand uvm_active_passive_enum            is_active;
rand bit                                trn_log_enabled;
// 方法示例
extern function int unsigned calc_random_latency();
extern function bit[1:0] random_err();
  • is_active:枚举类型变量,用于设置 AXI 代理是处于活动模式(UVM_ACTIVE)还是被动模式(UVM_PASSIVE)。
  • trn_log_enabled:布尔类型变量,用于控制事务日志是否启用。
  • calc_random_latency():函数,根据 drv_slv_mode 计算随机延迟。
  • random_err():函数,根据配置计算随机错误响应。

3. 参数介绍

类中定义了多个随机化和非随机化的成员变量,这些变量作为配置参数影响 AXI 代理的行为:

rand uvm_active_passive_enum            is_active;
rand bit                                trn_log_enabled;
rand uvma_axi_drv_slv_mode_enum         drv_slv_mode;
rand uvma_axi_drv_slv_err_mode_enum     drv_slv_err_mode;
rand int unsigned             drv_slv_fixed_latency;
rand int unsigned             drv_slv_random_latency_min;
rand int unsigned             drv_slv_random_latency_max;
rand int unsigned             drv_slv_err_ok;
rand int unsigned             drv_slv_err_dec;
rand int unsigned             drv_slv_err_slv;
rand bit                      drv_slv_err_one_shot_mode;
rand bit                      drv_slv_err_one_shot_flag;
bit                           directed_slv_err_valid;
bit[1:0]                      drv_slv_fixed_resp = 2'b10;
  • is_active:控制 AXI 代理的活动状态。
  • trn_log_enabled:决定是否开启事务日志。
  • drv_slv_mode:驱动从设备的模式,如固定延迟、随机延迟等。
  • drv_slv_err_mode:驱动从设备的错误模式,如随机错误、固定错误等。
  • drv_slv_fixed_latency:驱动从设备的固定延迟值。
  • drv_slv_random_latency_mindrv_slv_random_latency_max:驱动从设备随机延迟的最小值和最大值。
  • drv_slv_err_okdrv_slv_err_decdrv_slv_err_slv:分别表示不同错误类型的权重。
  • drv_slv_err_one_shot_mode:是否启用单次错误模式。
  • drv_slv_err_one_shot_flag:单次错误模式的标志位。
  • directed_slv_err_valid:是否启用定向错误响应。
  • drv_slv_fixed_resp:固定的错误响应值。

4. 模块实现介绍

4.1 版权和许可证声明
// Copyright 2022 Thales DIS SAS
//
// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0
// You may obtain a copy of the License at https://solderpad.org/licenses/
//
// Original Author: Alae Eddine EZ ZEJJARI (alae-eddine.ez-zejjari@external.thalesgroup.com)
// Co-Author: Abdelaali Khardazi
  • 代码介绍:声明文件的版权归属、所遵循的开源硬件许可证以及作者信息。
  • 逻辑分析:告知使用者文件的版权所有者和使用限制,遵循开源协议规范。
4.2 条件编译
`ifndef __UVMA_AXI_CFG_SV__
`define __UVMA_AXI_CFG_SV__

// ... 中间代码 ...

`endif
  • 代码介绍:使用条件编译指令防止文件被重复包含。若 __UVMA_AXI_CFG_SV__ 宏未定义,则定义该宏并编译中间代码;若已定义,则跳过。
  • 逻辑分析:避免在编译过程中多次包含该文件,导致类重复定义的错误。
4.3 类定义和成员变量声明
class uvma_axi_cfg_c extends uvm_object;

   rand uvm_active_passive_enum            is_active;
   rand bit                                trn_log_enabled;
   // 其他成员变量...
endclass : uvma_axi_cfg_c
  • 代码介绍:定义 uvma_axi_cfg_c 类,继承自 uvm_object。声明多个随机化和非随机化的成员变量,用于存储 AXI 代理的配置信息。
  • 逻辑分析:借助 UVM 类机制,封装 AXI 代理的配置参数,方便管理和使用。
4.4 UVM 对象实用工具宏
`uvm_object_utils_begin(uvma_axi_cfg_c)
   `uvm_field_enum(uvm_active_passive_enum, is_active, UVM_DEFAULT);
   `uvm_field_int (directed_slv_err_valid, UVM_DEFAULT)
   // 其他字段注册...
`uvm_object_utils_end
  • 代码介绍:使用 UVM 对象实用工具宏将类及其成员变量注册到 UVM 工厂,使类支持 UVM 的对象创建、复制、打印等功能。
  • 逻辑分析:通过 UVM 工厂机制,方便在验证环境中动态创建和操作 uvma_axi_cfg_c 类的对象。
4.5 约束条件
constraint defaults_config {
   soft is_active                   == UVM_ACTIVE;
   soft drv_slv_err_one_shot_mode   == 0;
   // 其他约束...
}

constraint err_wgts_cons {
   drv_slv_err_ok  inside {[0:1000]};
   drv_slv_err_dec inside {[0:1000]};
   drv_slv_err_slv inside {[0:1000]};
}
  • 代码介绍defaults_config 约束为部分成员变量设置软约束,在随机化时这些变量有默认值,但可被外部覆盖;err_wgts_cons 约束确保错误权重在 0 到 1000 之间。
  • 逻辑分析:通过约束条件,为随机化的成员变量提供合理的取值范围和默认值,增强配置的灵活性和合理性。
4.6 构造函数
function uvma_axi_cfg_c::new(string name = "uvma_axi_cfg");
   super.new(name);
endfunction : new
  • 代码介绍:实现类的构造函数,调用父类 uvm_object 的构造函数完成初始化。
  • 逻辑分析:初始化 uvma_axi_cfg_c 类的对象,为后续使用做准备。
4.7 calc_random_latency 函数
function int unsigned uvma_axi_cfg_c::calc_random_latency();
   int unsigned effective_latency;

   case (drv_slv_mode)
      UVMA_AXI_DRV_SLV_MODE_CONSTANT      : effective_latency = 0;
      UVMA_AXI_DRV_SLV_MODE_FIXED_LATENCY : effective_latency = drv_slv_fixed_latency;
      UVMA_AXI_DRV_SLV_MODE_RANDOM_LATENCY: begin
         effective_latency = $urandom_range(drv_slv_random_latency_min, drv_slv_random_latency_max);
      end
   endcase

   return effective_latency;
endfunction : calc_random_latency
  • 代码介绍:根据 drv_slv_mode 计算驱动从设备的有效延迟。若为固定延迟模式,返回 drv_slv_fixed_latency;若为随机延迟模式,返回 drv_slv_random_latency_mindrv_slv_random_latency_max 之间的随机值。
  • 逻辑分析:为验证环境提供灵活的延迟配置,模拟不同的 AXI 从设备行为。
4.8 random_err 函数
function bit[1:0] uvma_axi_cfg_c::random_err();
   bit[1:0] err;

   if (drv_slv_err_one_shot_mode && drv_slv_err_one_shot_flag) begin
      return 0;
   end

   if (directed_slv_err_valid) begin
      if (drv_slv_err_one_shot_mode) begin
         drv_slv_err_one_shot_flag = 1;
      end
      return drv_slv_fixed_resp;
   end

   case (drv_slv_err_mode)
      UVMA_AXI_DRV_SLV_ERR_MODE_OK      : err = 2'b00;
      UVMA_AXI_DRV_SLV_ERR_MODE_RANDOM  : begin
         randcase
            drv_slv_err_ok : err = 2'b00;
            drv_slv_err_dec: err = 2'b11;
            drv_slv_err_slv: err = 2'b10;
         endcase
      end
   endcase

   if (err != 0 && drv_slv_err_one_shot_mode) begin
      drv_slv_err_one_shot_flag = 1;
   end

   return err;
endfunction : random_err
  • 代码介绍:根据配置计算随机错误响应。若处于单次错误模式且标志位已设置,返回 0;若启用定向错误响应,返回固定错误响应值;否则,根据错误模式和权重随机生成错误响应。
  • 逻辑分析:模拟 AXI 从设备的错误响应,帮助验证人员测试系统对错误的处理能力。

5. 总结

uvma_axi_cfg.sv 文件通过定义 uvma_axi_cfg_c 类,为 UVM 验证环境中的 AXI 代理提供了全面的配置管理。利用 UVM 的特性,如对象工厂、随机化和约束,实现了灵活的配置方式。通过 calc_random_latencyrandom_err 函数,可模拟不同的 AXI 从设备行为和错误响应,方便验证人员对 AXI 协议进行各种场景的测试。条件编译和版权声明保证了代码的可维护性和合规性。

2. core-v-verif/lib/uvm_agents/uvma_axi/src/obj/uvma_axi_cfg.sv

// Copyright 2022 Thales DIS SAS
//
// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0
// You may obtain a copy of the License at https://solderpad.org/licenses/
//
// Original Author: Alae Eddine EZ ZEJJARI (alae-eddine.ez-zejjari@external.thalesgroup.com)
// Co-Author: Abdelaali Khardazi

`ifndef __UVMA_AXI_CNTXT_SV__
`define __UVMA_AXI_CNTXT_SV__

/**
 * Object encapsulating all state variables for all AXI agent
 * (uvma_axi_agent_c) components.
 */
class uvma_axi_cntxt_c extends uvm_object;

   // Handle to agent interface
   virtual uvma_axi_intf  axi_vi;

   // Handle to memory storage for active slaves
   uvml_mem_c mem;

   uvma_axi_reset_state_enum  reset_state = UVMA_AXI_RESET_STATE_PRE_RESET;

   `uvm_object_utils_begin(uvma_axi_cntxt_c)
      `uvm_field_enum(uvma_axi_reset_state_enum, reset_state, UVM_DEFAULT)
   `uvm_object_utils_end
   /**
    * Builds events.
    */
   extern function new(string name = "uvma_axi_cntxt");

endclass : uvma_axi_cntxt_c


function uvma_axi_cntxt_c::new(string name = "uvma_axi_cntxt");

   super.new(name);
   mem = uvml_mem_c#(64)::type_id::create("mem");

endfunction : new

`endif // __UVMA_AXI_CNTXT_SV__

1. 简要介绍

uvma_axi_cntxt.sv 文件定义了一个名为 uvma_axi_cntxt_c 的类,该类继承自 uvm_object。在 UVM(通用验证方法学)环境中,uvma_axi_cntxt_c 类的作用是封装 AXI 代理(uvma_axi_agent_c)所有组件的状态变量,为 AXI 代理的各个部分提供统一的状态管理和数据存储。

2. 接口介绍

此文件定义的类没有传统意义上的硬件接口,主要通过成员变量和 UVM 机制与外部交互。外部代码可以创建 uvma_axi_cntxt_c 类的对象,访问和修改其成员变量,从而获取和设置 AXI 代理的状态信息。

// 成员变量,作为与外部交互的接口
virtual uvma_axi_intf  axi_vi;
uvml_mem_c mem;
uvma_axi_reset_state_enum  reset_state = UVMA_AXI_RESET_STATE_PRE_RESET;
  • axi_vi:虚拟接口句柄,用于连接 AXI 接口,外部代码可以通过这个句柄访问和控制 AXI 接口的信号。
  • memuvml_mem_c 类型的对象,作为主动从设备的内存存储句柄,可用于存储和读取数据。
  • reset_stateuvma_axi_reset_state_enum 枚举类型的变量,记录 AXI 代理的复位状态,初始值为 UVMA_AXI_RESET_STATE_PRE_RESET

3. 参数介绍

文件中没有显式的参数定义,但类的成员变量可看作配置和状态参数:

// 见接口介绍部分代码
  • axi_vi:无参数,是一个虚拟接口句柄,用于连接实际的 AXI 接口。
  • mem:无参数,是 uvml_mem_c 类型的对象,在构造函数中创建。
  • reset_state:枚举类型,取值由 uvma_axi_reset_state_enum 定义,用于表示 AXI 代理的复位状态。

4. 模块实现介绍

4.1 版权声明与许可证信息
// Copyright 2022 Thales DIS SAS
//
// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0
// You may obtain a copy of the License at https://solderpad.org/licenses/
//
// Original Author: Alae Eddine EZ ZEJJARI (alae-eddine.ez-zejjari@external.thalesgroup.com)
// Co-Author: Abdelaali Khardazi
  • 代码介绍:这部分代码声明了文件的版权归属、使用的开源硬件许可证以及作者信息。
  • 逻辑分析:告知开发者文件的版权和使用限制,遵循开源协议规范。
4.2 条件编译
`ifndef __UVMA_AXI_CNTXT_SV__
`define __UVMA_AXI_CNTXT_SV__

// ... 中间代码 ...

`endif
  • 代码介绍:使用条件编译指令防止文件被重复包含。如果 __UVMA_AXI_CNTXT_SV__ 宏未定义,则定义该宏并编译中间代码;如果已定义,则跳过。
  • 逻辑分析:避免在编译过程中多次包含该文件,导致类重复定义的错误。
4.3 类定义与成员变量声明
/**
 * Object encapsulating all state variables for all AXI agent
 * (uvma_axi_agent_c) components.
 */
class uvma_axi_cntxt_c extends uvm_object;

   // Handle to agent interface
   virtual uvma_axi_intf  axi_vi;

   // Handle to memory storage for active slaves
   uvml_mem_c mem;

   uvma_axi_reset_state_enum  reset_state = UVMA_AXI_RESET_STATE_PRE_RESET;
  • 代码介绍:定义 uvma_axi_cntxt_c 类,继承自 uvm_object。类注释说明了该类用于封装 AXI 代理所有组件的状态变量。声明了三个成员变量,分别是虚拟接口句柄 axi_vi、内存存储句柄 mem 和复位状态变量 reset_state
  • 逻辑分析:通过继承 uvm_object,使该类可以利用 UVM 的对象管理机制。成员变量为 AXI 代理的状态管理提供了数据存储和接口连接的能力。
4.4 UVM 对象实用工具宏
`uvm_object_utils_begin(uvma_axi_cntxt_c)
   `uvm_field_enum(uvma_axi_reset_state_enum, reset_state, UVM_DEFAULT)
`uvm_object_utils_end
  • 代码介绍:使用 UVM 的对象实用工具宏将 uvma_axi_cntxt_c 类注册到 UVM 对象工厂,并将 reset_state 成员变量注册为可被 UVM 管理的字段。UVM_DEFAULT 表示使用默认的 UVM 操作。
  • 逻辑分析:注册到 UVM 对象工厂后,该类可以在 UVM 环境中动态创建、复制和打印。注册 reset_state 字段使得该变量可以参与 UVM 的对象操作,如打印和比较。
4.5 构造函数声明与实现
/**
 * Builds events.
 */
extern function new(string name = "uvma_axi_cntxt");

// ...

function uvma_axi_cntxt_c::new(string name = "uvma_axi_cntxt");

   super.new(name);
   mem = uvml_mem_c#(64)::type_id::create("mem");

endfunction : new
  • 代码介绍:在类中使用 extern 关键字声明构造函数,在类外实现构造函数。构造函数接受一个字符串参数 name,默认值为 "uvma_axi_cntxt"。在构造函数中,首先调用父类 uvm_object 的构造函数完成初始化,然后使用 UVM 的工厂机制创建 uvml_mem_c#(64) 类型的对象 mem
  • 逻辑分析:调用父类构造函数确保父类部分的初始化,创建 mem 对象为主动从设备提供内存存储。

5. 总结

uvma_axi_cntxt.sv 文件通过定义 uvma_axi_cntxt_c 类,为 UVM 验证环境中的 AXI 代理提供了统一的状态管理和数据存储。利用条件编译避免文件重复包含,使用 UVM 对象实用工具宏将类和成员变量注册到 UVM 对象工厂,方便在 UVM 环境中使用。构造函数完成了类的初始化和内存对象的创建。该类作为 AXI 代理状态信息的载体,有助于提高验证环境的可维护性和可扩展性。

3. core-v-verif/lib/uvm_agents/uvma_axi/src/comps/uvma_axi_agent.sv

// Copyright 2022 Thales DIS SAS
//
// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0
// You may obtain a copy of the License at https://solderpad.org/licenses/
//
// Original Author: Alae Eddine EZ ZEJJARI (alae-eddine.ez-zejjari@external.thalesgroup.com)
// Co-Author: Abdelaali Khardazi

/**** AXI4 (top) agent ****/

`ifndef __UVMA_AXI_AGENT_SV__
`define __UVMA_AXI_AGENT_SV__

class uvma_axi_agent_c extends uvm_agent;

   `uvm_component_utils(uvma_axi_agent_c)

   uvma_axi_aw_agent_c        aw_agent;
   uvma_axi_w_agent_c         w_agent;
   uvma_axi_b_agent_c         b_agent;
   uvma_axi_ar_agent_c        ar_agent;
   uvma_axi_r_agent_c         r_agent;
   uvma_axi_vsqr_c            vsequencer;

   uvma_axi_seq_item_logger_c seq_item_logger;

   uvma_axi_cfg_c      cfg;
   uvma_axi_cntxt_c    cntxt;

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

   function void build_phase(uvm_phase phase);

      super.build_phase(phase);
      get_and_set_cfg  ();
      get_and_set_cntxt();
      retrieve_vif     ();
      create_components();

   endfunction : build_phase

   function void get_and_set_cntxt();

      void'(uvm_config_db#(uvma_axi_cntxt_c)::get(this, "", "cntxt", cntxt));
      if (cntxt == null) begin
         `uvm_info("CNTXT", "Context handle is null; creating", UVM_DEBUG)
         cntxt = uvma_axi_cntxt_c::type_id::create("cntxt");
      end
      uvm_config_db#(uvma_axi_cntxt_c)::set(this, "*", "cntxt", cntxt);

   endfunction : get_and_set_cntxt

   function void get_and_set_cfg();

      void'(uvm_config_db#(uvma_axi_cfg_c)::get(this, "", "cfg", cfg));
      if (cfg == null) begin
         `uvm_fatal("CFG", "Configuration handle is null")
      end
      else begin
         `uvm_info("CFG", $sformatf("Found configuration handle:\n%s", cfg.sprint()), UVM_DEBUG)
         uvm_config_db#(uvma_axi_cfg_c)::set(this, "*", "cfg", cfg);
      end

   endfunction : get_and_set_cfg

   function void retrieve_vif();

      if (!uvm_config_db#(virtual uvma_axi_intf)::get(this, "", "axi_vif", cntxt.axi_vi)) begin
         `uvm_fatal("VIF", $sformatf("Could not find vif handle of type %s in uvm_config_db", $typename(cntxt.axi_vi)))
      end
      else begin
         `uvm_info("VIF", $sformatf("Found vif handle of type %s in uvm_config_db", $typename(cntxt.axi_vi)), UVM_DEBUG)
      end

   endfunction : retrieve_vif

   function void create_components();

      this.aw_agent = uvma_axi_aw_agent_c :: type_id :: create("aw_agent", this);
      this.w_agent  = uvma_axi_w_agent_c  :: type_id :: create("w_agent",  this);
      this.b_agent  = uvma_axi_b_agent_c  :: type_id :: create("b_agent",  this);
      this.ar_agent = uvma_axi_ar_agent_c :: type_id :: create("ar_agent", this);
      this.r_agent  = uvma_axi_r_agent_c  :: type_id :: create("r_agent",  this);
      this.seq_item_logger = uvma_axi_seq_item_logger_c::type_id::create("seq_item_logger", this);
      if( cfg.is_active == UVM_ACTIVE) begin
         vsequencer = uvma_axi_vsqr_c::type_id::create("sequencer", this);
      end

   endfunction : create_components

   function void connect_phase(uvm_phase phase);

      //super.connect_phase(phase);
      if( cfg.is_active == UVM_ACTIVE) begin
         connect_mon_2_sqr();
         assemble_vsequencer();
      end else begin
         `uvm_info(get_type_name(), $sformatf("PASSIVE MODE"), UVM_LOW)
      end

      if (cfg.trn_log_enabled) begin
         connect_trn_loggers();
         `uvm_info(get_type_name(), $sformatf("Transaction Loger enable"), UVM_LOW)
      end

   endfunction

   function void connect_mon_2_sqr();

      this.aw_agent.monitor.uvma_aw_mon2drv_port.connect(aw_agent.sequencer.aw_req_export);

      this.w_agent.monitor.uvma_w_mon2drv_port.connect(w_agent.sequencer.w_req_export);

      this.aw_agent.monitor.uvma_aw_mon2drv_port.connect(w_agent.sequencer.aw_req_export.analysis_export);

      this.aw_agent.monitor.uvma_aw_mon_port.connect(b_agent.sequencer.aw_req_export.analysis_export);

      this.w_agent.monitor.uvma_w_mon_port.connect(b_agent.sequencer.w_req_export.analysis_export);

      this.b_agent.monitor.uvma_b_mon2drv_port.connect(b_agent.sequencer.b_resp_export);

      this.ar_agent.monitor.uvma_ar_mon2drv_port.connect(ar_agent.sequencer.ar_req_export);

      this.ar_agent.monitor.uvma_ar_mon_port.connect(r_agent.sequencer.ar_req_export.analysis_export);

      this.r_agent.monitor.uvma_r_mon_port.connect(r_agent.sequencer.r_resp_export);

   endfunction: connect_mon_2_sqr

   function void assemble_vsequencer();

      vsequencer.aw_sequencer  = aw_agent.sequencer;
      vsequencer.ar_sequencer  = ar_agent.sequencer;
      vsequencer.w_sequencer   = w_agent.sequencer;
      vsequencer.b_sequencer   = b_agent.sequencer;
      vsequencer.r_sequencer   = r_agent.sequencer;

   endfunction: assemble_vsequencer

   function void connect_trn_loggers();

      this.aw_agent.monitor.aw_mon2log_port.connect(seq_item_logger.analysis_export);
      this.w_agent.monitor.w_mon2log_port.connect(seq_item_logger.analysis_export);
      this.b_agent.monitor.b_mon2log_port.connect(seq_item_logger.analysis_export);
      this.ar_agent.monitor.ar_mon2log_port.connect(seq_item_logger.analysis_export);
      this.r_agent.monitor.r_mon2log_port.connect(seq_item_logger.analysis_export);

   endfunction : connect_trn_loggers

endclass : uvma_axi_agent_c

`endif //__UVMA_AXI_AGENT_SV__

1. 简要介绍

uvma_axi_agent.sv 文件定义了一个名为 uvma_axi_agent_c 的类,该类继承自 uvm_agent,是 UVM(通用验证方法学)中用于 AXI4 协议验证的顶层代理类。它整合了 AXI4 协议各个通道(写地址、写数据、写响应、读地址、读数据)的子代理,同时包含一个虚拟序列器和一个序列项记录器。该代理类负责完成配置和上下文的获取、接口句柄的检索、组件的创建以及组件之间的连接等操作,以构建完整的 AXI4 验证环境。

2. 接口介绍

此文件主要定义类,无传统硬件接口。在 UVM 环境中,通过 UVM 配置数据库和分析端口进行交互:

// 通过 UVM 配置数据库获取配置和上下文信息
void'(uvm_config_db#(uvma_axi_cfg_c)::get(this, "", "cfg", cfg));
void'(uvm_config_db#(uvma_axi_cntxt_c)::get(this, "", "cntxt", cntxt));
void'(uvm_config_db#(virtual uvma_axi_intf)::get(this, "", "axi_vif", cntxt.axi_vi));

// 通过分析端口连接组件
this.aw_agent.monitor.uvma_aw_mon2drv_port.connect(aw_agent.sequencer.aw_req_export);
  • uvm_config_db:用于在 UVM 环境中传递配置信息、上下文信息和虚拟接口句柄。
  • 分析端口:如 uvma_aw_mon2drv_port 等,用于将监视器的数据传递给序列器或记录器。

3. 参数介绍

文件中无显式参数定义,但类包含多个成员变量,这些变量在代理的运行过程中起关键作用:

uvma_axi_aw_agent_c        aw_agent;
uvma_axi_w_agent_c         w_agent;
uvma_axi_b_agent_c         b_agent;
uvma_axi_ar_agent_c        ar_agent;
uvma_axi_r_agent_c         r_agent;
uvma_axi_vsqr_c            vsequencer;
uvma_axi_seq_item_logger_c seq_item_logger;
uvma_axi_cfg_c      cfg;
uvma_axi_cntxt_c    cntxt;
  • 子代理对象(如 aw_agentw_agent 等):分别负责 AXI4 协议不同通道的验证。
  • vsequencer:虚拟序列器,用于协调各个子序列器的工作。
  • seq_item_logger:序列项记录器,用于记录事务信息。
  • cfg:配置对象,存储 AXI4 代理的配置信息。
  • cntxt:上下文对象,存储 AXI4 代理的上下文信息,包括虚拟接口句柄。

4. 模块实现介绍

4.1 版权和许可证声明
// Copyright 2022 Thales DIS SAS
//
// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0
// You may obtain a copy of the License at https://solderpad.org/licenses/
//
// Original Author: Alae Eddine EZ ZEJJARI (alae-eddine.ez-zejjari@external.thalesgroup.com)
// Co-Author: Abdelaali Khardazi
  • 代码介绍:声明文件的版权归属、使用的开源硬件许可证以及作者信息。
  • 逻辑分析:告知开发者文件的版权和使用限制,遵循开源协议规范。
4.2 条件编译
`ifndef __UVMA_AXI_AGENT_SV__
`define __UVMA_AXI_AGENT_SV__

// ... 中间代码 ...

`endif
  • 代码介绍:使用条件编译指令防止文件被重复包含。若 __UVMA_AXI_AGENT_SV__ 宏未定义,则定义该宏并编译中间代码;若已定义,则跳过。
  • 逻辑分析:避免在编译过程中多次包含该文件,导致类重复定义的错误。
4.3 类定义和 UVM 注册
class uvma_axi_agent_c extends uvm_agent;

   `uvm_component_utils(uvma_axi_agent_c)
  • 代码介绍:定义 uvma_axi_agent_c 类,继承自 uvm_agent,并使用 uvm_component_utils 宏将该类注册到 UVM 组件工厂。
  • 逻辑分析:继承 uvm_agent 使该类成为 UVM 验证环境中的代理组件,注册到 UVM 组件工厂后可在 UVM 环境中动态创建。
4.4 构造函数
function new(string name = "uvma_axi_agent_c", uvm_component parent = null);
   super.new(name, parent);
endfunction
  • 代码介绍:定义构造函数,接受 nameparent 两个参数,默认名称为 "uvma_axi_agent_c",默认父组件为 null。调用父类 uvm_agent 的构造函数完成初始化。
  • 逻辑分析:初始化 uvma_axi_agent_c 类的对象,为后续操作做准备。
4.5 build_phase 函数
function void build_phase(uvm_phase phase);

   super.build_phase(phase);
   get_and_set_cfg  ();
   get_and_set_cntxt();
   retrieve_vif     ();
   create_components();

endfunction : build_phase
  • 代码介绍:在 UVM 的 build_phase 中,先调用父类的 build_phase 方法,然后依次调用 get_and_set_cfgget_and_set_cntxtretrieve_vifcreate_components 函数。
  • 逻辑分析:在构建阶段完成配置和上下文的获取、虚拟接口句柄的检索以及组件的创建。
4.6 get_and_set_cfg 函数
function void get_and_set_cfg();

   void'(uvm_config_db#(uvma_axi_cfg_c)::get(this, "", "cfg", cfg));
   if (cfg == null) begin
      `uvm_fatal("CFG", "Configuration handle is null")
   end
   else begin
      `uvm_info("CFG", $sformatf("Found configuration handle:\n%s", cfg.sprint()), UVM_DEBUG)
      uvm_config_db#(uvma_axi_cfg_c)::set(this, "*", "cfg", cfg);
   end

endfunction : get_and_set_cfg
  • 代码介绍:从 UVM 配置数据库中获取 uvma_axi_cfg_c 类型的配置对象 cfg。若获取失败(cfgnull),则输出致命错误信息;若获取成功,则输出调试信息并将该配置对象设置到 UVM 配置数据库中,供其他组件使用。
  • 逻辑分析:确保整个验证环境使用统一的配置信息。
4.7 get_and_set_cntxt 函数
function void get_and_set_cntxt();

   void'(uvm_config_db#(uvma_axi_cntxt_c)::get(this, "", "cntxt", cntxt));
   if (cntxt == null) begin
      `uvm_info("CNTXT", "Context handle is null; creating", UVM_DEBUG)
      cntxt = uvma_axi_cntxt_c::type_id::create("cntxt");
   end
   uvm_config_db#(uvma_axi_cntxt_c)::set(this, "*", "cntxt", cntxt);

endfunction : get_and_set_cntxt
  • 代码介绍:从 UVM 配置数据库中获取 uvma_axi_cntxt_c 类型的上下文对象 cntxt。若获取失败(cntxtnull),则输出调试信息并创建新的上下文对象;最后将该上下文对象设置到 UVM 配置数据库中,供其他组件使用。
  • 逻辑分析:确保整个验证环境使用统一的上下文信息。
4.8 retrieve_vif 函数
function void retrieve_vif();

   if (!uvm_config_db#(virtual uvma_axi_intf)::get(this, "", "axi_vif", cntxt.axi_vi)) begin
      `uvm_fatal("VIF", $sformatf("Could not find vif handle of type %s in uvm_config_db", $typename(cntxt.axi_vi)))
   end
   else begin
      `uvm_info("VIF", $sformatf("Found vif handle of type %s in uvm_config_db", $typename(cntxt.axi_vi)), UVM_DEBUG)
   end

endfunction : retrieve_vif
  • 代码介绍:从 UVM 配置数据库中获取虚拟接口句柄 cntxt.axi_vi。若获取失败,则输出致命错误信息;若获取成功,则输出调试信息。
  • 逻辑分析:确保代理能够通过虚拟接口与 DUT 进行交互。
4.9 create_components 函数
function void create_components();

   this.aw_agent = uvma_axi_aw_agent_c :: type_id :: create("aw_agent", this);
   this.w_agent  = uvma_axi_w_agent_c  :: type_id :: create("w_agent",  this);
   this.b_agent  = uvma_axi_b_agent_c  :: type_id :: create("b_agent",  this);
   this.ar_agent = uvma_axi_ar_agent_c :: type_id :: create("ar_agent", this);
   this.r_agent  = uvma_axi_r_agent_c  :: type_id :: create("r_agent",  this);
   this.seq_item_logger = uvma_axi_seq_item_logger_c::type_id::create("seq_item_logger", this);
   if( cfg.is_active == UVM_ACTIVE) begin
      vsequencer = uvma_axi_vsqr_c::type_id::create("sequencer", this);
   end

endfunction : create_components
  • 代码介绍:使用 UVM 的工厂机制创建各个子代理对象和序列项记录器。若代理处于活动模式(cfg.is_active == UVM_ACTIVE),则创建虚拟序列器。
  • 逻辑分析:构建 AXI4 代理的各个组件。
4.10 connect_phase 函数
function void connect_phase(uvm_phase phase);

   if( cfg.is_active == UVM_ACTIVE) begin
      connect_mon_2_sqr();
      assemble_vsequencer();
   end else begin
      `uvm_info(get_type_name(), $sformatf("PASSIVE MODE"), UVM_LOW)
   end

   if (cfg.trn_log_enabled) begin
      connect_trn_loggers();
      `uvm_info(get_type_name(), $sformatf("Transaction Loger enable"), UVM_LOW)
   end

endfunction
  • 代码介绍:在 UVM 的 connect_phase 中,若代理处于活动模式,则调用 connect_mon_2_sqr 函数连接监视器和序列器,调用 assemble_vsequencer 函数组装虚拟序列器;若代理处于被动模式,则输出被动模式信息。若配置中启用了事务日志记录,则调用 connect_trn_loggers 函数连接事务记录器并输出日志启用信息。
  • 逻辑分析:在连接阶段完成组件之间的连接和配置。
4.11 connect_mon_2_sqr 函数
function void connect_mon_2_sqr();

   this.aw_agent.monitor.uvma_aw_mon2drv_port.connect(aw_agent.sequencer.aw_req_export);
   // 其他连接代码...

endfunction: connect_mon_2_sqr
  • 代码介绍:将各个通道的监视器端口连接到对应的序列器导出端口,实现监视器和序列器之间的数据传递。
  • 逻辑分析:确保监视器采集的数据能够传递给序列器,用于驱动激励。
4.12 assemble_vsequencer 函数
function void assemble_vsequencer();

   vsequencer.aw_sequencer  = aw_agent.sequencer;
   vsequencer.ar_sequencer  = ar_agent.sequencer;
   vsequencer.w_sequencer   = w_agent.sequencer;
   vsequencer.b_sequencer   = b_agent.sequencer;
   vsequencer.r_sequencer   = r_agent.sequencer;

endfunction: assemble_vsequencer
  • 代码介绍:将各个子代理的序列器赋值给虚拟序列器的对应成员,完成虚拟序列器的组装。
  • 逻辑分析:使虚拟序列器能够协调各个子序列器的工作。
4.13 connect_trn_loggers 函数
function void connect_trn_loggers();

   this.aw_agent.monitor.aw_mon2log_port.connect(seq_item_logger.analysis_export);
   // 其他连接代码...

endfunction : connect_trn_loggers
  • 代码介绍:将各个通道的监视器日志端口连接到序列项记录器的分析导出端口,实现事务信息的记录。
  • 逻辑分析:确保监视器采集的事务信息能够被记录器记录。

5. 总结

uvma_axi_agent.sv 文件定义的 uvma_axi_agent_c 类是 AXI4 协议验证环境中的关键组件。它通过 UVM 的各个阶段(build_phaseconnect_phase 等)完成了配置和上下文的管理、组件的创建以及组件之间的连接,构建了一个完整的 AXI4 验证代理。利用 UVM 配置数据库和分析端口实现了组件之间的信息传递和交互,同时支持活动模式和被动模式,并且可以根据配置启用事务日志记录。该代理类提高了 AXI4 协议验证环境的可维护性和可扩展性。

4. core-v-verif/lib/uvm_agents/uvma_axi/src/comps/uvma_axi_seq_item_logger.sv

// Copyright 2022 Thales DIS SAS
//
// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0
// You may obtain a copy of the License at https://solderpad.org/licenses/
//
// Original Author: Alae Eddine EZ ZEJJARI (alae-eddine.ez-zejjari@external.thalesgroup.com)


`ifndef __UVMA_AXI_SEQ_ITEM_LOGGER_SV__
`define __UVMA_AXI_SEQ_ITEM_LOGGER_SV__


/**
 * Component writing Open Bus Interface sequence items debug data to disk as plain text.
 */
class uvma_axi_seq_item_logger_c extends uvml_logs_seq_item_logger_c #(
   .T_TRN  (uvma_axi_base_seq_item_c),
   .T_CFG  (uvma_axi_cfg_c          ),
   .T_CNTXT(uvma_axi_cntxt_c        )
);

   `uvm_component_utils(uvma_axi_seq_item_logger_c)


   /**
    * Default constructor.
    */
   function new(string name="uvma_axi_seq_item_logger", uvm_component parent=null);
      super.new(name, parent);
   endfunction : new

   /**
    * Writes contents of t to disk.
    */
   virtual function void write(uvma_axi_base_seq_item_c t);
      if(cntxt.reset_state == UVMA_AXI_RESET_STATE_POST_RESET)begin

         string write_address_access = "";
         string aw_access_type  = "";
         string aw_address   = "";
         string aw_id_str     = "";

         string write_data_access = "";
         string w_data    = "";
         string w_access_complet = "";

         string write_response_access = "";
         string b_err    = "";
         string b_id_str     = "";

         string read_address_access = "";
         string ar_access_type  = "";
         string ar_address   = "";
         string ar_id_str     = "";

         string read_data_access = "";
         string r_err    = "";
         string r_data   = "";
         string r_id_str     = "";
         string r_access_complet = "";

         if(t.aw_valid && t.aw_ready) begin

            write_address_access = "write_address_access";
            if(t.aw_lock) begin
               aw_access_type = "Exclusive_access";
            end else begin
               aw_access_type = "Normal_access";
            end
            aw_address = $sformatf("%h", t.aw_addr);
            aw_id_str = $sformatf("%b", t.aw_id);
            fwrite($sformatf("----> %t | %s | %s | %s | %s", $realtime(), write_address_access, aw_address, aw_access_type, aw_id_str));

         end else begin

            write_address_access = "";
            aw_access_type  = "";
            aw_address   = "";
            aw_id_str     = "";

         end

         if(t.w_valid && t.w_ready) begin

            write_data_access = "write_data_access";
            w_data = $sformatf("%h", t.w_data);
            if(t.w_last) begin
               w_access_complet = "Yes";
            end else begin
               w_access_complet = "No";
            end
            fwrite($sformatf("----> %t | %s | %s | %s", $realtime(), write_data_access, w_data, w_access_complet));

         end else begin

            write_data_access = "";
            w_data  = "";
            w_access_complet   = "";

         end

         if(t.b_valid && t.b_ready) begin

            write_response_access = "write_response_access";
            case (t.b_resp)
               00 : b_err = "No Err";
               01 : b_err  = "Err";
               10 : b_err  = "Err";
               11 : b_err  = "Err";
               default : b_err = " ? ";
            endcase
            b_id_str = $sformatf("%b", t.b_id);
            fwrite($sformatf("----> %t | %s | __ | %s | __ | %s", $realtime(), write_response_access, b_id_str, b_err));

         end else begin

            write_response_access = "";
            b_err  = "";
            b_id_str     = "";

         end

         if(t.ar_valid && t.ar_ready) begin

            read_address_access = "read_address_access";
            if(t.ar_lock) begin
               ar_access_type = "Exclusive_access";
            end else begin
               ar_access_type = "Normal_access";
            end
            ar_address = $sformatf("%h", t.ar_addr);
            ar_id_str = $sformatf("%b", t.ar_id);
            fwrite($sformatf("----> %t | %s | %s | %s | %s", $realtime(), read_address_access, ar_address, ar_access_type, ar_id_str));

         end else begin

            read_address_access = "";
            ar_address  = "";
            ar_access_type  = "";
            ar_id_str     = "";

         end

         if(t.r_valid && t.r_ready) begin

            read_data_access = "read_data_access";
            r_data = $sformatf("%h", t.r_data);
            r_id_str = $sformatf("%b", t.r_id);
            if(t.r_last) begin
               r_access_complet = "Yes";
            end else begin
               r_access_complet = "No";
            end
            case (t.r_resp)
               00 : r_err = "No Err";
               01 : r_err  = "Err";
               10 : r_err  = "Err";
               11 : r_err  = "Err";
               default : r_err = " ? ";
            endcase
            fwrite($sformatf("----> %t | %s | %s | %s | %s | %s", $realtime(), read_data_access, r_data, r_access_complet, r_id_str, r_err));

         end else begin

            read_data_access = "";
            r_data  = "";
            r_access_complet   = "";
            r_err   = "";
            r_id_str     = "";

         end
      end
   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.
    */

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

      fwrite("-------------------------------------------------------------------------------------------");
      fwrite("        TIME        | AW/W/B/AR/R | ADDRESS : AW/AR | ACCESS TYPE : AW/AR | ID | ERR : B/R ");
      fwrite("        TIME        |   ACCESS    |  DATA   : W/R   | LAST DATA   : W/R   |    |           ");
      fwrite("-------------------------------------------------------------------------------------------");

   endfunction : print_header

endclass : uvma_axi_seq_item_logger_c

/**
 * Component writing Open Bus Interface monitor transactions debug data to disk as JavaScript Object Notation (JSON).
 */
class uvma_axi_seq_item_logger_json_c extends uvma_axi_seq_item_logger_c;

   `uvm_component_utils(uvma_axi_seq_item_logger_json_c)

   /**
    * Set file extension to '.json'.
    */
   function new(string name="uvma_axi_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_axi_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_axi_seq_item_logger_json_c


`endif // __UVMA_AXI_SEQ_ITEM_LOGGER_SV__

1. 简要介绍

uvma_axi_seq_item_logger.sv 文件定义了两个类,用于将 AXI 序列项的调试数据写入磁盘。uvma_axi_seq_item_logger_c 类将数据以纯文本形式写入,而 uvma_axi_seq_item_logger_json_c 类继承自前者,计划将数据以 JSON 格式写入。这两个类在 UVM 验证环境中帮助调试人员记录和分析 AXI 序列项的相关信息。

2. 接口介绍

这两个类主要通过 UVM 分析端口和文件操作函数与外部交互,以下是关键接口相关代码:

// 在 uvma_axi_seq_item_logger_c 类中
virtual function void write(uvma_axi_base_seq_item_c t);
virtual function void print_header();

// 在 uvma_axi_seq_item_logger_json_c 类中重写的方法
virtual function void write(uvma_axi_base_seq_item_c t);
virtual function void print_header();
  • write 函数:用于将 AXI 序列项 t 的内容写入磁盘。uvma_axi_seq_item_logger_c 类实现了以纯文本格式写入,uvma_axi_seq_item_logger_json_c 类计划实现以 JSON 格式写入。
  • print_header 函数:用于将日志头信息写入磁盘。uvma_axi_seq_item_logger_c 类会输出文本格式的表头,uvma_axi_seq_item_logger_json_c 类由于 JSON 文件不需要表头,该函数为空。

3. 参数介绍

文件中未显式定义参数,但类继承时使用了参数化的父类,并且类内有一些与日志记录相关的隐含信息:

class uvma_axi_seq_item_logger_c extends uvml_logs_seq_item_logger_c #(
   .T_TRN  (uvma_axi_base_seq_item_c),
   .T_CFG  (uvma_axi_cfg_c          ),
   .T_CNTXT(uvma_axi_cntxt_c        )
);
  • T_TRN:指定序列项的类型为 uvma_axi_base_seq_item_c,表示要记录的事务类型。
  • T_CFG:指定配置类的类型为 uvma_axi_cfg_c,可能包含日志记录的相关配置。
  • T_CNTXT:指定上下文类的类型为 uvma_axi_cntxt_c,可能包含与 AXI 环境相关的上下文信息。

4. 模块实现介绍

4.1 版权和许可证声明
// Copyright 2022 Thales DIS SAS
//
// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0
// You may obtain a copy of the License at https://solderpad.org/licenses/
//
// Original Author: Alae Eddine EZ ZEJJARI (alae-eddine.ez-zejjari@external.thalesgroup.com)
  • 代码介绍:声明文件的版权归属、使用的开源硬件许可证以及作者信息。
  • 逻辑分析:告知开发者文件的版权和使用限制,遵循开源协议规范。
4.2 条件编译
`ifndef __UVMA_AXI_SEQ_ITEM_LOGGER_SV__
`define __UVMA_AXI_SEQ_ITEM_LOGGER_SV__

// ... 中间代码 ...

`endif
  • 代码介绍:使用条件编译指令防止文件被重复包含。若 __UVMA_AXI_SEQ_ITEM_LOGGER_SV__ 宏未定义,则定义该宏并编译中间代码;若已定义,则跳过。
  • 逻辑分析:避免在编译过程中多次包含该文件,导致类重复定义的错误。
4.3 uvma_axi_seq_item_logger_c 类定义和注册
/**
 * Component writing Open Bus Interface sequence items debug data to disk as plain text.
 */
class uvma_axi_seq_item_logger_c extends uvml_logs_seq_item_logger_c #(
   .T_TRN  (uvma_axi_base_seq_item_c),
   .T_CFG  (uvma_axi_cfg_c          ),
   .T_CNTXT(uvma_axi_cntxt_c        )
);

   `uvm_component_utils(uvma_axi_seq_item_logger_c)
  • 代码介绍:定义 uvma_axi_seq_item_logger_c 类,继承自 uvml_logs_seq_item_logger_c 并进行参数化。类注释说明该类将 AXI 序列项的调试数据以纯文本形式写入磁盘。使用 uvm_component_utils 宏将该类注册到 UVM 组件工厂。
  • 逻辑分析:通过继承和参数化,复用父类的功能,注册到 UVM 工厂方便在 UVM 环境中动态创建。
4.4 uvma_axi_seq_item_logger_c 构造函数
/**
 * Default constructor.
 */
function new(string name="uvma_axi_seq_item_logger", uvm_component parent=null);
   super.new(name, parent);
endfunction : new
  • 代码介绍:定义默认构造函数,接受 nameparent 两个参数,默认名称为 "uvma_axi_seq_item_logger",默认父组件为 null。调用父类的构造函数完成初始化。
  • 逻辑分析:初始化 uvma_axi_seq_item_logger_c 类的对象。
4.5 uvma_axi_seq_item_logger_cwrite 函数
virtual function void write(uvma_axi_base_seq_item_c t);
   if(cntxt.reset_state == UVMA_AXI_RESET_STATE_POST_RESET)begin
      // 定义各种字符串变量用于存储不同通道的信息
      string write_address_access = "";
      string aw_access_type  = "";
      string aw_address   = "";
      string aw_id_str     = "";
      // ... 其他通道信息变量

      if(t.aw_valid && t.aw_ready) begin
         write_address_access = "write_address_access";
         if(t.aw_lock) begin
            aw_access_type = "Exclusive_access";
         end else begin
            aw_access_type = "Normal_access";
         end
         aw_address = $sformatf("%h", t.aw_addr);
         aw_id_str = $sformatf("%b", t.aw_id);
         fwrite($sformatf("----> %t | %s | %s | %s | %s", $realtime(), write_address_access, aw_address, aw_access_type, aw_id_str));
      end 
      // ... 其他通道的判断和写入逻辑

   end
endfunction : write
  • 代码介绍:该函数用于将 AXI 序列项 t 的内容写入磁盘。首先判断当前是否处于复位后状态,然后针对写地址、写数据、写响应、读地址和读数据等不同通道,根据通道的 validready 信号,提取相应信息并格式化为字符串,最后使用 fwrite 函数写入文件。
  • 逻辑分析:在复位后状态下,将 AXI 序列项各通道的有效信息以固定格式写入文件,方便调试人员查看。
4.6 uvma_axi_seq_item_logger_cprint_header 函数
virtual function void print_header();

   fwrite("-------------------------------------------------------------------------------------------");
   fwrite("        TIME        | AW/W/B/AR/R | ADDRESS : AW/AR | ACCESS TYPE : AW/AR | ID | ERR : B/R ");
   fwrite("        TIME        |   ACCESS    |  DATA   : W/R   | LAST DATA   : W/R   |    |           ");
   fwrite("-------------------------------------------------------------------------------------------");

endfunction : print_header
  • 代码介绍:该函数用于将日志的表头信息写入磁盘,输出多行字符串作为表头。
  • 逻辑分析:为日志文件添加表头,使调试人员能够清晰地了解每行数据的含义。
4.7 uvma_axi_seq_item_logger_json_c 类定义和注册
/**
 * Component writing Open Bus Interface monitor transactions debug data to disk as JavaScript Object Notation (JSON).
 */
class uvma_axi_seq_item_logger_json_c extends uvma_axi_seq_item_logger_c;

   `uvm_component_utils(uvma_axi_seq_item_logger_json_c)
  • 代码介绍:定义 uvma_axi_seq_item_logger_json_c 类,继承自 uvma_axi_seq_item_logger_c。类注释说明该类将 AXI 监视器事务的调试数据以 JSON 格式写入磁盘。使用 uvm_component_utils 宏将该类注册到 UVM 组件工厂。
  • 逻辑分析:通过继承,复用 uvma_axi_seq_item_logger_c 类的部分功能,同时扩展实现 JSON 格式的日志记录。
4.8 uvma_axi_seq_item_logger_json_c 构造函数
/**
 * Set file extension to '.json'.
 */
function new(string name="uvma_axi_seq_item_logger_json", uvm_component parent=null);

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

endfunction : new
  • 代码介绍:定义构造函数,接受 nameparent 两个参数,默认名称为 "uvma_axi_seq_item_logger_json",默认父组件为 null。调用父类的构造函数完成初始化,并将文件扩展名设置为 json
  • 逻辑分析:初始化 uvma_axi_seq_item_logger_json_c 类的对象,并指定日志文件的扩展名。
4.9 uvma_axi_seq_item_logger_json_cwrite 函数
/**
 * Writes contents of t to disk.
 */
virtual function void write(uvma_axi_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
  • 代码介绍:该函数计划将 AXI 序列项 t 的内容以 JSON 格式写入磁盘,但目前只是一个占位函数,有待实现。注释中给出了示例代码。
  • 逻辑分析:预留 JSON 格式日志记录的实现接口。
4.10 uvma_axi_seq_item_logger_json_cprint_header 函数
/**
 * Empty function.
 */
virtual function void print_header();

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

endfunction : print_header
  • 代码介绍:该函数为空,因为 JSON 文件不需要表头。
  • 逻辑分析:符合 JSON 文件的格式规范,避免写入不必要的表头信息。

5. 总结

uvma_axi_seq_item_logger.sv 文件实现了两个用于记录 AXI 序列项调试数据的类。uvma_axi_seq_item_logger_c 类将数据以纯文本形式写入磁盘,包含了详细的 AXI 各通道信息记录和表头输出功能;uvma_axi_seq_item_logger_json_c 类继承自前者,计划将数据以 JSON 格式写入,但目前 write 函数尚未实现。这两个类借助 UVM 的组件机制,方便在验证环境中使用,有助于调试人员对 AXI 序列项进行分析和调试。不过,uvma_axi_seq_item_logger_json_c 类的 write 函数需要进一步完善以实现 JSON 格式的日志记录。

资源下载链接为: https://pan.quark.cn/s/9a27693985af 《基于SSM的JSP招聘网》是一款功能丰富的在线招聘平台,主要面向普通游客、求职者、企业和管理员四种用户角色,提供了多样化的服务与管理功能。该系统采用SSM(Spring、SpringMVC、MyBatis)技术栈开发,确保了系统的稳定性与高效性。以下是对系统功能模块及其技术实现的介绍。 对于普通游客,系统提供职位浏览功能。游客可以查看平台上的各种招聘信息,如职位描述、工作职责、薪资待遇等。这需要后台数据库对招聘信息进行有效存储和检索。在SSM框架中,SpringMVC负责处理HTTP请求,将数据传递给Spring服务层进行业务逻辑处理,MyBatis作为持久层工具,执行SQL查询并将结果映射为Java对象。 求职者注册成为平台用户后,可进行职位收藏和投递。收藏的职位信息会保存在个人中心,方便随时查看。职位投递功能涉及用户个人信息与简历的提交,需要系统具备用户认证和授权机制,可通过Spring Security或Apache Shiro实现。此外,系统可能采用AJAX技术进行异步操作,如即时刷新收藏夹状态,以提升用户体验。 企业用户可在系统中发布职位、查看求职者简历。发布职位时,需进行表单验证和数据合法性检查,SpringMVC的控制器可协同前端校验库(如Hibernate Validator)完成。查看简历时,企业可对求职者进行筛选和评价,这要求数据库设计合理,以便快速查询和分析求职者信息。 管理员负责管理平台运行,包括用户管理、职位审核、系统设置等。管理员模块通常包含后台管理界面,通过SpringMVC的模型视图解析器和模板引擎(如Thymeleaf或FreeMarker)生成动态页面。同时,日志记录和异常处理必不可少,Spring框架提供了强大的日志和AOP支持,可方便实现这些功
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值