FPGA时序技巧
0赞 FPGA写代码写久了需要点技巧。程序健壮性,稳定性很需要考虑。
比如说一个例子,把一个RAMA的数据写入另外一个RAMB中。
新手肯定是读一个写一个。关键问题是,RAM的厂家的IP读数据过程是会有一个时钟或者2个时钟延时问题。所以很多人写的代码如下:
always @(clk)
begin
case(ram_STATE)
ramA_en_wraddr:
ramA_en_delaytwo:
ramB_en_wrout:
end
从RAMA到RAMB 搬移数据,花费的时间是4*地址 *clk时间,尤其是地址超过256长度,容易引起前端的ram的数据覆盖的问题。
这个时候解决问题方式是把数据和地址分开不同模块写的。这个也是sdram操作核心思想之一。
always @(clk)
begin
case(ram_STATE)
ramA_en_wraddr:
end
wire rama_en;
assign ram_en =(ram_STATE == ramA_en_wraddr);
///// delaytwo time
reg rama_en_delayone;
reg rama_en_delaytwo;
always @(posedge clk)
begin
rama_en_delayone <= rama_en;
rama_en_delaytwo <= rama_en_delayone ;
end
always @(posedge clk)
begin
if( rama_en_delaytwo)
ramb_wrdata <= rama_rddata;
end
上面是数据是延时2个时钟之后的。地址也是必须延时2个时钟再给RAMB.
reg[5:0] rama_addr_delayone;
reg[5:0] rama_addr_delaytwo;
always @(posedge clk)
begin
rama_addr_delayone<= rama_addr;
rama_addr_delaytwo<= rama_en_delayone ;
end
assign ramb_addr = (rama_en_delaytwo)?rama_addr_delaytwo:0};
肯定有人觉得 这种ramb地址赋值方式,是没有时钟输出,会导致时序约束不好的。但是地址延时后,数据也是必须延时。
//////延时数据
always @(posedge clk)
begin
rama_rddata_delay<= rama_rddata;
end
注意rama-en 也得延时三次
always @(posedge clk)
begin
if( rama_en_delaythree)
ramb_wrdata <= rama_rddata_delay;
end
/////////////ramb地址赋值
always @(posedge clk)
begin
if(rama_en_delaythree)
ramb_addr <= rama_addr_delaytwo;
else
ramb_addr <= 0;
end
以上的代码不是完整的代码。只是提供一些思路。
