UVM环境介绍
HEAD commitID: 1f968ef
lib/uvm_agents/uvma_obi_memory/src/comps
//
// Copyright 2021 OpenHW Group
// Copyright 2021 Datum Technology Corporation
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
//
// Licensed under the Solderpad Hardware License v 2.1 (the "License"); you may
// not use this file except in compliance with the License, or, at your option,
// the Apache License version 2.0. You may obtain a copy of the License at
//
// https://solderpad.org/licenses/SHL-2.1/
//
// Unless required by applicable law or agreed to in writing, any work
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
//
`ifndef __UVMA_OBI_MEMORY_MON_TRN_LOGGER_SV__
`define __UVMA_OBI_MEMORY_MON_TRN_LOGGER_SV__
/**
* Component writing Open Bus Interface monitor transactions debug data to disk as plain text.
*/
class uvma_obi_memory_mon_trn_logger_c extends uvml_logs_mon_trn_logger_c#(
.T_TRN (uvma_obi_memory_mon_trn_c),
.T_CFG (uvma_obi_memory_cfg_c ),
.T_CNTXT(uvma_obi_memory_cntxt_c )
);
`uvm_component_utils(uvma_obi_memory_mon_trn_logger_c)
/**
* Default constructor.
*/
function new(string name="uvma_obi_memory_mon_trn_logger", uvm_component parent=null);
super.new(name, parent);
endfunction : new
/**
* Writes contents of t to disk
*/
virtual function void write(uvma_obi_memory_mon_trn_c t);
string format_header_str_1p1 = "%15s | %6s | %2s | %8s | %4s | %8s";
string format_header_str_1p2 = "%15s | %6s | %2s | %8s | %4s | %8s | %2s | %2s | %2s | %2s | %2s | %2s | %2s";
string log_msg;
// Log the 1p1 signals
log_msg = $sformatf("%15s | %6s | %2s | %08x | %1x | %8s",
$sformatf("%t", $time),
cfg.mon_logger_name,
t.access_type == UVMA_OBI_MEMORY_ACCESS_READ ? "R" : "W",
t.address,
t.be,
t.get_data_str());
if (cfg.version == UVMA_OBI_MEMORY_VERSION_1P2) begin
log_msg = $sformatf("%s | %2x | %1x | %2x | %3s",
log_msg,
t.aid,
t.prot,
t.atop,
t.err ? "ERR" : "OK");
if (cfg.auser_width > 0)
log_msg = $sformatf("%s | %1x", log_msg, t.auser);
if (cfg.wuser_width > 0)
log_msg = $sformatf("%s | %1x", log_msg, t.wuser);
if (cfg.ruser_width > 0)
log_msg = $sformatf("%s | %1x", log_msg, t.ruser);
end
fwrite(log_msg);
endfunction : write
/**
* Writes log header to disk
*/
virtual function void print_header();
if (cfg.version == UVMA_OBI_MEMORY_VERSION_1P1) begin
string banner_str = {80{"-"}};
string format_header_str_1p1 = "%15s | %6s | %2s | %8s | %2s | %8s";
fwrite(banner_str);
fwrite($sformatf(format_header_str_1p1,
"TIME", "OBI", "RW", "ADDR", "BE", "DATA"));
fwrite(banner_str);
end
else begin
string banner_str = {106{"-"}};
string format_header_str_1p2 = "%15s | %6s | %2s | %8s | %2s | %8s | %2s | %2s | %2s | %2s";
string header_str;
header_str = $sformatf(format_header_str_1p2,
"TIME", "OBI", "RW", "ADDR", "BE", "DATA",
"ID", "PROT", "ATOP", "ERR");
if (cfg.auser_width > 0)
header_str = $sformatf("%s | %2s", header_str, "AUSER");
if (cfg.ruser_width > 0)
header_str = $sformatf("%s | %2s", header_str, "RUSER");
if (cfg.wuser_width > 0)
header_str = $sformatf("%s | %2s", header_str, "WUSER");
fwrite(banner_str);
fwrite(header_str);
fwrite(banner_str);
end
endfunction : print_header
endclass : uvma_obi_memory_mon_trn_logger_c
/**
* Component writing OBI monitor transactions debug data to disk as JavaScript Object Notation (JSON).
*/
class uvma_obi_memory_mon_trn_logger_json_c extends uvma_obi_memory_mon_trn_logger_c;
`uvm_component_utils(uvma_obi_memory_mon_trn_logger_json_c)
/**
* Set file extension to '.json'.
*/
function new(string name="uvma_obi_memory_mon_trn_logger_json", uvm_component parent=null);
super.new(name, parent);
fextension = "json";
endfunction : new
/**
* Writes contents of t to disk.
*/
virtual function void write(uvma_obi_memory_mon_trn_c t);
// TODO Implement uvma_obi_memory_mon_trn_logger_json_c::write()
// Ex: fwrite({"{",
// $sformatf("\"time\":\"%0t\",", $realtime()),
// $sformatf("\"a\":%h," , t.a ),
// $sformatf("\"b\":%b," , t.b ),
// $sformatf("\"c\":%d," , t.c ),
// $sformatf("\"d\":%h," , t.c ),
// "},"});
endfunction : write
/**
* Empty function.
*/
virtual function void print_header();
// Do nothing: JSON files do not use headers.
endfunction : print_header
endclass : uvma_obi_memory_mon_trn_logger_json_c
`endif // __UVMA_OBI_MEMORY_MON_TRN_LOGGER_SV__
uvma_obi_memory_mon_trn_logger.sv
1. 简要介绍
该文件是OBI内存监控事务日志记录组件,主要功能包括:
- 将监控事务数据写入磁盘
- 支持文本和JSON两种格式
- 根据协议版本动态调整输出格式
- 作为验证环境的调试辅助组件
2. 接口介绍
2.1 类定义
class uvma_obi_memory_mon_trn_logger_c extends uvml_logs_mon_trn_logger_c#(
.T_TRN(uvma_obi_memory_mon_trn_c),
.T_CFG(uvma_obi_memory_cfg_c)
);
- 代码介绍:定义OBI监控事务日志记录类
- 继承关系:继承自参数化基础日志记录类
- 特点:支持协议特定字段记录
3. 参数介绍
3.1 日志格式定义
string format_header_str_1p1 = "%15s | %6s | %2s | %8s | %4s | %8s";
string format_header_str_1p2 = "%15s | %6s | %2s | %8s | %4s | %8s | %2s | %2s | %2s | %2s";
- 参数说明:
- 1p1格式:基础协议字段
- 1p2格式:扩展协议字段
4. 模块实现介绍
4.1 写入函数
function void write(uvma_obi_memory_mon_trn_c t);
log_msg = $sformatf("%15s | %6s | %2s | %08x | %1x | %8s",
$sformatf("%t", $time),
cfg.mon_logger_name,
t.access_type == UVMA_OBI_MEMORY_ACCESS_READ ? "R" : "W",
t.address,
t.be,
t.get_data_str());
endfunction
- 代码分析:
- 格式化时间戳
- 记录操作类型(R/W)
- 输出地址和数据
- 根据协议版本扩展字段
4.2 JSON日志类
class uvma_obi_memory_mon_trn_logger_json_c extends uvma_obi_memory_mon_trn_logger_c;
function new();
fextension = "json";
endfunction
endclass
- 代码分析:
- 继承基础日志类
- 设置文件扩展名为json
- 预留JSON格式实现
5. 总结
该OBI监控事务日志记录组件具有以下特点:
- 灵活的多格式支持
- 协议版本自适应
- 清晰的输出格式
- 可扩展的JSON实现
作为验证环境的调试辅助工具,它为OBI接口的调试和分析提供了直观的事务记录能力,确保能够方便地追踪接口行为。
//
// Copyright 2021 OpenHW Group
// Copyright 2021 Datum Technology Corporation
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
//
// Licensed under the Solderpad Hardware License v 2.1 (the "License"); you may
// not use this file except in compliance with the License, or, at your option,
// the Apache License version 2.0. You may obtain a copy of the License at
//
// https://solderpad.org/licenses/SHL-2.1/
//
// Unless required by applicable law or agreed to in writing, any work
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
//
`ifndef __UVMA_OBI_MEMORY_MON_SV__
`define __UVMA_OBI_MEMORY_MON_SV__
/**
* Component sampling transactions from a Open Bus Interface virtual interface
* (uvma_obi_if).
*/
class uvma_obi_memory_mon_c extends uvm_monitor;
// Objects
uvma_obi_memory_cfg_c cfg;
uvma_obi_memory_cntxt_c cntxt;
// TLM
uvm_analysis_port#(uvma_obi_memory_mon_trn_c) ap;
uvm_analysis_port#(uvma_obi_memory_mon_trn_c) sequencer_ap;
// Handles to virtual interface modport
virtual uvma_obi_memory_if.passive_mp passive_mp;
`uvm_component_utils_begin(uvma_obi_memory_mon_c)
`uvm_field_object(cfg , UVM_DEFAULT)
`uvm_field_object(cntxt, UVM_DEFAULT)
`uvm_component_utils_end
/**
* Default constructor.
*/
extern function new(string name="uvma_obi_memory_mon", uvm_component parent=null);
/**
* 1. Ensures cfg & cntxt handles are not null.
* 2. Builds ap.
*/
extern virtual function void build_phase(uvm_phase phase);
/**
* TODO Describe uvma_obi_memory_mon_c::run_phase()
*/
extern virtual task run_phase(uvm_phase phase);
/**
* Monitors passive_mp for asynchronous reset and updates the context's reset state.
*/
extern task observe_reset();
/**
* TODO Describe uvma_obi_memory_mon_c::mon_chan_a_pre_reset/mon_chan_a_in_reset/mon_chan_a_post_reset()
*/
extern task mon_chan_a_pre_reset ();
extern task mon_chan_a_in_reset ();
extern task mon_chan_a_post_reset();
/**
* TODO Describe uvma_obi_memory_mon_c::mon_chan_r_pre_reset/mon_chan_r_in_reset/mon_chan_r_post_reset()
*/
extern task mon_chan_r_pre_reset ();
extern task mon_chan_r_in_reset ();
extern task mon_chan_r_post_reset();
/**
* TODO Describe uvma_obi_memory_mon_c::mon_chan_a_trn()
*/
extern task mon_chan_a_trn(output uvma_obi_memory_mon_trn_c trn);
/**
* TODO Describe uvma_obi_memory_mon_c::mon_chan_r_trn()
*/
extern task mon_chan_r_trn(uvma_obi_memory_mon_trn_c trn);
/**
* User hooks for modifying transactions after they've been sampled but before they're sent out the analysis port(s).
*/
extern virtual function void process_a_trn(uvma_obi_memory_mon_trn_c trn);
extern virtual function void process_r_trn(uvma_obi_memory_mon_trn_c trn);
/**
* TODO Describe uvma_obi_memory_mon_c::send_trn_to_sequencer()
*/
extern task send_trn_to_sequencer(ref uvma_obi_memory_mon_trn_c trn);
/**
* TODO Describe uvma_obi_memory_mon_c::sample_trn_a_from_vif()
*/
extern task sample_trn_a_from_vif(uvma_obi_memory_mon_trn_c trn);
extern task sample_trn_r_from_vif(uvma_obi_memory_mon_trn_c trn);
endclass : uvma_obi_memory_mon_c
function uvma_obi_memory_mon_c::new(string name="uvma_obi_memory_mon", uvm_component parent=null);
super.new(name, parent);
endfunction : new
function void uvma_obi_memory_mon_c::build_phase(uvm_phase phase);
super.build_phase(phase);
void'(uvm_config_db#(uvma_obi_memory_cfg_c)::get(this, "", "cfg", cfg));
if (cfg == null) begin
`uvm_fatal("CFG", "Configuration handle is null")
end
void'(uvm_config_db#(uvma_obi_memory_cntxt_c)::get(this, "", "cntxt", cntxt));
if (cntxt == null) begin
`uvm_fatal("CNTXT", "Context handle is null")
end
passive_mp = cntxt.vif.passive_mp;
ap = new("ap" , this);
sequencer_ap = new("sequencer_ap", this);
endfunction : build_phase
task uvma_obi_memory_mon_c::run_phase(uvm_phase phase);
super.run_phase(phase);
if (cfg.enabled) begin
fork
observe_reset();
begin : chan_a
forever begin
case (cntxt.reset_state)
UVMA_OBI_MEMORY_RESET_STATE_PRE_RESET : mon_chan_a_pre_reset ();
UVMA_OBI_MEMORY_RESET_STATE_IN_RESET : mon_chan_a_in_reset ();
UVMA_OBI_MEMORY_RESET_STATE_POST_RESET: mon_chan_a_post_reset();
endcase
end
end
begin : chan_r
forever begin
case (cntxt.reset_state)
UVMA_OBI_MEMORY_RESET_STATE_PRE_RESET : mon_chan_r_pre_reset ();
UVMA_OBI_MEMORY_RESET_STATE_IN_RESET : mon_chan_r_in_reset ();
UVMA_OBI_MEMORY_RESET_STATE_POST_RESET: mon_chan_r_post_reset();
endcase
end
end
join_none
end
endtask : run_phase
task uvma_obi_memory_mon_c::observe_reset();
forever begin
wait (cntxt.vif.reset_n === 0);
cntxt.reset_state = UVMA_OBI_MEMORY_RESET_STATE_IN_RESET;
`uvm_info("OBI_MEMORY_MON", $sformatf("RESET_STATE_IN_RESET"), UVM_NONE)
wait (cntxt.vif.reset_n === 1);
cntxt.reset_state = UVMA_OBI_MEMORY_RESET_STATE_POST_RESET;
`uvm_info("OBI_MEMORY_MON", $sformatf("RESET_STATE_POST_RESET"), UVM_NONE)
end
endtask : observe_reset
task uvma_obi_memory_mon_c::mon_chan_a_pre_reset();
@(passive_mp.mon_cb);
endtask : mon_chan_a_pre_reset
task uvma_obi_memory_mon_c::mon_chan_a_in_reset();
@(passive_mp.mon_cb);
endtask : mon_chan_a_in_reset
task uvma_obi_memory_mon_c::mon_chan_a_post_reset();
uvma_obi_memory_mon_trn_c trn;
mon_chan_a_trn(trn);
trn.cfg = cfg;
cntxt.mon_outstanding_reads_q.push_back(trn);
`uvm_info("OBI_MEMORY_MON", $sformatf("monitored transaction on channel A:\n%s", trn.sprint()), UVM_HIGH)
process_a_trn(trn);
`uvm_info("OBI_MEMORY_MON", $sformatf("monitored transaction on channel A after process_a_trn():\n%s", trn.sprint()), UVM_HIGH)
if (cfg.enabled && cfg.is_active && (cfg.drv_mode == UVMA_OBI_MEMORY_MODE_SLV)) begin
send_trn_to_sequencer(trn);
`uvm_info("OBI_MEMORY_MON", $sformatf("Sent trn to sequencer"), UVM_HIGH)
end
`uvml_hrtbt()
@(passive_mp.mon_cb);
endtask : mon_chan_a_post_reset
task uvma_obi_memory_mon_c::mon_chan_r_pre_reset();
@(passive_mp.mon_cb);
endtask : mon_chan_r_pre_reset
task uvma_obi_memory_mon_c::mon_chan_r_in_reset();
@(passive_mp.mon_cb);
endtask : mon_chan_r_in_reset
task uvma_obi_memory_mon_c::mon_chan_r_post_reset();
uvma_obi_memory_mon_trn_c trn;
wait (cntxt.mon_outstanding_reads_q.size());
trn = cntxt.mon_outstanding_reads_q.pop_front();
mon_chan_r_trn(trn);
trn.cfg = cfg;
`uvm_info("OBI_MEMORY_MON", $sformatf("monitored transaction on channel R:\n%s", trn.sprint()), UVM_HIGH)
process_r_trn(trn);
`uvm_info("OBI_MEMORY_MON", $sformatf("monitored transaction on channel R after process_r_trn():\n%s", trn.sprint()), UVM_HIGH)
ap.write(trn);
`uvml_hrtbt()
@(passive_mp.mon_cb);
endtask : mon_chan_r_post_reset
task uvma_obi_memory_mon_c::mon_chan_a_trn(output uvma_obi_memory_mon_trn_c trn);
trn = uvma_obi_memory_mon_trn_c::type_id::create("trn");
while((passive_mp.mon_cb.req !== 1'b1) || (passive_mp.mon_cb.gnt !== 1'b1)) begin
@(passive_mp.mon_cb);
trn.gnt_latency++;
end
sample_trn_a_from_vif(trn);
trn.__timestamp_start = $realtime();
endtask : mon_chan_a_trn
task uvma_obi_memory_mon_c::mon_chan_r_trn(uvma_obi_memory_mon_trn_c trn);
// 1.1 only requires rvalid
// fixme:strichmo:for 1.2 this must take rready into account as well
while (passive_mp.mon_cb.rvalid !== 1'b1) begin
@(passive_mp.mon_cb);
trn.rvalid_latency++;
end
sample_trn_r_from_vif(trn);
trn.__timestamp_end = $realtime();
endtask : mon_chan_r_trn
function void uvma_obi_memory_mon_c::process_a_trn(uvma_obi_memory_mon_trn_c trn);
endfunction : process_a_trn
function void uvma_obi_memory_mon_c::process_r_trn(uvma_obi_memory_mon_trn_c trn);
endfunction : process_r_trn
task uvma_obi_memory_mon_c::send_trn_to_sequencer(ref uvma_obi_memory_mon_trn_c trn);
sequencer_ap.write(trn);
endtask : send_trn_to_sequencer
task uvma_obi_memory_mon_c::sample_trn_a_from_vif(uvma_obi_memory_mon_trn_c trn);
trn.__originator = this.get_full_name();
if (passive_mp.mon_cb.we === 1'b1) begin
trn.access_type = UVMA_OBI_MEMORY_ACCESS_WRITE;
end
else if (passive_mp.mon_cb.we === 1'b0) begin
trn.access_type = UVMA_OBI_MEMORY_ACCESS_READ;
end
else begin
`uvm_error("OBI_MEMORY_MON", $sformatf("Invalid value for we:%b", passive_mp.mon_cb.we))
trn.__has_error = 1;
end
for (int unsigned ii=0; ii<cfg.addr_width; ii++) begin
trn.address[ii] = passive_mp.mon_cb.addr[ii];
end
for (int unsigned ii=0; ii<(cfg.data_width/8); ii++) begin
trn.be[ii] = passive_mp.mon_cb.be[ii];
end
if (trn.access_type == UVMA_OBI_MEMORY_ACCESS_WRITE) begin
for (int unsigned ii=0; ii<cfg.data_width; ii++) begin
trn.data[ii] = passive_mp.mon_cb.wdata[ii];
end
end
// 1P2 signals
if (cfg.is_1p2_or_higher()) begin
for (int unsigned ii=0; ii<cfg.auser_width; ii++) begin
trn.auser[ii] = passive_mp.mon_cb.auser[ii];
end
if (trn.access_type == UVMA_OBI_MEMORY_ACCESS_WRITE) begin
for (int unsigned ii=0; ii<cfg.wuser_width; ii++) begin
trn.wuser[ii] = passive_mp.mon_cb.wuser[ii];
end
end
// ID: Use zero for aid if id_width is configured to 0
if (cfg.id_width == 0) begin
trn.aid = '0;
end
else begin
for (int unsigned ii=0; ii<cfg.id_width; ii++) begin
trn.aid[ii] = passive_mp.mon_cb.aid[ii];
end
end
trn.atop = passive_mp.mon_cb.atop;
trn.memtype = passive_mp.mon_cb.memtype;
trn.prot = passive_mp.mon_cb.prot;
for (int unsigned ii=0; ii<cfg.achk_width; ii++) begin
trn.achk = passive_mp.mon_cb.achk[ii];
end
end
endtask : sample_trn_a_from_vif
task uvma_obi_memory_mon_c::sample_trn_r_from_vif(uvma_obi_memory_mon_trn_c trn);
trn.__originator = this.get_full_name();
if (trn.access_type == UVMA_OBI_MEMORY_ACCESS_READ) begin
for (int unsigned ii=0; ii<cfg.data_width; ii++) begin
trn.data[ii] = passive_mp.mon_cb.rdata[ii];
end
end
// 1P2 signals
if (cfg.is_1p2_or_higher()) begin
trn.err = passive_mp.mon_cb.err;
for (int unsigned ii=0; ii<cfg.ruser_width; ii++) begin
trn.ruser[ii] = passive_mp.mon_cb.ruser[ii];
end
for (int unsigned ii=0; ii<cfg.id_width; ii++) begin
trn.rid[ii] = passive_mp.mon_cb.rid[ii];
end
trn.exokay = passive_mp.mon_cb.exokay;
for (int unsigned ii=0; ii<cfg.rchk_width; ii++) begin
trn.rchk = passive_mp.mon_cb.rchk[ii];
end
end
endtask : sample_trn_r_from_vif
`endif // __UVMA_OBI_MEMORY_MON_SV__
uvma_obi_memory_mon.sv
1. 简要介绍
该文件是OBI内存接口的监控组件,主要功能包括:
- 采样OBI接口的事务数据
- 跟踪复位状态变化
- 处理通道A和通道R的事务
- 将监控数据发送给分析端口
2. 接口介绍
2.1 类定义
class uvma_obi_memory_mon_c extends uvm_monitor;
- 代码介绍:定义OBI内存监控类
- 继承关系:继承自UVM基础监控类
- 特点:支持被动模式监控
3. 参数介绍
3.1 分析端口
uvm_analysis_port#(uvma_obi_memory_mon_trn_c) ap;
uvm_analysis_port#(uvma_obi_memory_mon_trn_c) sequencer_ap;
- 参数说明:
- ap:标准分析端口
- sequencer_ap:序列发生器分析端口
3.2 虚拟接口
virtual uvma_obi_memory_if.passive_mp passive_mp;
- 参数说明:被动模式虚拟接口
- 用途:采样信号不驱动
4. 模块实现介绍
4.1 运行阶段
task run_phase(uvm_phase phase);
fork
observe_reset();
forever begin
case (cntxt.reset_state)
UVMA_OBI_MEMORY_RESET_STATE_POST_RESET: mon_chan_a_post_reset();
endcase
end
join_none
endtask
- 代码分析:
- 并行运行复位监控
- 根据复位状态调用不同监控任务
- 使用fork-join_none实现并发
4.2 通道A监控
task mon_chan_a_post_reset();
mon_chan_a_trn(trn);
cntxt.mon_outstanding_reads_q.push_back(trn);
process_a_trn(trn);
if (cfg.enabled && cfg.is_active) begin
send_trn_to_sequencer(trn);
end
endtask
- 代码分析:
- 监控通道A事务
- 存储未完成读事务
- 处理事务数据
- 条件化发送给序列发生器
5. 总结
该OBI内存监控组件具有以下特点:
- 完整的协议监控能力
- 灵活的复位状态处理
- 可靠的事务跟踪机制
- 标准化的UVM实现
作为验证环境的核心监控组件,它为OBI接口的验证提供了全面的监控能力,确保能够准确捕获接口行为。
//
// Copyright 2021 OpenHW Group
// Copyright 2021 Datum Technology Corporation
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
//
// Licensed under the Solderpad Hardware License v 2.1 (the "License"); you may
// not use this file except in compliance with the License, or, at your option,
// the Apache License version 2.0. You may obtain a copy of the License at
//
// https://solderpad.org/licenses/SHL-2.1/
//
// Unless required by applicable law or agreed to in writing, any work
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
//
`ifndef __UVMA_OBI_MEMORY_SEQ_ITEM_LOGGER_SV__
`define __UVMA_OBI_MEMORY_SEQ_ITEM_LOGGER_SV__
/**
* Component writing Open Bus Interface sequence items debug data to disk as plain text.
*/
class uvma_obi_memory_seq_item_logger_c extends uvml_logs_seq_item_logger_c#(
.T_TRN (uvma_obi_memory_base_seq_item_c),
.T_CFG (uvma_obi_memory_cfg_c ),
.T_CNTXT(uvma_obi_memory_cntxt_c )
);
`uvm_component_utils(uvma_obi_memory_seq_item_logger_c)
/**
* Default constructor.
*/
function new(string name="uvma_obi_memory_seq_item_logger", uvm_component parent=null);
super.new(name, parent);
endfunction : new
/**
* Writes contents of t to disk.
*/
virtual function void write(uvma_obi_memory_base_seq_item_c t);
uvma_obi_memory_mstr_seq_item_c mstr_t;
uvma_obi_memory_slv_seq_item_c slv_t;
case (cfg.drv_mode)
UVMA_OBI_MEMORY_MODE_MSTR: begin
if (!$cast(mstr_t, t)) begin
`uvm_fatal("OBI_MEMORY_SEQ_ITEM_LOGGER", $sformatf("Could not cast 't' (%s) to 'mstr_t' (%s)", $typename(t), $typename(mstr_t)))
end
write_mstr(mstr_t);
end
UVMA_OBI_MEMORY_MODE_SLV: begin
if (!$cast(slv_t, t)) begin
`uvm_fatal("OBI_MEMORY_SEQ_ITEM_LOGGER", $sformatf("Could not cast 't' (%s) to 'slv_t' (%s)", $typename(t), $typename(slv_t)))
end
write_slv(slv_t);
end
default: `uvm_fatal("OBI_MEMORY_SEQ_ITEM_LOGGER", $sformatf("Invalid drv_mode: %0d", cfg.drv_mode))
endcase
endfunction : write
// A significant chunk of the write_mstr method is common between this
// sequence item logger and the monitor transaction logger. Given that
// much of this code is template generated, and is not expected to be edited
// further, the duplicated code has a lint waiver.
//
//@DVT_LINTER_WAIVER_START "MT20210901_2" disable SVTB.33.1.0, SVTB.33.2.0
/**
* Writes contents of mstr t to disk.
*/
virtual function void write_mstr(uvma_obi_memory_mstr_seq_item_c t);
string access_str = "";
string err_str = "";
string be_str = "";
string data_str = "";
string auser_str = "";
string wuser_str = "";
string ruser_str = "";
string id_str = "";
case (t.access_type)
UVMA_OBI_MEMORY_ACCESS_READ : access_str = "R ";
UVMA_OBI_MEMORY_ACCESS_WRITE: access_str = " W";
default : access_str = " ? ";
endcase
case (t.__has_error)
0: err_str = " ";
1: err_str = " ERR";
endcase
case (t.access_type)
UVMA_OBI_MEMORY_ACCESS_READ : data_str = $sformatf("%b", t.rdata);
UVMA_OBI_MEMORY_ACCESS_WRITE: data_str = $sformatf("%h", t.wdata);
endcase
case (t.access_type)
UVMA_OBI_MEMORY_ACCESS_READ : ruser_str = $sformatf("%h", t.rdata);
UVMA_OBI_MEMORY_ACCESS_WRITE: wuser_str = $sformatf("%h", t.wdata);
endcase
auser_str = $sformatf("%h", t.auser);
be_str = $sformatf("%b", t.be );
id_str = $sformatf("%b", t.id );
fwrite($sformatf(" %t | %s | %s | %s | %s | %s | %s | %h | %s | %s ", $realtime(), access_str, id_str, auser_str, wuser_str, ruser_str, err_str, t.address, be_str, data_str));
endfunction : write_mstr
//@DVT_LINTER_WAIVER_END "MT20210901_2"
/**
* Writes contents of slv t to disk.
*/
virtual function void write_slv(uvma_obi_memory_slv_seq_item_c t);
string access_str = "";
string err_str = "";
string be_str = "";
string data_str = "";
string auser_str = "";
string wuser_str = "";
string ruser_str = "";
string id_str = "";
case (t.access_type)
UVMA_OBI_MEMORY_ACCESS_READ : access_str = "R ";
UVMA_OBI_MEMORY_ACCESS_WRITE: access_str = " W";
default : access_str = " ? ";
endcase
case (t.err)
0: err_str = " ";
1: err_str = " ERR";
endcase
case (t.access_type)
UVMA_OBI_MEMORY_ACCESS_READ : data_str = $sformatf("%h", t.rdata);
UVMA_OBI_MEMORY_ACCESS_WRITE: data_str = $sformatf("%h", t.orig_trn.data);
endcase
case (t.access_type)
UVMA_OBI_MEMORY_ACCESS_READ : ruser_str = $sformatf("%h", t.rdata);
UVMA_OBI_MEMORY_ACCESS_WRITE: wuser_str = $sformatf("%h", t.orig_trn.data);
endcase
auser_str = $sformatf("%h", t.orig_trn.auser);
be_str = $sformatf("%b", t.orig_trn.be );
id_str = $sformatf("%b", t.orig_trn.aid );
fwrite($sformatf(" %t | %s | %s | %s | %s | %s | %s | %h | %s | %s ", $realtime(), access_str, id_str, auser_str, wuser_str, ruser_str, err_str, t.orig_trn.address, be_str, data_str));
endfunction : write_slv
/**
* Writes log header to disk.
*/
virtual function void print_header();
fwrite("---------------------------------------------------------------------------------");
fwrite(" TIME | R/W | ID | AUSER | WUSER | RUSER | ERR | ADDRESS | BE | DATA");
fwrite("---------------------------------------------------------------------------------");
endfunction : print_header
endclass : uvma_obi_memory_seq_item_logger_c
/**
* Component writing Open Bus Interface monitor transactions debug data to disk as JavaScript Object Notation (JSON).
*/
class uvma_obi_memory_seq_item_logger_json_c extends uvma_obi_memory_seq_item_logger_c;
`uvm_component_utils(uvma_obi_memory_seq_item_logger_json_c)
/**
* Set file extension to '.json'.
*/
function new(string name="uvma_obi_memory_seq_item_logger_json", uvm_component parent=null);
super.new(name, parent);
fextension = "json";
endfunction : new
/**
* Writes contents of t to disk.
*/
virtual function void write(uvma_obi_memory_base_seq_item_c t);
// TODO Implement uvma_obi_memory_seq_item_logger_json_c::write()
// Ex: fwrite({"{",
// $sformatf("\"time\":\"%0t\",", $realtime()),
// $sformatf("\"a\":%h," , t.a ),
// $sformatf("\"b\":%b," , t.b ),
// $sformatf("\"c\":%d," , t.c ),
// $sformatf("\"d\":%h," , t.c ),
// "},"});
endfunction : write
/**
* Empty function.
*/
virtual function void print_header();
// Do nothing: JSON files do not use headers.
endfunction : print_header
endclass : uvma_obi_memory_seq_item_logger_json_c
`endif // __UVMA_OBI_MEMORY_SEQ_ITEM_LOGGER_SV__
uvma_obi_memory_seq_item_logger.sv
1. 简要介绍
该文件是OBI内存序列项日志记录组件,主要功能包括:
- 将序列项数据写入磁盘
- 支持文本和JSON两种格式
- 区分主设备和从设备模式
- 提供标准化的日志输出格式
2. 接口介绍
2.1 类定义
class uvma_obi_memory_seq_item_logger_c extends uvml_logs_seq_item_logger_c#(
.T_TRN(uvma_obi_memory_base_seq_item_c),
.T_CFG(uvma_obi_memory_cfg_c)
);
- 代码介绍:定义OBI序列项日志记录类
- 继承关系:继承自参数化基础日志记录类
- 特点:支持多种驱动模式
3. 参数介绍
3.1 日志写入函数
virtual function void write(uvma_obi_memory_base_seq_item_c t);
case (cfg.drv_mode)
UVMA_OBI_MEMORY_MODE_MSTR: write_mstr(mstr_t);
UVMA_OBI_MEMORY_MODE_SLV: write_slv(slv_t);
endcase
endfunction
- 参数说明:
- drv_mode:驱动模式选择
- mstr_t:主设备事务
- slv_t:从设备事务
4. 模块实现介绍
4.1 主设备日志写入
virtual function void write_mstr(uvma_obi_memory_mstr_seq_item_c t);
case (t.access_type)
UVMA_OBI_MEMORY_ACCESS_READ: access_str = "R ";
UVMA_OBI_MEMORY_ACCESS_WRITE: access_str = " W";
endcase
fwrite($sformatf(" %t | %s | ...", $realtime(), access_str));
endfunction
- 代码分析:
- 格式化操作类型
- 记录时间戳
- 输出完整事务信息
4.2 JSON日志类
class uvma_obi_memory_seq_item_logger_json_c extends uvma_obi_memory_seq_item_logger_c;
function new();
fextension = "json";
endfunction
endclass
- 代码分析:
- 继承基础日志类
- 设置JSON文件扩展名
- 预留JSON格式实现
5. 总结
该OBI序列项日志记录组件具有以下特点:
- 灵活的多模式支持
- 清晰的文本输出格式
- 可扩展的JSON实现
- 标准化的UVM集成
作为验证环境的调试辅助工具,它为OBI接口的事务分析提供了可靠的日志记录能力,确保能够方便地追踪接口行为。
//
// Copyright 2021 OpenHW Group
// Copyright 2021 Datum Technology Corporation
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
//
// Licensed under the Solderpad Hardware License v 2.1 (the "License"); you may
// not use this file except in compliance with the License, or, at your option,
// the Apache License version 2.0. You may obtain a copy of the License at
//
// https://solderpad.org/licenses/SHL-2.1/
//
// Unless required by applicable law or agreed to in writing, any work
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
//
`ifndef __UVMA_OBI_MEMORY_SQR_SV__
`define __UVMA_OBI_MEMORY_SQR_SV__
/**
* Component running Open Bus Interface sequences extending uvma_obi_base_seq_c.
* Provides sequence items for uvma_obi_drv_c.
*/
class uvma_obi_memory_sqr_c extends uvm_sequencer#(
.REQ(uvma_obi_memory_base_seq_item_c),
.RSP(uvma_obi_memory_mon_trn_c )
);
// Objects
uvma_obi_memory_cfg_c cfg;
uvma_obi_memory_cntxt_c cntxt;
// TLM
uvm_tlm_analysis_fifo #(uvma_obi_memory_mon_trn_c) mon_trn_fifo;
`uvm_component_utils_begin(uvma_obi_memory_sqr_c)
`uvm_field_object(cfg , UVM_DEFAULT)
`uvm_field_object(cntxt, UVM_DEFAULT)
`uvm_component_utils_end
/**
* Default constructor.
*/
extern function new(string name="uvma_obi_memory_sqr", uvm_component parent=null);
/**
* Ensures cfg & cntxt handles are not null
*/
extern virtual function void build_phase(uvm_phase phase);
endclass : uvma_obi_memory_sqr_c
function uvma_obi_memory_sqr_c::new(string name="uvma_obi_memory_sqr", uvm_component parent=null);
super.new(name, parent);
endfunction : new
function void uvma_obi_memory_sqr_c::build_phase(uvm_phase phase);
super.build_phase(phase);
void'(uvm_config_db#(uvma_obi_memory_cfg_c)::get(this, "", "cfg", cfg));
if (cfg == null) begin
`uvm_fatal("CFG", "Configuration handle is null")
end
void'(uvm_config_db#(uvma_obi_memory_cntxt_c)::get(this, "", "cntxt", cntxt));
if (cntxt == null) begin
`uvm_fatal("CNTXT", "Context handle is null")
end
mon_trn_fifo = new("mon_trn_fifo", this);
endfunction : build_phase
`endif // __UVMA_OBI_MEMORY_SQR_SV__
uvma_obi_memory_sqr.sv
1. 简要介绍
该文件是OBI内存接口的序列发生器组件,主要功能包括:
- 运行OBI接口序列
- 为驱动组件提供序列项
- 管理监控事务FIFO
- 作为序列和驱动之间的桥梁
2. 接口介绍
2.1 类定义
class uvma_obi_memory_sqr_c extends uvm_sequencer#(
.REQ(uvma_obi_memory_base_seq_item_c),
.RSP(uvma_obi_memory_mon_trn_c)
);
- 代码介绍:定义OBI内存序列发生器类
- 继承关系:继承自UVM参数化序列发生器类
- 特点:支持基础序列项和监控事务响应
3. 参数介绍
3.1 配置对象
uvma_obi_memory_cfg_c cfg;
uvma_obi_memory_cntxt_c cntxt;
- 参数说明:
- cfg:配置对象
- cntxt:上下文对象
- 用途:存储运行时配置和状态
3.2 分析FIFO
uvm_tlm_analysis_fifo #(uvma_obi_memory_mon_trn_c) mon_trn_fifo;
- 参数说明:监控事务FIFO
- 用途:存储来自监控组件的事务
4. 模块实现介绍
4.1 构造函数
function new(string name="uvma_obi_memory_sqr", uvm_component parent=null);
super.new(name, parent);
endfunction
- 代码分析:
- 调用父类构造函数
- 初始化序列发生器
- 无额外初始化逻辑
4.2 构建阶段
function void build_phase(uvm_phase phase);
void'(uvm_config_db#(uvma_obi_memory_cfg_c)::get(this, "", "cfg", cfg));
mon_trn_fifo = new("mon_trn_fifo", this);
endfunction
- 代码分析:
- 从配置数据库获取配置对象
- 创建监控事务FIFO
- 检查配置和上下文有效性
5. 总结
该OBI内存序列发生器组件具有以下特点:
- 标准化的UVM实现
- 灵活的序列项管理
- 可靠的监控事务处理
- 清晰的接口定义
作为验证环境的核心组件,它为OBI接口的序列执行提供了可靠的基础设施,确保能够高效地执行各类测试场景。