欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

记录一次血崩式的CPLD不稳定 bug经验

发布时间:2025/4/5 编程问答 54 豆豆
生活随笔 收集整理的这篇文章主要介绍了 记录一次血崩式的CPLD不稳定 bug经验 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

-------------分界
北京地区,4月24日,一场大雨,来得异常突然,不同寻常的天气预示着不同寻常的事情要发生。妖气弥漫了帝都,一阵狂风飘过,收到报告,你写的这个CPLD程序门控有不正常了,又没有了。
what?肯定是硬件问题,之前测试都是非常正常的,然后再装到设备里面去的,就一个门控电路,这么low的东西,毕竟学习了FPGA一年了,写个延时可调的门控,那真的是不到30分钟的事情。怎么会老是出错呢?我用前仿真,后仿真,时序约束,可达到85°的高温,slack都满足,怎么会错?
种种不惑,不解摆在我面前,我仔仔细细又看了程序,雨依旧很大,我去吃了饭,点餐前,我直接拿出自己的电脑,迟迟未点餐,我modelsim仿真,每一个信号,都没问题。虽然程序很简单,但是这种死去活来抓不住的问题,让我怀疑自己能力,让我领导怀疑我的能力,甚至可能导致我不能接下一个FPGA任务,因为我写的程序是不可靠的,在现实中,如果你的程序一个月出一次问题,都是不可靠的。这样的不稳定,可能会导致比如门控,在不该开的时候开,可能会打坏器件,而一个器件可能价值10W,所以,虽然是一个简单的东西,但十分重要。
可以说,我从来没遇到过这种问题,回到实验室,我测了又测,争辩了又争辩,晚上11点回到寝室,我觉得我的状态机,设置为格雷码,不会有任何跑飞的情况了。但是,烧了两台CPLD,看似正常了,但是第二天,接到报告,有一台又不工作了,重启一下才工作。我去,这简直不能忍受了,不就一个受到触发后,延时一段时间(可调)然后出一个高电平(可调),这样的r j 程序,怎么还会错,我也想不通呀,我怀疑了一次又一次的硬件,我感觉我智商到了0,我熟悉不能再熟悉的状态机,我简直不敢用了。
然而,CPLD这种器件是不支持Signal tap的,所以我也没办法调试。后来我决定用计数器的方式,计数到某个值出高电平,计数到最后一个值,恢复至低。最后烧到8台CPLD程序中,都正常运行了,截止目前,没收到报告说有错。虽然这个事情暂时过去了,但是,这个原因找不出来可能会导致我的程序是不可靠的我的代码是不可靠的,这个印象将会存在于领导中,这对我的打击将是非常巨大的。
于是,我用我的EP4CE10F17C8来调试,想观察一下状态机,于是我添加了一句防止优化的命令,在定义状态机的后面,FPGA一直都完美运行,状态都没问题。到了今天,事情过去了三天了,我又去实验室,拿了一个CPLD,我用这个程序,下载进去,纳闷儿的事情发生了,也是一个偶然发现了一个惊天秘密,我发现我在没有写/synthesis preserve/ ,此时有个管脚是不输出波形的,然而我一旦写了这个,管脚输出波形,恢复正常,我试过很多次,上电重启,上电重启,上电重启,上电重启。。。发现真的是这样。
难道CPLD这种器件把我的状态寄存器给我优化掉了?这个偶然的发现。既让我兴奋,又让我不解,虽然我还不敢保证是不是真正凶手导致的不稳定,但是事情确实是在我眼皮子底下发生了,而且我验证了很多次。我打算明天后天,将继续验证这个结论,如果确实是这样,只能说明/synthesis preserve/ 将影响实际布线,在CPLD这种器件中写状态机,要尤其小心。
我觉得这个事情,也算是一个血泪史吧,这几天淋了一身雨,倒头就睡了,一场大雨似乎让我觉得一定要武装自己的知识,不断让自己强大再强大。

以下是代码:如果有哪位有经验的大哥,可以说说你的看法,代码非常简单,仿真,slack均以满足85°高温等均已经测试。

顶层:

module ex_pulse_triger # (parameter low_leval_time_pulse_1=1, //ex_triger外部触发后的延时时间,实际测试+2 parameter high_leval_time_pulse_1=300,//高电平时间,实际测试:保持不变parameter low_leval_time_pulse_2=23, //pulse_out1触发后的延时时间,实际测试+2 parameter high_leval_time_pulse_2=250,//高电平时间,实际测试,保持不变parameter low_leval_time_pulse_3=23, //pulse_out2触发后的延时时间,实际测试+2 parameter high_leval_time_pulse_3=200,//高电平时间,实际测试,保持不变parameter data_width_1=9, //第一个脉冲高电平宽度 parameter data_width_2=9, //第二个脉冲高电平宽度 parameter data_width_3=9//) ( input ex_triger, //外部触发 input sys_clk, //output ex_triger_test,output pulse_out1, // output pulse_out1_n,output pulse_out2, output pulse_out2_n,output pulse_out3, output pulse_out3_n );reg ex_triger_reg; //寄存外部信号 reg ex_triger_reg_reg; reg ex_triger_reg_reg_reg; reg ex_triger_reg_reg_reg_reg;reg pulse_out1_reg; //寄存外部信号2 reg pulse_out1_reg_reg; reg pulse_out1_reg_reg_reg; reg pulse_out1_reg_reg_reg_reg;reg pulse_out2_reg; //寄存外部信号3 reg pulse_out2_reg_reg; reg pulse_out2_reg_reg_reg; reg pulse_out2_reg_reg_reg_reg;reg start_pulse1; //启动信号脉冲1reg start_pulse2; //启动信号脉冲2reg start_pulse3; //启动信号脉冲3always @ (posedge sys_clk ) beginex_triger_reg<=ex_triger;ex_triger_reg_reg<=ex_triger_reg;ex_triger_reg_reg_reg<=ex_triger_reg_reg;ex_triger_reg_reg_reg_reg<=ex_triger_reg_reg_reg;start_pulse1<=ex_triger_reg_reg_reg_reg&!ex_triger_reg; end//---------------------------------------------------always @ (posedge sys_clk) beginpulse_out1_reg<=pulse_out1;pulse_out1_reg_reg<=pulse_out1_reg;pulse_out1_reg_reg_reg<=pulse_out1_reg_reg;pulse_out1_reg_reg_reg_reg<=pulse_out1_reg_reg_reg;start_pulse2<=!pulse_out1_reg_reg_reg_reg&pulse_out1_reg; end//---------------------------------------------------always @ (posedge sys_clk) begin pulse_out2_reg<=pulse_out2;pulse_out2_reg_reg<=pulse_out2_reg;pulse_out2_reg_reg_reg<=pulse_out2_reg_reg;pulse_out2_reg_reg_reg_reg<=pulse_out2_reg_reg_reg;start_pulse3=!pulse_out2_reg_reg_reg_reg&pulse_out2_reg; end//--------------------------脉冲1的控制 pulse_out_module # ( .low_leval_time(low_leval_time_pulse_1),//触发后延迟时间.high_leval_time(high_leval_time_pulse_1), //高电平时间.data_width(data_width_1))pulse_out_module_inst1 ( .start(start_pulse1), //输入启动信号 .sys_clk(sys_clk), .ex_triger(ex_triger), .pulse_out(pulse_out1) );//--------------------------脉冲2的控制 pulse_out_module # ( .low_leval_time(low_leval_time_pulse_2),//触发后延迟时间.high_leval_time(high_leval_time_pulse_2), //高电平时间.data_width(data_width_2))pulse_out_module_inst2 ( .start(start_pulse2), //输入启动信号 .sys_clk(sys_clk), .ex_triger(ex_triger), .pulse_out(pulse_out2) );//--------------------------脉冲3的控制 pulse_out_module # ( .low_leval_time(low_leval_time_pulse_3),//触发后延迟时间.high_leval_time(high_leval_time_pulse_3), //高电平时间.data_width(data_width_3))pulse_out_module_inst3 ( .start(start_pulse3), //输入启动信号 .ex_triger(ex_triger), .sys_clk(sys_clk), .pulse_out(pulse_out3) );assign pulse_out1_n=~pulse_out1; assign pulse_out2_n=~pulse_out2; assign pulse_out3_n=~pulse_out3;endmodule module pulse_out_module # ( parameter low_leval_time=0,//触发后延迟时间parameter high_leval_time=0, //高电平时间parameter data_width=0 //高电平计数器宽度 ) ( input start, //输入启动信号 input ex_triger, input sys_clk, output pulse_out);localparam IDLE_state=2'b00; localparam IDLE_state_rst=2'b01; localparam low_level_state=2'b11; localparam high_level_state=2'b10;reg pulse_out_reg=0;reg [1:0] now_state /*synthesis preserve*/ = IDLE_state; reg [1:0] next_state /*synthesis preserve*/= IDLE_state;reg [data_width-1:0] leval_cnt; reg start_high_flag=1'b0; reg start_idle_flag=1'b0;//1、实现状态转换 always @ (posedge sys_clk) beginnow_state<=next_state; end//2、根据条件产生下一个状态 always @ (*) begincase (now_state)IDLE_state:beginif(!ex_triger)next_state=IDLE_state_rst; elsenext_state=IDLE_state;endIDLE_state_rst:beginif(start)next_state=low_level_state;elsenext_state=IDLE_state_rst;endlow_level_state:beginif(start_high_flag)next_state=high_level_state; elsenext_state=low_level_state;endhigh_level_state:beginif(start_idle_flag)next_state=IDLE_state; elsenext_state=high_level_state;enddefault:beginnext_state=IDLE_state;endendcaseend //3、状态条件输出 always @ (posedge sys_clk) begin case (next_state)IDLE_state:beginleval_cnt<=0;pulse_out_reg<=0;//high_leval_cnt<=0;endIDLE_state_rst:beginleval_cnt<=0;pulse_out_reg<=0;endlow_level_state:beginleval_cnt<=leval_cnt+1;pulse_out_reg<=0;endhigh_level_state:beginleval_cnt<=leval_cnt+1;pulse_out_reg<=1;enddefault:beginleval_cnt<=0;pulse_out_reg<=0;endendcaseendalways @ (posedge sys_clk) begin if(leval_cnt==low_leval_time-1|low_leval_time==0) start_high_flag<=1; else start_high_flag<=0; endalways @ (posedge sys_clk) begin if(leval_cnt==low_leval_time+high_leval_time-1) start_idle_flag<=1; else start_idle_flag<=0; endassign pulse_out=pulse_out_reg;endmodule

用FPGA的signal tap均正常

总结

以上是生活随笔为你收集整理的记录一次血崩式的CPLD不稳定 bug经验的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。