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