碎碎念:
今日学习,可没时间碎碎念(bushi)
这两天涨了几个粉丝,谢谢大家的关注!我一定认真更新,我们一起进步!
目录
1 模块功能
设置参数WIDTH,从而可以将接收到的单周期脉冲,展宽为脉宽为WIDTH的脉冲信号。
2 模块代码
//--------------------------------------------------------------------------------
// pulse_stretch.sv
// Konstantin Pavlov, [email protected]
//--------------------------------------------------------------------------------
// INFO --------------------------------------------------------------------------------
// Pulse stretcher/extender module
// this implementftion uses a simple delay line or counter to stretch pulses
// WIDTH parameter sets output pulse width
// if you need variable output poulse width, see pulse_gen.sv module
/* --- INSTANTIATION TEMPLATE BEGIN ---
pulse_stretch #(
.WIDTH( 8 ),
.USE_CNTR( 0 )
) ps1 (
.clk( clk ),
.nrst( nrst ),
.in( ),
.out( )
);
--- INSTANTIATION TEMPLATE END ---*/
module pulse_stretch #( parameter
WIDTH = 8,
USE_CNTR = 0 // ==0 - stretcher is implemented on delay line
// ==1 - stretcher is implemented on counter
)(
input clk,
input nrst,
input in,
output out
);
localparam CNTR_WIDTH = $clog2(WIDTH) + 1;
generate
if ( WIDTH == 0 ) begin
assign out = 0;
end else if( WIDTH == 1 ) begin
assign out = in;
end else begin
if( USE_CNTR == '0 ) begin
// delay line
logic [WIDTH-1:0] shifter = '0;
always_ff @(posedge clk) begin
if( ~nrst ) begin
shifter[WIDTH-1:0] <= '0;
end else begin
// shifting
shifter[WIDTH-1:0] <= {shifter[WIDTH-2:0],in};
end // nrst
end // always
assign out = (shifter[WIDTH-1:0] != '0);
end else begin
// counter
logic [CNTR_WIDTH-1:0] cntr = '0;
always_ff @(posedge clk) begin
if( ~nrst ) begin
cntr[CNTR_WIDTH-1:0] <= '0;
end else begin
if( in ) begin
// setting counter
cntr[CNTR_WIDTH-1:0] <= CNTR_WIDTH'(WIDTH);
end else if( out ) begin
// decrementing counter
cntr[CNTR_WIDTH-1:0] <= cntr[CNTR_WIDTH-1:0] - 1'b1;
end
end // nrst
end // always
assign out = (cntr[CNTR_WIDTH-1:0] != '0);
end
end // if WIDTH
endgenerate
endmodule
3 模块思路
据代码介绍所说,利用简单的延时或计数器来实现脉冲的展宽处理,下面来具体分析一下实现过程以及值得关注的点。
1.USE_CNTR(第29行)
这里注释提到,可以自行选择是通过延时线还是计数器来实现本模块的功能,这就直接容易想到利用System Verilog中的generate(42行)来实现,前面在边沿检测器我们对这一结构进行过介绍:传送门。
2.$clog2函数(第40行)
$clog2这个计算是log2,就是求2对数,例如log2(8)=3。这里通过利用这一函数,计算出了对应WIDTH需要的计数器的位数大小CNTR_WIDTH,并作为常量进行保存。
3.功能核心部分(42-88行)
利用generate结构,实现对代码实现方式的控制。由于是两种实现方式,因此我就分为两个部分进行分别介绍。
3.1 延时线实现(54-64行)
这个地方的实现我个人认为非常巧妙。首先根据设定的WIDTH数值,建立一个长度为WIDTH的以移位寄存器shifter。利用always_ff构建D触发器,在非复位情况下,依次将之进行左移处理,并将输入信号in放到最低位,之后检测shifter是否全为0,来控制当前输出信号out的值。若shifter所有位不全为0,则输出为1。
这种方式非常直接地将输出控制在了需要的宽度内,不过一个问题是如果所输入的脉冲不是一个周期的,则可能会导致输出展宽后的脉宽比WIDTH更宽。
3.2 计数器实现(69-84行)
首先,计数器的话就需要利用到上面调用log2函数获得的结果,构建出一个刚好满足要求的计数器。之后同样是利用always_ff构建D触发器,在非复位情况下,当检测到输入信号in为高电平时,会将WIDTH这个值存储到cntr中。当输出为高电平时,逐周期对计数器进行减一操作。
输出信号out的控制逻辑,就是检测计数器结果cntr的值,如果不为0,则输出1,否则输出0。不过也同样会有上面延时线实现时会遇到的相同的问题,可能作者本身就是这样设计的。
4 TestBench与仿真结果
//------------------------------------------------------------------------------
// pulse_stretch_tb.sv
// Konstantin Pavlov, [email protected]
//------------------------------------------------------------------------------
// INFO ------------------------------------------------------------------------
// testbench for pulse_stretch.sv module
`timescale 1ns / 1ps
module pulse_stretch_tb();
logic clk200;
initial begin
#0 clk200 = 1'b0;
forever
#2.5 clk200 = ~clk200;
end
logic rst;
initial begin
#0 rst = 1'b0;
#10.2 rst = 1'b1;
#5 rst = 1'b0;
//#10000;
forever begin
#9985 rst = ~rst;
#5 rst = ~rst;
end
end
logic nrst;
assign nrst = ~rst;
logic rst_once;
initial begin
#0 rst_once = 1'b0;
#10.2 rst_once = 1'b1;
#5 rst_once = 1'b0;
end
logic start;
initial begin
#0 start = 1'b0;
#100 start = 1'b1;
#5 start = 1'b0;
end
// Modules under test ==========================================================
pulse_stretch #(
.WIDTH( 8 ),
.USE_CNTR( 0 )
) ps1 (
.clk( clk200 ),
.nrst( nrst ),
.in( start ),
.out( )
);
pulse_stretch #(
.WIDTH( 8 ),
.USE_CNTR( 1 )
) ps2 (
.clk( clk200 ),
.nrst( nrst ),
.in( start ),
.out( )
);
endmodule
下面开始介绍TestBench的内容,这里就比较简单没有涉及到对之前信号的复用问题,只是单纯通过构建时钟信号以及start模拟一个输入脉冲,从而实现对模块的测试。
可以看到最后例化了两个待测试信号,分别通过修改参数,前者是通过延时线实现的方式,后者是通过计数器实现的方式。
从仿真波形中可以看出,红色波形是使用延时线实现的方式,设定的WIDTH=8,当输入为一个周期的脉冲时,会输出宽度为8个时钟周期的脉冲信号。绿色波形是使用计数器实现的方式,放输入脉冲到达时,计数器会从8依次递减到1,从而输出输出宽度为8个时钟周期的脉冲信号。与我们对代码的分析说一致的。
这就是本期的全部内容啦,如果你喜欢我的文章,不要忘了点赞+收藏+关注,分享给身边的朋友哇~