用于FSM的三種最受歡迎的編碼是二進制(Binary)、格雷(Gray)和獨熱碼(one-hot)。
二進制編碼
二進制編碼是在將值順序分配給狀態時可以直觀使用的簡單方法。這樣,您將使用盡可能少的位來編碼狀態。
二進制編碼的示例
格雷碼
在一組數的編碼中,若任意兩個相鄰的代碼只有一位二進制數不同,則稱這種編碼為格雷碼(Gray Code),另外由于最大數與最小數之間也僅一位數不同,即“首尾相連”,因此又稱循環碼或反射碼。此外如果狀態序列得到最佳遵循,則此編碼還可將動態功耗降至最低。
格雷碼輪
獨熱編碼
獨熱編碼任何狀態只有1bit為1,其余皆為0,編碼密度低,由于使用的位數和無效狀態的過多,這似乎不太有效。但是,獨熱編碼非常適合簡化觸發器的激勵邏輯,因為位就是狀態,因此無需解碼狀態。
獨熱編碼的示例
這是一個棘手的問題,主要是因為每種編碼都有它的優點和缺點,所以它歸根結底是一個優化問題,取決于很多因素。
如果一個非常簡單的系統在不同的編碼中產生非常相似的結果,那么原始編碼就是最好的選擇。
如果FSM在一條路徑上循環地通過其狀態(像計數器一樣),那么格雷碼是一個非常好的選擇。
如果FSM有一組任意的狀態轉換,或者預計在高頻下運行,也許獨熱碼是最好的方式。
現在,所有這些說法都只是有根據的猜測,找到最佳狀態分配是一個復雜的問題。正因為如此,我建議是讓邏輯綜合替你決定。盡管如此,下面我決定在三種不同的開發工具和三種不同的狀態機對這三種編碼的結果進行比較。
接下來的三個實驗說明了確定哪種編碼適合給定FPGA的過程。
對于此實驗,我想大量實例化一個狀態機,以放大使用二進制,格雷和獨熱編碼時所得硬件的差異。
我最終選擇的系統是康威的《生命的游戲》,這是一種細胞自動機,它模擬了活細胞在其環境中的行為,模擬了這些細胞的出生、繁殖和死亡過程,命游戲是一個二維網格游戲,這個網格中每個方格居住著一個活著或死了的細胞。一個細胞在下一個時刻的生死取決于相鄰8個方格中活著或死了的細胞的數量。如果相鄰方格活著的細胞數量過多,這個細胞會因為資源匱乏而在下一個時刻死去;相反,如果周圍活細胞過少,這個細胞會因為孤單而死去。
在康威的生命游戲中,規定了如下生存定律。
(1)當前細胞為死亡狀態時,當周圍有3個存活細胞時,則迭代后該細胞變成存活狀態(模擬繁殖);若原先為生,則保持不變。
(2)當前細胞為存活狀態時,當周圍的鄰居細胞低于兩個(不包含兩個)存活時,該細胞變成死亡狀態(模擬生命數量稀少)。
(3)當前細胞為存活狀態時,當周圍有兩個或3個存活細胞時,該細胞保持原樣。
(4)當前細胞為存活狀態時,當周圍有3個以上的存活細胞時,該細胞變成死亡狀態(模擬生命數量過多)。
這些規則創建了許多有趣的行為和模式,這些行為和模式已在計算機科學中廣泛研究。
這就是生命游戲在運行所謂的Gosper滑翔槍時的圖例。
《生命游戲》的一種變體,稱為Bill Gosper的滑翔機槍。
回到我們的測試系統,每個單元被設計為一個具有8個狀態的狀態機。不可否認,生命游戲中的細胞邏輯可以在一個周期內解決,但我決定制作一個8狀態機,以便在使用不同編碼時產生顯著差異。這些狀態被用來計算一個細胞的存活鄰居。
下面一段Verilog代碼顯示了這些細胞的單元模塊結構,包括狀態的原始二進制編碼。
`define STATE_0 3'b000
`define STATE_1 3'b001
`define STATE_2 3'b010
`define STATE_3 3'b011
`define STATE_4 3'b100
`define STATE_5 3'b101
`define STATE_6 3'b110
`define STATE_7 3'b111
module LifeCell(
inputclk,
inputnrst,
inputseed,
input[7:0] neighbors,
outputreg alive);
reg [2:0] state;
always @ (posedge clk)
if(nrst == 0)
state<= `STATE_0;
else
case(state)
`STATE_0:begin
//...
state<= `STATE_1;
end
`STATE_1:begin
//...
state<= `STATE_2;
end
//...
`STATE_7:begin
//...
state<= `STATE_1;
end
endcase
endmodule
如果您想更深入地了解代碼,可以在GitHub上查看該項目。
https://github.com/kuashio/conways-game-of-life
FPGA編碼實現
該系統被綜合并實現為一個23x23細胞的世界,共有27個變體:使用了三種不同的FSM,都使用了上述三種編碼,并且都在三種不同的目標FPGA上實現。
FSM#1:原始模型
該機器有一個初始狀態,運行一次,然后循環運行其余7個狀態。這幾乎是一個完整的序列,所以一開始我覺得格雷編碼很有希望。
FSM#2:序列
這臺機器表現為3位計數器,所以我也期待格雷編碼能碾壓競爭對手。
FSM#3:任意路徑糾結
該機器具有與FSM#1相同的關鍵路徑,但是當已知存在的鄰居數量超過3個時,它將會通過任意路徑。
對于這種任意狀態轉換行為,我希望獨熱編碼是最佳選擇。
目標架構
該系統針對三款目標FPGA,利用其供應商的開發工具實現。
結果比較
比較兩個或多個系統的性能很困難,主要是因為判決取決于我們使用的指標以及我們認為哪些方面比其他方面更重要。在本實驗中,我收集了以下數據以為每個實現產生一個分數:
比較兩個或更多系統的性能是很困難的,主要是因為判決取決于我們使用的指標,以及我們認為哪些方面比其他方面更重要。在這個實驗中,我收集了以下數據,以便為每個實現打一個分數:
對于每一個實施方案,這四個方面在三個編碼之間進行比較,所以在編碼之間,我得到一個最好的,一個最差的,一個中間的結果。最好的得正分,最差的得負分,中間的得0分。
將每個模型的所有分數相加后,我得到以下結果:
所有27種實現的結果表。在每一行中,最好的編碼用綠色顯示,最差的用紅色顯示,如果沒有平局,中間的用黃色顯示。
這似乎表明要遠離獨熱編碼,只有兩種情況下它會獲勝,其中一種是平局。此外,雖然我最初認為獨熱編碼是FSM模型#3的最佳編碼,但結果卻是最差的編碼,沒有開發工具推薦它。不過在某些情況下,獨熱編碼會勝過其他的,主要是在頻率和功率指標上。
總體而言,格雷編碼似乎是此特定系統的最佳選擇。
從該表中提取贏家,我們得到以下信息:
盡管這次比較似乎偏向于格雷編碼而不是二進制和獨熱,但結果在很大程度上取決于我們使用的指標,而這些指標是反映了對我們重要的東西。例如,在這次比較中,我們認為頻率和功率比使用率(設計中的邏輯元件和寄存器數量)更重要。如果我重視使用率而不是頻率,或重視頻率而不是功率,肯定會得出不同的排名。
這個比較并不是為了成為使用這些編碼所獲得的性能的權威性工作。相反,它顯示了我在使用的架構中的個人偏好所產生的排名。
提醒一下,如果你想看看代碼,看看27個實現,或者看看我對《生命游戲》的模擬操作,請查看GitHub上的項目:
https://github.com/kuashio/conways-game-of-life