找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開(kāi)始

搜索
查看: 6943|回復(fù): 4
收起左側(cè)

FPGA經(jīng)典設(shè)計(jì)案例

[復(fù)制鏈接]
ID:588548 發(fā)表于 2019-7-30 08:44 | 顯示全部樓層 |閱讀模式
學(xué)習(xí)FPGA,最關(guān)鍵的是學(xué)什么?有讀者學(xué)了大半年時(shí)間的FPGA,學(xué)了串口就只懂串口的設(shè)計(jì),學(xué)了SPI就只懂SPI接口的設(shè)計(jì)。每個(gè)接口、每個(gè)功能,都只是學(xué)一個(gè)懂一個(gè)。換個(gè)功能需求,或者對(duì)接口做一個(gè)小小的改動(dòng),就無(wú)從下手了。
設(shè)計(jì)代碼,從來(lái)都只是模仿,或者不斷地調(diào)試修改,湊代碼。設(shè)計(jì)出的代碼也沒(méi)有任何規(guī)律,相同的功能,今天設(shè)計(jì)和明天設(shè)計(jì)都不一樣。這就如學(xué)功夫,今天學(xué)下少林,明天學(xué)下武當(dāng),后天又學(xué)下華山,在這樣的情況下,能成長(zhǎng)為高手,那就奇怪了。
在明德?lián)P看來(lái),FPGA設(shè)計(jì)應(yīng)該有一套通用的設(shè)計(jì)方法。該方法能夠應(yīng)付所有的功能設(shè)計(jì),無(wú)論功能怎么變,都可以用該方法來(lái)套用。明德?lián)P發(fā)明的這套方法就是至簡(jiǎn)設(shè)計(jì)法。
至簡(jiǎn)設(shè)計(jì)法從宏觀上,適應(yīng)所有的功能設(shè)計(jì)需求。例如,無(wú)論是什么功能,我們都先將其轉(zhuǎn)化成需求波形。然后在此基礎(chǔ)上設(shè)計(jì)模塊架構(gòu);在模塊架構(gòu)基礎(chǔ)上設(shè)計(jì)信號(hào)。這步驟都是通用的、是固化的。
至簡(jiǎn)設(shè)計(jì)法在微觀上,則制定得實(shí)用的規(guī)范。詳細(xì)到,要不要添加信號(hào);怎么添加信號(hào);添加信號(hào)的名字規(guī)范等,我們都做了詳細(xì)的規(guī)定。
下面我們用4個(gè)經(jīng)典例子,講述了至簡(jiǎn)設(shè)計(jì)法的使用技巧。其他復(fù)雜功能,無(wú)論怎么變,都是這4個(gè)經(jīng)典案例的變種。讀者只需要強(qiáng)化、鞏固技巧,多訓(xùn)練,多應(yīng)用,逐步成長(zhǎng)為高手。
至簡(jiǎn)設(shè)計(jì)法經(jīng)典案例1
案例1. 當(dāng)收到en=1后,dout產(chǎn)生一個(gè)寬度為10個(gè)時(shí)鐘周期的高電平脈沖。
需要說(shuō)明,根據(jù)看波形規(guī)則,在第3個(gè)時(shí)鐘上沿的時(shí)候,看到en==1,根據(jù)功能要求,上升沿之后dout就會(huì)變?yōu)?/font>110個(gè)時(shí)鐘周期后,dout將變?yōu)?/font>0
從功能要求中,看到數(shù)字10,我們就知道要計(jì)數(shù),并且是dout==1的次數(shù)為10個(gè)。所以我們計(jì)算的是dout==1的時(shí)鐘次數(shù),并且是10次。為此,補(bǔ)充一個(gè)計(jì)數(shù)器信號(hào)cnt,更新后的波形如下圖。
計(jì)數(shù)器cnt要遵守如下原則。
初值一定為0。
除了最后一個(gè),在時(shí)鐘上升沿,看到dout==1,就將cnt值加1
在時(shí)鐘上升沿時(shí)看到dout==1,并且是最后一個(gè)時(shí),cnt值不加1,直接清零。
從功能要求和波形圖,我們確認(rèn),計(jì)數(shù)器cnt是對(duì)dout==1進(jìn)行計(jì)數(shù),并且一共數(shù)10個(gè)。為此,在GVIM編輯器中輸入“Jsq”并回車,將出現(xiàn)如下代碼。
在第13行,輸入dout==1,在第14行代碼中,輸入10-1,這樣就完成了計(jì)數(shù)器設(shè)計(jì)。
代碼解釋:第1至第11行,是一個(gè)時(shí)序always的代碼。該代碼要描述的功能是:
在時(shí)鐘clk上升沿或者復(fù)位rst_n的下降沿的時(shí)候,always就對(duì)cnt判斷條件并變化一次。具體變化過(guò)程如下:
如果是rst_n==0,則將cnt變?yōu)?/font>0。
否則(即rst_n==1),如果add_cnt有效,也就是為1的時(shí)候。繼續(xù)判斷條件并執(zhí)行。
如果end_cnt有效,即end_cnt==1,則將cnt變?yōu)?/font>0。
否則(即end_cnt==0),cnt就自加1。
否則(即rst_n==1add_cnt==0的時(shí)鐘),cnt保持不變。
上面代碼中add_cnt表示計(jì)數(shù)器加1條件,end_cnt表示計(jì)數(shù)器數(shù)到最后一個(gè)。
上面代碼描述過(guò)于復(fù)雜,其實(shí)概括起來(lái),功能就是:時(shí)鐘上升沿時(shí),如果計(jì)數(shù)器加1條件有效,并且是數(shù)到最后一個(gè),則計(jì)數(shù)器清零;如果計(jì)數(shù)器加1條件有效,但不是最后一個(gè),則計(jì)數(shù)器就加1;其他時(shí)候,計(jì)數(shù)器就保持不變。
那么加1條件,即add_cnt是什么呢?在第13行進(jìn)行了定義。該行代碼表示,dout==1就是計(jì)數(shù)器的加1條件。
那么結(jié)束條件,即end_cnt是什么呢?在第14行進(jìn)行了定義。該行代碼表示,數(shù)到10個(gè)就結(jié)束。其中我們關(guān)注的是那個(gè)數(shù)字10,而-1是固定的格式。
add_cnt && cnt==10-1,含義是表示“數(shù)到第10個(gè)的時(shí)候”,add_cnt &&cnt==x-1表示“數(shù)到第x個(gè)的時(shí)候”。記住這個(gè)規(guī)則。end_cnt==1也表示數(shù)完了。
設(shè)計(jì)好計(jì)數(shù)器cnt后,我們就可以設(shè)計(jì)輸出信號(hào)dout了。仔細(xì)分析dout,該信號(hào)有兩個(gè)變化點(diǎn):變1和變0。我們分析原因,dout1是由于收到en==1;dout0,則是數(shù)到了10個(gè)或者是數(shù)完了。所以綜上所述,dout的代碼是:
至此,我們完成了主體程序的設(shè)計(jì),接下來(lái)補(bǔ)充module的其他部分。
module的名稱定義為my_ex1。并且我們已經(jīng)知道該模塊有4個(gè)信號(hào):clk、rst_nendout。為此,代碼如下:
其中clk、rst_nen是輸入信號(hào),dout是輸出信號(hào),并且4個(gè)信號(hào)都是1比特的,根據(jù)這些信息,我們補(bǔ)充輸入輸出端口定義。代碼如下:
接下來(lái)定義信號(hào)類型。
cnt是用always產(chǎn)生的信號(hào),因此類型為reg。cnt計(jì)數(shù)的最大值為9,需要用4根線表示,即位寬是4位。add_cntend_cnt都是用assign方式設(shè)計(jì)的,因此類型為wire。并且其值是0或者1,1個(gè)線表示即可。因此代碼如下:
dout是用always方式設(shè)計(jì)的,因此類型為reg。并且其值是0或者1,1根線表示即可。因此代碼如下:
至此,整個(gè)代碼的設(shè)計(jì)工作已經(jīng)完成。整體代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
module my_ex1(
     clk      ,
     rst_n    ,
     en       ,
     dout      
);
input    clk     ;
input    rst_n   ;
input    en      ;
output   dout    ;

reg [ 3:0]  cnt     ;
wire        add_cnt ;
wire        end_cnt ;
reg         dout    ;


always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        cnt <= 0;
    end
    else if(add_cnt)begin
        if(end_cnt)
            cnt <= 0;
        else
            cnt <= cnt + 1;
    end
end

assign add_cnt = (dout==1);      
assign end_cnt = add_cnt && cnt==10 -1 ;  

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        dout <= 0;
    end
    else if(en==1)begin
        dout <= 1;
    end
    else if(add_cnt && cnt==10-1)begin
        dout <= 0;
    end
end

endmodule
  如果你覺(jué)得有用的話,就請(qǐng)你回個(gè)貼或者贊,證明我的付出沒(méi)有白費(fèi),大家都不容易,q328908175,讓我們共同學(xué)習(xí)。

回復(fù)

使用道具 舉報(bào)

ID:137243 發(fā)表于 2019-11-12 11:48 | 顯示全部樓層
本帖最后由 天上跑著玩 于 2019-11-12 13:59 編輯

樓主
這里的

  if(end_cnt)
       cnt<=0;
     else
     cnt <= cnt+1;
    end
根據(jù)上面的cnt最大加到9時(shí)就會(huì)變成0
else if(en==1)
    begin
       dout<=1;
    end

else if(add_cnt && cnt==10-1)
    begin
       dout<=0;
    end

這邊也是cnt計(jì)數(shù)到9時(shí)就運(yùn)行。
那么dout只會(huì)在clk上升沿觸發(fā),那么dout在這個(gè)程序里會(huì)觸發(fā)不了。
要改成 cnt==10;


回復(fù)

使用道具 舉報(bào)

ID:632402 發(fā)表于 2019-10-30 15:20 | 顯示全部樓層
不錯(cuò),確實(shí)提倡樓主的做法
回復(fù)

使用道具 舉報(bào)

ID:435708 發(fā)表于 2019-9-1 13:42 | 顯示全部樓層
不錯(cuò),最近在看正點(diǎn)原子FPGA的視頻,看了樓主的帖子,對(duì)程序的設(shè)計(jì)又有了新的理解
回復(fù)

使用道具 舉報(bào)

ID:275826 發(fā)表于 2019-9-1 10:55 | 顯示全部樓層
例子不錯(cuò),規(guī)范,有代表性
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表