UVM环境介绍
HEAD commitID: 1f968ef
1. core-v-verif/lib/uvm_agents/uvma_axi5/src/seq/uvma_axi_seq_lib.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) – sub-contractor MU-Electronics for Thales group
`ifndef __UVMA_AXI_SEQ_LIB_SV__
`define __UVMA_AXI_SEQ_LIB_SV__
`include "uvma_axi_base_seq.sv"
`include "uvma_axi_slv_seq.sv"
`include "uvma_axi_fw_preload_seq.sv"
`include "uvma_axi_vseq.sv"
/**
* Object holding sequence library for Open Bus Interface agent.
*/
class uvma_axi_seq_lib_c extends uvm_sequence_library;
`uvm_object_utils (uvma_axi_seq_lib_c)
`uvm_sequence_library_utils(uvma_axi_seq_lib_c)
/**
* Initializes sequence library
*/
extern function new(string name="uvma_axi_seq_lib");
endclass : uvma_axi_seq_lib_c
function uvma_axi_seq_lib_c::new(string name="uvma_axi_seq_lib");
super.new(name);
init_sequence_library();
endfunction : new
`endif // __UVMA_AXI_SEQ_LIB_SV__
1. 简要介绍
当前文件定义了一个 SystemVerilog 类 uvma_axi_seq_lib_c
,它继承自 uvm_sequence_library
。该类的主要作用是管理和组织与 AXI 代理相关的序列库,为 AXI 协议验证提供一系列可复用的序列。
2. 接口介绍
此文件定义的是类,并非硬件模块,所以没有传统意义上的输入输出接口。不过,作为 UVM 序列库类,它通过 UVM 框架与其他组件交互。主要通过 UVM 的注册机制和序列启动方法与序列器、环境等组件进行交互。
3. 参数介绍
该类没有显式定义的参数。不过,它继承了 uvm_sequence_library
的特性,在创建对象时可以传入一个字符串参数 name
,用于标识该序列库对象。默认值为 "uvma_axi_seq_lib"
。
extern function new(string name="uvma_axi_seq_lib");
name
:序列库对象的名称,方便在 UVM 调试和日志输出中识别该对象。
4. 模块实现介绍
4.1 条件编译保护
`ifndef __UVMA_AXI_SEQ_LIB_SV__
`define __UVMA_AXI_SEQ_LIB_SV__
- 代码介绍:使用
ifndef
和define
进行条件编译。如果__UVMA_AXI_SEQ_LIB_SV__
宏未定义,则定义该宏,后续代码会被编译;若已定义,则跳过后续代码。 - 逻辑分析:防止文件被重复包含,避免类的重复定义。
4.2 包含其他文件
`include "uvma_axi_base_seq.sv"
`include "uvma_axi_slv_seq.sv"
`include "uvma_axi_fw_preload_seq.sv"
`include "uvma_axi_vseq.sv"
- 代码介绍:使用
include
指令将其他与 AXI 序列相关的文件包含进来,使得这些文件中定义的类和类型可以在当前文件中使用。 - 逻辑分析:将不同功能的序列文件整合到当前文件中,方便统一管理和使用。
4.3 类定义与注册
class uvma_axi_seq_lib_c extends uvm_sequence_library;
`uvm_object_utils (uvma_axi_seq_lib_c)
`uvm_sequence_library_utils(uvma_axi_seq_lib_c)
- 代码介绍:
class uvma_axi_seq_lib_c extends uvm_sequence_library;
:定义uvma_axi_seq_lib_c
类,继承自uvm_sequence_library
,表明这是一个 UVM 序列库类。
- 逻辑分析:通过继承和注册,让
uvma_axi_seq_lib_c
类成为一个标准的 UVM 序列库类,可在 UVM 验证环境中使用。
4.4 构造函数声明与实现
// 声明
extern function new(string name="uvma_axi_seq_lib");
// 实现
function uvma_axi_seq_lib_c::new(string name="uvma_axi_seq_lib");
super.new(name);
init_sequence_library();
endfunction : new
- 代码介绍:
extern function new(string name="uvma_axi_seq_lib");
:在类定义中声明构造函数,extern
表示函数体在类外部实现。function uvma_axi_seq_lib_c::new(string name="uvma_axi_seq_lib");
:构造函数的实现部分。super.new(name);
:调用父类uvm_sequence_library
的构造函数,完成父类部分的初始化。init_sequence_library();
:调用init_sequence_library
方法初始化序列库,该方法应该是uvm_sequence_library
类提供的,用于初始化序列库中的序列列表。
- 逻辑分析:构造函数负责初始化序列库对象,先完成父类的初始化,再初始化序列库本身。
4.5 条件编译结束
`endif // __UVMA_AXI_SEQ_LIB_SV__
- 代码介绍:结束
ifndef
条件编译块。 - 逻辑分析:标志着条件编译部分的结束。
5. 总结
该文件定义了一个 UVM 序列库类 uvma_axi_seq_lib_c
,用于管理和组织 AXI 协议验证所需的序列。通过条件编译防止文件重复包含,使用 include
指令整合相关序列文件,借助 UVM 宏将类注册到对象工厂和序列库系统。构造函数完成对象的初始化工作。这个序列库类为 AXI 协议的验证提供了一个可复用的框架,方便验证人员在 UVM 环境中管理和使用各种 AXI 序列。
2. core-v-verif/lib/uvm_agents/uvma_axi5/src/seq/uvma_axi_slv_seq.sv
// Copyright 2023 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) – sub-contractor MU-Electronics for Thales group
//=============================================================================
// Description: Sequence for agent axi_ar
//=============================================================================
`ifndef UVMA_AXI_SLV_SEQ_SV
`define UVMA_AXI_SLV_SEQ_SV
/**
* Virtual sequence implementing the CVA6 memory iterface virtual peripheral.
*/
class uvma_axi_slv_seq_c extends uvma_axi_base_seq_c;
uvma_axi_synchronizer_c synchronizer;
int ar_seq_status = 0;
int aw_seq_status = 0;
int w_seq_status = 0;
int last_ar_ready_delay = 0;
int last_aw_ready_delay = 0;
int last_w_ready_delay = 0;
`uvm_object_utils_begin(uvma_axi_slv_seq_c)
`uvm_object_utils_end
extern function new(string name = "uvma_axi_slv_seq_c");
/**
* Assigns synchronizer handles from p_sequencer.
*/
extern virtual task pre_body();
/**
* TODO Describe uvma_axi_slv_base_seq_c::body()
*/
extern task body();
/**
* TODO Describe uvma_axi_slv_seq_c::do_response()
*/
extern virtual task do_response();
/**
* Convenience function to encapsulate the axi request in the synchronizer
*/
extern virtual task trs_registration(uvma_axi_transaction_c mon_req);
/**
* TODO Describe uvma_axi_slv_seq_c::do_mem_operation()
*/
extern virtual task do_mem_operation(uvma_axi_transaction_c mon_req);
/**
* Method to prepare the write response in the B channel
*/
extern virtual task prepare_w_resp();
/**
* Method to prepare the read response in the R channel
*/
extern virtual task prepare_r_resp();
/**
* Method to prepare the read response in the R channel
*/
extern virtual task prepare_ar_resp();
/**
* Method to prepare the read response in the R channel
*/
extern virtual task prepare_aw_resp();
/**
* Method to prepare the read response in the R channel
*/
extern virtual task prepare_wdata_resp();
endclass : uvma_axi_slv_seq_c
function uvma_axi_slv_seq_c::new(string name = "uvma_axi_slv_seq_c");
super.new(name);
endfunction : new
task uvma_axi_slv_seq_c::pre_body();
synchronizer = p_sequencer.synchronizer;
endtask : pre_body
task uvma_axi_slv_seq_c::body();
uvma_axi_transaction_c ar_mon_trn;
uvma_axi_transaction_c aw_mon_trn;
uvma_axi_transaction_c w_mon_trn;
uvma_axi_transaction_c mon_trn;
ar_mon_trn = uvma_axi_transaction_c::type_id::create("ar_mon_trn");
aw_mon_trn = uvma_axi_transaction_c::type_id::create("aw_mon_trn");
w_mon_trn = uvma_axi_transaction_c::type_id::create("w_mon_trn");
mon_trn = uvma_axi_transaction_c::type_id::create("mon_trn");
// Wait for the monitor to send us the mstr's "req" with an access request
fork
begin
forever begin
p_sequencer.ar_mon2seq_fifo_port.get(ar_mon_trn);
do_mem_operation(ar_mon_trn);
end
end
begin
forever begin
p_sequencer.aw_mon2seq_fifo_port.get(aw_mon_trn);
do_mem_operation(aw_mon_trn);
end
end
begin
forever begin
p_sequencer.w_mon2seq_fifo_port.get(w_mon_trn);
do_mem_operation(w_mon_trn);
end
end
begin
forever begin
p_sequencer.mon2seq_fifo_port.get(mon_trn);
do_response();
end
end
join_none
endtask : body
task uvma_axi_slv_seq_c::do_response();
if(cntxt.reset_state == UVMA_AXI_RESET_STATE_POST_RESET) begin
prepare_w_resp();
prepare_r_resp();
prepare_ar_resp();
prepare_aw_resp();
prepare_wdata_resp();
end else begin
synchronizer.w_trs_queue.delete();
synchronizer.r_trs_queue.delete();
synchronizer.w_trs_item_bp.delete();
synchronizer.w_trs_class.delete();
synchronizer.w_finished_trs_id.delete();
synchronizer.r_finished_trs_id.delete();
synchronizer.exclusive_r_access.delete();
synchronizer.exclusive_w_access.delete();
synchronizer.outstanding_read_call_times = 0;
synchronizer.outstanding_write_call_times = 0;
ar_seq_status = 0;
aw_seq_status = 0;
w_seq_status = 0;
last_ar_ready_delay = 0;
last_aw_ready_delay = 0;
last_w_ready_delay = 0;
end
endtask : do_response
task uvma_axi_slv_seq_c::do_mem_operation(uvma_axi_transaction_c mon_req);
if(cntxt.reset_state == UVMA_AXI_RESET_STATE_POST_RESET) begin
`uvm_info(get_type_name(), $sformatf("TRX TYPE = %s", mon_req.m_txn_type), UVM_HIGH)
trs_registration(mon_req);
end
endtask : do_mem_operation
task uvma_axi_slv_seq_c::trs_registration(uvma_axi_transaction_c mon_req);
if(mon_req.m_txn_type == UVMA_AXI_WRITE_ADD_REQ || mon_req.m_txn_type == UVMA_AXI_WRITE_DATA_REQ) begin
`uvm_info(get_type_name(), $sformatf("Write trx registration "), UVM_HIGH)
synchronizer.add_w_trs(mon_req);
end else if(mon_req.m_txn_type == UVMA_AXI_READ_REQ) begin
`uvm_info(get_type_name(), $sformatf("Read trx registration "), UVM_HIGH)
synchronizer.add_r_trs(mon_req);
end
endtask : trs_registration
task uvma_axi_slv_seq_c::prepare_w_resp();
uvma_axi_transaction_c w_slv_rsp;
int exc_resp = 0;
int w_selected_id;
w_selected_id = synchronizer.w_select_id(synchronizer.w_finished_trs_id);
if(w_selected_id != -1) begin
`uvm_create(w_slv_rsp)
w_slv_rsp = new synchronizer.w_trs_queue[w_selected_id][0];
`uvm_info(get_type_name(), $sformatf("Write Response Transaction is created"), UVM_HIGH)
exc_resp = synchronizer.check_exclusive_resp(w_selected_id);
if(exc_resp == 1) w_slv_rsp.m_resp.push_back(1) ;
else w_slv_rsp.m_resp.push_back(0);
w_slv_rsp.m_id = w_selected_id;
w_slv_rsp.m_user = 0;
w_slv_rsp.m_txn_type = UVMA_AXI_WRITE_RSP;
w_slv_rsp.set_config(cfg.txn_config) ;
if(!cfg.disable_trs_randomization) begin
w_slv_rsp.m_id.rand_mode(0);
w_slv_rsp.m_txn_type.rand_mode(0);
w_slv_rsp.m_axi_version.rand_mode(0);
w_slv_rsp.m_lite.rand_mode(0);
w_slv_rsp.m_err.rand_mode(0);
// w_slv_rsp.lower_byte_lane.rand_mode(0);
// w_slv_rsp.upper_byte_lane.rand_mode(0);
if(!cfg.resp_randomization_enabled) begin
w_slv_rsp.m_resp.rand_mode(0);
end
if(!cfg.user_randomization_enabled) begin
w_slv_rsp.m_user.rand_mode(0);
end
if(!cfg.rand_channel_delay_enabled) begin
w_slv_rsp.m_delay_cycle_chan_X.rand_mode(0);
w_slv_rsp.m_delay_cycle_chan_X = 0;
end
// Randomization of the transaction
w_slv_rsp.randomize();
end else begin
w_slv_rsp.m_delay_cycle_chan_X = 0;
end
`uvm_info(get_type_name(), $sformatf("FINICH WRITE TRANSACTION"), UVM_HIGH)
synchronizer.write_burst_complete(w_selected_id);
w_slv_rsp.set_sequencer(p_sequencer);
`uvm_send(w_slv_rsp)
end
endtask : prepare_w_resp
task uvma_axi_slv_seq_c::prepare_r_resp();
uvma_axi_transaction_c r_slv_rsp;
int r_selected_id = -1;
synchronizer.r_select_id(synchronizer.r_finished_trs_id, r_selected_id);
if(r_selected_id != -1) begin
`uvm_create(r_slv_rsp)
foreach(synchronizer.r_trs_queue[r_selected_id][i]) begin
if(synchronizer.r_trs_queue[r_selected_id][i].m_trs_status == WAITING_RESP) begin
r_slv_rsp = new synchronizer.r_trs_queue[r_selected_id][i];
break;
end
end
if(r_slv_rsp.m_last[0]) synchronizer.read_burst_complete(r_selected_id);
else synchronizer.read_data_complete(r_selected_id);
r_slv_rsp.set_config(cfg.txn_config) ;
r_slv_rsp.m_txn_type = UVMA_AXI_READ_RSP;
if(!cfg.disable_trs_randomization) begin
r_slv_rsp.m_id.rand_mode(0);
r_slv_rsp.m_txn_type.rand_mode(0);
r_slv_rsp.m_axi_version.rand_mode(0);
r_slv_rsp.m_lite.rand_mode(0);
r_slv_rsp.m_err.rand_mode(0);
// r_slv_rsp.lower_byte_lane.rand_mode(0);
// r_slv_rsp.upper_byte_lane.rand_mode(0);
if(!cfg.resp_randomization_enabled == 1) begin
r_slv_rsp.m_resp.rand_mode(0);
end
if(!cfg.user_randomization_enabled == 1) begin
r_slv_rsp.m_x_user.rand_mode(0);
end
if(!cfg.rand_channel_delay_enabled) begin
r_slv_rsp.m_delay_cycle_flits.rand_mode(0);
for(int i = 0; i <= r_slv_rsp.m_len; i++)
r_slv_rsp.m_delay_cycle_flits.push_back(0);
end
r_slv_rsp.m_last.rand_mode(0);
r_slv_rsp.m_data.rand_mode(0);
r_slv_rsp.c_last.constraint_mode(0);
// Randomization of the transaction
r_slv_rsp.randomize();
end else begin
for(int i = 0; i <= r_slv_rsp.m_len; i++)
r_slv_rsp.m_delay_cycle_flits.push_back(0);
end
r_slv_rsp.set_sequencer(p_sequencer);
`uvm_send(r_slv_rsp)
end
endtask : prepare_r_resp
task uvma_axi_slv_seq_c::prepare_ar_resp();
uvma_axi_transaction_c ar_slv_rsp;
`uvm_info(get_type_name(), $sformatf("ARREADY Transaction Response Started"), UVM_HIGH)
if(ar_seq_status == last_ar_ready_delay) begin
`uvm_create(ar_slv_rsp)
ar_seq_status = -1;
ar_slv_rsp.set_config(cfg.txn_config) ;
ar_slv_rsp.m_txn_type = UVMA_AXI_READ_REQ;
ar_slv_rsp.m_txn_type.rand_mode(0);
// Randomization of the transaction
if(cfg.rand_channel_delay_enabled) ar_slv_rsp.randomize();
else ar_slv_rsp.ready_delay_cycle_chan_ax = 0;
ar_slv_rsp.set_sequencer(p_sequencer);
last_ar_ready_delay = ar_slv_rsp.ready_delay_cycle_chan_ax;
`uvm_send(ar_slv_rsp)
end
ar_seq_status++;
endtask : prepare_ar_resp
task uvma_axi_slv_seq_c::prepare_aw_resp();
uvma_axi_transaction_c aw_slv_rsp;
`uvm_info(get_type_name(), $sformatf("AWREADY Transaction Response Started"), UVM_HIGH)
if(aw_seq_status == last_aw_ready_delay) begin
`uvm_create(aw_slv_rsp)
aw_seq_status = -1;
aw_slv_rsp.set_config(cfg.txn_config) ;
aw_slv_rsp.m_txn_type = UVMA_AXI_WRITE_ADD_REQ;
aw_slv_rsp.m_txn_type.rand_mode(0);
// Randomization of the transaction
if(cfg.rand_channel_delay_enabled) aw_slv_rsp.randomize();
else aw_slv_rsp.ready_delay_cycle_chan_ax = 0;
aw_slv_rsp.set_sequencer(p_sequencer);
last_aw_ready_delay = aw_slv_rsp.ready_delay_cycle_chan_ax;
`uvm_send(aw_slv_rsp)
end
aw_seq_status++;
endtask : prepare_aw_resp
task uvma_axi_slv_seq_c::prepare_wdata_resp();
uvma_axi_transaction_c wdata_slv_rsp;
`uvm_info</