FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训
登录
首页-所有问题-其他-正文

FPGA笔试题:用Verilog写一个同步FIFO,并考虑深度为2的幂次方的情况。

芯片小学生芯片小学生
其他
3天前
0
0
7
这道题在各大公司的FPGA笔试和面试中出现的频率极高,堪称“典中典”。题目要求通常包括:1. 编写同步FIFO的Verilog代码,包含写使能、读使能、数据输入输出、满空标志等。2. 深度参数化,且要求深度为2的幂次方(如16,32,64),以便用指针高效判断满空。3. 可能会追问如何判断“满”和“空”,以及格雷码指针的作用。有没有朋友可以分享一下标准的实现代码和设计思路?一起讨论下其中的关键点和易错点。
芯片小学生

芯片小学生

这家伙真懒,几个字都不愿写!
212700
分享:
FPGA和嵌入式软件开发,对于应届生来说哪个更好找工作?上一篇
想成为一名合格的FPGA工程师,需要学习哪些知识和技能?求推荐学习路线。下一篇
回答列表总数:18
  • aipowerup

    aipowerup

    我直接贴一段我常用的代码吧,深度参数用DEPTH,位宽用DATA_WIDTH。核心是读写指针ptr_w和ptr_r,用格雷码打拍同步到对方时钟域(虽然同步FIFO是一个时钟,但用格雷码是好习惯)。空标志assign empty = (rgray_w == rgray_r),满标志assign full = (wgray_next == rgray_r_sync)但要注意指针比较前要同步。关键点:1. 读写指针用格雷码可以避免跨时钟域问题,即使同步FIFO也推荐。2. 满空判断用格雷码比较时,需要将格雷码转换为二进制或者用扩展位方法。我常用的是指针位宽比地址多一位,最高位区分绕圈。当指针除了最高位外相同且最高位不同就是满。代码里注意用非阻塞赋值,RAM用块RAM实现。

    3天前
  • 数字电路初学者

    数字电路初学者

    同步FIFO这个题确实太经典了,我面试被问过好几次。我的思路是用双端口RAM做存储,读写指针用格雷码。深度是2的幂次方的话,指针可以直接用二进制,满空判断也简单。空就是读写指针相等,满的话我习惯用最高位当标志位,比如深度8,指针用4位,当读写指针高两位相反但低三位相同时就是满。代码结构一般是参数化深度和位宽,然后always块处理指针和标志位。注意读写使能同时有效时的优先级,一般同时操作没问题。易错点是满空标志的生成时序,最好用组合逻辑,但小心毛刺。

    3天前
  • aipowerup

    aipowerup

    贴一段我常用的参数化代码思路吧。先定义参数ADDR_WIDTH = log2(DEPTH)。指针位宽是ADDR_WIDTH+1。always @(posedge clk) begin if (rst) begin wptr <= 0; rptr <= 0; end else begin if (wr_en && !full) begin mem[wptr[ADDR_WIDTH-1:0]] <= data_in; wptr <= wptr + 1; end if (rd_en && !empty) begin data_out <= mem[rptr[ADDR_WIDTH-1:0]]; rptr <= rptr + 1; end end end assign full = (wptr == {~rptr[ADDR_WIDTH], rptr[ADDR_WIDTH-1:0]}); assign empty = (wptr == rptr); 注意mem用reg数组,深度是2ADDR_WIDTH。

    3天前
  • FPGA入门生

    FPGA入门生

    我一般习惯用格雷码来传递指针,跨时钟域的时候有用,虽然题目是同步FIFO,但面试官可能想考察这个知识点。深度为2的幂次方时,格雷码相邻值只有一位变化,能降低亚稳态风险。判断满空的话,如果直接用二进制指针,满的条件是(wptr[ADDR_WIDTH] != rptr[ADDR_WIDTH]) && (wptr[ADDR_WIDTH-1:0] == rptr[ADDR_WIDTH-1:0])。空就是完全相等。易错点嘛,满空标志生成要用组合逻辑还是时序逻辑?通常组合逻辑生成快,但可能产生毛刺,看设计需求。

    3天前
  • 数字电路初学者

    数字电路初学者

    同步FIFO啊,笔试老熟人了。核心就是两个指针,写指针和读指针,在时钟上升沿动作。深度是2的幂次方,比如parameter DEPTH = 16,这样指针位宽多取一位,最高位用来区分“套圈”。满的判断是(wptr == {~rptr[ADDR_WIDTH], rptr[ADDR_WIDTH-1:0]}),空的判断是(wptr == rptr)。代码骨架大概是这样,注意用非阻塞赋值。

    3天前
  • 硅农实习生

    硅农实习生

    直接给个简单代码框架吧,深度参数用DEPTH,宽度用DATA_WIDTH。假设是2的幂次方。

    module sync_fifo #(parameter DATA_WIDTH=8, DEPTH=16) (input clk, rst_n, wr_en, rd_en, input [DATA_WIDTH-1:0] din, output reg [DATA_WIDTH-1:0] dout, output full, empty);

    localparam PTR_WIDTH = $clog2(DEPTH)+1;
    reg [PTR_WIDTH-1:0] wr_ptr, rd_ptr;
    reg [DATA_WIDTH-1:0] mem [0:DEPTH-1];

    // 指针更新
    always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin wr_ptr<=0; rd_ptr<=0; end
    else begin
    if(wr_en && !full) begin wr_ptr<=wr_ptr+1; mem[wr_ptr[PTR_WIDTH-2:0]]<=din; end
    if(rd_en && !empty) begin rd_ptr<=rd_ptr+1; dout<=mem[rd_ptr[PTR_WIDTH-2:0]]; end
    end
    end

    // 满空判断
    assign empty = (wr_ptr == rd_ptr);
    assign full = (wr_ptr[PTR_WIDTH-1] != rd_ptr[PTR_WIDTH-1]) && (wr_ptr[PTR_WIDTH-2:0] == rd_ptr[PTR_WIDTH-2:0]);

    endmodule

    注意,这里指针低部分(去掉最高位)直接当地址用,因为深度是2的幂次方,所以不会溢出。满空判断就是上面说的。实际笔试可能要求用格雷码指针,但同步FIFO一般不需要,不过为了扩展性可以写上。

    3天前
  • 芯片设计新人

    芯片设计新人

    我面试被问过好几次。我的写法是参数化深度和宽度,用localparam定义指针宽度(深度位宽+1)。读写指针用格雷码,但同步FIFO其实用二进制也行,面试官可能想看你知不知道格雷码在异步FIFO里的作用。满空判断的关键:空是读写指针完全相等(包括扩展位);满是读写指针最高位不同,其余位相同。代码里,满信号要在写操作时组合逻辑产生,确保同一周期能阻止写入。易错点是复位后指针要对齐,空满标志初始状态要对(通常空有效,满无效)。

    3天前
  • 嵌入式小白打怪

    嵌入式小白打怪

    同步FIFO确实经典,核心就是读写指针和满空判断。深度是2的幂次方的话,指针可以直接用二进制计数,然后转格雷码来跨时钟域(虽然这里是同步的,但习惯这么写)。满的判断是(wr_ptr == rd_ptr)但方向相反,空就是两者相等。我一般会用一个额外的位来扩展指针,比如深度8,用4位指针,最高位用来区分满和空。代码结构就是always块更新指针和生成标志,一个RAM块(用reg数组模拟)存数据。注意写满不写,读空不读就行。

    3天前
  • 电子爱好者小张

    电子爱好者小张

    分享个简洁的实现要点吧。1. 存储用二维reg或者例化RAM。2. 读写指针每次+1时要取模,因为深度是2的幂,所以直接溢出截断低地址位就行,比如 ptr_next = ptr + 1; ptr = ptr_next; 地址取 ptr[$clog2(DEPTH)-1:0]。3. 满空判断用指针的整个位宽比较,不需要单独最高位,因为深度2的幂时,指针从0加到DEPTH-1再回到0,其二进制值会自然循环。但这样判断满需要区分“真满”和“真空”时指针相等的情况,所以通常还是多一位。我推荐用计数器记录FIFO内数据个数,最简单直观,满空直接比较计数器和0、DEPTH。但面试官可能想要指针方案。易错点:复位后指针清零,满空标志要正确。测试时多覆盖边界情况,比如同时读写、写满、读空。

    3天前
  • 码电路的小王

    码电路的小王

    我一般直接写个可综合的版本,深度参数化用$clog2。关键确实在指针。为什么用格雷码?因为读写指针是跨时钟域比较吗?不对,同步FIFO是同一个时钟,其实可以不用格雷码,用二进制也行。但很多题目要求格雷码可能是为了和异步FIFO统一思路,或者考察知识迁移。实际写的时候,我习惯把指针多设一位作为wrap-around位。比如深度8,指针用4位。空:wr_ptr == rd_ptr;满:wr_ptr[3] != rd_ptr[3] && wr_ptr[2:0] == rd_ptr[2:0]。注意写使能和读使能同时有效时,如果满了就不能写,空了就不能读,但非满非空时可以同时操作。代码里标志逻辑要用组合逻辑还是时序看要求,笔试通常组合生成,但实际可能会打一拍。

    3天前
  • FPGA学号2

    FPGA学号2

    同步FIFO啊,笔试老熟人了。我的思路是用双端口RAM做存储,读写指针用格雷码。深度是2的幂,这样指针绕回的时候用位宽截断就行,比如深度16,指针用5位,低4位是地址,最高位用来区分是否绕了一圈。判断空就是读写指针完全相等,判断满是读写指针最高位不同但低地址位相同。代码骨架大概这样:module sync_fifo #(parameter DEPTH=16, WIDTH=8) (input clk, rst_n, wr_en, rd_en, input [WIDTH-1:0] din, output reg [WIDTH-1:0] dout, output full, empty); 然后定义读写指针reg [$clog2(DEPTH):0] wr_ptr, rd_ptr; 存RAM。always @(posedge clk) if (wr_en && !full) ram[wr_ptr[$clog2(DEPTH)-1:0]] <= din; 指针更新和标志生成是重点,记得用格雷码转换函数减少亚稳态风险。易错点:满空标志要用次态指针判断,别用现态,不然会滞后一个周期。

    3天前
  • FPGA实验小白

    FPGA实验小白

    从经验分享角度,这道题除了写代码,面试官常问:为什么深度要2的幂次方?答案就是为了指针回绕方便,用二进制加法自然溢出就能实现,不需要比较器判断是否达到深度-1。还有,格雷码指针在同步FIFO里不是必须的,但如果你写了,面试官可能会觉得你考虑周全,知道异步FIFO的常见做法。另一个关键点是FIFO的“保守”设计:满空标志可以提前一点或延迟一点生成,比如“几乎满”“几乎空”,但笔试题一般要求精确。最后,测试时一定要覆盖边界情况:连续写直到满、连续读直到空、同时读写等。代码风格上,建议用 parameter 定义深度,方便修改。

    3天前
1
2
跳至
我要回答answer.notCanPublish
回答被采纳奖励100个积分
FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训
请先登录