日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

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

编程问答

记录一次CPLD资源过少、时序伪例的解决办法

發布時間:2025/4/5 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 记录一次CPLD资源过少、时序伪例的解决办法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 1、背景:
  • 2、代碼
  • 3、心得

1、背景:

CPLD雖然是幾乎淘汰產品,但是體積非常小,而且不需要額外的EPCS存儲器,所以完成簡單的時序來說,也有尚存的一席之地。

這次使用的是MAX V系列的CPLD,完成外部觸發后,產生一個可控低電平,接著是可控高電平的pulse_out1,接著pulse_out2又受pulse_out1的上升沿觸發,接著pulse_out3又受pulse_out2的觸發,以此完成類似的可控操作。

上圖,我已經在我的quartus 13.1中安裝了MAX V系列的CPLD,安裝過程類似于曾經寫的一篇文章:https://blog.csdn.net/ciscomonkey/article/details/87896715

2、代碼

代碼如下:
頂層模塊:
實現了三個pulse的觸發,和上升沿的檢測

module ex_pulse_triger # (parameter low_leval_time_pulse_1=4, //ex_triger外部觸發后的延時時間,實際測試+1 parameter high_leval_time_pulse_1=100,//高電平時間,實際測試:保持不變parameter low_leval_time_pulse_2=4, //pulse_out1觸發后的延時時間,實際測試+2 parameter high_leval_time_pulse_2=75,//高電平時間,實際測試,保持不變parameter low_leval_time_pulse_3=4, //pulse_out2觸發后的延時時間,實際測試+2 parameter high_leval_time_pulse_3=30,//高電平時間,實際測試,保持不變parameter data_width_1=8, //第一個脈沖高電平寬度 parameter data_width_2=8, //第二個脈沖高電平寬度 parameter data_width_3=7 //) ( input ex_triger, //外部觸發 input sys_clk, input rst, //低電平復位 output pulse_out1, // output pulse_out2, output pulse_out3 );reg ex_triger_reg; //寄存外部信號 reg ex_triger_reg_reg;reg pulse_out1_reg; //寄存外部信號2 reg pulse_out1_reg_reg;reg pulse_out2_reg; //寄存外部信號3 reg pulse_out2_reg_reg;wire start_pulse1; //啟動信號脈沖1wire start_pulse2; //啟動信號脈沖2wire start_pulse3; //啟動信號脈沖3always @ (posedge sys_clk) beginex_triger_reg<=ex_triger;ex_triger_reg_reg<=ex_triger_reg; endassign start_pulse1=!ex_triger_reg_reg&ex_triger; //---------------------------------------------------always @ (posedge sys_clk) beginpulse_out1_reg<=pulse_out1;pulse_out1_reg_reg<=pulse_out1_reg; endassign start_pulse2=!pulse_out1_reg_reg&pulse_out1; //---------------------------------------------------always @ (posedge sys_clk) beginpulse_out2_reg<=pulse_out2;pulse_out2_reg_reg<=pulse_out2_reg; endassign start_pulse3=!pulse_out2_reg_reg&pulse_out2;//--------------------------脈沖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), .rst(rst), //低電平復位 .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), .rst(rst), //低電平復位 .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), //輸入啟動信號 .sys_clk(sys_clk), .rst(rst), //低電平復位 .pulse_out(pulse_out3) );endmodule

底層模塊:

module pulse_out_module # ( parameter low_leval_time=0,//觸發后延遲時間parameter high_leval_time=0, //高電平時間parameter data_width=0 //高電平計數器寬度 ) ( input start, //輸入啟動信號 input sys_clk, input rst, //低電平復位 output pulse_out);localparam IDLE_state=2'b0; localparam low_level_state=2'b01; localparam high_level_state=2'b10;reg pulse_out_reg=0;reg [1:0] now_state=0; reg [1:0] next_state=0;reg [data_width-1:0] leval_cnt; reg start_high_flag=1'b0; reg start_idle_flag=1'b0;//1、實現狀態轉換 always @ (posedge sys_clk or negedge rst) beginif(!rst) //低電平復位now_state<=IDLE_state;elsenow_state<=next_state; end//2、根據條件產生下一個狀態 always@(*) begincase (now_state)IDLE_state:beginif(start)next_state=low_level_state; elsenext_state=IDLE_state;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:next_state=IDLE_state;endcaseend //3、狀態條件輸出 always @ (posedge sys_clk) begin case (next_state)IDLE_state:beginleval_cnt<=0;//high_leval_cnt<=0;endlow_level_state:beginleval_cnt<=leval_cnt+1;endhigh_level_state:beginleval_cnt<=leval_cnt+1;enddefault:;endcaseendalways @ (posedge sys_clk or negedge rst) beginif(!rst)pulse_out_reg<=0;else if(now_state==high_level_state)pulse_out_reg<=1;elsepulse_out_reg<=0; endalways @ (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|low_leval_time==0) start_idle_flag<=1; else start_idle_flag<=0; endassign pulse_out=pulse_out_reg;endmodule

時序分析:
以下選擇的是后來我們決定用5M10ZE64C4,時序也是完全符合的,不存在時序違規。

3、心得

1、CPLD體積小,如果僅僅是完成簡單的觸發等時序,完全可以采用CPLD這類器件。
2、CPLD資源相當少,一般邏輯資源如上圖,才160,稍微不注意,就會超標,所以,寄存器輸入一定要盡量減少,位寬需要多少就定義多少,不要定義太寬,可以用assign的,就不用寄存器。能用一個計數器的,絕不用兩個計數器,狀態機位寬、狀態機狀態數目能少盡量少。條件能寫==的,就不寫<=
3、很容易造成時序違規問題,所以,要解決時序違規,可以適當增加一個或兩個寄存器。特別是狀態機里面的條件,可以把條件化為一個寄存器flag標志,滿足條件,輸出flag,從而減小了數據路徑,從而解決時序偽例。在本實際例子中就是這么解決的,從而能讓fmax能跑到如此大。如果忘記了,看看我寫的底層模塊即可。

總結

以上是生活随笔為你收集整理的记录一次CPLD资源过少、时序伪例的解决办法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。