真实面经题目 · 原创解析
Verilog 如何写一个带复位的计数器?
这题考时序 always 块、异步复位、同步清零、模计数边界和非阻塞赋值,重点是写出可综合且边界正确的计数器。
真实面经题目 · 原创解析
这题考时序 always 块、异步复位、同步清零、模计数边界和非阻塞赋值,重点是写出可综合且边界正确的计数器。
我会先明确规格:这里是异步复位、同步清零、17 进制计数器,所以计数范围是 0 到 16,需要 5 位寄存器。异步复位要放在敏感列表里,优先级最高;同步清零在时钟上升沿内部判断;正常计数时,如果当前值是 16,下一个周期回到 0,否则加 1。时序逻辑里用非阻塞赋值,避免混用组合赋值。面试时还要说明复位极性、清零优先级和终值判断,防止写成 0 到 17 或位宽不够。
17 进制意味着一共有 17 个状态,通常编码为 0 到 16,因此至少需要 5 位寄存器。终值判断应写 current == 5'd16,满足后下一个时钟回到 0。
异步复位不等时钟,通常写进 always 敏感列表;同步清零只在时钟边沿生效,写在时序块内部。若两者同时出现,通常异步复位优先,其次同步清零,再正常计数。
寄存器赋值使用非阻塞赋值,所有分支都给计数器确定赋值。不要在同一个寄存器上混用多个 always 块,也不要把组合逻辑清零写成会推锁存器的形式。
写完代码要主动解释为什么位宽是 5、为什么比较 16、为什么加一后回 0、复位和清零分别何时生效。这样能证明不是只背模板。
module mod17_counter (
input wire clk,
input wire rst_n,
input wire clr,
output reg [4:0] cnt
);
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt <= 5'd0;
end else if (clr) begin
cnt <= 5'd0;
end else if (cnt == 5'd16) begin
cnt <= 5'd0;
end else begin
cnt <= cnt + 5'd1;
end
end
endmodule 同步复位只保留 posedge clk,在时钟边沿内部判断 reset;异步复位要把 reset 边沿加入敏感列表,reset 到来时不等时钟立即生效。
因为 17 进制有 17 个状态,若从 0 开始计数,最后一个合法状态是 16。比较 17 会多出一个状态,变成 18 个周期。
我会至少做仿真、lint、综合后资源检查、时序约束和 STA;涉及跨时钟域还要做 CDC 检查,涉及板级接口还要结合时序裕量和实测波形验证。