• 你要的fpga&数字前端笔面试题都在这儿了


    转自http://ninghechuan.com

    你要的FPGA&数字前端笔面试题来了

    FPGA&ASIC基本开发流程

    题目:简述ASIC设计流程,并列举出各部分用到的工具。

    image

    勘误:Calibre是Mentor公司的

    ASIC开发基本流程

    芯片架构,考虑芯片定义、工艺、封装

    RTL设计,使用Verilog、System Verilog、VHDL进行描述

    功能仿真,理想情况下的仿真

    验证,UVM验证方法学、FPGA原型验证

    综合,逻辑综合,将描述的RTL代码映射到基本逻辑单元门、触发器上

    DFT技术,插入扫描链

    等价性检查,使用形式验证技术

    STA,静态时序分析

    布局规划,保证没有太多的内部交互,避免布线上的拥堵和困扰

    时钟树综合,均匀地分配时钟,减少设计中不同部分间的时钟偏移

    DRC,设计规则检查

    LVS,布线图和原理图进行比较

    生成GDSII

    这整个流程称为RTL2GDSII,利用GDSII来生产芯片的过程称作流片(Tapeout),以上是一个Fabless公司的简易设计流程,最后将GDSII送至Foundry生产芯片。

    题目:简述FPGA的开发流程。

    image

    FPGA开发基本流程

    系统规划,系统功能,功能模块划分

    RTL设计,使用Verilog、System Verilog、VHDL进行描述

    功能仿真,理想情况下的仿真

    综合、编译、布局布线,FPGA厂商自带工具完成

    时序仿真,时序分析约束

    板级验证

    题目:名词解释:

    ROM:Read Only Memory,只读存储器,手机、计算机等设备的存储器,但现在的所说的ROM不只是Read Only了,也是可以写入的。

    RAM:Random Access Memory,随机存取存储器,手机、计算机的运行内存。

    SRAM:Static Random-Access Memory,静态随机存取存储器,只要供电数据就会保持,但断电数据就会消失,也被称为Volatile Memory

    DRAM:Dynamic Random Access Memory,动态随机存储器,主要原理是利用电容存储电荷的多少来代表一个bit是0还是1,由于晶体管的漏电电流现象,电容会放电,所以要周期性的给电容充电,叫刷新。SRAM不需要刷新也会保持数据丢失,但是两者断电后数据都会消失,称为Volatile Memory

    SDRAM:Synchronous Dynamic Random Access Memory,同步动态随机存储器,同步写入和读出数据的DRAM。

    EEPROM:Electrically Erasable Programmable Read Only Memory,电可擦除可编程只读存储器,

    DDR:Double Data Synchronous Dynamic Random Access Memory,双倍速率同步动态随机存储器,双倍速率传输的SDRAM,在时钟的上升沿和下降沿都可以进行数据传输。我们电脑的内存条都是DDR芯片。

    FLASH: Flash Memory,闪存,非易失性固态存储,如制成内存卡或U盘。

    数字电路基础

    题目:数制转换

    R进制数转换为十进制数:按权展开,相加

    十进制数转化为R进制数:整数部分,除R取余法,除到商为0为止。小数部分,乘R取整法,乘到积为0为止。

    二进制数转化八进制数:三位一组,整数部分左边补0,小数部分右边补0。反之亦然。

    二进制数转化十六进制数:四位一组,整数部分左边补0,小数部分右边补0。反之亦然。

    题目:逻辑函数及其化简

    公式法

    卡诺图法

    题目:什么是冒险和竞争,如何消除?

    下面这个电路,使用了两个逻辑门,一个非门和一个与门,本来在理想情况下F的输出应该是一直稳定的0输出,但是实际上每个门电路从输入到输出是一定会有时间延迟的,这个时间通常叫做电路的开关延迟。而且制作工艺、门的种类甚至制造时微小的工艺偏差,都会引起这个开关延迟时间的变化。

    image

    image

    实际上如果算上逻辑门的延迟的话,那么F最后就会产生毛刺。信号由于经由不同路径传输达到某一汇合点的时间有先有后的现象,就称之为竞争,由于竞争现象所引起的电路输出发生瞬间错误的现象,就称之为冒险,FPGA设计中最简单的避免方法是尽量使用时序逻辑同步输入输出。

    • 加滤波电容,消除毛刺的影响

    • 加选通信号,避开毛刺

    • 增加冗余项,消除逻辑冒险。

    题目:用与非门等设计一个全加法器

    image

    image

    题目:MOS逻辑门

    与非门:上并下串(上为PMOS,下为NMOS)

    image

    或非门:上串下并

    image

    反相器

    image

    练习:画出Y = A·B + C的CMOS电路图

    ​ Y = (A·B + C)” = ((A·B)’·C’)’,一个反相器,两个而输入与非门。

    题目:用D触发器带同步高置数和异步高复位端的二分频的电路,画出逻辑电路,Verilog描述。

    image

    reg     Q;
    always @(posedge clk or posedge rst)begin
    if(rst == 1'b1)
       Q <= 1'b0;
    
    else if(set == 1'b1)
       Q <= 1'b1;
    
    else 
       Q <= ~Q;
    end
    

    题目:ASIC中低功耗的设计方法和思路(不适用于FPGA)

    • 合理规划芯片的工作模式,通过功耗管理模块控制芯片各模块的Clock,Reset起到控制功耗的目的。

    • 门控时钟(Clockgateing):有效降低动态功耗

    • 多电压供电:通过控制模块的电压来降低功耗

    • 多阈值电压

    时序逻辑电路基础

    题目:简述建立时间和保持时间,作图说明

    image

    建立时间Tsu(setup):触发器在时钟上升沿到来之前,其数据输入端的数据必须保持不变的最小时间。

    保持时间Th(hold):触发器在时钟上升沿到来之后,其数据输入端的数据必须保持不变的最小时间。

    题目:说明D触发器与Latch的区别。

    锁存器对电平信号敏感,在输入脉冲的电平作用下改变状态。

    D触发器对时钟边沿敏感,检测到上升沿或下降沿触发瞬间改变状态。

    https://www.vlsifacts.com/difference-latch-flip-flop/

    题目:最小周期计算

    image

    Tco:寄存器更新延迟。clock output delay,时钟触发到数据输出的最大延迟时间

    最小时钟周期:Tmin = Tco + Tdata + Tsu - Tskew。最快频率Fmax = 1/Tmin

    Tskew = Tclkd – Tclks。

    题目:什么是Clock Jitter和Clock Skew,这两者有什么区别。

    时钟抖动(Clock Jitter):指芯片的某一个给定点上时钟周期发生暂时性变化,使得时钟周期在不同的周期上可能加长或缩短。

    时钟偏移(Clock Skew):是由于布线长度及负载不同引起的,导致同一个时钟信号到达相邻两个时序单元的时间不一致。

    区别:Jitter是在时钟发生器内部产生的,和晶振或者PLL内部电路有关,布线对其没有影响。Skew是由不同布线长度导致的不同路径的时钟上升沿到来的延时不同。

    题目:什么是亚稳态,产生的原因,如何消除?

    亚稳态:是指触发器无法在某个规定时间段内达到一个确定的状态。

    原因:由于触发器的Tsu和Th不满足,当触发器进入亚稳态,使得无法预测该单元的输出,这种不稳定是会沿信号通道的各个触发器级联传播。

    消除:两级或多级寄存器同步。理论上亚稳态不能完全消除,只能降低,一般采用两级触发器同步就可以大大降低亚稳态发生的概率,再加多级触发器改善不大。

    image

    image

    题目:同步和异步

    同步复位和异步复位的区别

    同步复位是复位信号随时钟边沿触发有效。异步复位是复位信号有效和时钟无关。

    同步逻辑和异步逻辑的区别

    同步逻辑是时钟之间有固定的因果关系。异步逻辑是各时钟之间没有固定的因果关系

    同步电路和异步电路区别

    同步电路有统一的时钟源,经过PLL分频后的时钟驱动的模块,因为是一个统一的时钟源驱动,所以还是同步电路。异步电路没有统一的时钟源。

    跨时钟域处理

    题目:谈谈对Retiming技术的理解

      Retiming就是重新调整时序,例如电路中遇到复杂的组合逻辑,延迟过大,电路时序不满足,这个时候采用流水线技术,在组合逻辑中插入寄存器加流水线,进行操作,面积换速度思想。

    数字集成电路

    题目:反相器的速度与哪些因素有关?什么是转换时间(transition time)和传播延迟(propagation delay)?

    反相器的速度与哪些因素有关。

    • 电容(负载电容、自载电容、连线电容)较小,漏端扩散区的面积应尽可能小。输入电容要考虑: (1)Cgs 随栅压而变化(2)密勒效应(3)自举效应

    • 加大晶体管的尺寸(驱动能力),使晶体管的等效导通电阻(输出电阻)较小。但这同时加大自载电容和负载电容(下一级晶体管的输入电容)。

    • 提高电源电压,提高电源电压可以降低延时,即用功耗换取性能但超过一定程度后改善有限。电压过高会引起可靠性问题(氧化层击穿、热电子等)。

    Transition Time(转换时间):上升时间:从10%Vdd上升到90%Vdd的时间,下降时间L从90%Vdd下降到10%dd的时间。上升时间和下降时间统称为Transition Time,也有定义为20%到80%。

    image

    Propagation Delay(传播延时):在输入信号变化到50%Vdd到输出信号变化到50%Vdd之间的时间。

    image

    ### 题目:什么是高阻态

    高阻态:电路的一种输出状态,既不是高电平也不是低电平,如果高阻态再输入下一级电路的话,对下级电路无任何影响,可以理解为断路,不被任何东西所驱动,也不驱动任何东西

    ### 题目:什么是open-drain output?

    Open-Drain Output漏极开路输出,称为OD门,两个OD门并联可以实现线与功能,输出端外接的上拉电阻提高驱动能力

    image

    题目:相同面积的cmos与非门和或非门哪个更快?

    电子迁移率是空穴的2.5倍(在硅基CMOS工艺中),运算就是用这些大大小小的MOS管驱动后一级的负载电容,翻转速度和负载大小一级前级驱动能力相关。为了上升延迟和下降延迟相同,PMOS需要做成NMOS两倍多大小。

    载流子的迁移率,对PMOS而言,载流子是空穴;对NMOS而言,载流子是电子。

    PMOS采用空穴导电,NMOS采用电子导电,由于PMOS的载流子的迁移率比NMOS的迁移率小,所以,同样尺寸条件下,PMOS的充电时间要大于NMOS的充电时间长,在互补CMOS电路中,与非门是PMOS管并联,NMOS管串联,而或非门正好相反,所以,同样尺寸条件下,与非门的速度快,所以,在互补CMOS电路中,优先选择与非门。

    题目:画出clock gating cell的原理图。

    image

    http://vlsi.pro/integrated-clock-gating-cell/

    题目:解释一下亚稳态。

    亚稳态指触发器的输出无法再某个规定时间段内达到一个可以确定的状态,介于0和1之间,如图中的2号小球既可能回到1状态,也可能达到3状态,亚稳态也是可以传输的,导致逻辑误判系统不稳定。亚稳态有恢复时间。解决亚稳态的方法

    • 降低系统时钟
    • 用更快的FF
    • 引入同步机制,防止亚稳态传播
    • 改善时钟质量

    image

    解释一下Latch的建立时间与保持时间。

    在Latch的输入开关断开和环路开关闭合时,有效的D输入信号在跳变前(建立时间)和跳变后(保持时间)的短时间内不能发生变化。以保证数据被锁存。

    image

    image

    RTL代码

    题目:多时钟域设计中,如何处理跨时钟域

    • 单bit:两级触发器同步(适用于慢到快)

    • 多bit:采用异步FIFO,异步双口RAM

    • 加握手信号

    • 格雷码转换

    题目:编写Verilog代码描述跨时钟域信号传输,慢时钟域到快时钟域

    reg     [1:0]   signal_r;
    //------------------------------------------------------- // always @(posedge clk or negedge rst_n)begin
        if(rst_n == 1'b0)begin
            signal_r <= 2'b00;
        end
    
    else begin
           signal_r <= {signal_r[0], signal_in};
        end
    
    end
    
    assign  signal_out = signal_r[1];
    

    image

    题目:编写Verilog代码描述跨时钟域信号传输,快时钟域到慢时钟域

    ​ 跨时钟域处理从快时钟域到慢时钟域,如果是下面第一个图,cklb则可以采样到signal_a_in,但是如果只有单脉冲,如第二个图,则不能确保采样掉signal_a_in。这个时候用两级触发器同步是没有用的。

    image

    image

    代码如下:
    //Synchronous module Sync_Pulse(
        input           clka,
        input           clkb,
        input           rst_n,
        input           pulse_ina,
        output          pulse_outb,
        output          signal_outb
    );
    
    //------------------------------------------------------- reg             signal_a;
    reg             signal_b;
    reg     [1:0]   signal_b_r;
    reg     [1:0]   signal_a_r;
    
    //------------------------------------------------------- //在clka下,生成展宽信号signal_a always @(posedge clka or negedge rst_n)begin
        if(rst_n == 1'b0)begin
            signal_a <= 1'b0;
        end
        else if(pulse_ina == 1'b1)begin
            signal_a <= 1'b1;
        end
        else if(signal_a_r[1] == 1'b1)
            signal_a <= 1'b0;
        else 
           signal_a <= signal_a;
    end
    
    //------------------------------------------------------- //在clkb下同步signal_a always @(posedge clkb or negedge rst_n)begin
        if(rst_n == 1'b0)begin
            signal_b <= 1'b0;
        end
        else begin
            signal_b <= signal_a;
        end
    end
    
    //------------------------------------------------------- //在clkb下生成脉冲信号和输出信号 always @(posedge clkb or negedge rst_n)begin
        if(rst_n == 1'b0)begin
           signal_b_r <= 2'b00;
       end
       else begin
           signal_b_r <= {signal_b_r[0], signal_b};
        end
    end
    
    assign    pulse_outb = ~signal_b_r[1] & signal_b_r[0];
    assign    signal_outb = signal_b_r[1];
    
    //------------------------------------------------------- //在clka下采集signal_b[1],生成signal_a_r[1]用于反馈拉低signal_a always @(posedge clka or negedge rst_n)begin
        if(rst_n == 1'b0)begin
           signal_a_r <= 2'b00;
        end
       else begin
           signal_a_r <= {signal_a_r[0], signal_b_r[1]};
        end
    
    end
    
    endmodule
    

    这部分代码参考:

    作者:肉娃娃  

    出处:https://home.cnblogs.com/u/rouwawa/

    慢到快,单脉冲

    image

    慢到快,长信号传递

    image

    快到慢,单脉冲

    image

    单脉冲,长信号传递

    image

    上述代码可以实现快到慢,慢到快时钟域任意转换,pulse_outb会输出单个脉冲,signal_outb输出信号时间长度最少为clkb的四个周期,当signal_a_in的信号长度大于clkb的四个周期,signal_outb输出与signal_a_in时间长度相同。

    题目:用Verilog实现1bit信号边沿检测功能,输出一个周期宽度的脉冲信号。

    • 上升沿
    • 下降沿
    • 上升沿或下降沿
    input clk, rst_n, data; 
    output data_edge;
    
    module Edge_Detect(
        input       clk,
        input       rst_n,
        input       data,
        output      pos_edge,
        output      neg_edge,
        output      data_edge
        );
    
    reg     [1:0]   data_r;
    always @(posedge clk or negedge rst_n)begin
        if(rst_n == 1'b0)begin
            data_r <= 2'b00;
        end
        else begin
            data_r <= {data_r[0], data};
        end
    end
    
    assign  pos_edge = ~data_r[1] & data_r[0];
    assign  neg_edge = data_r[1] & ~data_r[0];
    assign  data_edge = pos_edge | neg_edge;
    
    endmodule
    

    ​ 怎么记忆:上升沿之前是0,现在变成1,所以上个周期传输到的signal_r[1]是0所以取反。反之亦然。

    题目:用Verilog实现串并转换

    • lsb优先
    • msb优先
    input clk, rst_n, data_i; 
    output [7:0] data_o;
    
    module Deserialize(
        input           clk,
        input           rst_n,
        input           data_i,
        output   reg [7:0] data_o
        );
    
    //lsb first /* always @(posedge clk or negedge rst_n)begin if(rst_n == 1'b0)begin data_o <= 8'b0; end else begin data_o <= {data_o[6:0], data_i}; end end */
    
    //msb first reg     [2:0]   cnt;
    always @(posedge clk or negedge rst_n)begin
        if(rst_n == 1'b0)begin
            data_o <= 8'b0;
            cnt <= 3'd0;
        end
        else begin
            data_o[7 - cnt] <= data_i;
            cnt <= cnt + 1'b1;
        end
    end
    
    endmodule
    

    题目:序列检测器:有“101”序列输入时输出为1,其他输入情况下,输出为0。画出状态转移图,并用Verilog描述。

    input clk, rst_n, data; 
    output flag_101;
    

    image

    module Detect_101(
        input           clk,
        input           rst_n,
        input           data,
        output          flag_101
        );
    
    parameter   S0 = 0,
                S1 = 1,
                S2 = 2,
                S3 = 3;
    
    reg     [1:0]   state;
    
    always @(posedge clk or negedge rst_n)begin
        if(rst_n == 1'b0)begin
            state <= S0;
        end
        else begin
            case(state)
            S0: 
                if(data == 1)
                    state <= S1;
                else 
                    state <= S0;
            S1: 
                if(data == 0)
                    state <= S2;
                else 
                    state <= S1;
            S2:
                if(data == 1)
                    state <= S3;
                else 
                    state <= S0;
            S3:
                if(data == 1)
                    state <= S1;
                else 
                    state <= S2;
            endcase
        end
    end
    
    assign  flag_101 = (state == S3)? 1'b1: 1'b0;
    
    endmodule
    

    题目:用Verilog实现一个异步双端口ram,深度16,位宽8bit。A口读出,B口写入。支持片选,读写请求,要求代码可综合。

    module dpram_16x8 ( 
        input clk_a, 
        input [3:0] addr_a, 
        output [7:0] dout_a, 
        ...
        input clk_b, 
        input [7:0] din_b, 
        input [3:0] addr_b, 
        ... 
    ); 
    ... 
    endmodule
    
    module Dual_Port_Sram
    #(
        parameter           ADDR_WIDTH  =   4,
        parameter           DATA_WIDTH  =   8,
        parameter           DATA_DEPTH  =   1 << ADDR_WIDTH
    )
    (
        input               clka,
        input               clkb,
        input               rst_n,
        input               csen_n,
        //Port A Signal     input       [ADDR_WIDTH-1:0]   addra,
        output   reg   [DATA_WIDTH-1:0]   data_a,
        input               rdena_n,
        //Port B Signal     input       [ADDR_WIDTH-1:0]   addrb,
        input               wrenb_n,
        input       [DATA_WIDTH-1:0]    data_b 
    );
    
    integer     i;
    reg     [DATA_WIDTH-1:0]   register[DATA_DEPTH-1:0];
    
    always @(posedge clkb or negedge rst_n)begin
        if(rst_n == 1'b0)begin
            for(i = 0; i < DATA_DEPTH; i = i + 1)
                register[i] <= 'b0000_1111;
        end
        else if(wrenb_n == 1'b0 && csen_n == 1'b0)
            register[addrb] <= data_b;  
    end
    
    always @(posedge clka or negedge rst_n)begin
        if(rst_n == 1'b0)begin
            data_a <= 0;
        end
        else if(rdena_n == 1'b0 && csen_n == 1'b0)
            data_a <= register[addra];
        else 
            data_a <= data_a;
    end
    
    endmodule 
    

    题目:用Verilog实现三分频电路,要求输出50%占空比。

    module Div_three(
        input       clk,
        input       rst_n,
        output      div_three
    );
    
    reg     [1:0]   cnt;  
    reg             div_clk1;
    reg             div_clk2;
    always @(posedge clk or negedge rst_n)begin
        if(rst_n == 1'b0)begin
            cnt <= 0;
        end
        else if(cnt == 2)
            cnt <= 0;
        else begin
            cnt <= cnt + 1;
        end
    end
    
    always @(posedge clk or negedge rst_n)begin
        if(rst_n == 1'b0)begin
            div_clk1 <= 0;
        end
        else if(cnt == 0)begin
            div_clk1 <= ~div_clk1;
        end
        else 
            div_clk1 <= div_clk1;
    end
    
    always @(negedge clk or negedge rst_n)begin
        if(rst_n == 1'b0)begin
            div_clk2 <= 0;
        end
        else if(cnt == 2)begin
            div_clk2 <= ~div_clk2;
        end
        else 
            div_clk2 <= div_clk2;
    end
    
    assign  div_three = div_clk2 ^ div_clk1;
    
    endmodule 
    

    题目:用Verilog实现glitch free时钟切换电路。输入sel,clka,clkb,sel为1输出clka,sel为0输出clkb。

    part1是比较垃圾的写法

    part2 是两个时钟源是倍数的关系

    part3是两个时钟源为异步时钟的关系

    module Change_Clk_Source(
        input           clk1,
        input           clk0,
        input           select,
        input           rst_n,
        output          outclk
    );
    
    //------------------------------------------------------- //part 1 //assign outclk = (clk1 & select) | (~select & clk0); 
    //------------------------------------------------------- //part 2 reg     out1;
    reg     out0;
    always @(negedge clk1 or negedge rst_n)begin
        if(rst_n == 1'b0)begin
            out1 <= 0;
        end
        else begin
            out1 <= ~out0 & select;
        end
    end
    
    
    always @(negedge clk0 or negedge rst_n)begin
        if(rst_n == 1'b0)begin
            out0 <= 0;
        end
        else begin
            out0 <= ~select & ~out1;
        end
    end
    
    assign outclk = (out1 & clk1) | (out0 & clk0);
    /* //------------------------------------------------------- //part 3 reg out_r1; reg out1; reg out_r0; reg out0; always @(posedge clk1 or negedge rst_n)begin if(rst_n == 1'b0)begin out_r1 <= 0; end else begin out_r1 <= ~out0 & select; end end always @(negedge clk1 or negedge rst_n)begin if(rst_n == 1'b0)begin out1 <= 0; end else begin out1 <= out_r1; end end always @(posedge clk0 or negedge rst_n)begin if(rst_n == 1'b0)begin out_r0 <= 0; end else begin out_r0 <= ~select & ~out1; end end always @(negedge clk0 or negedge rst_n)begin if(rst_n == 1'b0)begin out0 <= 0; end else begin out0 <= out_r0; end end assign outclk = (out1 & clk1) | (out0 & clk0); */
    endmodule 
    

    两个时钟源频率呈倍数关系

    image

    两个时钟源是异步时钟。

    image

    题目:用Verilog实现异步复位同步释放电路。

    module Sys_Rst(
        input       clk,
        input       rst,
        output      sys_rst
    );
    
    reg     rst_r0;
    reg     rst_r1;
    
    always @(posedge clk or posedge rst)begin
        if(rst)begin
            rst_r0 <= 1'b1;
            rst_r1 <= 1'b1;
        end
        else begin
            rst_r0 <= 1'b0;
            rst_r1 <= rst_r0;
        end
    end
    
    assign  sys_rst = rst_r1;
    
    endmodule
    

    题目:用Verilog实现按键抖动消除电路,抖动小于15ms,输入时钟12MHz。

    module debounce(
        input           clk,//12Mhz     input           rst_n,
        input           key_in,
        output          key_flag
    );
    
    parameter   JITTER  =   240;//12Mhz / (1/20ms) 
    reg   [1:0]     key_r;
    wire             change;
    reg   [15:0]    delay_cnt;
    
    always @(posedge clk or negedge rst_n)begin
        if(rst_n == 1'b0)begin
            key_r <= 0;
        end
        else begin
            key_r <= {key_r[0],key_in};
        end
    end
    
    assign  change = (~key_r[1] & key_r[0]) | (key_r[1] & ~key_r[0]);
    
    always @(posedge clk or negedge rst_n)begin
        if(rst_n == 1'b0)begin
            delay_cnt <= 0;
        end
        else if(change == 1'b1)
            delay_cnt <= 0;
        else if(delay_cnt == JITTER)
            delay_cnt <= delay_cnt;
        else 
            delay_cnt <= delay_cnt + 1;
    end
    
    assign  key_flag = ((delay_cnt == JITTER - 1) && (key_in == 1'b1))? 1'b1: 1'b0;
    
    endmodule
    

    题目:用Verilog实现一个同步FIFO,深度16,数据位宽8bit。

    module Syn_fifo
    #(
        parameter   DATA_WIDTH  =   8,
        parameter   ADDR_WIDTH  =   4,
        parameter   RAM_DEPTH   =   (1 << ADDR_WIDTH)
    )
    (
        input           clk,
        input           rst_n,
        input   [DATA_WIDTH-1:0]    data_in,
        input           wr_en,
        input           rd_en,
        output reg  [DATA_WIDTH-1:0]    data_out,
        output          empty,          //fifo empty     output          full            //fifo full );
    
    reg     [ADDR_WIDTH-1:0]    wr_cnt;
    reg     [ADDR_WIDTH-1:0]    rd_cnt;
    reg     [ADDR_WIDTH-1:0]    status_cnt;
    reg     [DATA_WIDTH-1:0]    data_ram;
    
    //------------------------------------------------------- assign  full = (status_cnt == (RAM_DEPTH-1))? 1'b1: 1'b0;
    assign  empty = (status_cnt == 0)? 1'b1: 1'b0;
    
    
    //Syn reg     rd_en_r;
    always @(posedge clk or negedge rst_n)begin
        if(rst_n == 1'b0)begin
            rd_en_r <= 0;
        end
        else begin
            rd_en_r <= rd_en;
        end
    end
    
    
    //------------------------------------------------------- always @(posedge clk or negedge rst_n)begin
        if(rst_n == 1'b0)begin
            wr_cnt <= 0;
        end
        else if(wr_cnt == RAM_DEPTH-1)
            wr_cnt <= 0;
        else if(wr_en)begin
            wr_cnt <= wr_cnt + 1'b1;
        end
        else 
            wr_cnt <= wr_cnt;
    end
    
    always @(posedge clk or negedge rst_n)begin
        if(rst_n == 1'b0)begin
            rd_cnt <= 0;
        end
        else if(rd_cnt == RAM_DEPTH-1)
            rd_cnt <= 0;
        else if(rd_en)begin
            rd_cnt <= rd_cnt + 1'b1;
        end
        else 
            rd_cnt <= rd_cnt;
    end
    
    always @(posedge clk or negedge rst_n)begin
        if(rst_n == 1'b0)begin
            data_out <= 0;
        end
        else if(rd_en_r)begin
            data_out <= data_ram;
        end
    end
    
    
    always @(posedge clk or negedge rst_n)begin
        if(rst_n == 1'b0)begin
            status_cnt <= 0;
        end
        else if(rd_en && !wr_en && (status_cnt != 0))begin
            status_cnt <= status_cnt - 1;
        end
        else if(wr_en && !rd_en && (status_cnt != RAM_DEPTH-1))
            status_cnt <= status_cnt + 1;
        else 
            status_cnt <= status_cnt;
    end
    
    //------------------------------------------------------- //Syn_Dual_Port_RAM integer     i;
    reg     [DATA_WIDTH-1:0]   register[RAM_DEPTH-1:0];
    
    always @(posedge clk or negedge rst_n)begin
        if(rst_n == 1'b0)begin
            for(i = 0; i < RAM_DEPTH; i = i + 1)
                register[i] <= 0;
        end
        else if(wr_en == 1'b1)
            register[wr_cnt] <= data_in;  
    end
    
    always @(posedge clk or negedge rst_n)begin
        if(rst_n == 1'b0)begin
            data_ram <= 0;
        end
        else if(rd_en == 1'b1)
            data_ram <= register[rd_cnt];
        else 
            data_ram <= data_ram;
    end
    
    endmodule
    

    Reference

    http://www.asic-world.com/examples/verilog/syn_fifo.html

    题目:IIC协议的RTL设计

    题目:Verilog设计异步FIFO

    Verilog设计异步FIFO

    题目:FIFO最小深度计算

    你问我FIFO有多深

  • 相关阅读:
    [leetcode]Search for a Range
    Codeforces 432 D. Prefixes and Suffixes
    FZU2127:养鸡场
    安德鲁斯----多媒体编程
    hive RegexSerDe View
    Android 随着输入框控件的清除功能ClearEditText,抄IOS输入框
    Eclipse——热键&amp;Help
    图像形态学操作—腐蚀扩展深度
    基于速度学习机的局部感受野
    Qt:使用Model-View,动态的加载显示数据
  • 原文地址:https://www.cnblogs.com/lionsde/p/10597036.html
Copyright © 2020-2023  润新知