记录一次血崩式的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经验的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 个人书法记录-2019.4.22
- 下一篇: matlab---spectrogram