?
前面不知道施主們感覺到?jīng)]有,老僧一直在把大伙兒從電路往 Verilog 語言上拉。這才是正路,很多人卻不曉得,可悲啊。
前面學到的語言要素已經(jīng)可以支持基本的、工程中的數(shù)字邏輯系統(tǒng)設計了。我們所缺少的就是算法和經(jīng)驗。算法這個東東呢,需要數(shù)學知識,所謂的“熟讀唐詩三百首,不會作詩也會吟”;經(jīng)驗的來源是實踐,包括對芯片外圍的理解,這是“讀萬卷書不如行萬里路”。這些實踐包含按鍵與復位處理、多時鐘域處理等,《玩轉(zhuǎn) IP core》/《IP 核芯志》里面介紹過的內(nèi)容,也有老衲以前忽略的可變移位和有限狀態(tài)機設計問題。對于后面兩個問題,這里來個“亡羊補牢,為時不晚”。
1. 變寬移位,流水實現(xiàn)
這一講呢,老衲不務正業(yè)了。給大伙兒講一下,如何實現(xiàn)移位位數(shù)可變的移位操作。
在前面關(guān)于移位操作的內(nèi)容里面,那是千叮嚀萬囑咐?。阂莆坏奈粩?shù)必須是常數(shù)。大多數(shù)人被這個說法迷惑了,認為可變位數(shù)的移位操作是不可實現(xiàn)的,是數(shù)字邏輯界的永動機。其實這是誤解,想想人家 CPU 里面早就可以實現(xiàn)這個功能了。他們可以,我們也自然可以,不可妄自菲薄。鄙人,在這里就要和大家一起突破一下這個語言的限制了,所謂:語言是死的,人是活的。語言上說不成,僅僅是說不能直接用語言 ---- 或者說,簡單的電路 ---- 實現(xiàn)這個功能。換句話說,需要用更加復雜的電路來實現(xiàn),需要用復雜到綜合軟件無能為力的電路來實現(xiàn)。
然后,會被聯(lián)系到的實現(xiàn)變量位數(shù)移位方法就是:每次移位 1 比特直至移到需要的位數(shù)位置。這個屬于時序電路的實現(xiàn)了,有流水方法和時分復用方法兩種。具體討論,如果真的象上面的算法,那么根據(jù)需要移位的位數(shù)的不同,輸出結(jié)果的時刻是不一樣的。一般時序電路完成的操作不喜歡時快時慢的結(jié)果輸出,可能需要插入一些無效的時序來達到輸出時刻的統(tǒng)一。
存在很大的難度,至少老衲目前還沒想通如何實現(xiàn)。下來是揭曉正規(guī)答案的時候了,請看圖 6.15。這個設計還利用了移位操作的分配率,即:
?
以及 shift_width 的二進制編碼特性。這樣,
這個權(quán)值操作,對于時分復用也是可以采用的,可以節(jié)約處理時延。
圖 1 流水線、帶權(quán)值移動的對應電路
對應代碼如例 1 所示。
【例 1】流水線、帶權(quán)值移動的對應代碼
module variable_shift_pipeline
? (
??? input CLK, input RST,
??? input[7:0] a,
??? input[2:0] shift_width,
??? output[7:0] shifted_a
? );
//Definition for Variables in the module
wire[2:0] width_0;
reg[1:0]? width_1;
reg?????? width_2;
//Shift_width chain
wire[7:0] a0;
reg[7:0]? a1, a2, a3;
//Operates chain
//Load other module(s)
???????????????
//Logical
assign a0 = a;
assign width_0 = shift_width;
assign shifted_a = a3;
always @(posedge CLK or negedge RST)
//Shift_width chain
begin
?? if (!RST)
?? //Reset
?? begin
?????? width_1 <= 2'b00;
?????? width_2 <= 1'b0;
?? end
?? else
?? begin
?????? width_1 <= width_0[2:1];
?????? width_2 <= width_1[1];
?? end
end
always @(posedge CLK or negedge RST)
//Operation
begin
?? if (!RST)
?? begin
?????? a1 <= 8'h0;
?? end
?? else
?? begin
?????? if (width_0[0])
?????? begin
?????????? a1 <= a0 << 1;
?????? end
?????? else
?????? begin
?????????? a1 <= a0;
?????? end
?? end
end
always @(posedge CLK or negedge RST)
//Operation
begin
?? if (!RST)
?? begin
?????? a2 <= 8'h0;
?? end
?? else
?? begin
?????? if (width_1[0])
?????? begin
?????????? a2 <= a1 << 2;
?????? end
?????? else
?????? begin
?????????? a2 <= a1;
?????? end
?? end
end
always @(posedge CLK or negedge RST)
//Operation
begin
?? if (!RST)
?? begin
?????? a3 <= 8'h0;
?? end
?? else
?? begin
?????? if (width_2)
?????? begin
?????????? a3 <= a2 << 4;
?????? end
?????? else
?????? begin
?????????? a3 <= a2;
?????? end
?? end
end
endmodule
?
2. 有限狀態(tài),同步變化
數(shù)學家,以及很像數(shù)學家的理論物理學家,孜孜不倦地追求統(tǒng)一場論,至今未遂。數(shù)字邏輯領(lǐng)域,倒是得到了一個統(tǒng)一的模型,這就是有限狀態(tài)機(Finite-state machine,F(xiàn)SM)。理論上,所有數(shù)字邏輯電路系統(tǒng)都可以被看做這個狀態(tài)機的一個實例。所以呢,這一講在下給大家詳細介紹有限狀態(tài)機。
欲了解有限狀態(tài)機,必先了解狀態(tài)轉(zhuǎn)移圖;欲了解狀態(tài)轉(zhuǎn)移圖,必先知道圖中各個單元和文字的含義。圖 2 是一個學生在上課的狀態(tài)轉(zhuǎn)移圖,假設到校后上四節(jié)課,之后放學;再到校,再上四節(jié)課,再放學;如此往復。圖里面的一個圓圈就是一個狀態(tài),圓的上方的文字是狀態(tài)名稱,下方是該狀態(tài)對應的操作。例如,狀態(tài)“上課”的操作就是“聽講”。如果圓的下方?jīng)]有文字,就是沒有具體操作。帶有箭頭的曲線代表狀態(tài)的轉(zhuǎn)移,線上的文字是狀態(tài)轉(zhuǎn)移的條件。例如,“到?!焙螅牭健按蜮彙本烷_始“上課”。如果線上沒有文字,則表示無條件轉(zhuǎn)移。狀態(tài)轉(zhuǎn)移的節(jié)拍,就是系統(tǒng)輸入時鐘的周期。
圖 2 學生上學的狀態(tài)圖
忽略復雜的數(shù)學理論,直接介紹有限狀態(tài)機實現(xiàn)。有限狀態(tài)機,對于實現(xiàn)非常重要的抽象模型圖圖分享給給為施主,見圖 3。
圖 3 有限狀態(tài)機的抽象模型
莫急莫急,這就到了一段、兩段、三四段的介紹了。什么叫四段啊?看看,被你催的,一著急敲錯了。
所謂“一段式”如就是“不管三七二十一”,把所有邏輯寫到一起。這種風格,可以借用程序語言里面的一個術(shù)語叫做“一團面條”。
“二段式”屬于一種比“一段式”更加奇怪的做法??磮D 6.19,二段式有兩種方式??偨Y(jié)起來都屬于亂來。按照排列組合 C_3^2=3,有三種配法:或者把“狀態(tài)轉(zhuǎn)移條件”和“狀態(tài)”配對,或者讓“狀態(tài)”與“輸出邏輯”結(jié)合,還有“狀態(tài)轉(zhuǎn)移條件”與“輸出邏輯”的路數(shù)。還是那句話:不建議,不鼓勵。
有限狀態(tài)機的“三段式”描述方法。有限狀態(tài)機 和其他設計一樣,最好使用同步時序方式設計,以提高設計的穩(wěn)定性,消除毛刺。狀態(tài)機實現(xiàn)后,一般來說,狀態(tài)轉(zhuǎn)移部分是同步時序電路而狀態(tài)的轉(zhuǎn)移條件的判斷是組合邏輯。三段式之所以比一段和二段式編碼合理,就在于三段式編碼將不同功能分別放到不同的 always 程序塊中實現(xiàn)。這樣做的好處不僅僅是便于閱讀、理解、維護,更重要的是利于綜合器優(yōu)化代碼,利于用戶添加合適的時序約束條件,利于布局布線器實現(xiàn)設計。
說的很抽象,現(xiàn)在用一個實例的不同代碼風格表演一下下。
“序列檢測器可用于檢測由二進制碼組成的脈沖序列信號。當序列檢測器連續(xù)收到一組串行二進制碼后,如果這組序列碼與檢測器中預先設置的序列碼相同,則輸出 1,否則輸出 0。這種檢測的關(guān)鍵是必須收到連續(xù)的正確碼,所以要求檢測器必須對前一次接受到的序列碼做記憶分析,直到在連續(xù)檢測中所收到的每一位二進制碼都與預置序列碼對應相同。在檢測過程中,只要有一位不相等都將回到初始狀態(tài)重新開始檢測。不考慮重疊的可能。”
為了真正達到可以實現(xiàn)的程度,再來細化一下輸入輸出和具體條件。先來定義同步字長度,就 4 比特吧。雖然沒有任何實際價值,判決失誤率很高;但是代碼短一點,該有的全有了,更常的寬度也只是力氣活了。還有輸入是一個時鐘周期,輸入一個比特的數(shù)據(jù),低比特在前面。如果匹配到同步字,才輸出高電平“1”;其他時間,輸出低電平“0”。
先設計系統(tǒng)的狀態(tài)轉(zhuǎn)移圖,如圖 3 所示。每次檢測到一個比特,狀態(tài)前進一次;沒有檢測到,則狀態(tài)回退到空閑 /IDLE。
圖 3 比特序列檢測單元的狀態(tài)轉(zhuǎn)移圖
例 2 是這個模塊的二段式代碼,例 3 是這個模塊的三段式代碼。
?
【例 2】比特序列檢測單元的代碼(二段式)
`define STATE_IDLE? 0
`define STATE_BIT0? 1
`define STATE_BIT1? 2
`define STATE_BIT2? 3
`define STATE_BIT3? 4
//State defination
`define SYNC_CODE?? 4'b1001
//Sequence to be detected
module sequence_detect
? (
??? input clk,
??? input Reset,
??? input data,
??? output reg detected
? );
//Defination for Varables in the module
reg[3:0] state;
wire[3:0] detecting_sequnce;
//Logicals
//Combanitory logicals
assign detecting_sequnce = `SYNC_CODE;
//Timing
always @ (posedge clk or negedge Reset)
//Statement management part
begin
??? if (!Reset)
??? //Reset enable
??? begin
??????? state <= `STATE_IDLE;
??? end
??? else
??? //state change
??? begin
??????? case (state)
??????????? `STATE_IDLE:
??????????? //Idle statement, waiting for bit 0
??????????? begin
??????????????? if ( data == detecting_sequnce[0])
??????????????? //Bit 0 detected
??????????????? begin
??????????????????? state <= `STATE_BIT0;
??????????????? end
??????????????? else
??????????????? begin
??????????????? end
??????????? end
???????????
??????????? `STATE_BIT0:
??????????? //Bit0 statement, waiting for bit 1 or return idle
??????????? begin
??????????????? if ( data == detecting_sequnce[1])
??????????????? //Bit 1 detected
??????????????? begin
??????????????????? state <= `STATE_BIT1;
??????????????? end
??????????????? else
??????????????? //Return idle statement
??????????????? begin
??????????????????? state <= `STATE_IDLE;
??????????????? end
??????????? end
???????????
??????????? `STATE_BIT1:
??????????? //Bit1 statement, waiting for bit 2 or return idle
??????????? begin
??????????????? if ( data == detecting_sequnce[2])
??????????????? //Bit 2 detected
??????????????? begin
??????????????????? state <= `STATE_BIT2;
??????????????? end
??????????????? else
??????????????? //Return idle statement
??????????????? begin
??????????????????? state <= `STATE_IDLE;
??????????????? end
??????????? end
???????????
??????????? `STATE_BIT2:
??????????? //Bit2 statement, waiting for bit 3 or return idle
??????????? begin
??????????????? if ( data == detecting_sequnce[3])
??????????????? //Bit 2 detected
??????????????? begin
??????????????????? state <= `STATE_BIT3;
??????????????? end
??????????????? else
??????????????? //Return idle statement
??????????????? begin
??????????????????? state <= `STATE_IDLE;
??????????????? end
??????????? end
???????????
??????????? `STATE_BIT3:
??????????? //Bit3 statement, return idle
??????????? begin
??????????? //Return idle statement
??????????? state <= `STATE_IDLE;
??????????? end
???????????
??????????? default:
??????????? begin
??????????? //Return idle statement
??????????? state <= `STATE_IDLE;
??????????? end
??????? endcase
??? end
end
always @ (posedge clk or negedge Reset)
//Output part
begin
??? if (!Reset)
??? //Reset enable
??? begin
??????? detected <= 1'b0;
??? end
??? else if (`STATE_BIT3 == state)
??? //Sequence detected
??? begin
??????? detected <= 1'b1;
??? end
??? else
??? //Idle and detecting
??? begin
??????? detected <= 1'b0;
??? end
end
endmodule
?
【例 3】比特序列檢測單元的代碼(三段式)
……
//Defination for Varables in the module
reg[3:0] state;
reg[3:0] next_state;
//State variables
……
//Timing
always @ (posedge clk or negedge Reset)
//Statement management part
begin
??? if (!Reset)
??? //Reset enable
??? begin
??????? next_state <= `STATE_IDLE;
??? end
??? else
??? //state change
??? begin
??????? case (state)
??????????? `STATE_IDLE:
??????????? //Idle statement, waiting for bit 0
??????????? begin
??????????????? if ( data == detecting_sequnce[0])
??????????????? //Bit 0 detected
??????????????? begin
??????????????????? next_state <= `STATE_BIT0;
??????????????? end
??????????????? else
??????????????? begin
??????????????? end
??????????? end
???????????
??????????? `STATE_BIT0:
??????????? //Bit0 statement, waiting for bit 1 or return idle
??????????? begin
??????????????? if ( data == detecting_sequnce[1])
??????????????? //Bit 1 detected
??????????????? begin
??????????????????? next_state <= `STATE_BIT1;
??????????????? end
??????????????? else
??????????????? //Return idle statement
??????????????? begin
??????????????????? next_state <= `STATE_IDLE;
??????????????? end
??????????? end
???????????
??????????? `STATE_BIT1:
??????????? //Bit1 statement, waiting for bit 2 or return idle
??????????? begin
??????????????? if ( data == detecting_sequnce[2])
??????????????? //Bit 2 detected
??????????????? begin
??????????????????? next_state <= `STATE_BIT2;
??????????????? end
??????????????? else
??????????????? //Return idle statement
??????????????? begin
??????????????????? next_state <= `STATE_IDLE;
??????????????? end
??????????? end
???????????
??????????? `STATE_BIT2:
??????????? //Bit2 statement, waiting for bit 3 or return idle
??????????? begin
??????????????? if ( data == detecting_sequnce[3])
??????????????? //Bit 2 detected
??????????????? begin
??????????????????? next_state <= `STATE_BIT3;
??????????????? end
??????????????? else
??????????????? //Return idle statement
??????????????? begin
??????????????????? next_state <= `STATE_IDLE;
??????????????? end
??????????? end
???????????
??????????? `STATE_BIT3:
??????????? //Bit3 statement, return idle
??????????? begin
??????????? //Return idle statement
??????????????? next_state <= `STATE_IDLE;
??????????? end
???????????
??????????? default:
??????????? begin
??????????? //Return idle statement
??????????????? next_state <= `STATE_IDLE;
??????????? end
??????? endcase
??? end
end
always @ (posedge clk or negedge Reset)
//State part
begin
??? if (!Reset)
??? //Reset enable
??? begin
??????? state <= `STATE_IDLE;
??? end
??? else
??? //State change
??? begin
??????? state <= next_state;
??? end
end
……
endmodule
三段式比二段式多了一個 next_state 這個過渡的寄存器,其他寫法非常類似。
其他課題還有很多,等到施主遇到的時候,在單獨討論好了。
這正是:
“
工程問題萬萬千,理論知識無極限。系統(tǒng)設計百般變,電路描述有語言。
數(shù)學早有研究遠,都會教材根本源。模式變化數(shù)字三,有限狀態(tài)模型間。
”
與非網(wǎng)原創(chuàng)內(nèi)容,謝絕轉(zhuǎn)載!
系列匯總:
之二:Verilog 編程無法一蹴而就,語言層次講究“名正則言順”