推荐答案
测试一下
题目
使用 v/sv 编写如下功能模块,求输入信号序列 din 在 din_vld 为高电平的时间段内的次小值与次小值出现的次数
参考答案与知识点
参考答案
使用Verilog/SystemVerilog设计模块,实现输入有效数据序列中次小值及其出现次数的统计。模块输入:时钟clk、复位rst_n、数据din、有效标志din_vld;输出:次小值sec_min、次数sec_cnt(可附加有效标志sec_vld)。内部使用三个寄存器:min1(最小值)、min2(次小值)、cnt1(最小值计数)、cnt2(次小值计数)。初始时,min1和min2置为最大值(如'b111...1),cnt1和cnt2清零。每个时钟上升沿,若rst_n有效则复位;否则当din_vld为高时,按如下逻辑更新:
1. 若din < min1,则min2 <= min1,cnt2 <= cnt1,min1 <= din,cnt1 <= 1。
2. 若din == min1,则cnt1 <= cnt1 + 1。
3. 若din > min1且din < min2,则min2 <= din,cnt2 <= 1。
4. 若din == min2,则cnt2 <= cnt2 + 1。
5. 其他情况不更新。
最后,sec_min <= min2,sec_cnt <= cnt2。需注意:若仅有一个有效数据或所有数据相同,则min2保持为初始最大值,cnt2为0,此时可输出sec_vld=0表示次小值无效。易错点:边界情况下min2初始值需足够大(比任何可能数据大),否则误判;当din小于min1时,原min1及计数需正确转移到min2;对相等情况的处理避免计数丢失。时序逻辑中赋值使用非阻塞赋值,防止竞争。代码示例:
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
min1 <= {WIDTH{1'b1}}; min2 <= {WIDTH{1'b1}};
cnt1 <= 0; cnt2 <= 0;
end else if (din_vld) begin
if (din < min1) begin
min2 <= min1; cnt2 <= cnt1;
min1 <= din; cnt1 <= 1;
end else if (din == min1) begin
cnt1 <= cnt1 + 1;
end else if (din < min2) begin
min2 <= din; cnt2 <= 1;
end else if (din == min2) begin
cnt2 <= cnt2 + 1;
end
end
end
此外,可增加输出有效标志:assign sec_vld = (cnt2 != 0);
涉及知识点
- 状态机与比较器设计
- 时序逻辑非阻塞赋值
- 边界条件与初始化处理
- Verilog/SystemVerilog模块编写
- 有限状态数据流处理