加入星計劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴散
  • 作品版權(quán)保護(hù)
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入
  • 正文
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請入駐 產(chǎn)業(yè)圖譜

從電路到Verilog | 熟讀語言要素,不會編程也懂verilog

2016/08/09
24
  • 1評論
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

?

前面不知道施主們感覺到?jīng)]有,老僧一直在把大伙兒從電路往 Verilog 語言上拉。這才是正路,很多人卻不曉得,可悲啊。


前面學(xué)到的語言要素已經(jīng)可以支持基本的、工程中的數(shù)字邏輯系統(tǒng)設(shè)計了。我們所缺少的就是算法和經(jīng)驗。算法這個東東呢,需要數(shù)學(xué)知識,所謂的“熟讀唐詩三百首,不會作詩也會吟”;經(jīng)驗的來源是實踐,包括對芯片外圍的理解,這是“讀萬卷書不如行萬里路”。這些實踐包含按鍵與復(fù)位處理、多時鐘域處理等,《玩轉(zhuǎn) IP core》/《IP 核芯志》里面介紹過的內(nèi)容,也有老衲以前忽略的可變移位和有限狀態(tài)機設(shè)計問題。對于后面兩個問題,這里來個“亡羊補牢,為時不晚”。


1. 變寬移位,流水實現(xiàn)
這一講呢,老衲不務(wù)正業(yè)了。給大伙兒講一下,如何實現(xiàn)移位位數(shù)可變的移位操作。
在前面關(guān)于移位操作的內(nèi)容里面,那是千叮嚀萬囑咐啊:移位的位數(shù)必須是常數(shù)。大多數(shù)人被這個說法迷惑了,認(rèn)為可變位數(shù)的移位操作是不可實現(xiàn)的,是數(shù)字邏輯界的永動機。其實這是誤解,想想人家 CPU 里面早就可以實現(xiàn)這個功能了。他們可以,我們也自然可以,不可妄自菲薄。鄙人,在這里就要和大家一起突破一下這個語言的限制了,所謂:語言是死的,人是活的。語言上說不成,僅僅是說不能直接用語言 ---- 或者說,簡單的電路 ---- 實現(xiàn)這個功能。換句話說,需要用更加復(fù)雜的電路來實現(xiàn),需要用復(fù)雜到綜合軟件無能為力的電路來實現(xiàn)。


然后,會被聯(lián)系到的實現(xiàn)變量位數(shù)移位方法就是:每次移位 1 比特直至移到需要的位數(shù)位置。這個屬于時序電路的實現(xiàn)了,有流水方法和時分復(fù)用方法兩種。具體討論,如果真的象上面的算法,那么根據(jù)需要移位的位數(shù)的不同,輸出結(jié)果的時刻是不一樣的。一般時序電路完成的操作不喜歡時快時慢的結(jié)果輸出,可能需要插入一些無效的時序來達(dá)到輸出時刻的統(tǒng)一。


存在很大的難度,至少老衲目前還沒想通如何實現(xiàn)。下來是揭曉正規(guī)答案的時候了,請看圖 6.15。這個設(shè)計還利用了移位操作的分配率,即:


?
以及 shift_width 的二進(jìn)制編碼特性。這樣,
這個權(quán)值操作,對于時分復(fù)用也是可以采用的,可以節(jié)約處理時延。


圖 1 流水線、帶權(quán)值移動的對應(yīng)電路


對應(yīng)代碼如例 1 所示。


【例 1】流水線、帶權(quán)值移動的對應(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)一場論,至今未遂。數(shù)字邏輯領(lǐng)域,倒是得到了一個統(tǒng)一的模型,這就是有限狀態(tài)機(Finite-state machine,F(xiàn)SM)。理論上,所有數(shù)字邏輯電路系統(tǒng)都可以被看做這個狀態(tài)機的一個實例。所以呢,這一講在下給大家詳細(xì)介紹有限狀態(tài)機。


欲了解有限狀態(tài)機,必先了解狀態(tài)轉(zhuǎn)移圖;欲了解狀態(tài)轉(zhuǎn)移圖,必先知道圖中各個單元和文字的含義。圖 2 是一個學(xué)生在上課的狀態(tài)轉(zhuǎn)移圖,假設(shè)到校后上四節(jié)課,之后放學(xué);再到校,再上四節(jié)課,再放學(xué);如此往復(fù)。圖里面的一個圓圈就是一個狀態(tài),圓的上方的文字是狀態(tài)名稱,下方是該狀態(tài)對應(yīng)的操作。例如,狀態(tài)“上課”的操作就是“聽講”。如果圓的下方?jīng)]有文字,就是沒有具體操作。帶有箭頭的曲線代表狀態(tài)的轉(zhuǎn)移,線上的文字是狀態(tài)轉(zhuǎn)移的條件。例如,“到?!焙?,聽到“打鈴”就開始“上課”。如果線上沒有文字,則表示無條件轉(zhuǎn)移。狀態(tài)轉(zhuǎn)移的節(jié)拍,就是系統(tǒng)輸入時鐘的周期。


圖 2 學(xué)生上學(xué)的狀態(tài)圖


忽略復(fù)雜的數(shù)學(xué)理論,直接介紹有限狀態(tài)機實現(xiàn)。有限狀態(tài)機,對于實現(xiàn)非常重要的抽象模型圖圖分享給給為施主,見圖 3。


圖 3 有限狀態(tài)機的抽象模型


莫急莫急,這就到了一段、兩段、三四段的介紹了。什么叫四段?。靠纯?,被你催的,一著急敲錯了。


所謂“一段式”如就是“不管三七二十一”,把所有邏輯寫到一起。這種風(fēng)格,可以借用程序語言里面的一個術(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)機 和其他設(shè)計一樣,最好使用同步時序方式設(shè)計,以提高設(shè)計的穩(wěn)定性,消除毛刺。狀態(tài)機實現(xiàn)后,一般來說,狀態(tài)轉(zhuǎn)移部分是同步時序電路而狀態(tài)的轉(zhuǎn)移條件的判斷是組合邏輯。三段式之所以比一段和二段式編碼合理,就在于三段式編碼將不同功能分別放到不同的 always 程序塊中實現(xiàn)。這樣做的好處不僅僅是便于閱讀、理解、維護(hù),更重要的是利于綜合器優(yōu)化代碼,利于用戶添加合適的時序約束條件,利于布局布線器實現(xiàn)設(shè)計。


說的很抽象,現(xiàn)在用一個實例的不同代碼風(fēng)格表演一下下。


“序列檢測器可用于檢測由二進(jìn)制碼組成的脈沖序列信號。當(dāng)序列檢測器連續(xù)收到一組串行二進(jìn)制碼后,如果這組序列碼與檢測器中預(yù)先設(shè)置的序列碼相同,則輸出 1,否則輸出 0。這種檢測的關(guān)鍵是必須收到連續(xù)的正確碼,所以要求檢測器必須對前一次接受到的序列碼做記憶分析,直到在連續(xù)檢測中所收到的每一位二進(jìn)制碼都與預(yù)置序列碼對應(yīng)相同。在檢測過程中,只要有一位不相等都將回到初始狀態(tài)重新開始檢測。不考慮重疊的可能?!?/p>


為了真正達(dá)到可以實現(xiàn)的程度,再來細(xì)化一下輸入輸出和具體條件。先來定義同步字長度,就 4 比特吧。雖然沒有任何實際價值,判決失誤率很高;但是代碼短一點,該有的全有了,更常的寬度也只是力氣活了。還有輸入是一個時鐘周期,輸入一個比特的數(shù)據(jù),低比特在前面。如果匹配到同步字,才輸出高電平“1”;其他時間,輸出低電平“0”。


先設(shè)計系統(tǒng)的狀態(tài)轉(zhuǎn)移圖,如圖 3 所示。每次檢測到一個比特,狀態(tài)前進(jìn)一次;沒有檢測到,則狀態(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ù)學(xué)早有研究遠(yuǎn),都會教材根本源。模式變化數(shù)字三,有限狀態(tài)模型間。

與非網(wǎng)原創(chuàng)內(nèi)容,謝絕轉(zhuǎn)載!

系列匯總:

之一:溫故而知新:從電路里來,到 Verilog 里去!

之二:Verilog 編程無法一蹴而就,語言層次講究“名正則言順”

之三:數(shù)字邏輯不容小窺,電路門一統(tǒng)江湖

之四:Verilog 語言:還真的是人格分裂的語言

之五:Verilog 不難學(xué),聊聊時序邏輯那些事兒

之六:數(shù)字電路設(shè)計:有理論、有電路、有代碼“三位一體”

相關(guān)推薦

電子產(chǎn)業(yè)圖譜

本名:吳濤,通信專業(yè)博士,畢業(yè)后十多年從事無線通訊產(chǎn)品的研發(fā)工作。了解W-CDMA、TDS-CDMA和LTE的標(biāo)準(zhǔn)協(xié)議、接收機算法以及系統(tǒng)架構(gòu)和開發(fā)。從事過關(guān)于W-CDMA的FPGA IP core設(shè)計工作,也完成過W-CDMA和TDS-CDMA的接收機理論研究和鏈路仿真工作。綜合上面的工作,最終選擇了無線通訊的系統(tǒng)設(shè)計和標(biāo)準(zhǔn)設(shè)計工作。目前擁有100多個已授權(quán)的發(fā)明專利,是某通訊行業(yè)標(biāo)準(zhǔn)文件的第一作者,亦有專利思想被寫入3GPP協(xié)議。已出版FPGA設(shè)計專業(yè)著作《IP核芯志-數(shù)字邏輯設(shè)計思想》和《Verilog傳奇-從電路出發(fā)的HDL代碼設(shè)計》。