继续最近的交付总结系列更新,本篇遇到和处理的问题和带宽统计以及性能有关。简单说就是在推进过程中,需要一些方法来实时/分阶段/整体的统计一下有效带宽,以确定一些环境的异常报错是环境引起的还是RTL内部的问题。
最开始想到了多年前的一个统计带宽的脚本,这个脚本是tcl做的工具,能够嵌入verdi里,然后对着你的波形一顿扫描。只要你的波形里做了en和size两个信号,脚本就能够统计出从黄线到白线之间的总数据量,然后根据时间计算出来平均带宽。
对了,统计的时候这个黄线还在实时动态的往白线那移动,所以很长时间我都觉得这个脚本太神奇了。后来试了好几次想复现但是因为tcl的基础太弱对verdi的dpi也不熟悉,所以一直搞不出来,如果谁会咱们好好聊一聊。所以没有办法,就另辟蹊径吧。
目前需求比较明确:
1.能够进行感兴趣时间段的流量带宽统计;
2.不影响已有的RTL结构和验证环境,独立于RTL交付和验证环境之外;
3.可以同时监控多个模块、多个接口的流量;
基于这三个需求,我觉得用一个RTL的组件来做可以了,没有太难。于是快进到组件的开发,在此也没研究有没有现成的组件哈,总觉得简单的这个功夫自己就写完了(ಥ_ಥ)。先看进行带宽统计,这个其实不难办,核心就是跟刚刚提到的脚本一样做一个模块对关心的接口进行采样。所以把这个模块的顶层搞出来:
module flow_cnt
//parameter
parameter realtime START_TIME = 0ns,
parameter realtime END_TIME = -1ns,
parameter BIT_W = 10, //max 1023bit per cycle
parameter MAX_W = 64 //bit cnt max
)( /*AUTOARG*/
// Inputs
clk, rst_n, power, bit_cnt
);
// ----------------------------------------------------------------
// Interface declare
// ----------------------------------------------------------------
input clk;
input rst_n;
input power;
input [BIT_W -1:0]bit_cnt;
endmodule
接口就更简单了,时钟复位使能和使能时的数据有效量。顶层搞定了,那里面怎么办呢,也很简单在关心的时间段里power有效就把bit_cnt往上累加呗(要是累加加翻了就把MAX_W设置的大一些嗷):
logic [MAX_W -1:0]whole_bit_cnt;
always @(posedge clk or negedge rst_n) begin
begin
whole_bit_cnt <= {MAX_W{1'b0}};
end
else if($realtime>=START_TIME && ($realtime<END_TIME || END_TIME<=0)) begin
whole_bit_cnt <= whole_bit_cnt + bit_cnt;
end
end
initial begin: BANDWIDTH_REPORT
real flow_bandwidth;
realtime time_duration;
while(1)begin
@(posedge clk);
if($realtime<END_TIME)begin
continue;
end
else begin
time_duration = $realtime - START_TIME;
flow_bandwidth = whole_bit_cnt/time_duration;
$display("==============================================================================");
$display("%m bandwidth report at %t:", $realtime);
$display(" whole_bit_cnt = %0dbit = %0dByte", whole_bit_cnt, whole_bit_cnt/8);
$display(" time_duration = %t", time_duration);
$display(" flow_bandwidth = %fGbps", flow_bandwidth);
$display("==============================================================================");
break;
end
end
end
在绝大部分场景中,bind都是用来搞并发断言的,但其实bind的使用场景很多,各种我们自己写的不需要交付的辅助小组件小模块都可以用bind的方式与需要监控的模块或结构进行绑定。那么再看下第三个需求,可以监控多模块多接口。那其实这件事也就简单了,在flow_cnt上封装一个顶层,在顶层里对确切的某个inst进行bind就可以了呀!
我们借助sync_fifo那个验证环境,在该环境中sync_fifo例化在testbench中:
//-------------------------------------{{{rtl inst
sync_fifo
.WIDTH(WIDTH),
.DEPTH(DEPTH))
u_sync_fifo(
.clk(clk),
.rst_n(rst_n),
.afull_th(afull_th),
.aempty_th(aempty_th),
.winc(winc),
.wdata(wdata),
.wfull(wfull),
.almost_wfull(almost_wfull),
.rinc(rinc),
.rdata(rdata),
.rempty(rempty),
.rvld(rvld),
.almost_rempty(almost_rempty)
);
bind testbench.u_sync_fifo flow_cnt #(
.START_TIME(800ns),
.END_TIME(80000ns)
) u_fifo_flow_cnt(
.clk(clk),
.rst_n(rst_n),
.power(rvld),
.bit_cnt(WIDTH)
);
然后只需要把这两个文件放到filelist中,而不需要对验证环境进行任何的改动:
+libext+.v+.sv
+incdir+/home/ICer/gitee_path/verilog_fifo_code/src/ut_ver/../rtl
-y /home/ICer/gitee_path/verilog_fifo_code/src/ut_ver/../rtl
/home/ICer/gitee_path/verilog_fifo_code/src/bind/flow_cnt.sv
/home/ICer/gitee_path/verilog_fifo_code/src/bind/bind_fifo_flow_cnt.sv
../ver/sync_fifo_pkg.sv
/home/ICer/gitee_path/verilog_fifo_code/src/ut_ver/../rtl/sync_fifo.v
../top/testbench.sv
16bit/10ns = 1.6 * 10^9 bps = 1.6Gbps
对应时间段的波形确实是满带宽输出:
看起来好像算的还是挺准的。那么因为有个bind_fifo_flow_cnt.sv这个顶层存在,只需要在bind时给定具体inst路径,就可以在该文件里对感兴趣的多个模块和内部总线进行监控了。
基本的工作就完成啦!后面只需要按自己的需求,在flow_cnt.sv的基础上分装一个axi_flow_cnt.sv来对AXI总监挂接监控带宽就可以,这里就不多聊了。
系列文章入口——
【芯片验证】sva_assertion: 15道助力飞升的断言练习 |
【芯片验证】可能是RTL定向验证的巅峰之作 |
【芯片验证】RTL仿真中X态行为的传播 —— 从xprop说起 |
【芯片验证】年轻人的第一个systemVerilog验证环境全工程与解析 |
【芯片设计】verilog中有符号数和无符号数的本质探究 |
【芯片设计】论RTL中always语法的消失术 |
【芯片设计】代码即注释,注释即代码 |
【芯片设计】700行代码的risc处理器你确实不能要求太多了 |
入职芯片开发部门后,每天摸鱼之外的时间我们要做些什么呢 |
如何计算系统的outstanding 和 burst length? |
芯片搬砖日常·逼死强迫症的关键词不对齐事件 |
熟人社会里,一群没有社会价值的局外人 |