新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > FPGA計(jì)數(shù)器的藝術(shù)

FPGA計(jì)數(shù)器的藝術(shù)

作者: 時間:2023-12-28 來源:EEPW 收藏

計(jì)數(shù)器構(gòu)成了一個基本的構(gòu)建塊。 它們有各種形狀和形式......

本文引用地址:http://2s4d.com/article/202312/454304.htm

計(jì)數(shù)器 1 - 計(jì)數(shù)器

最簡單的計(jì)數(shù)器

可以使用幾行 Verilog 構(gòu)建快速高效的計(jì)數(shù)器。例如,下面是一個 32 位計(jì)數(shù)器。

reg [31:0] cnt;

always @(posedge clk) cnt <= cnt+1;

此類計(jì)數(shù)器從 0 計(jì)數(shù)到 4294967295,然后回滾 0 以繼續(xù)其進(jìn)程。 它占用的資源很少,并且在中運(yùn)行速度快,這要?dú)w功于隱藏的攜帶鏈(稍后會詳細(xì)介紹)。 現(xiàn)在,讓我們看看一些變化。

首先,最好明確給出一個起始值,即使它是 0。

reg [31:0] cnt = 0;

always @(posedge clk) cnt <= cnt+1;

請注意,如果我們不指定起始值,仿真工具將拒絕工作,并且某些合成工具也可能會自行更改起始值......因此,最好始終指定一個起始值。 我們也可以使用異步重置來指定起始值,但最簡單的方法如上所示。

現(xiàn)在,如果您需要更多功能,這里有一個 10 位計(jì)數(shù)器(最多計(jì)數(shù) 1023)的示例,該計(jì)數(shù)器從 300 開始計(jì)數(shù),并具有啟用和方向控制。

reg [9:0] cnt = 10'd300;  // 10bit counter, starts at 300

wire cnt_enable;  // 0 to disable the counter, 1 to enable it

wire cnt_direction;  // 0 to counter backward, 1 to count forward

always @(posedge clk) if(cnt_enable) cnt <= cnt_direction ? cnt+1 : cnt-1;

請注意,綜合工具必須采取一些技巧才能使計(jì)數(shù)器從300開始。 FPGA 內(nèi)部的觸發(fā)器總是從 0 開始,因此您可以認(rèn)為計(jì)數(shù)器初始值必須為 0...但是,通過在邏輯中放置一些位置良好的逆變器,任何起始值都是可能的。 逆變器在FPGA中是“免費(fèi)”的,因此沒有缺點(diǎn)。

計(jì)數(shù)器滴答聲

假設(shè)我們需要一個“滴答”信號,該信號每 1024 個時鐘斷言一次。 最有可能的是,我們會創(chuàng)建一個 10 位計(jì)數(shù)器和一些邏輯來生成“滴答聲”。 讓我們看看如何做到這一點(diǎn)。

首先,我們制作 10 位計(jì)數(shù)器。它從 0 到 1023 計(jì)數(shù)。

reg [9:0] cnt = 0;

always @(posedge clk) cnt <= cnt+1;

現(xiàn)在我們可以決定,當(dāng)計(jì)數(shù)器達(dá)到其最大值時(就在回滾到 0 之前),我們的“tick”被斷言。

wire tick = (cnt==1023);

另一種寫作方式是

wire tick = &cnt;  // assert "tick" when all the cnt bits are 1這些滴答信號的缺點(diǎn)是它們會產(chǎn)生一大塊邏輯(這里是 10 位 AND 門)。 只有 10 位沒什么大不了的,但如果我們的計(jì)數(shù)器是 32 位或更大,那將是一種浪費(fèi)。 另一種方法是依賴FPGA在后臺使用的(通常是隱藏的)進(jìn)位鏈。 我們只需要稍微扭動一下手臂來說服FPGA提供他隱藏的信息......

reg [31:0] cnt = 0;  // 32bit counter

wire [32:0] cnt_next = cnt+1;  // next value calculated with 33bit (one bit more than the counter)

always @(posedge clk) cnt <= cnt_next[31:0];  // now the counter uses only 32 bits

wire tick = cnt_next[32];  // but we access to the last bit of the carry chain to create the tick (asserted when the counter reaches its maximum value)

嘗試一下,你會發(fā)現(xiàn)它的工作原理是一樣的,但在FPGA中占用的空間更少 (注意:在撰寫本文時,我們嘗試了 ISE 和 Quartus-II,并且都以 0 作為起始值做得很好)。

計(jì)數(shù)器 2 - 特殊計(jì)數(shù)器

模量計(jì)數(shù)器

模量計(jì)數(shù)器是在其自然結(jié)束值之前回滾的計(jì)數(shù)器。 例如,假設(shè)你想要一個模數(shù) 10 計(jì)數(shù)器(從 0 到 9 計(jì)數(shù)),你可以寫這個。

reg [3:0] cnt = 0;  // we need 4 bits to be able to reach 9

always @(posedge clk)

if(cnt==9)

    cnt <= 0;

else

    cnt <= cnt+1;

或者這個(更緊湊一點(diǎn))

reg [3:0] cnt = 0;

always @(posedge clk) cnt <= (cnt==9) ? 0 : cnt+1;

現(xiàn)在,如果您意識到我們實(shí)際上不需要將計(jì)數(shù)器的所有 4 位與 9 位進(jìn)行比較,則可以進(jìn)行一些(免費(fèi))優(yōu)化。 下面的代碼在比較中僅使用位 0 和位 3。

always @(posedge clk) cnt <= ((cnt & 9)==9) ? 0 : cnt+1;

灰色計(jì)數(shù)器

灰色計(jì)數(shù)器是一種二進(jìn)制計(jì)數(shù)器,一次只有一個位發(fā)生變化。

以下是 4bit Gray 計(jì)數(shù)器的運(yùn)行方式。

0000

0001

0011

0010

0110

0111

0101

0100

1100

1101

1111

1110

1010

1011

1001

1000

and then wraps back to 0000...

格雷碼對于跨時鐘域發(fā)送值很有用(這樣它的不確定性僅為 1)。

創(chuàng)建 Gray 計(jì)數(shù)器的最簡單方法是首先創(chuàng)建一個二進(jìn)制計(jì)數(shù)器,然后將值轉(zhuǎn)換為 Gray。

module GrayCounter(

  input clk,

  output [3:0] cnt_gray

);

reg [3:0] cnt = 0;

always @(posedge clk) cnt <= cnt+1;  // 4bit binary counter

assign cnt_gray = cnt ^ cnt[3:1];  // then convert to gray

endmodule

也可以創(chuàng)建本機(jī) Gray 計(jì)數(shù)器。

module GrayCounter(

  input clk,

  output reg [3:0] cnt_gray = 0

);

wire [3:0] cnt_cc = {cnt_cc[2:1] & ~cnt_gray[1:0], ^cnt_gray, 1'b1};  // carry-chain type logic

always @(posedge clk) cnt_gray <= cnt_gray ^ cnt_cc ^ cnt_cc[3:1];

endmodule

計(jì)數(shù)器 3 - LFSR 計(jì)數(shù)器

假設(shè)您想要一個或多或少“隨機(jī)”計(jì)數(shù)的計(jì)數(shù)器,您可以使用 LFSR。

下面是一個示例。

如您所見,LFSR是帶有一些XOR門的移位寄存器。 上圖所示的是 8 抽頭 LFSR(它使用 8 個人字拖)。

輸出序列開始如下(假設(shè)所有觸發(fā)器都從“1”開始):

11111111

11000111

11011011

11010101

11010010

01101001

10001100

01000110

00100011

10101001

11101100

01110110

00111011

10100101

...

這是 LFSR 源代碼。

module LFSR8_11D(

  input clk,

  output reg [7:0] LFSR = 255   // put here the initial value

);

wire feedback = LFSR[7];

always @(posedge clk)

begin

  LFSR[0] <= feedback;

  LFSR[1] <= LFSR[0];

  LFSR[2] <= LFSR[1] ^ feedback;

  LFSR[3] <= LFSR[2] ^ feedback;

  LFSR[4] <= LFSR[3] ^ feedback;

  LFSR[5] <= LFSR[4];

  LFSR[6] <= LFSR[5];

  LFSR[7] <= LFSR[6];

end

endmodule

請注意,我們從 255 開始。 這是因?yàn)?0 是死胡同狀態(tài),因此我們可以選擇除 0 以外的任何起始值。 之后,LFSR 在每個時鐘周期更改值,但永遠(yuǎn)不會達(dá)到 0,因此在重新開始之前,它只經(jīng)過 255 個 8 位值(256 位輸出的 8 種可能組合)。

現(xiàn)在,我們可以只輸出一位,而不是輸出完整的 255 位(即選擇任何觸發(fā)器進(jìn)行輸出,將其他 0 位保留在內(nèi)部)。 這會產(chǎn)生一個由 1 個 255 和 <> 組成的字符串,看起來是隨機(jī)的(盡管它在 <> 個時鐘后會重復(fù))。 對噪聲發(fā)生器很有用...

定制

您可以調(diào)整 LFSR:

選擇不同數(shù)量的水龍頭(我們在上面選擇了 8 個)。

改變反饋網(wǎng)絡(luò)的接線方式 - 例如更改XOR門的數(shù)量,它們的放置位置,或用XNOR替換XOR門。

某些反饋配置將創(chuàng)建可能值的孤島。 例如,此 LFSR 看起來與第一個 LFSR 類似,但僅循環(huán)遍歷 30 個值。

module LFSR8_105(

  input clk,

  output reg [7:0] LFSR = 255

);

wire feedback = LFSR[7];

always @(posedge clk)

begin

  LFSR[0] <= feedback;

  LFSR[1] <= LFSR[0];

  LFSR[2] <= LFSR[1] ^ feedback;

  LFSR[3] <= LFSR[2];

  LFSR[4] <= LFSR[3];

  LFSR[5] <= LFSR[4];

  LFSR[6] <= LFSR[5];

  LFSR[7] <= LFSR[6];

end

endmodule

也可以在反饋中添加一些邏輯,以便LFSR達(dá)到所有可能的狀態(tài)。

module LFSR8_11D(

  input clk,

  output reg [7:0] LFSR = 255

);


wire feedback = LFSR[7] ^ (LFSR[6:0]==7'b0000000);  // modified feedback allows reaching 256 states instead of 255


always @(posedge clk)

begin

  LFSR[0] <= feedback;

  LFSR[1] <= LFSR[0];

  LFSR[2] <= LFSR[1] ^ feedback;

  LFSR[3] <= LFSR[2] ^ feedback;

  LFSR[4] <= LFSR[3] ^ feedback;

  LFSR[5] <= LFSR[4];

  LFSR[6] <= LFSR[5];

  LFSR[7] <= LFSR[6];

end

endmodule

LFSR測試臺

我們制作了一個小型 Windows 實(shí)用程序,允許對 LFSR 設(shè)計(jì)進(jìn)行試驗(yàn)。

在此處下載。

計(jì)數(shù)器4-攜帶鏈

進(jìn)位鏈?zhǔn)窃试S FPGA 高效運(yùn)算(計(jì)數(shù)器、加法器等)的功能。 讓我們更多地了解使用計(jì)數(shù)器的進(jìn)位鏈。 使用 T 字拖可以輕松構(gòu)建計(jì)數(shù)器。

T 字拖非常簡單。 在時鐘上升沿,如果 T 輸入為高電平,則其 Q 輸出切換,如果 T 為低電平,則不會改變。

FPGA 內(nèi)部使用 D 觸發(fā)器,但 D 和 T 觸發(fā)器很容易互換,只需一些邏輯即可。 因此,我們在此頁面上使用T觸發(fā)器,因?yàn)槲覀冎繤PGA軟件可以很容易地將它們映射到FPGA中。

紋波計(jì)數(shù)器

最小的二進(jìn)制計(jì)數(shù)器是紋波計(jì)數(shù)器。 這是一個 4 位紋波計(jì)數(shù)器。

基本上,每個T觸發(fā)器輸出驅(qū)動下一個觸發(fā)器的時鐘。 它在硬件方面非常高效,但對于FPGA來說不是很好,因?yàn)槲覀儸F(xiàn)在的時鐘域與計(jì)數(shù)器中的位數(shù)一樣多。 FPGA 針對同步電路進(jìn)行了優(yōu)化,因此我們需要所有計(jì)數(shù)器位同時切換的東西。

同步計(jì)數(shù)器

在同步計(jì)數(shù)器中,時鐘同時饋送所有觸發(fā)器,因此只有一個時鐘域。

現(xiàn)在,如果我們看一下二進(jìn)制計(jì)數(shù)器的計(jì)數(shù)方式,我們會看到 bit0 總是切換,并且對于任何要切換的更高位,所有低階位都需要為 1。 因此,我們的同步計(jì)數(shù)器通過使用幾個 AND 門來形成。

只要柜臺小就好。 我們的示例 4 位計(jì)數(shù)器只需要兩個 AND 門(顯然還有觸發(fā)器),因此它非常高效。 但這并不能很好地?cái)U(kuò)展。 對于 32 位計(jì)數(shù)器,我們需要 30 個 AND 門,最后一個有 31 個輸入...... 但是,我們可以很容易地以這種方式重新繪制計(jì)數(shù)器(這次我們制作了一個 6 位計(jì)數(shù)器)。

基本上,我們沒有讓 AND 門變大,而是將它們保持較小并將它們鏈接起來。

這就是 FPGA 實(shí)現(xiàn)計(jì)數(shù)器的方式。 它在硬件方面是高效的,但問題是速度...... 例如,一個 32 位計(jì)數(shù)器需要 30 個鏈?zhǔn)?AND 門。 而這個鏈?zhǔn)怯?jì)數(shù)器“關(guān)鍵路徑”(設(shè)置最大計(jì)數(shù)器時鐘速度)的主要部分。 因此,保持這條道路的快速性很重要......FPGA 有一個很好的技巧來保持速度。 它被稱為...

攜帶鏈

FPGA 由“邏輯元件”組成,每個元件包含一個 LUT 和一個 D 觸發(fā)器。 每個邏輯元件可以實(shí)現(xiàn)一個計(jì)數(shù)器位(一個 32 位計(jì)數(shù)器需要 32 個邏輯元件)。

邏輯元素可以通過通用路由結(jié)構(gòu)與周圍環(huán)境進(jìn)行通信,但這速度很慢。 因此,F(xiàn)PGA 設(shè)計(jì)人員確保并排放置的邏輯元件具有額外的本地路由信號。

實(shí)現(xiàn)為

此本地路由通常用作進(jìn)位鏈。 每次要求FPGA軟件實(shí)現(xiàn)二進(jìn)制計(jì)數(shù)器時,它都會將位彼此相鄰映射,以便將本地路由用作進(jìn)位鏈。 這給映射增加了一些限制,但軟件會處理它。

FPGA 制造商還確保邏輯元件針對沿?cái)y帶鏈路徑的速度進(jìn)行了大量優(yōu)化。 結(jié)果是計(jì)數(shù)器可以在數(shù)百M(fèi)Hz的頻率下輕松運(yùn)行...計(jì)數(shù)器的速度通常不是問題(FPGA設(shè)計(jì)的關(guān)鍵路徑比進(jìn)位鏈更有可能通過常規(guī)邏輯)。 當(dāng)然,這取決于您希望以多快的速度運(yùn)行設(shè)計(jì)。 大型計(jì)數(shù)器具有較長的進(jìn)位鏈,因此無法像小型計(jì)數(shù)器那樣快速計(jì)時。 如果這是一個問題,您可以分解進(jìn)位鏈(即使用一系列小計(jì)數(shù)器)或選擇不使用進(jìn)位鏈的計(jì)數(shù)器架構(gòu)。

對于那些喜歡冒險(xiǎn)的人,請單擊此處查看 Spartan-3A FPGA 設(shè)計(jì)中實(shí)現(xiàn)計(jì)數(shù)器的切片(兩個邏輯元件)的 ISE FPGA 編輯器屏幕截圖。 該視圖適用于計(jì)數(shù)器的第 6 位和第 7 位。 我們可以立即識別出從下到上穿過中間切片的攜帶鏈。 不太明顯的是 AND 門和 T 形觸發(fā)器在哪里。 他們實(shí)際上都在那里...... AND門是使用運(yùn)載鏈線上的大多路復(fù)用器制成的 T觸發(fā)器使用異或門和D觸發(fā)器輸出,環(huán)回LUT輸入(通過邏輯元件外部的布線)。 LUT 只是直通。

進(jìn)位鏈也用于加法器和比較器。 但感謝數(shù)百名工程師致力于構(gòu)建智能 HDL 工具,我們可以使用攜帶鏈的強(qiáng)大功能而不必?fù)?dān)心它們。 生活是美好的。



關(guān)鍵詞: FPGA 計(jì)時器 二進(jìn)制

評論


相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉