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_min
和drv_slv_random_latency_max
:驱动从设备随机延迟的最小值和最大值。drv_slv_err_ok
、drv_slv_err_dec
和drv_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_min
到drv_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_latency
和 random_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 接口的信号。mem
:uvml_mem_c
类型的对象,作为主动从设备的内存存储句柄,可用于存储和读取数据。reset_state
:uvma_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_agent
、w_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
- 代码介绍:定义构造函数,接受
name
和parent
两个参数,默认名称为"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_cfg
、get_and_set_cntxt
、retrieve_vif
和create_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
。若获取失败(cfg
为null
),则输出致命错误信息;若获取成功,则输出调试信息并将该配置对象设置到 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
。若获取失败(cntxt
为null
),则输出调试信息并创建新的上下文对象;最后将该上下文对象设置到 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_phase
、connect_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
- 代码介绍:定义默认构造函数,接受
name
和parent
两个参数,默认名称为"uvma_axi_seq_item_logger"
,默认父组件为null
。调用父类的构造函数完成初始化。 - 逻辑分析:初始化
uvma_axi_seq_item_logger_c
类的对象。
4.5 uvma_axi_seq_item_logger_c
的 write
函数
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
的内容写入磁盘。首先判断当前是否处于复位后状态,然后针对写地址、写数据、写响应、读地址和读数据等不同通道,根据通道的valid
和ready
信号,提取相应信息并格式化为字符串,最后使用fwrite
函数写入文件。 - 逻辑分析:在复位后状态下,将 AXI 序列项各通道的有效信息以固定格式写入文件,方便调试人员查看。
4.6 uvma_axi_seq_item_logger_c
的 print_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
- 代码介绍:定义构造函数,接受
name
和parent
两个参数,默认名称为"uvma_axi_seq_item_logger_json"
,默认父组件为null
。调用父类的构造函数完成初始化,并将文件扩展名设置为json
。 - 逻辑分析:初始化
uvma_axi_seq_item_logger_json_c
类的对象,并指定日志文件的扩展名。
4.9 uvma_axi_seq_item_logger_json_c
的 write
函数
/**
* 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_c
的 print_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 格式的日志记录。