电子说
使用后门方式测量时钟频率的需求来源更多是SOC验证的场景,由于SOC的规模较大,一次编译时间成本较高,在N个小时级别。如果采用前门方式,比如编写测量频率的module或者interface,一旦有新的测量需求则就需要TB重新连接时钟信号,重新编译环境。
此前的一篇文章,提出了一个问题:如何后门准确地捕获到信号地跳变沿?
如何捕获后门路径信号的跳变?
如果无法精确捕获到信号地跳变沿,那么也就无法"精确地"测量出时钟地频率。容易想到的办法,是可以使用如下的方法进行测量:
bit dut_value=1 //step1:找到信号低电平 while(dut_value) begin hdl_read("xxx",dut_value) #N end //step2:找到高电平,作为测量的第一个上升沿时刻 bit dut_value=0 //找到信号低电平 while(!dut_value) begin hdl_read("xxx",dut_value) #N end //step3: 找到低电平,作为下降沿 ... //step4: 找到高电平,作为测量的第二个上升沿。记录此时的仿真时间,减去step2的仿真时间,得到时钟周期 ...
上述的代码需要考虑如下问题:
时钟频率,时钟频率的大小决定了两次后门读取的间隔,即上述代码中的#N,这也是后门方式测不准的来源。
timescale,dut信号的timescale和后门测量所在的scope的timescale可能并不一致。
那怎么解决测不准的问题?
第一次意识到这个问题,作者也曾一度陷入苦思冥想,始终找不到完美的解决办法。曾经也想过用#1step来进行step级别的delay,但也由于仿真器的差异、环境结构的差异,表现不够稳定。虽然已过去了近一年的时间,工作也换了新的公司,还好对此的思考没有停止。
最近终于开发出了clock_probe_pkg,一个可以使用后门方式,精确测量时钟频率的package。
请看下面的demo:
`timescale 1ps/1ps module tb; import clock_probe_pkg::*; reg clk1,clk2,clk3; initial begin clk1=0; clk2=0; clk3=0; fork forever begin #11; clk1 = ~clk1; end forever begin #17; clk2 = ~clk2; end forever begin #19; clk3 = ~clk3; end join_none end initial begin real freq1,freq2,freq3; #100; get_clock_freq("tb.clk1",freq1); get_clock_freq("tb.clk2",freq2); get_clock_freq("tb.clk3",freq3); $display("freq1=%f, freq2=%f, freq3=%f",freq1,freq2,freq3); $finish(); end endmodule
仿真结果如下:
clock_probe_pkg: get clock hier :tb,2 clock_probe_pkg: get clock scope timeunit: -12 clock_probe_pkg: @110.000000 tb.clk1 = 0,0 clock_probe_pkg: @121.000000 tb.clk1 = 1,1 clock_probe_pkg: @132.000000 tb.clk1 = 0,2 probe clock freq done, freq=45454.545455 @0 clock_probe_pkg: get clock hier :tb,2 clock_probe_pkg: get clock scope timeunit: -12 clock_probe_pkg: @153.000000 tb.clk2 = 1,0 clock_probe_pkg: @170.000000 tb.clk2 = 0,1 clock_probe_pkg: @187.000000 tb.clk2 = 1,2 probe clock freq done, freq=29411.764706 @0 clock_probe_pkg: get clock hier :tb,2 clock_probe_pkg: get clock scope timeunit: -12 clock_probe_pkg: @209.000000 tb.clk3 = 1,0 clock_probe_pkg: @228.000000 tb.clk3 = 0,1 clock_probe_pkg: @247.000000 tb.clk3 = 1,2 probe clock freq done, freq=26315.789474 @0 freq1=45454.545455, freq2=29411.764706, freq3=26315.789474 $finish called from file "testbench.sv", line 26. $finish at simulation time 266
clock_probe_pkg可以自动识别时钟信号所在scope的timescale,而且仅有一个接口,方便使用。get_clock_freq:
task get_clock_freq(string path, output real x_freq); ... endtask
第一个参数为字符串类型的时钟信号的后门路径,第二个参数即为返回的时钟频率,单位为MHz。
clock_probe_pkg也是目前作者能找到的"完美"解决方案。虽然这个需求非常小众,可能也不一定能完全满足需求,可能后续还会更好的解决方案,但这个尝试的过程,作者觉得仍然是有意义的尝试,因为:
真理存在于寻求过程之中。
审核编辑:汤梓红
全部0条评论
快来发表一下你的评论吧 !