FPGA面试笔试题

 

1、什么是同步逻辑和异步逻辑?

 

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

〔补充〕:

同步时序逻辑电路的特点:各触发器的时钟端全部连接在一起,并接在系统时钟端,只有当时钟脉冲到来时,电路的状态才能改变。改变后的状态将一直保持到下一个时钟脉冲的到来,此时无论外部输入有无变化,状态表中的每个状态都是稳定的。

异步时序逻辑电路的特点:电路中除可以使用带时钟的触发器外,还可以使用不带时钟的触发器和延迟元件作为存储元件,电路中没有统一的时钟,电路状态的改变由外部输入的变化直接引起。

 

2、同步电路和异步电路的区别是什么?

 

同步电路:存储电路中所有触发器的时钟输入端都接同一个时钟脉冲源,因而所有触发器的状态的变化都与所加的时钟脉冲信号同步。

异步电路:电路没有统一的时钟,有些触发器的时钟输入端与时钟脉冲源相连,这有这些触发器的状态变化与时钟脉冲同步,而其他的触发器的状态变化不与时钟脉冲同步。

 

3、时序设计的实质:

 

电路设计的难点在时序设计,时序设计的实质就是满足每一个触发器的建立/保持时间的而要求。

 

4、建立时间与保持时间的概念?

 

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

保持时间:触发器在时钟上升沿到来之后,其数据输入端的数据必须保持不变的时间。 不考虑时钟的偏移,D2的建立时间不能大于(时钟周期T-D1数据最迟到达时间T1max+T2max);保持时间不能大于(D1数据最快到达时间T1min+T2min);否则D2的数据将进入亚稳态并向后级电路传播。

 

5、什么是亚稳态?为什么两级触发器可以防止亚稳态传播?

 

亚稳态是指触发器无法在某个规定的时间段内到达一个可以确认的状态。 使用两级触发器来使异步电路同步化的电路其实叫做“一步同位器”,他只能用来对一位异步信号进行同步。 两级触发器可防止亚稳态传播的原理:假设第一级触发器的输入不满足其建立保持时间,它在第一个脉冲沿到来后输出的数据就为亚稳态,那么在下一个脉冲沿到来之前,其输出的亚稳态数据在一段恢复时间后必须稳定下来,而且稳定的数据必须满足第二级触发器的建立时间,如果都满足了,在下一个脉冲沿到来时,第二级触发器将不会出现亚稳态,因为其输入端的数据满足其建立保持时间。同步器有效的条件:同步器有效的条件:第一级触发器进入亚稳态后的恢复时间+第二级触发器的建立时间 <= 时钟周期。 更确切地说,输入脉冲宽度必须大于同步时钟周期与第一级触发器所需的保持时间之和。最保险的脉冲宽度是两倍同步时钟周期。所以,这样的同步电路对于从较慢的时钟域来的异步信号进入较快的时钟域比较有效,对于进入一个较慢的时钟域,则没有作用。

 

6、对竞争冒险的理解,以及如何消除?

 

在组合逻辑中,由于门的输入信号通路中经过了不同的延时,导致到达该门的时间不一致叫竞争。产生毛刺叫冒险。如果布尔式中有相反的信号则可能产生竞争和冒险现象。

解决方法:一是添加布尔式的消去项,二是在芯片外部加电容。

 

7、FPGA结构一般分为三部分:

 

可编程逻辑块(CLB)、可编程I/O模块和可编程内部连线。

 

8、用VHDL/Veilog HDL语言开发可编程逻辑电路的完整流程:

 

文本编辑享有→功能仿真→逻辑综合→布局布线→时序仿真。

综合其目的是将多个模块化设计文件合并为一个网表文件,供布局布线使用,网表中包含了目标器件中的逻辑单元和互连的信息。

布局布线就是根据设计者指定的约束条件(如面积、延时、时钟等)、目标器件的结构资源和工艺特性,以最优的方式对逻辑元件布局,并准确地实现元件间的互连,完成实现方案(网表)到使实际目标器件(FPGA或CPLD)的变换。

 

9、FPGA过程中的仿真有三种:

 

行为仿真、逻辑仿真、时序仿真。

 

10、锁存器(latch)和触发器(flip-flop)区别?

 

电平敏感的存储期间称为锁存器。可分为高电平锁存器和低电平锁存器,用于不同时钟之间的信号同步。

有交叉耦合的门构成的双稳态的存储原件称为触发器。分为上升沿触发和下降沿触发。可以认为是两个不同电平敏感的锁存器串连而成。前一个锁存器决定了触发器的建立时间,后一个锁存器则决定了保持时间。

 

11、系统最高速度计算(最快时钟频率)和流水线设计思想:

 

同步电路的速度是指同步系统时钟的速度,同步时钟愈快,电路处理数据的时间间隔越短,电路在单位时间内处理的数据量就愈大。假设Tco是触发器的输入数据被时钟打入到触发器到数据到达触发器输出端的延时时间;Tdelay是组合逻辑的延时;Tsetup是D触发器的建立时间。假设数据已被时钟打入D触发器,那么数据到达第一个触发器的Q输出端需要的延时时间是Tco,经过组合逻辑的延时时间为Tdelay,然后到达第二个触发器的D端,要希望时钟能在第二个触发器再次被稳定地打入触发器,则时钟的延迟必须大于Tco+Tdelay+Tsetup,也就是说最小的时钟周期Tmin=Tco+Tdelay+Tsetup,即最快的时钟频率Fmax=1/Tmin。FPGA开发软件也是通过这种方法来计算系统最高运行速度Fmax。因为Tco和Tsetup是由具体的器件工艺决定的,故设计电路时只能改变组合逻辑的延迟时间Tdelay,所以说缩短触发器间组合逻辑的延时时间是提高同步电路速度的关键所在。由于一般同步电路都大于一级锁存,而要使电路稳定工作,时钟周期必须满足最大延时要求。故只有缩短最长延时路径,才能提高电路的工作频率。可以将较大的组合逻辑分解为较小的N块,通过适当的方法平均分配组合逻辑,然后在中间插入触发器,并和原触发器使用相同的时钟,就可以避免在两个触发器之间出现过大的延时,消除速度瓶颈,这样可以提高电路的工作频率。这就是所谓"流水线"技术的基本设计思想,即原设计速度受限部分用一个时钟周期实现,采用流水线技术插入触发器后,可用N个时钟周期实现,因此系统的工作速度可以加快,吞吐量加大。注意,流水线设计会在原数据通路上加入延时,另外硬件面积也会稍有增加。

 

12、用D触发器实现2倍分频的Verilog描述?

 

module divide2( clk , clk_o, reset);
input   clk , reset;
output  clk_o;
wire  in;  
reg   out ;
always @ ( posedge clk or posedge reset)
begin
    if ( reset)
        out <= 0;
    else
        out <= in;
end
assign in = ~out;
assign clk_o = out;
endmodule            

 

13、用Verilog或VHDL写一段代码,实现10进制计数器。

 

`timescale 1ns/10ps
module counter10(clk,rst,count);
    input        clk,rst;
    output       [3:0]    count;
    reg          [3:0]    q;
assign count = q;
always@(posedge clk or negedge rst)
begin
    if(!rst)
        q <= 0;
    else if(q >= 4'd9)
    q <= 0;
    else
    q <= q + 1;
end
endmodule 

 

14、请用Verilog描述四位的全加法器。

 

module add_4(
    input     [3:0]    a,b,
    output    [3:0]    sum,
    output    cout,
    input     cin
);
assign{cout,sum} = a+b+cin;
endmodule

 

15、画出可以检测10010串的状态图,并用verilog实现。

 

module     seq_dect(
    input    wire    clk,
    input    wire    rst_n,
    input    wire    num_in,
    output   wire    res
);
    parameter   Idle      =    3'b000,    //
                s1        =    3'b001,    //1
                s2        =    3'b010,    //10
                s3        =    3'b011,    //100
                s4        =    3'b100,    //1001
                s5        =    3'b101,    //10010
                s6        =    3'b110,    //10001
                s7        =    3'b111;    //1000

    reg[2:0]    current_state;
    reg[2:0]    next_state;
    
    always@(posedge    clk    or    posedge    rst_n)
    begin
        if(rst_n    ==    1'b0)
        begin
            current_state    =    Idle;
            next_state       =    Idle;
        end
        else    begin
            current_state    =     next_state;
        end
    end
    
    assign res =   (current_state==s4 && num_in==0)? 1 : 0;
    
    always@(posedge    clk    or    negedge    rst_n)
    begin
        if(rst_n    ==    1'b0)
        begin
            current_state    <=      Idle;
        end
        else    begin
            case(current_state)
                    Idle:begin
                        if(num_in    ==    1'b0)
                            next_state    <=  Idle;
                        else
                            next_state    <=  s1;    
                    end
                    s1:begin
                        if(num_in    ==    1'b0)
                            next_state    <=  s2;
                        else
                            next_state    <=  s1;    
                    end
                    s2:begin
                        if(num_in    ==    1'b0)
                            next_state    <=  s3;
                        else
                            next_state    <=  s1;    
                    end
                    s3:begin
                        if(num_in    ==    1'b0)
                            next_state    <=  s7;
                        else
                            next_state    <=  s4;
                    end
                    s4:begin
                        if(num_in    ==    1'b0)
                            next_state    <=  s5;
                        else
                            next_state    <=  s1;
                    end
                    s5:begin
                        if(num_in    ==    1'b0)
                            next_state    <=  s3;
                        else
                            next_state    <=  s1;
                    end
                    s6:begin
                        if(num_in    ==    1'b0)
                            next_state    <=  s2;
                        else
                            next_state    <=  s1;
                    end
                    s7:begin
                        if(num_in    ==    1'b0)
                            next_state    <=  s7;
                        else
                            next_state    <=  s1;
                    end
                    default:begin
                        current_state    <=  Idle;
                    end
            endcase
        end    
    end
endmodule

 

16、用Verilog设计一个5分频器。

 

方法一:5分频,奇数分频都可以类似这么做,只需要改div1和div2的参数。div1为奇数分频除2的余数。采用上升延和下降延分别触发不同波形,最后叠加的方式产生奇数分频。

    module divfreq(clk, clk1x, rst, clk1xpose, clk1xnege, coutpose, coutnege);

        input clk;
        input rst; 
        output clk1x;
        output clk1xpose;
        output clk1xnege;
        output[2:0] coutpose;
        output[2:0] coutnege;
        reg clk1xpose;
        reg clk1xnege;
        reg[2:0] coutpose;
        reg[2:0] coutnege;
        
        parameter div1 = 2 , div2 = 4;
        // div1 = ( 5 - 1 ) / 2, div2 = 5 - 1
        assign clk1x = clk1xpose | clk1xnege;
        always@(posedge clk or negedge rst)
        begin    
            if(!rst)
                clk1xpose = 0;
            else if(coutpose == div1)
                clk1xpose = ~clk1xpose;
            else if(coutpose == div2)
                clk1xpose = ~clk1xpose;
            else
                clk1xpose = clk1xpose;
        end
        
        always@(negedge clk or negedge rst)
        begin
            if(!rst)
                clk1xnege = 0;
            else if(coutnege == div1)
                clk1xnege = ~clk1xnege;
            else if(coutnege == div2)
                clk1xnege = ~clk1xnege;
            else
                clk1xnege = clk1xnege; 
        end
        
        always@(posedge clk or negedge rst)
        begin
            if(!rst)
                coutpose = 0;
            else if(coutpose == div2)
                outpose = 0;
            else
                coutpose = coutpose + 1; 
        end
        
        always@(negedge clk or negedge rst) 
        begin
            if(!rst)
                coutnege = 0;
            else if(coutnege == div2)
                coutnege = 0;    
            else
                coutnege = coutnege + 1; 
        end
    endmodule

 

上一篇:数字 IC 技能树之(5)浅谈可编程逻辑器件


下一篇:学习FPGA需要注意的几个重要问题