真实面经题目 · 原创解析

Verilog 如何写一个带复位的计数器?

这题考时序 always 块、异步复位、同步清零、模计数边界和非阻塞赋值,重点是写出可综合且边界正确的计数器。

出现于:华为 · FPGA

60 秒回答模板

我会先明确规格:这里是异步复位、同步清零、17 进制计数器,所以计数范围是 0 到 16,需要 5 位寄存器。异步复位要放在敏感列表里,优先级最高;同步清零在时钟上升沿内部判断;正常计数时,如果当前值是 16,下一个周期回到 0,否则加 1。时序逻辑里用非阻塞赋值,避免混用组合赋值。面试时还要说明复位极性、清零优先级和终值判断,防止写成 0 到 17 或位宽不够。

考点 计数范围
难度 真实面经题
回答目标 写出异步复位、同步清零、0 到 16 循环的可综合计数器,并能解释位宽和边界。

深入解析

01

先定规格和边界

17 进制意味着一共有 17 个状态,通常编码为 0 到 16,因此至少需要 5 位寄存器。终值判断应写 current == 5'd16,满足后下一个时钟回到 0。

02

复位和清零优先级

异步复位不等时钟,通常写进 always 敏感列表;同步清零只在时钟边沿生效,写在时序块内部。若两者同时出现,通常异步复位优先,其次同步清零,再正常计数。

03

可综合写法

寄存器赋值使用非阻塞赋值,所有分支都给计数器确定赋值。不要在同一个寄存器上混用多个 always 块,也不要把组合逻辑清零写成会推锁存器的形式。

04

面试解释要补边界

写完代码要主动解释为什么位宽是 5、为什么比较 16、为什么加一后回 0、复位和清零分别何时生效。这样能证明不是只背模板。

verilog

异步复位、同步清零的 17 进制计数器

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
  • cnt 需要 5 位才能表示 0 到 16。
  • rst_n 为异步复位,clr 为同步清零,终值状态 16 后回到 0。

易错点

  • 位宽写成 4 位,导致无法表示 16。
  • 把 17 进制写成计到 17 再清零,实际多了一个状态。
  • 把同步清零写到敏感列表里,混淆同步和异步控制。
  • 时序块里使用阻塞赋值,面试解释不清寄存器更新语义。

面试官追问

同步复位和异步复位怎么改?

同步复位只保留 posedge clk,在时钟边沿内部判断 reset;异步复位要把 reset 边沿加入敏感列表,reset 到来时不等时钟立即生效。

为什么终值比较 16 而不是 17?

因为 17 进制有 17 个状态,若从 0 开始计数,最后一个合法状态是 16。比较 17 会多出一个状态,变成 18 个周期。

实现后你会用哪些检查来避免硬件问题?

我会至少做仿真、lint、综合后资源检查、时序约束和 STA;涉及跨时钟域还要做 CDC 检查,涉及板级接口还要结合时序裕量和实测波形验证。