FPGA建立时间与保持时间 联系客服

发布时间 : 星期六 文章FPGA建立时间与保持时间更新完毕开始阅读

图9 状态机的组成

所有通常写状态机时也按照这三个模块将状态机分成三部分来写,如下面就是一种良好的状态机设计方法:

1 /*----------------------------------------------------- 2 This is FSM demo program 3 Design Name : arbiter 4 File Name : arbiter2.v

5 -----------------------------------------------------*/ 6 module arbiter2 ( 7 clock , // clock

8 reset , // Active high, syn reset 9 req_0 , // Request 0 10 req_1 , // Request 1 11 gnt_0 , 12 gnt_1); 13

14 //-------------Input Ports----------------------------- 15 input clock ; 16 input reset ; 17 input req_0 ; 18 input req_1 ;

19 //-------------Output Ports---------------------------- 20 output gnt_0 ; 21 output gnt_1 ;

22 //-------------Input ports Data Type------------------- 23 wire clock ; 24 wire reset ; 25 wire req_0 ; 26 wire req_1 ;

27 //-------------Output Ports Data Type------------------ 28 reg gnt_0 ; 29 reg gnt_1 ;

30 //-------------Internal Constants-------------------------- 31 parameter SIZE = 3 ; 32 parameter IDLE = 3'b001 , 33 GNT0 = 3'b010 , 34 GNT1 = 3'b100 ;

35 //-------------Internal Variables--------------------------- 36 reg [SIZE-1:0] state ;// Seq part of the FSM 37 wire [SIZE-1:0] next_state ;// combo part of FSM 38 //----------Code startes Here------------------------

39 assign next_state = fsm_function(req_0, req_1); 40 function [SIZE-1:0] fsm_function; 41 input req_0; 42 input req_1; 43 case(state)

44 IDLE : if (req_0 == 1'b1) 45 fsm_function = GNT0; 46 else if (req_1 == 1'b1) 47 fsm_function= GNT1; 48 else

49 fsm_function = IDLE; 50 GNT0 : if (req_0 == 1'b1) 51 fsm_function = GNT0; 52 else

53 fsm_function = IDLE; 54 GNT1 : if (req_1 == 1'b1) 55 fsm_function = GNT1; 56 else

57 fsm_function =IDLE; 58 default : fsm_function = IDLE; 59 endcase 60 endfunction 61

62 always@(posedge clock) 63 begin

64 if (reset == 1'b1) 65 state <=IDLE; 66 else

67 state <=next_state; 68 end

69 //----------Output Logic----------------------------- 70 always @ (posedge clock) 71 begin

72 if (reset == 1'b1) begin 73 gnt_0 <= #1 1'b0; 74 gnt_1 <= #1 1'b0; 75 end

76 else begin 77 case(state) 78 IDLE : begin

79 gnt_0 <= #1 1'b0; 80 gnt_1 <= #1 1'b0; 81 end

82 GNT0 : begin

83 gnt_0 <= #1 1'b1; 84 gnt_1 <= #1 1'b0; 85 end

86 GNT1 : begin

87 gnt_0 <= #1 1'b0; 88 gnt_1 <= #1 1'b1; 89 end

90 default : begin 91 gnt_0 <= #1 1'b0; 92 gnt_1 <= #1 1'b0; 93 end 94 endcase 95 end

96 end // End Of Block 97

98 endmodule

状态机通常要写成3段式,从而避免出现过大的组合逻辑。

上面说的都是可以通过流水的方式切割组合逻辑的情况,但是有些情况下我们是很 难去切割组合逻辑的,在这些情况下我们又该怎么做呢?

状态机就是这么一个例子,我们不能通过往状态译码组合逻辑中加入流水。如果我们的设计中有一个几十个状态的状态机,它的状态译码逻辑将非常之巨大,毫无疑问,这极有可能是设计中的关键路径。那我们该怎么做呢?还是老思路,减少组合逻辑。我们可以对状态的输出进行分析,对它们进行重新分类,并根据这个重新定义成一组组小状态机,通过对输入进行选择(case语句)并去触发相应的小状态机,从而实现了将大的状态机切割成小的状态机。在ATA6的规范中(硬盘的标准),输入的命令大概有20十种,每一个命令又对应很多种状态,如果用一个大的状态机(状态套状态)去做那是不可想象的,我们可以通过case语句去对命令进行译码,并触发相应的状态机,这样做下来 这一个模块的频率就 可以跑得比较高了。

总结:提高工作频率的本质就是要减少寄存器到寄存器的时延,最有效的方法就是 避免出现大的组合逻辑,也就是要尽量去满足四输入的条件,减少LUT级联的数量。我们 可以通过加约束、流水、切割状态的方法提高工作频率。 在FPGA中进行时钟设计时也要注意一下几点:

1. 一个模块尽量只用一个时钟,这里的一个模块是指一个module或者是一个entity。在多时钟域的设计中涉及到跨时钟域的设计中最好有专门一个模块做时钟域的隔 离。这样做可以让综合器综合出更优的结果。

2. 除非是低功耗设计,不然不要用门控时钟--这会增加设计的不稳定性,在要用到门控时钟的地方,也要将门控信号用时钟的下降沿 打一拍再输出与时钟相与。

3. 禁止用计数器分频后的信号做其它模块的时钟,而要用改成时钟使能的方式,否则这种时钟满天飞的方式对设计的可靠性极为不利,也大大增加了静态时序分析的复杂性。

1.4 不同时钟域之间的同步

当一个设计中的两个模块分别用的是两个工作时钟,那么在它们的接口处就工作在异步模式,这时为了保证数据能正确的处理那么就要对两个模块进行同步。 这里的不同的时钟域通常是以下的两种情况: 1、 两个时钟的频率不同;

2、 虽然两个时钟的频率相同,但是它们是两个独立的时钟,其相位没有任何关系。 分别如下两个图所示:

图10 两个时钟的频率完全不同

图11两个时钟的频率相同,但相位不相关

两个时钟域之间传输的数据根据不同的位宽通常采用不同的同步的方法。 1、单bit之间的同步且发送的每个pulse至少有1个周期宽度的情况

这类同步主要是用于一些控制信号自己的同步。通常的采用方法就是输出数据在接收的模块中利用两个触发器采用系统时钟打两拍,如下图12所示。对于这种同步需要说明以下几点。