FPGA研发之道(23)-控制(上)
发布时间:2014-12-9 13:45
发布者:看门狗
关键词:
FPGA
作者:阿昏豆 本质上说,FPGA的模块设计就是将输入转化成想要得到的输出结果。而除了某些简单模块,即在当拍内完成,即将输入进行逻辑操作后,再输出。(如简单加法器等)。其余大部分的设计需要通过时序逻辑和组合逻辑混合实现,时序逻辑带来就是延迟起效的问题,举例说,如实现某个信号(start)起效后,接下来五个周期需要分别进行五种操作,分别是op0,op1,op2,op3,op4 等等。如何进行控制,这就是每个工程师要面对的问题。 对于简单控制,分别可以采用计数和移位寄存器的方式来解决问题。而对于较为复杂的控制,则需要设计状态机来解决。下面将分别介绍 计数器: 对于上述操作来说,start起效后,可以通过计数实现,设置寄存器count[2:0],有效信号开始时计数自加。 计数的方式带来的问题就是,计数从零开始还是从1开始,假如计数器初始化为0,则从0-4状态可以分别输出op0,op1,op2,op3,op4,但是在无有效信号时,计数会保持0,从而造成op0的输出。 上述举例虽然简单,但是确实很多初学者或者工程师在仿真时会经常会犯的错误。从设计来说,计数需要考虑初始值对于输出的影响。同样计数带来的另一个问题就是,从零开始的计数会导致设计与实际不一致,例如,一个信号9拍后拉低,但从零计数到8时,已经到9拍了(0-8),这种设计会导致命名count==8 与9拍存在不一致的现象。当然也可以从1计数到9,这样状态在count==9时触发。这样就会初始化需要复位寄存器为1。当然这个问题大端和小端的争斗一样,没有终点。一个设计中如果多种计数来驱动计数的话,就需要特别小心这个问题计数。当然也可把问题交给仿真器,仿真时根据波形调整,计数的状态。 移位寄存器:如采用移位寄存器,根据上述例子,则start信号有效后,设计5bit的移位寄存器flag[4:0]分别利用寄存器的某BIT来控制输出,从而在每BIT有效时,分别输出op0,op1,op2,op3,op4。假设此种状态较少,FPGA寄存器资源较为丰富,因此利用移位寄存器是一个不错的注意。 assign op4 = ( count == 3’b100) ; assign op4 = flag[4] ; 比较上述两种输出,则可以看出,通过计数的方式占用输出资源较多,而移位寄存器在此种应用下,占用逻辑就相对简单。(仅针对小规模的计数来说,对于超过16的计数,则使用计数器更优)。另外,通过移位寄存器可以方便的进行时序控制,不用纠结从零开始还是从1开始的问题,在某些简单的处理下能够达到更小的面积和更快的时序。 对于复杂的控制,则状态机,就是必须的。对于FPGA实现状态机,其实并不需要那么多的设计的方法。主要就是两个要点。(1)独热码。(2)三段式。 对于第一点来说,独热码,因为FPGA内部寄存器资源较多,另外独热码将会带来额外的面积和时序优化的好处。则以上述例子为例,增加状态转移的触发信号,状态转移图如下所示: ![]() 状态独热码(也可以用define localparam)建议使用parameter或者localparam parameter idle == 6’b000001, op0_state == 6’b000010, op1_state == 6’b000100, op2_state == 6’b001000, op3_state == 6’b010000, op4_state == 6’b100000; 三段式结构如下 //(1)当前状态 always@(posedge sys_clk or negedge rst_n) if(!rst_n) cs_state <= idle; else cs_state <= ns_state; //(2)下一状态的赋值 always@(*) case(cs_state) idle : if(start) ns_state = op0_state; else ns_state = idle; op0_state : if(op0_over) ns_state = op1_state; else ns_state = op0_state; op1_state : if(op1_over) ns_state = op2_state; else ns_state = op1_state; op2_state : if(op2_over) ns_state = op3_state; else ns_state = op2_state; op3_state : if(op3_over) ns_state = op4_state; else ns_state = op3_state; op4_state : if(op4_over) ns_state = op4_state; else ns_state = idle; default ns_state = idle; endcase //(3)输出状态 assign out1 = (cs_state == op0_state); always@(posedge sys_clk or negedge rst_n) if(!rst_n) out2_reg <= 1'b0; else if (cs_state == op2_state) out2_reg <= 1'b1; else out2_reg <= 1'b0; 上述例子,介绍独热码和三段式。三段式的好处不用说,就是逻辑清楚。可以看出out1输出为组合输出。out_2_reg为寄存输出。那么独热码在FPGA内部的优势又有哪些? (1)综合后,逻辑简单 例如assign out1 = (cs_state == op0_state); 综合后的电路等同于 assign out1= cs_state(0) ;//可以看出无逻辑消耗 而 out2_reg 的电路等同于 将cs_state(2)寄存一拍,只需一个寄存器的消耗 (2)时序优化。 从上述同样得出结论,如果是使用某状态cs_state(n)作为其他信号的输入来说,其本身为寄存器信号,因此关键路径就会减少一级。可能运行较快的频率就会增加。如不是独**,对比这两条语句cs_state = 3 与cs_state(3) 一个是组合输出,一个寄存器输出。其不同也就是上述计数与移位寄存器的区别一致。 那么一般状态机会产生的错误会有哪些那? 首先;就是状态不全产生LATCH,前文已述,这是FPGA设计的大敌,解决这个问题的方法可以通过所有分支都设定确定状态,如上例中。有没有更简单的方式? 其此:状态机上述描述,并不直观的显现综合后电路的描述,有没有更直接的rtl的描述,一眼就能看出独热码的特征和好处? 最后:状态机是一个较为成熟技术,还会有哪些值得关注的地方? 这些问题,下节再述。 |
网友评论