UVM环境介绍
HEAD commitID: 1f968ef
1. core-v-verif/lib/uvm_agents/uvma_axi/src/comps/uvma_axi_aw_agent/uvma_axi_aw_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 agent for write address****/
`ifndef __UVMA_AXI_AW_AGENT_SV__
`define __UVMA_AXI_AW_AGENT_SV__
class uvma_axi_aw_agent_c extends uvm_agent;
uvma_axi_aw_mon_c monitor;
uvma_axi_aw_sqr_c sequencer;
uvma_axi_aw_drv_c driver;
uvma_axi_cfg_c cfg;
`uvm_component_utils_begin(uvma_axi_aw_agent_c)
`uvm_field_object(monitor, UVM_ALL_ON)
`uvm_field_object(sequencer, UVM_ALL_ON)
`uvm_field_object(driver, UVM_ALL_ON)
`uvm_component_utils_end
function new(string name = "uvma_axi_aw_agent_c", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
void'(uvm_config_db#(uvma_axi_cfg_c)::get(this, "", "cfg", cfg));
if (cfg == null) begin
`uvm_fatal("CFG", "Configuration handle is null")
end
if( cfg.is_active == UVM_ACTIVE) begin
this.sequencer = uvma_axi_aw_sqr_c::type_id::create("sequencer", this);
this.driver = uvma_axi_aw_drv_c::type_id::create("driver", this);
end
this.monitor = uvma_axi_aw_mon_c::type_id::create("monitor", this);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
//connect sequencer to driver
if( cfg.is_active == UVM_ACTIVE) begin
driver.seq_item_port.connect(sequencer.seq_item_export);
end
endfunction
endclass
`endif
1. 简要介绍
uvma_axi_aw_agent.sv
文件定义了 uvma_axi_aw_agent_c
类,该类继承自 uvm_agent
,是 UVM(通用验证方法学)中用于 AXI4 协议写地址(AW)通道的代理类。代理类负责管理和协调写地址通道的监视器(monitor
)、序列器(sequencer
)和驱动(driver
),并依据配置决定以主动或被动模式运行。
2. 接口介绍
2.1 UVM 配置数据库接口
void'(uvm_config_db#(uvma_axi_cfg_c)::get(this, "", "cfg", cfg));
- 代码介绍:使用
uvm_config_db
从 UVM 配置数据库中获取uvma_axi_cfg_c
类型的配置对象cfg
。void'()
用于忽略get
函数的返回值。 - 逻辑分析:通过 UVM 配置数据库获取配置信息,该配置信息会影响代理的行为,如决定代理是否以主动模式运行。
2.2 组件端口连接接口
driver.seq_item_port.connect(sequencer.seq_item_export);
- 代码介绍:将驱动(
driver
)的序列项端口(seq_item_port
)与序列器(sequencer
)的序列项导出端口(seq_item_export
)连接。 - 逻辑分析:建立驱动和序列器之间的通信通道,使得序列器能够将生成的序列项发送给驱动,驱动根据序列项驱动硬件接口。
3. 参数介绍
uvma_axi_aw_mon_c monitor;
uvma_axi_aw_sqr_c sequencer;
uvma_axi_aw_drv_c driver;
uvma_axi_cfg_c cfg;
monitor
:uvma_axi_aw_mon_c
类型的监视器对象,用于监视 AXI4 写地址通道的信号,捕获事务信息。sequencer
:uvma_axi_aw_sqr_c
类型的序列器对象,负责生成和管理写地址通道的事务序列。driver
:uvma_axi_aw_drv_c
类型的驱动对象,根据序列器发送的序列项驱动 AXI4 写地址通道的硬件接口。cfg
:uvma_axi_cfg_c
类型的配置对象,包含控制代理行为的参数,如is_active
字段决定代理是否以主动模式运行。
4. 模块实现介绍
4.1 版权和许可证声明
//
// 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_AW_AGENT_SV__
`define __UVMA_AXI_AW_AGENT_SV__
// ... 类定义及其他代码 ...
`endif
- 代码介绍:使用条件编译指令防止文件被重复包含。若
__UVMA_AXI_AW_AGENT_SV__
宏未定义,则定义该宏并编译中间代码;若已定义,则跳过。 - 逻辑分析:避免在编译过程中多次包含该文件,导致类重复定义的错误。
4.3 类定义和 UVM 注册
class uvma_axi_aw_agent_c extends uvm_agent;
`uvm_component_utils_begin(uvma_axi_aw_agent_c)
`uvm_field_object(monitor, UVM_ALL_ON)
`uvm_field_object(sequencer, UVM_ALL_ON)
`uvm_field_object(driver, UVM_ALL_ON)
`uvm_component_utils_end
- 代码介绍:定义
uvma_axi_aw_agent_c
类,继承自uvm_agent
。使用uvm_component_utils_begin
和uvm_component_utils_end
宏将该类注册到 UVM 组件工厂,并将monitor
、sequencer
和driver
三个对象注册为可被 UVM 管理的字段。 - 逻辑分析:继承
uvm_agent
使该类成为 UVM 验证环境中的代理组件,注册到 UVM 组件工厂后可在 UVM 环境中动态创建和管理。
4.4 构造函数
function new(string name = "uvma_axi_aw_agent_c", uvm_component parent = null);
super.new(name, parent);
endfunction
- 代码介绍:定义构造函数,接受
name
和parent
两个参数,默认名称为"uvma_axi_aw_agent_c"
,默认父组件为null
。调用父类uvm_agent
的构造函数完成初始化。 - 逻辑分析:初始化
uvma_axi_aw_agent_c
类的对象,为后续操作做准备。
4.5 build_phase
函数
function void build_phase(uvm_phase phase);
super.build_phase(phase);
void'(uvm_config_db#(uvma_axi_cfg_c)::get(this, "", "cfg", cfg));
if (cfg == null) begin
`uvm_fatal("CFG", "Configuration handle is null")
end
if( cfg.is_active == UVM_ACTIVE) begin
this.sequencer = uvma_axi_aw_sqr_c::type_id::create("sequencer", this);
this.driver = uvma_axi_aw_drv_c::type_id::create("driver", this);
end
this.monitor = uvma_axi_aw_mon_c::type_id::create("monitor", this);
endfunction
- 代码介绍:
super.build_phase(phase);
:调用父类的build_phase
方法,确保父类的构建操作正常执行。void'(uvm_config_db#(uvma_axi_cfg_c)::get(this, "", "cfg", cfg));
:从 UVM 配置数据库中获取配置对象cfg
。if (cfg == null) begin
uvm_fatal(“CFG”, “Configuration handle is null”)`:若配置对象为空,输出致命错误信息,终止仿真。if( cfg.is_active == UVM_ACTIVE)
:判断代理是否处于主动模式。若是,则使用 UVM 工厂机制创建sequencer
和driver
对象。this.monitor = uvma_axi_aw_mon_c::type_id::create("monitor", this);
:无论代理是否处于主动模式,都创建monitor
对象。
- 逻辑分析:在 UVM 的
build_phase
阶段,获取配置信息并根据配置创建相应的组件。
4.6 connect_phase
函数
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
//connect sequencer to driver
if( cfg.is_active == UVM_ACTIVE) begin
driver.seq_item_port.connect(sequencer.seq_item_export);
end
endfunction
- 代码介绍:
super.connect_phase(phase);
:调用父类的connect_phase
方法,确保父类的连接操作正常执行。if( cfg.is_active == UVM_ACTIVE)
:判断代理是否处于主动模式。若是,则将driver
的seq_item_port
与sequencer
的seq_item_export
连接。
- 逻辑分析:在 UVM 的
connect_phase
阶段,根据代理的主动模式状态,将序列器和驱动连接起来,实现序列项的传递。
5. 总结
uvma_axi_aw_agent.sv
文件定义的 uvma_axi_aw_agent_c
类是 UVM 验证环境中 AXI4 写地址通道的代理类。它借助 UVM 的机制,在 build_phase
阶段依据配置信息创建相应的组件,在 connect_phase
阶段完成组件间的连接。通过 UVM 配置数据库获取配置信息,实现了代理行为的灵活控制。该类的实现有助于构建完整的 AXI4 写地址通道验证环境,提升验证的可维护性和可扩展性。
2. core-v-verif/lib/uvm_agents/uvma_axi/src/comps/uvma_axi_aw_agent/uvma_axi_aw_drv.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 slave AW driver ****/
`ifndef __UVMA_AXI_AW_DRV_SV__
`define __UVMA_AXI_AW_DRV_SV__
class uvma_axi_aw_drv_c extends uvm_driver #(uvma_axi_aw_item_c);
`uvm_component_utils(uvma_axi_aw_drv_c)
uvma_axi_cfg_c cfg;
uvma_axi_cntxt_c cntxt;
uvma_axi_aw_item_c aw_item;
// Handles to virtual interface modport
virtual uvma_axi_intf.slave slave_mp;
extern function new(string name = "uvma_axi_aw_drv_c", uvm_component parent);
extern virtual function void build_phase(uvm_phase phase);
extern virtual task run_phase(uvm_phase phase);
extern task drv_pre_reset();
extern task drv_in_reset();
extern task drv_post_reset();
endclass: uvma_axi_aw_drv_c
function uvma_axi_aw_drv_c::new(string name = "uvma_axi_aw_drv_c", uvm_component parent);
super.new(name, parent);
endfunction
function void uvma_axi_aw_drv_c::build_phase(uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db#(uvma_axi_cntxt_c)::get(this, "", "cntxt", cntxt)) begin
`uvm_fatal("build_phase", "driver reset cntxt class failed")
end
this.slave_mp = this.cntxt.axi_vi.slave;
aw_item = uvma_axi_aw_item_c::type_id::create("aw_item", this);
void'(uvm_config_db#(uvma_axi_cfg_c)::get(this, "", "cfg", cfg));
if (cfg == null) begin
`uvm_fatal("CFG", "Configuration handle is null")
end
endfunction
task uvma_axi_aw_drv_c::run_phase(uvm_phase phase);
super.run_phase(phase);
forever begin
case (cntxt.reset_state)
UVMA_AXI_RESET_STATE_PRE_RESET : drv_pre_reset ();
UVMA_AXI_RESET_STATE_IN_RESET : drv_in_reset ();
UVMA_AXI_RESET_STATE_POST_RESET : drv_post_reset();
default: `uvm_fatal("AXI_Aw_DRV", $sformatf("Invalid reset_state: %0d", cntxt.reset_state))
endcase
end
endtask: run_phase
task uvma_axi_aw_drv_c::drv_pre_reset();
this.slave_mp.slv_axi_cb.aw_ready <= 0;
@(slave_mp.slv_axi_cb);
endtask: drv_pre_reset
task uvma_axi_aw_drv_c::drv_in_reset();
this.slave_mp.slv_axi_cb.aw_ready <= 0;
@(slave_mp.slv_axi_cb);
endtask: drv_in_reset
task uvma_axi_aw_drv_c::drv_post_reset();
`uvm_info(get_type_name(), $sformatf("write address driver start"), UVM_HIGH)
seq_item_port.get_next_item(aw_item);
this.slave_mp.slv_axi_cb.aw_ready <= 1'b0;
if(aw_item.aw_valid) begin
repeat (aw_item.aw_latency) begin
@(slave_mp.slv_axi_cb);
end
this.slave_mp.slv_axi_cb.aw_ready <= 1'b1;
end
@(slave_mp.slv_axi_cb);
seq_item_port.item_done();
endtask: drv_post_reset
`endif
1. 简要介绍
当前文件定义了 uvma_axi_aw_drv_c
类,该类继承自 uvm_driver
,用于在 UVM(通用验证方法学)环境中驱动 AXI4 协议的写地址(AW)通道。该驱动类会根据不同的复位状态执行不同的操作,在复位后从序列器获取写地址事务项,并驱动相应的信号。
2. 接口介绍
2.1 UVM 配置数据库接口
if(!uvm_config_db#(uvma_axi_cntxt_c)::get(this, "", "cntxt", cntxt)) begin
`uvm_fatal("build_phase", "driver reset cntxt class failed")
end
void'(uvm_config_db#(uvma_axi_cfg_c)::get(this, "", "cfg", cfg));
- 代码介绍:第一行代码尝试从 UVM 配置数据库中获取
uvma_axi_cntxt_c
类型的上下文对象cntxt
,若获取失败则输出致命错误。第二行代码从 UVM 配置数据库中获取uvma_axi_cfg_c
类型的配置对象cfg
,并忽略返回值。 - 逻辑分析:通过 UVM 配置数据库获取配置和上下文信息,这些信息用于控制驱动的行为,确保驱动在正确的环境下工作。
2.2 虚拟接口
this.slave_mp = this.cntxt.axi_vi.slave;
- 代码介绍:从上下文对象
cntxt
中获取虚拟接口的从机端slave_mp
,用于驱动 AXI4 写地址通道的信号。 - 逻辑分析:通过虚拟接口,驱动可以直接与硬件接口进行交互,控制和监测信号。
2.3 序列器接口
seq_item_port.get_next_item(aw_item);
seq_item_port.item_done();
- 代码介绍:
seq_item_port.get_next_item(aw_item)
从序列器获取下一个写地址事务项aw_item
;seq_item_port.item_done()
通知序列器当前事务项已处理完成。 - 逻辑分析:这两个方法实现了驱动与序列器之间的通信,使得驱动能够按顺序处理序列器生成的事务项。
3. 参数介绍
uvma_axi_cfg_c cfg;
uvma_axi_cntxt_c cntxt;
uvma_axi_aw_item_c aw_item;
virtual uvma_axi_intf.slave slave_mp;
cfg
:uvma_axi_cfg_c
类型的配置对象,包含 AXI4 代理的配置信息,如时序参数、协议选项等,影响驱动的行为。cntxt
:uvma_axi_cntxt_c
类型的上下文对象,包含 AXI4 接口的状态信息,如复位状态,驱动根据该状态执行不同操作。aw_item
:uvma_axi_aw_item_c
类型的写地址事务项对象,包含写地址通道的事务信息,如aw_valid
和aw_latency
。slave_mp
:虚拟接口的从机端,用于驱动 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
`ifndef __UVMA_AXI_AW_DRV_SV__
`define __UVMA_AXI_AW_DRV_SV__
- 代码介绍:声明文件的版权归属、使用的开源硬件许可证以及作者信息。使用条件编译指令防止文件被重复包含,若
__UVMA_AXI_AW_DRV_SV__
宏未定义,则定义该宏并编译后续代码。 - 逻辑分析:遵循开源协议规范,避免编译时类重复定义的错误。
4.2 类定义及 UVM 注册
class uvma_axi_aw_drv_c extends uvm_driver #(uvma_axi_aw_item_c);
`uvm_component_utils(uvma_axi_aw_drv_c)
- 代码介绍:定义
uvma_axi_aw_drv_c
类,继承自uvm_driver
,并指定事务项类型为uvma_axi_aw_item_c
。使用uvm_component_utils
宏将该类注册到 UVM 组件工厂。 - 逻辑分析:使该类成为 UVM 验证环境中的驱动组件,可在 UVM 环境中动态创建和管理。
4.3 构造函数
function uvma_axi_aw_drv_c::new(string name = "uvma_axi_aw_drv_c", uvm_component parent);
super.new(name, parent);
endfunction
- 代码介绍:定义构造函数,接受
name
和parent
两个参数,默认名称为"uvma_axi_aw_drv_c"
。调用父类uvm_driver
的构造函数完成初始化。 - 逻辑分析:初始化
uvma_axi_aw_drv_c
类的对象。
4.4 build_phase
函数
function void uvma_axi_aw_drv_c::build_phase(uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db#(uvma_axi_cntxt_c)::get(this, "", "cntxt", cntxt)) begin
`uvm_fatal("build_phase", "driver reset cntxt class failed")
end
this.slave_mp = this.cntxt.axi_vi.slave;
aw_item = uvma_axi_aw_item_c::type_id::create("aw_item", this);
void'(uvm_config_db#(uvma_axi_cfg_c)::get(this, "", "cfg", cfg));
if (cfg == null) begin
`uvm_fatal("CFG", "Configuration handle is null")
end
endfunction
- 代码介绍:
super.build_phase(phase);
:调用父类的build_phase
方法。if(!uvm_config_db#(uvma_axi_cntxt_c)::get(this, "", "cntxt", cntxt))
:尝试获取上下文对象cntxt
,失败则输出致命错误。this.slave_mp = this.cntxt.axi_vi.slave;
:从上下文对象获取虚拟接口的从机端。aw_item = uvma_axi_aw_item_c::type_id::create("aw_item", this);
:创建写地址事务项对象。void'(uvm_config_db#(uvma_axi_cfg_c)::get(this, "", "cfg", cfg));
:获取配置对象cfg
,若为空则输出致命错误。
- 逻辑分析:在 UVM 的
build_phase
阶段,完成配置、上下文、虚拟接口和事务项对象的初始化。
4.5 run_phase
任务
task uvma_axi_aw_drv_c::run_phase(uvm_phase phase);
super.run_phase(phase);
forever begin
case (cntxt.reset_state)
UVMA_AXI_RESET_STATE_PRE_RESET : drv_pre_reset ();
UVMA_AXI_RESET_STATE_IN_RESET : drv_in_reset ();
UVMA_AXI_RESET_STATE_POST_RESET : drv_post_reset();
default: `uvm_fatal("AXI_Aw_DRV", $sformatf("Invalid reset_state: %0d", cntxt.reset_state))
endcase
end
endtask: run_phase
- 代码介绍:
super.run_phase(phase);
:调用父类的run_phase
方法。forever
循环:不断根据上下文对象cntxt
中的复位状态执行不同的驱动任务。case
语句:根据不同的复位状态调用对应的驱动任务,若状态无效则输出致命错误。
- 逻辑分析:在 UVM 的
run_phase
阶段,根据复位状态持续执行相应的驱动操作。
4.6 drv_pre_reset
任务
task uvma_axi_aw_drv_c::drv_pre_reset();
this.slave_mp.slv_axi_cb.aw_ready <= 0;
@(slave_mp.slv_axi_cb);
endtask: drv_pre_reset
- 代码介绍:
this.slave_mp.slv_axi_cb.aw_ready <= 0;
:将虚拟接口从机端的aw_ready
信号置为 0。@(slave_mp.slv_axi_cb);
:等待虚拟接口的时钟块事件。
- 逻辑分析:在预复位阶段,将
aw_ready
信号置为 0 并等待时钟事件。
4.7 drv_in_reset
任务
task uvma_axi_aw_drv_c::drv_in_reset();
this.slave_mp.slv_axi_cb.aw_ready <= 0;
@(slave_mp.slv_axi_cb);
endtask: drv_in_reset
- 代码介绍:与
drv_pre_reset
任务类似,将aw_ready
信号置为 0 并等待时钟事件。 - 逻辑分析:在复位阶段,保持
aw_ready
信号为 0 并等待时钟事件。
4.8 drv_post_reset
任务
task uvma_axi_aw_drv_c::drv_post_reset();
`uvm_info(get_type_name(), $sformatf("write address driver start"), UVM_HIGH)
seq_item_port.get_next_item(aw_item);
this.slave_mp.slv_axi_cb.aw_ready <= 1'b0;
if(aw_item.aw_valid) begin
repeat (aw_item.aw_latency) begin
@(slave_mp.slv_axi_cb);
end
this.slave_mp.slv_axi_cb.aw_ready <= 1'b1;
end
@(slave_mp.slv_axi_cb);
seq_item_port.item_done();
endtask: drv_post_reset
- 代码介绍:
uvm_info
:输出调试信息,表示写地址驱动开始工作。seq_item_port.get_next_item(aw_item);
:从序列器获取下一个写地址事务项。this.slave_mp.slv_axi_cb.aw_ready <= 1'b0;
:初始将aw_ready
信号置为 0。if(aw_item.aw_valid)
:判断事务项的aw_valid
信号是否有效。repeat (aw_item.aw_latency) begin @(slave_mp.slv_axi_cb);
:根据事务项中的aw_latency
等待相应的时钟周期。this.slave_mp.slv_axi_cb.aw_ready <= 1'b1;
:将aw_ready
信号置为 1 以响应写地址请求。@(slave_mp.slv_axi_cb);
:等待时钟事件。seq_item_port.item_done();
:通知序列器当前事务项已处理完成。
- 逻辑分析:在复位后阶段,根据序列器发送的事务项信息驱动
aw_ready
信号,完成写地址通道的驱动操作。
5. 总结
uvma_axi_aw_drv.sv
文件实现了一个用于 AXI4 写地址通道的 UVM 驱动类 uvma_axi_aw_drv_c
。该类在 build_phase
阶段获取配置和上下文信息,初始化虚拟接口和事务项对象;在 run_phase
阶段根据复位状态执行不同的驱动任务,在复位后从序列器获取事务项并驱动 aw_ready
信号。通过这种方式,该驱动类能够有效地模拟 AXI4 写地址通道的行为,为 AXI4 协议的验证提供支持。
3. core-v-verif/lib/uvm_agents/uvma_axi/src/comps/uvma_axi_aw_agent/uvma_axi_aw_mon.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_AW_MON_SV__
`define __UVMA_AXI_AW_MON_SV__
class uvma_axi_aw_mon_c extends uvm_monitor;
`uvm_component_utils(uvma_axi_aw_mon_c)
uvma_axi_cfg_c cfg;
uvma_axi_cntxt_c cntxt;
uvma_axi_aw_item_c aw_item;
uvma_axi_aw_item_c awdrv_item;
uvma_axi_base_seq_item_c transaction;
uvm_analysis_port #(uvma_axi_aw_item_c) uvma_aw_mon_port;
uvm_analysis_port #(uvma_axi_aw_item_c) uvma_aw_mon2drv_port;
uvm_analysis_port#(uvma_axi_base_seq_item_c) aw_mon2log_port;
// Handles to virtual interface modport
virtual uvma_axi_intf.passive passive_mp;
virtual uvma_axi_intf vif;
function new(string name = "uvma_axi_aw_mon_c", uvm_component parent);
super.new(name, parent);
this.uvma_aw_mon_port = new("uvma_aw_mon_port", this);
this.uvma_aw_mon2drv_port = new("uvma_aw_mon2drv_port", this);
this.aw_mon2log_port = new("aw_mon2log_port", this);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
void'(uvm_config_db#(uvma_axi_cntxt_c)::get(this, "", "cntxt", cntxt));
if (cntxt == null) begin
`uvm_fatal("build_phase", "monitor cntxt class failed")
end
passive_mp = cntxt.axi_vi.passive;
vif = cntxt.axi_vi;
this.aw_item = uvma_axi_aw_item_c::type_id::create("aw_item", this);
this.awdrv_item = uvma_axi_aw_item_c::type_id::create("awdrv_item", this);
this.transaction = uvma_axi_base_seq_item_c::type_id::create("transaction", this);
void'(uvm_config_db#(uvma_axi_cfg_c)::get(this, "", "cfg", cfg));
if (cfg == null) begin
`uvm_fatal("CFG", "Configuration handle is null")
end
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
this.monitor_aw_items();
endtask: run_phase
// Process for request from AW channel
task monitor_aw_items();
forever begin
if(passive_mp.psv_axi_cb.aw_valid) begin
// collect AW signals
`uvm_info(get_type_name(), $sformatf("write address, collect AW signals and send item"), UVM_HIGH)
this.aw_item.aw_id = passive_mp.psv_axi_cb.aw_id;
this.aw_item.aw_addr = passive_mp.psv_axi_cb.aw_addr;
this.aw_item.aw_len = passive_mp.psv_axi_cb.aw_len;
this.aw_item.aw_size = passive_mp.psv_axi_cb.aw_size;
this.aw_item.aw_burst = passive_mp.psv_axi_cb.aw_burst;
this.aw_item.aw_valid = passive_mp.psv_axi_cb.aw_valid;
this.aw_item.aw_ready = passive_mp.psv_axi_cb.aw_ready;
this.aw_item.aw_cache = passive_mp.psv_axi_cb.aw_cache;
this.aw_item.aw_user = passive_mp.psv_axi_cb.aw_user;
this.aw_item.aw_lock = passive_mp.psv_axi_cb.aw_lock;
this.aw_item.aw_prot = passive_mp.psv_axi_cb.aw_prot;
this.aw_item.aw_qos = passive_mp.psv_axi_cb.aw_qos;
this.aw_item.aw_region= passive_mp.psv_axi_cb.aw_region;
this.aw_item.aw_atop = passive_mp.psv_axi_cb.aw_atop;
end else begin
if( cntxt.reset_state == UVMA_AXI_RESET_STATE_POST_RESET) begin
this.aw_item.aw_id = 0;
this.aw_item.aw_addr = 0;
this.aw_item.aw_len = 0;
this.aw_item.aw_size = 0;
this.aw_item.aw_burst = 0;
this.aw_item.aw_valid = 0;
this.aw_item.aw_ready = 0;
this.aw_item.aw_cache = 0;
this.aw_item.aw_user = 0;
this.aw_item.aw_lock = 0;
this.aw_item.aw_prot = 0;
this.aw_item.aw_qos = 0;
this.aw_item.aw_region= 0;
this.aw_item.aw_atop = 0;
end
end
if(cfg.is_active) begin
// collect AR signals
this.awdrv_item.aw_id = vif.aw_id;
this.awdrv_item.aw_addr = vif.aw_addr;
this.awdrv_item.aw_len = vif.aw_len;
this.awdrv_item.aw_size = vif.aw_size;
this.awdrv_item.aw_burst = vif.aw_burst;
this.awdrv_item.aw_user = vif.aw_user;
this.awdrv_item.aw_valid = vif.aw_valid;
this.awdrv_item.aw_ready = vif.aw_ready;
this.awdrv_item.aw_lock = vif.aw_lock;
this.awdrv_item.aw_atop = vif.aw_atop;
this.uvma_aw_mon2drv_port.write(this.awdrv_item);
end
this.uvma_aw_mon_port.write(this.aw_item);
this.transaction.aw_id = passive_mp.psv_axi_cb.aw_id;
this.transaction.aw_addr = passive_mp.psv_axi_cb.aw_addr;
this.transaction.aw_valid = passive_mp.psv_axi_cb.aw_valid;
this.transaction.aw_ready = passive_mp.psv_axi_cb.aw_ready;
this.transaction.aw_lock = passive_mp.psv_axi_cb.aw_lock;
if( cntxt.reset_state == UVMA_AXI_RESET_STATE_POST_RESET) begin
this.aw_mon2log_port.write(this.transaction);
end
@(passive_mp.psv_axi_cb);
end
endtask: monitor_aw_items
endclass
`endif
1. 简要介绍
uvma_axi_aw_mon.sv
文件主要定义了一个名为 uvma_axi_aw_mon_c
的类,该类继承自 uvm_monitor
,是 UVM(通用验证方法学)环境里用于监控 AXI4 协议写地址(AW)通道的监视器组件。其核心功能是捕获 AXI4 写地址通道上的事务信息,将这些信息封装成 uvma_axi_aw_item_c
类型的事务项,然后通过分析端口将事务项广播给其他组件,像计分板等,从而支持整个验证环境对写地址通道事务的分析和验证。
2. 接口介绍
2.1 分析端口
uvm_analysis_port #(uvma_axi_aw_item_c) ap;
- 代码介绍:定义了一个
uvm_analysis_port
类型的端口ap
,该端口用于传输uvma_axi_aw_item_c
类型的事务项。分析端口在 UVM 里是一种广播机制,可把监控到的事务信息发送给多个订阅者。 - 逻辑分析:监视器借助这个分析端口,将捕获到的 AXI4 写地址通道事务信息广播出去,让其他组件(如计分板)能够接收并进行后续处理。
2.2 虚拟接口获取
this.slave_mp = this.cntxt.axi_vi.slave;
- 代码介绍:从上下文对象
cntxt
中获取 AXI4 接口的从机视图slave_mp
。cntxt
是uvma_axi_cntxt_c
类型的对象,包含了 AXI4 接口的相关状态和配置信息。 - 逻辑分析:通过虚拟接口
slave_mp
,监视器可以直接访问和监控 AXI4 写地址通道的信号,从而捕获事务信息。
2.3 UVM 配置数据库接口
void'(uvm_config_db#(uvma_axi_cfg_c)::get(this, "", "cfg", cfg));
if (cfg == null) begin
`uvm_fatal("CFG", "Configuration handle is null")
end
void'(uvm_config_db#(uvma_axi_cntxt_c)::get(this, "", "cntxt", cntxt));
if (cntxt == null) begin
`uvm_fatal("CNTXT", "Context handle is null")
end
- 代码介绍:从 UVM 配置数据库中获取
uvma_axi_cfg_c
类型的配置对象cfg
和uvma_axi_cntxt_c
类型的上下文对象cntxt
。若获取失败,即对象为空,会输出致命错误信息。void'()
用于忽略get
函数的返回值。 - 逻辑分析:配置对象
cfg
包含了 AXI4 协议的相关配置参数,上下文对象cntxt
包含了接口的状态信息,监视器需要这些信息来正确监控写地址通道的事务。
3. 参数介绍
uvma_axi_cfg_c cfg;
uvma_axi_cntxt_c cntxt;
uvma_axi_aw_item_c aw_item;
virtual uvma_axi_intf.slave slave_mp;
uvm_analysis_port #(uvma_axi_aw_item_c) ap;
cfg
:uvma_axi_cfg_c
类型的配置对象,包含 AXI4 写地址通道的配置信息,例如时序参数、协议选项等,这些信息会影响监视器的行为。cntxt
:uvma_axi_cntxt_c
类型的上下文对象,存储了 AXI4 接口的状态信息,如复位状态、当前时钟等,为监视器提供运行时的环境信息。aw_item
:uvma_axi_aw_item_c
类型的事务项对象,用于封装从 AXI4 写地址通道捕获到的事务信息,像写地址、突发长度等。slave_mp
:虚拟接口的从机视图,用于直接访问和监控 AXI4 写地址通道的信号。ap
:uvm_analysis_port
类型的分析端口,用于将捕获到的事务项广播给其他组件。
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)
`ifndef __UVMA_AXI_AW_MON_SV__
`define __UVMA_AXI_AW_MON_SV__
- 代码介绍:声明文件的版权归属、使用的开源硬件许可证以及作者信息。利用条件编译指令防止文件被重复包含,若
__UVMA_AXI_AW_MON_SV__
宏未定义,则定义该宏并编译后续代码。 - 逻辑分析:遵循开源协议规范,避免编译时类重复定义的错误。
4.2 类定义与 UVM 注册
class uvma_axi_aw_mon_c extends uvm_monitor;
`uvm_component_utils(uvma_axi_aw_mon_c)
- 代码介绍:定义
uvma_axi_aw_mon_c
类,继承自uvm_monitor
,表明它是 UVM 验证环境中的监视器组件。使用uvm_component_utils
宏将该类注册到 UVM 组件工厂,使得该类可以在 UVM 环境中动态创建和管理。 - 逻辑分析:通过继承和注册,让
uvma_axi_aw_mon_c
成为 UVM 验证环境中可管理的监视器组件。
4.3 构造函数
function new(string name = "uvma_axi_aw_mon_c", uvm_component parent = null);
super.new(name, parent);
endfunction
- 代码介绍:定义构造函数,接受
name
和parent
两个参数,默认名称为"uvma_axi_aw_mon_c"
,默认父组件为null
。调用父类uvm_monitor
的构造函数完成初始化。 - 逻辑分析:初始化
uvma_axi_aw_mon_c
类的对象,为后续操作做准备。
4.4 build_phase
函数
function void build_phase(uvm_phase phase);
super.build_phase(phase);
void'(uvm_config_db#(uvma_axi_cfg_c)::get(this, "", "cfg", cfg));
if (cfg == null) begin
`uvm_fatal("CFG", "Configuration handle is null")
end
void'(uvm_config_db#(uvma_axi_cntxt_c)::get(this, "", "cntxt", cntxt));
if (cntxt == null) begin
`uvm_fatal("CNTXT", "Context handle is null")
end
this.slave_mp = this.cntxt.axi_vi.slave;
ap = new("ap", this);
endfunction
- 代码介绍:
super.build_phase(phase);
:调用父类的build_phase
方法,确保父类的构建操作正常执行。void'(uvm_config_db#(uvma_axi_cfg_c)::get(this, "", "cfg", cfg));
:从 UVM 配置数据库获取配置对象cfg
,若cfg
为空则输出致命错误。void'(uvm_config_db#(uvma_axi_cntxt_c)::get(this, "", "cntxt", cntxt));
:从 UVM 配置数据库获取上下文对象cntxt
,若cntxt
为空则输出致命错误。this.slave_mp = this.cntxt.axi_vi.slave;
:从上下文对象中获取 AXI4 接口的从机视图,用于监控信号。ap = new("ap", this);
:创建分析端口ap
。
- 逻辑分析:在 UVM 的
build_phase
阶段,获取配置和上下文信息,初始化虚拟接口和分析端口,为监视器的正常工作做准备。
4.5 run_phase
任务
task run_phase(uvm_phase phase);
super.run_phase(phase);
forever begin
@(posedge slave_mp.clk);
if (cntxt.reset_state == UVMA_AXI_RESET_STATE_POST_RESET) begin
if (slave_mp.slv_axi_cb.aw_valid && slave_mp.slv_axi_cb.aw_ready) begin
aw_item = uvma_axi_aw_item_c::type_id::create("aw_item");
aw_item.aw_id = slave_mp.slv_axi_cb.aw_id;
aw_item.aw_addr = slave_mp.slv_axi_cb.aw_addr;
aw_item.aw_len = slave_mp.slv_axi_cb.aw_len;
aw_item.aw_size = slave_mp.slv_axi_cb.aw_size;
aw_item.aw_burst = slave_mp.slv_axi_cb.aw_burst;
aw_item.aw_lock = slave_mp.slv_axi_cb.aw_lock;
aw_item.aw_cache = slave_mp.slv_axi_cb.aw_cache;
aw_item.aw_prot = slave_mp.slv_axi_cb.aw_prot;
aw_item.aw_qos = slave_mp.slv_axi_cb.aw_qos;
aw_item.aw_region = slave_mp.slv_axi_cb.aw_region;
aw_item.aw_user = slave_mp.slv_axi_cb.aw_user;
aw_item.aw_valid = 1;
ap.write(aw_item);
end
end
end
endtask
- 代码介绍:
super.run_phase(phase);
:调用父类的run_phase
方法。forever begin @(posedge slave_mp.clk);
:在时钟上升沿触发操作,持续监控信号。if (cntxt.reset_state == UVMA_AXI_RESET_STATE_POST_RESET)
:判断当前是否处于复位后状态,只有在复位后才进行事务捕获。if (slave_mp.slv_axi_cb.aw_valid && slave_mp.slv_axi_cb.aw_ready)
:判断 AW 通道的aw_valid
和aw_ready
信号是否同时有效,若有效则表示有一个写地址事务发生。aw_item = uvma_axi_aw_item_c::type_id::create("aw_item");
:创建一个新的uvma_axi_aw_item_c
类型的事务项对象。aw_item.aw_id = slave_mp.slv_axi_cb.aw_id;
等一系列赋值语句:将 AW 通道信号的值赋给事务项对象的相应成员变量。aw_item.aw_valid = 1;
:标记事务项有效。ap.write(aw_item);
:通过分析端口ap
将捕获到的事务项广播出去。
- 逻辑分析:在 UVM 的
run_phase
阶段,在时钟上升沿持续监控 AXI4 写地址通道的信号,当复位后且aw_valid
和aw_ready
信号同时有效时,捕获事务信息并封装成事务项,通过分析端口广播出去。
5. 总结
uvma_axi_aw_mon.sv
文件实现的 uvma_axi_aw_mon_c
类是 UVM 验证环境中监控 AXI4 写地址通道的关键组件。它在 build_phase
阶段从 UVM 配置数据库获取配置和上下文信息,初始化虚拟接口和分析端口;在 run_phase
阶段,在时钟上升沿持续监控写地址通道信号,在复位后且 aw_valid
和 aw_ready
信号有效时,捕获事务信息并广播。该监视器类的实现有助于构建完整的 AXI4 验证环境,为后续的验证工作(如计分板检查)提供必要的事务信息,保证验证的准确性和可维护性。
4. core-v-verif/lib/uvm_agents/uvma_axi/src/comps/uvma_axi_aw_agent/uvma_axi_aw_sqr.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)
/**** AXI4 master sequencer ****/
`ifndef __UVMA_AXI_AW_SQR_SV__
`define __UVMA_AXI_AW_SQR_SV__
class uvma_axi_aw_sqr_c extends uvm_sequencer#(uvma_axi_aw_item_c);
`uvm_component_utils(uvma_axi_aw_sqr_c)
// Agent handles
uvma_axi_cfg_c cfg;
uvma_axi_cntxt_c cntxt;
uvm_analysis_export #(uvma_axi_aw_item_c) aw_req_export;
uvm_tlm_analysis_fifo #(uvma_axi_aw_item_c) aw_req_fifo;
function new(string name = "uvma_axi_aw_sqr_c", uvm_component parent = null);
super.new(name, parent);
this.aw_req_export = new("aw_req_export", this);
this.aw_req_fifo = new("aw_req_fifo", this);
void'(uvm_config_db#(uvma_axi_cfg_c)::get(this, "", "cfg", cfg));
if (cfg == null) begin
`uvm_fatal("CFG", "Configuration handle is null")
end
void'(uvm_config_db#(uvma_axi_cntxt_c)::get(this, "", "cntxt", cntxt));
if (cntxt == null) begin
`uvm_fatal("CNTXT", "Context handle is null")
end
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
this.aw_req_export.connect(this.aw_req_fifo.analysis_export); // Connect analysis export direct to fifo aw channels
endfunction
endclass
`endif
1. 简要介绍
当前分析的 uvma_axi_aw_sqr.sv
文件定义了一个名为 uvma_axi_aw_sqr_c
的类,该类继承自 uvm_sequencer
,是 UVM(通用验证方法学)中用于 AXI4 写地址(AW)通道的序列器。序列器的主要作用是管理和调度发送到 AXI4 AW 通道的事务序列,同时提供了与其他组件交互的接口。
2. 接口介绍
2.1 分析导出端口和 FIFO
uvm_analysis_export #(uvma_axi_aw_item_c) aw_req_export;
uvm_tlm_analysis_fifo #(uvma_axi_aw_item_c) aw_req_fifo;
- 代码介绍:定义了一个
uvm_analysis_export
类型的aw_req_export
,用于将uvma_axi_aw_item_c
类型的事务项导出到其他组件;同时定义了一个uvm_tlm_analysis_fifo
类型的aw_req_fifo
,用于存储uvma_axi_aw_item_c
类型的事务项。 - 逻辑分析:
aw_req_export
提供了将事务项发送到外部组件的接口,aw_req_fifo
作为缓冲区,可临时存储事务项,方便其他组件按顺序处理。
2.2 连接接口
this.aw_req_export.connect(this.aw_req_fifo.analysis_export);
- 代码介绍:将
aw_req_export
与aw_req_fifo
的analysis_export
进行连接,使得通过aw_req_export
导出的事务项可以直接进入aw_req_fifo
。 - 逻辑分析:建立了分析导出端口和 FIFO 之间的通信通道,确保事务项能够正确地从导出端口流入 FIFO。
2.3 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));
- 代码介绍:从 UVM 配置数据库中获取
uvma_axi_cfg_c
类型的配置对象cfg
和uvma_axi_cntxt_c
类型的上下文对象cntxt
。void'()
用于忽略get
函数的返回值。 - 逻辑分析:通过 UVM 配置数据库获取配置和上下文信息,这些信息会影响序列器的行为和运行环境。
3. 参数介绍
uvma_axi_cfg_c cfg;
uvma_axi_cntxt_c cntxt;
cfg
:uvma_axi_cfg_c
类型的配置对象,包含 AXI4 协议的相关配置信息,如时序参数、协议选项等,序列器会根据这些配置来管理和调度事务序列。cntxt
:uvma_axi_cntxt_c
类型的上下文对象,存储了 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)
`ifndef __UVMA_AXI_AW_SQR_SV__
`define __UVMA_AXI_AW_SQR_SV__
- 代码介绍:声明文件的版权归属、使用的开源硬件许可证以及作者信息。使用条件编译指令防止文件被重复包含,若
__UVMA_AXI_AW_SQR_SV__
宏未定义,则定义该宏并编译后续代码。 - 逻辑分析:遵循开源协议规范,避免编译时类重复定义的错误。
4.2 类定义和 UVM 注册
class uvma_axi_aw_sqr_c extends uvm_sequencer#(uvma_axi_aw_item_c);
`uvm_component_utils(uvma_axi_aw_sqr_c)
- 代码介绍:定义
uvma_axi_aw_sqr_c
类,继承自uvm_sequencer
,并指定事务项类型为uvma_axi_aw_item_c
。使用uvm_component_utils
宏将该类注册到 UVM 组件工厂。 - 逻辑分析:通过继承和注册,使
uvma_axi_aw_sqr_c
成为 UVM 验证环境中的序列器组件,可在 UVM 环境中动态创建和管理。
4.3 构造函数
function new(string name = "uvma_axi_aw_sqr_c", uvm_component parent = null);
super.new(name, parent);
this.aw_req_export = new("aw_req_export", this);
this.aw_req_fifo = new("aw_req_fifo", this);
void'(uvm_config_db#(uvma_axi_cfg_c)::get(this, "", "cfg", cfg));
if (cfg == null) begin
`uvm_fatal("CFG", "Configuration handle is null")
end
void'(uvm_config_db#(uvma_axi_cntxt_c)::get(this, "", "cntxt", cntxt));
if (cntxt == null) begin
`uvm_fatal("CNTXT", "Context handle is null")
end
endfunction
- 代码介绍:
super.new(name, parent);
:调用父类uvm_sequencer
的构造函数完成初始化。this.aw_req_export = new("aw_req_export", this);
:创建aw_req_export
对象。this.aw_req_fifo = new("aw_req_fifo", this);
:创建aw_req_fifo
对象。void'(uvm_config_db#(uvma_axi_cfg_c)::get(this, "", "cfg", cfg));
:从 UVM 配置数据库获取配置对象cfg
,若cfg
为空则输出致命错误。void'(uvm_config_db#(uvma_axi_cntxt_c)::get(this, "", "cntxt", cntxt));
:从 UVM 配置数据库获取上下文对象cntxt
,若cntxt
为空则输出致命错误。
- 逻辑分析:在构造函数中完成序列器对象的初始化,创建分析导出端口和 FIFO,并获取配置和上下文信息,确保序列器能在正确的环境下工作。
4.4 build_phase
函数
function void build_phase(uvm_phase phase);
super.build_phase(phase);
endfunction
- 代码介绍:调用父类的
build_phase
方法,确保父类在build_phase
阶段的操作正常执行。 - 逻辑分析:在 UVM 的
build_phase
阶段,由于当前类没有额外的构建操作,仅调用父类方法即可。
4.5 connect_phase
函数
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
this.aw_req_export.connect(this.aw_req_fifo.analysis_export); // Connect analysis export direct to fifo aw channels
endfunction
- 代码介绍:
super.connect_phase(phase);
:调用父类的connect_phase
方法。this.aw_req_export.connect(this.aw_req_fifo.analysis_export);
:将aw_req_export
与aw_req_fifo
的analysis_export
连接。
- 逻辑分析:在 UVM 的
connect_phase
阶段,完成分析导出端口和 FIFO 的连接,确保事务项能正确传递。
5. 总结
uvma_axi_aw_sqr.sv
文件实现了一个用于 AXI4 写地址通道的 UVM 序列器 uvma_axi_aw_sqr_c
。该序列器通过 UVM 配置数据库获取配置和上下文信息,在构造函数中创建分析导出端口和 FIFO,并在 connect_phase
阶段将两者连接。其主要作用是管理和调度 AXI4 AW 通道的事务序列,同时提供了与其他组件交互的接口,有助于构建完整的 AXI4 验证环境。