请教,状态机跑飞和跑死,如何解决?
用的是xilinx的spatan 3a
发现有个状态机工作不正常:
1.当我用ont-hot编码的时候,用chipscope观察,出现全是0的现象,我在状态机的when others中也加了状态的回复,但是还是不行。
2.然后我换了gray编码,这次状态停到了“011”就不走了,而这个状态仅仅起到一个延迟作用,没有任何条件语句。
程序平时是没有问题的,大概运行300次左右就出现一次跑飞。用FPGA1年了,属于初学者,从来没有遇到过这种问题。
请教个位高手,如何解决?
以下是代码
p_reg2:process(S_Lclk,reset)
begin
if (reset='0') then
state1<=0;
S_ccs<='Z';
S_ads_o<='Z';
S_blast_o<='Z';
S_wr_o<='Z';
S_la_o<=(others=>'Z');
S_command<=(others=>'Z');
S_command_en<='1';
elsif rising_edge (S_Lclk) then
case state1 is
when 0 =>
if S_PCI_usero='0' then
S_ads_o<='1';
state1<=1;
else
S_ccs<='Z';
S_ads_o<='Z';
S_blast_o<='Z';
S_wr_o<='Z';
S_la_o<=(others=>'Z');
S_command<=(others=>'Z');
S_command_en<='1';
end if;
when 1 =>
S_ccs<='0';
S_ads_o<='0';
S_wr_o<='0';
S_la_o<=G_C8;
state1<=2;
when 2 =>
S_ccs<='Z';
S_ads_o<='1';
S_blast_o<='0';
state1<=3;
when 3 =>
S_ccs<='Z';
state1<=4;
when 4=>
if S_ready_i='0' then
S_command<=pci_ld;
S_command_en<='0';
state1<=5;
else
null;
end if;
when 5=>
state1<=6;
when 6 =>
if S_PCI_usero='1' then
S_command_en<='1';
state1<=0;
else
null;
end if;
S_blast_o<='Z';
S_wr_o<='Z';
S_ads_o<='Z';
when others =>
state1<=0;
end case;
else
null;
end if;
end process p_reg2;
这个进程的时钟是我用40M分频产生的(不是用DCM,就是写了个简单的分频代码,即如果上升沿A<=not A),
它即作为本进程的时钟,又作为外部PCI LOCAL总线的时钟。
其它的进程采用的是40M时钟
状态机编码类型是在ise的综合选项中选的。
另外,状态机工作在低频情况下,20MHz。
把你的代码贴上来看看,
已经贴上代码了,请指教!
抛开代码不说,首先你可以看下你编译后的报告,看下状态机里有几个状态,如果不是全编码将状态机进行全编码。即假如用格雷码的话,码的位宽为3,也就是8个状态。when others的时候直接能够跳转到你指定的状态即可。
如果看深层原因的话,应该是有亚稳态出现,查查有没有跨时钟域信号输入。
这只是个人经验,如果不行,还要高人指点。
首先谢谢你的回答!
我看了报告,没有什么异常,所有的状态都有对应,即one-hot的话是7位,从0000001~1000000,
gray的话是3位。
而且我的when others中也将它回到了初始状态。
给我的感觉就是干脆就没进去process,我看了,此时的reset是正常的。
process的敏感条件,会不会与这个有关系?虽说看上去以时钟为上升沿应问题不大。
要不你改成三段式一下,在逻辑组合语句里把所有相关的敏感条件都加进去,状态机的话直接选择自动就好,
另外,不知道你reset是高复位还是低复位,如果是低复位的话,最好名称以n或_n结束,
process的敏感条件,会不会与这个有关系?虽说看上去以时钟为上升沿应问题不大。
要不你改成三段式一下,在逻辑组合语句里把所有相关的敏感条件都加进去,状态机的话直接选择自动就好,
另外,不知道你reset是高复位还是低复位,如果是低复位的话,最好名称以n或_n结束,
我见过别人讨论过,用综合指令或者约束,强行规定综合后必须生成一旦进入非有效状态便立即复位随即进入有效状态的电路
请问这个东西在哪里设置?
问题解决了!
将状态机中外部的信号和它的时钟进行了一下同步
p_reg2_1: process(S_Lclk)
begin
if rising_edge(S_Lclk) then
S_PCI_usero<=PCI_usero;
S_ready_i<=ready;
else
null;
end if;
问题就解决了!
二段式或者三段式比较容易发现问题。还有你的写法存在一定问题,状态机中忌讳出现状态不全的情况,你有几个else里没写。后仿试过了没?
呵呵 确实亚稳态经常导致状态机跑飞 异步信号做状态跳转条件时,确实要这么2级同步到同一个时钟域后来用
我用在lattice的FPGA上出现状态机跳转异常,正常应该是S1->S2->S3,但rev分析看到直接由S1—>S3了,也是将跳转条件同步一下就解决了。看来这一招确实有用!
还是因为跨时钟域的问题产生的