1:FPGA程序代码中最好不要使用全局复位信号,即有一个信号rst,一按下去,程序中所有的模块都复位;
always@(敏感事件列表) 用于描述时序逻辑
敏感事件 上升沿 posedge,下降沿 negedge,或电平
敏感事件列表中可以包含多个敏感事件,但不可以同时包括电平敏感事件和边沿敏感事件,也不可以同时包括同一个信号的上升沿和下降沿,这两个事件可以合并为一个电平敏感事件。
在新的verilog2001中“,”和“or”都可以用来分割敏感事件了,可以用“*”代表所有输入信号,这可以防止遗漏。
合法的写法:
always@ *
always@ (posedge clk1,negedge clk2)
always@ (a or b)
`timescale 100ns/100ns //定义仿真基本周期为100ns
always #1 clk=~clk //#1代表一个仿真周期即100ns
所有的assign 和 always 块都是并行发生的!
并行块、顺序块
将要并行执行的语句写在
fork
//语句并行执行
join
将要顺序执行的语句写在
begin
//语句顺序执行
end
并行块和顺序块都可以写在
initial 或 always@ 之后,也就是说写在块中的语句是时序逻辑的
对assign之后不能加块,实现组合逻辑只能用逐句的使用assign
组合逻辑如果不考虑门的延时的话当然可以理解为瞬时执行的,因此没有并行和顺序之分,并行和顺序是针对时序逻辑来说的。值得注意的是所有的时序块都是并行执行的。initial块只在信号进入模块后执行1次而always块是由敏感事件作为中断来触发执行的
4:一些状态机可以不用case语句来写代码,比较大的状态机需要的case语句就很多,综合起来比较费劲,如果用一个ram,通过地址的变化,输出不同的数据给到特定的几个控制信号赋值这样也能起到状态机的效果,不过综合后占用的资源就好很多~~~~~~~~。
5:define是常量, 改不了的,parameter只是才模块内部是常量. 可以在模块外面修改.`define可以定义成一个表达式,比如 `define A a=(b>c)?1:0 ,parameter好像没见过这么用的
6:为了调试逻辑,现在很少再将FPGA中的信号引出,通过示波器或者逻辑分析仪来观察,更多的是在工程中生成stp或者cdc文件,通过signalTAP或者chipscope这两个工具来调试.
但我们发现,有时候在chipscope中很难找到你预期的信号,这往往是被综合器优化掉了,或者更改了信号名.我发现有效的方法是在源代码中加上约束语句,这样就不用对代码做大的改动.
例如:
在VHDL中:
为了观察sys_rst信号,sys_rst往往是组合逻辑,如果在chipscope中很难找到.我们先将 sys_rst用采样时钟打一拍,输出为sys_rst_d.
process(sys_clk)
begin
if sys_clk'event and sys_clk='1' then
sys_rst_d <= sys_rst;
end if;
end process;
然后在信号定义下面加上
attribute keep : string;
attribute keep of sys_rst_d : signal is "true";
这样在chipscope中很容易就能找到sys_rst_d 信号.
在Verilog中:
只需将需要监测的信号输出到port,然后加上约束就行.
例如:
output rx_sof_det_out /* synthesis syn_keep = 1 */;
output rx_eof_det_out /* synthesis syn_keep = 1 */
7:关于localparam,这个关键字书上很少会讲到。但是大公司的代码里经常会看到。这里特此,给出解释。
define:
可以跨模块的定义;
parameter:
本module内有效的定义,可用于参数传递;
localparam:
本module内有效的定义,不可用于参数传递;localparam cannot be used within the module port parameter list.
一般情况下,状态机的参数都是用localparam的
8:最近在维护一些FPGA板卡(EP4CE30F23C8N),发现有十几块FPGA板的3.3V和1.2V都出现了对地短路,拆下外围一些3.3V供电的芯片后,仍然短路,没办法最后直接一狠心把FPGA芯片给拆了,结果短路现象竟然都消失了,原来是FPGA的3.3V和1.2V击穿短路了;
进一步查找原因,确定究竟是FPGA的哪个Bank的电源出现了短路,连续测量了好几个FPGA芯片,发现都是Bank5的问题;
继续深究,为什么偏偏就是Bank5出问题了呢,其中定有内因,猜想应该是该Bank的某些信号出现了异常导致该Bank被击穿;
为了确认这个假设,测量Bank5的相关信号对地阻抗,竟然真的验证了之前的假设,接I2C的两根信号线的阻抗都不同程度的出现了异常(正常的板都是无穷大,而出现问题的板接FPGA的I2C信号线都仅有几欧到几百欧的阻抗),看来是I2C信号对FPGA的管脚造成了冲击而导致FPGA电源被击穿短路(FPGA还是挺脆弱的,要小心喽,呵呵)。
针对这次的维护工作,对FPGA系统的调试和维修也做一下小结了。
FPGA系统工作异常,一般常见的有以下两种情况:
1、FPGA上电配置不成功;
2、FPGA虽上电配置成功,但未正常工作。
不管是哪种情况,首先都应该先检查电源系统和晶振是否正常工作,确认它们都没问题后再继续往下查找问题。
对于第一种情况,通常可定位在FPGA的配置电路:1、确认配置模式选择是否正确;2、配置相关信号线阻抗是否正常,这些信号线有:Config_done,nConfig,nCE,nSTATUS,nCS,ASDO,DCLK,DATA,其中,测量Config_done信号对地阻抗较容易确定配置电路问题所在(个人认为)。正常情况下,Config_done对地阻抗应该是至少几千欧级别(此处的阻抗约为11K欧左右),若测量其阻抗低于了1K,那基本就可以肯定该配置电路出问题了。
对于第二种情况,除去电源问题,一般就是晶振的问题。若以上措施仍未有效查找并解决问题,可进一步确认FPGA的全局信号线的硬件连接、软件设置是否正确,如:DEV_OE、DEV_CLRn。
信号赋值在相应的进程、函数、过程执行完之后才更新,一般会被综合成时序电路;变量赋值立即更新,一般被综合成组合电路。3.1变量:
1、如果一个变量在一个信号跳变时被赋值,并且该值最终又被赋给另外的信号,那么综合后就会产生寄存器。
2、如果一个变量在还没有进行赋值操作时已经被使用了,也会产生寄存器。
如:计数器。
-- process(clk)
-- variable cnt : integer RANGE 0 to 5;
-- begin
-- if(rising_edge(clk))then
-- if(cnt < 5)then
-- cnt := cnt + 1;
-- else
-- cnt := 0;
-- end if;
-- if cnt = 3 then
-- q <= not q;
-- end if;
-- end if;
-- end process
在计数器里面,cnt:= cnt + 1这一句看着像是先赋值,然后才被使用,同时也没有将值赋给别的信号;实际上是先被使用了才被赋值的。因为像:=之类的运算符都是先算右边再算左边的,所以它是先使用再赋值的。所以会生成寄存器,用来保存cnt的值。
3.2信号:
如果信号的赋值是以另一个信号的跳变为条件的,该信号经过综合后会产生寄存器。
注:进程里面所有的信号都是在敏感信号跳变时发生改变的,但那不是以另一个信号的跳变为条件的赋值,它的赋值是一直都存在的,这种情况下的信号通常被综合成组合逻辑,如在if(rising_edge())then条件下的赋值算是以跳变为条件的赋值。
3.3建议:1)在需要表示连线的时候使用变量。
如在process里面需要将integer类型的A、B、C、D、E、F相加与100比较的时候,为了让if条件表达式简单,我们可以用变量sum:=A+B+C+D+E+F;然后if (sum与100比较),这样表达式看起来就要简单很多,也更加直观易懂。在这种情况下,并不会被综合成寄存器,用了只是为了方便代码的编写、阅读和理解。
另外,因为变量是即时更新的,上面的语句后面再用sum 来表示G、H、I、J、K之和,再用来与其他的值比较也是可以的。当然也可以定义其他变量来表示,反正在这种情况下他们是不占资源的。
在以上情况不要使用信号。如果是在时序电路中,用信号来表示会导致一个CLK的延时。
2)其他情况下建议使用信号吧,至少在计数器中使用信号比使用变量占用的资源要少。
用变量来做计数器,综合后得到的是加法器和寄存器。当脉冲上升沿到来的时候,触发器将上一次输出的值加1作为输入输出,传到加法器输出,用来比较使能其他寄存器。因为寄存器同步输出后又经过了加法器组合逻辑的运算,会产生延时,影响到建立时间和保持时间。在同步时序电路的设计中,这是不合理的
用户1687253 2013-9-27 09:35
用户436773 2013-8-14 09:51
用户403664 2013-8-13 15:50
xucun915_925777961 2013-3-25 21:18
多动手,多思考,多总结,电工的好习惯,加油^_^