【連載】【FPGA黑金開發板】Verilog HDL那些事兒–命令式的仿順序操作(十四)

來源:互聯網
上載者:User
文章目錄
  • 4.3 命令式的仿順序操作
  • 總結:

聲明:本文為原創作品,著作權歸akuei2及黑金動力社區(http://www.heijin.org)共同所有,如需轉載,請註明出處http://www.cnblogs.com/kingst/

4.3 命令式的仿順序操作

什麼是 Verilog HDL 式的仿順序操作!?在明白這東西之前,我們先看幾個例子:

假設我要建立 可以產生 SSS,S0S,0S0,000 這四種模組。如果模仿C語言函數會是如下:

//基礎函數

S_Function(){...}

O_Function(){...}

//基於基礎函數建立的函數

SSS_Function()

{

S_Function(); S_Function(); S_Function();

}

SOS_Fucntion()

{

S_Function(); O_Function(); S_Function();

}

OSO_Fucntion()

{

O_Function(); S_Function(); O_Function();

}

OOO_Fucntion()

{

O_Function(); O_Function(); O_Function();

}

我們會很自然的,以S_Function() 和 O_Fucntion() 為基礎,再建立出四個新的 SOS_Function(), SSS_Function(), OSO_Function(), 和 OOO_Fucntion()。在仿順序語言上(如C語言),這樣的方法當然,沒有問題,但是在 Verilog HDL上呢?

筆者說過“仿順序操作”歸根究底不是單純模仿順序操作而已,而是利用Verilog HDL語言本身的特質,去模仿順序操作。4.1章~4.2章的實驗,雖然達到以上這一點,但這隻是僅限於“少個函數”而已。

我們來看看,如果以 4.1章~4.2章為基礎,來模仿以上的順序操作的話,會是什麼樣一個結果。

上!可怕吧!逐漸建立 SSS組合模組,SOS組合模組,OSO組合模組和OOO模組。然而每一個組合模組都包含各自的 “控制模組”,“S摩斯碼模組”,“O模式碼模組”

和“選取器”。最後,每一個組合模組的輸出,還需要一個輸出選取器來協調操作。

我們從另一個方面來分析它的缺點:

(一)模組的重複,資源的消耗。

(二)建模量多,連線設計繁多。

(三)模組調用的難度。

諸如以上等。如果你有筆者這樣的耐性,當然沒有問題,但是實際上筆者也覺得非常“猥瑣”,而且建模的設計也很苦難。所以我們需要另一種“仿順序操作”的方法,畢竟4-1章 和 4-2章的方法,只適合小規模的“仿順序操作”。

那個方法即是“命令式的仿順序操作”。

何謂“命令式的仿順序操作?”我們來看看下面的一張圖,就可以知道個大概:

如!結果我們可以把如上的建模精簡到這樣的程度, 當然在各個所包含的內容中,代碼的結構也是有保障的。如果繼續引入以上的例子,那麼:

function_module.v

module function_module

(

......

Function_Start_Sig,

Function_Done_Sig,

Pin_Out

);

......

input [1:0]Function_Start_Sig;

input Function_Done_Sig;

output Pin_Out;

/******************************************/

//定時器和延時器

......

/*****************************************/

reg [3:0]i;

reg rPin_Out;

reg isDone;

......

always @ ( posedge or CLK or negedge RSTn )

if( !RSTn )

begin

i <= 4'd0;

rPin_Out <= 1'b0;

isDone <= 1'b0;

......

end

===> else if( Function_Start_Sig[1] )

case( i )

// S摩斯碼產生

......

4'd 9:

begin isDone <= 1'b1; i <= i + 1'b1; end

4'd10:

begin isDone <= 1'b0; i <= 4'd0;

endcase

===> else if( Function_Start_Sig[0] )

case( i )

// 0摩斯碼產生

......

4'd 9:

begin isDone <= 1'b1; i <= i + 1'b1; end

4'd10:

begin isDone <= 1'b0; i <= 4'd0;

endcase

/*************************************************/

assign Function_Done_Sig = isDone;

assign Pin_Out = rPin_Out;

/*************************************************/

endmodule

關於 function_module.v 關鍵的部分是 Function_Start_Sig 的位寬和 else if 部分。

Function_Start_Sig 的每一位“位寬”都代表不同的“Start_Sig”。

Function_Start_Sig[ 1..0 ]

位命令

功能

10

S莫斯碼產生

01

O摩斯碼產生

然而 “Done_Sig” 和以往一樣,沒有任何變化。假設我要產生 S模式碼,那麼我只要往 Function_Start_Sig 輸入 2'b10 即可。

cmd_control_module.v

module cmd_control_module

(

......

Command_Start_Sig,

Commnad_Done_Sig,

Function_Start_Sig,

Fucntion_Done_Sig

);

input [3:0]Command_Start_Sig;

output Command_Done_Sig;

output [1:0]Function_Start_Sig;

input Function_Done_Sig;

/********************************************/

reg [3:0]i;

reg [1:0]isStart;

reg isDone;

always @ ( posedge CLK or negedge RSTn )

if( !RSTn )

begin

i <= 4'd0;

isStart <= 2'b00;

isDone <= 1'b0;

end

==> else if( Start_Sig[3] ) // 產生SSS

case( i )

4'd0, 4'd1, 4'd2 :

if( Fucntion_Done_Sig ) begin isStart <= 2'b00; i <= i + 1'b1; end

else isStart <= 2'b10;

4'd3:

begin isDone <= 1'b1; i <= i + 1'b1; end

4'd4:

begin isDone <= 1'b0; i <= i + 1'b1; end

endcase

==> else if( Start_Sig[2] ) // 產生SOS

case( i )

4'd0, 4'd2 :

if( Fucntion_Done_Sig ) begin isStart <= 2'b00; i <= i + 1'b1; end

else isStart <= 2'b10;

4'd1 :

if( Fucntion_Done_Sig ) begin isStart <= 2'b00; i <= i + 1'b1; end

else isStart <= 2'b01;

4'd3:

begin isDone <= 1'b1; i <= i + 1'b1; end

4'd4:

begin isDone <= 1'b0; i <= i + 1'b1; end

endcase

==> else if( Start_Sig[1] ) // 產生OSO

case( i )

4'd0, 4'd2 :

if( Fucntion_Done_Sig ) begin isStart <= 2'b00; i <= i + 1'b1; end

else isStart <= 2'b01;

4'd1 :

if( Fucntion_Done_Sig ) begin isStart <= 2'b00; i <= i + 1'b1; end

else isStart <= 2'b10;

4'd3:

begin isDone <= 1'b1; i <= i + 1'b1; end

4'd4:

begin isDone <= 1'b0; i <= i + 1'b1; end

endcase

==> else if( Start_Sig[1] ) // 產生OOO

case( i )

4'd0, 4'd1, 4'd2 :

if( Fucntion_Done_Sig ) begin isStart <= 2'b00; i <= i + 1'b1; end

else isStart <= 2'b01;

4'd3:

begin isDone <= 1'b1; i <= i + 1'b1; end

4'd4:

begin isDone <= 1'b0; i <= i + 1'b1; end

endcase

/**********************************************************/

assign Function_Start_Sig = isStart;

assign Command_Done_Sig = isDone;

/**********************************************************/

endmodule

和 function_module.v 一樣 command_control_module 最關鍵的部分同樣是 Command_Start_Sig 的“位寬”和 else if 部分,位寬分配如下:

Command_Start_Sig[ 3..0 ]

位命令

功能

1000

產生SSS

0100

產生SOS

0010

產生OSO

0001

產生OOO

假設我輸入 Command_Start_Sig 是 0100,

一、對 function_module.v 輸入 2'b10 , 產生 S摩斯碼 ,返回 Function_Done_Sig。

二、對 function_module.v 輸入 2'b01 , 產生 O摩斯碼 ,返回 Function_Done_Sig。

三、對 function_module.v 輸入 2'b10 , 產生 S摩斯碼 ,返回 Function_Done_Sig。

四、返回Command_Done_Sig 。

“命令式仿順序操作”的基本思路就那麼簡單,下一章我們以一個實驗來說明。

實驗十三:DS1302 系統時鐘驅動

雖說有關 DS1302 的資料都是網路滿天飛,在這裡我還是介紹一點點吧。系統時鐘晶片,大家應該明白是什麼吧,就是一種控制時鐘的晶片。一旦初始化後,它就會隨著現實的時鐘一隻計數。要明白DS1302晶片最主要的關鍵,就是“時序”和晶片本身的“寄存器”啦。

嗯!是DS1302晶片寫操作的時序圖。第一個位元組是“訪問寄存器的地址”,第二位元組是“寫資料”。在寫操作的時候,都是“上升沿有效”,然而還有一個條件,就是CE(/RST)訊號必須拉高。(資料都是從LSB開始發送,亦即最低位開始最高位結束)

是DS1302晶片讀操作的時序圖。基本上和寫操作的時序圖大同小異,區別的地方就是在第二個位元組時“讀資料”的動作。同樣,在第二位元組讀資料的開始時,SCLK訊號都是“下降沿有效”。嗯,別忘了CE(/RST)訊號同樣是必須拉高。(第一節資料是從LSB開始輸出,第二節資料是從LSB開始讀入)

無論是讀操作還是寫操作,在時序圖中,第一個位元組都是“訪問寄存器的地址”,然而這一位元組資料有自己的格式。

BIT 7 固定。

BIT 6 表示是訪問寄存器本身,還是訪問RAM空間。

BIT 5 .. 1 表示是寄存器|RAM空間的地址。

BIT 0 表示是訪問寄存器本身是寫操作,還是讀操作。

是寄存器地址的全家福。啊有一點,我必須強調,Verilog HDL語言有的是很強的位操作,“訪問寄存器的地址”可以這樣表示:

{ 2'b10 , 5'd Addr, 1'b RD/W }

(這樣就可以再度提高解讀性)我們知道BIT 7是固定的位,然而BIT 6表示“訪問RAM空間還是訪問寄存器”。在寄存器地址的全家福中,BIT 6 都是清一色的為“邏輯0”。

假設要寫秒寄存器,那麼我可以如此輸入:

{ 2'b10, 5'd0, 1'b0 }

再假設我要讀秒寄存器,那麼我可以這樣表示:

{ 2'b10, 5'd0, 1'b1 }

表達了每一個寄存器的位元組配置。秒寄存器(第一個),前高四位(BIT7除外),表示“秒的十位”,低四位表示“秒的個位”。其他的寄存器的位元組配置也是如此。但是有3個寄存器比較特別,那就是“秒寄存器”,“時寄存器”,“控制寄存器”(最後第二個)。

秒寄存器的最高位(BIT7),如果寫入“邏輯0”DS1302晶片就開始啟動,反之就關閉。

時寄存器的最高位(BIT7),表示了“邏輯1是 12小時進位”,“邏輯0 24小時進位”,筆者保守的認為,還是24小時進位比較方便工作。

控制寄存器的最高位(BIT7),如果寫入“邏輯0”表示關閉防寫保護,寫入“邏輯1”表示開啟防寫保護。所以呀,每當要變更寄存器的內容之前,就要關閉防寫保護。

是RAM的全家福。RAM的空間有 2^5 - 2 = 0~30 , 亦即 31 words x 8 bits 的空間。由於是訪問RAM,所以“訪問寄存器的地址”的BIT6必須是邏輯1。RAM地址的範圍如下:

{ 2'b11 , 5'd0 , 1'b RD/W } ~ { 2'b11 , 5'd30 , 1'b RD/W }

如果我要關閉防寫保護,那麼我需要的操作如下:

{ 2'b10, 5'd 7, 1'b0 }

{ 8'h00 }

如果我要在時寄存器寫入 10 十進位( 如果以24小時進位 ),那麼我需要如下的操作:

{ 2'b10, 5'd2, 1'b0 }

{ 4'h1, 4'h0 }

如果我要在分寄存器寫入 20 十進位,那麼我需要的操作如下:

{ 2'b10, 5'd1, 1'b0 }

{ 4'h2, 4'h0 }

如果我要在秒寄存器寫入 33 十進位,那麼我需要的操作如下:

{ 2'b10, 5'd0, 1'b0 }

{ 4'h3, 4'h3 }

(在這裡我們知道,秒寄存器的最高位,控制著DS1302晶片的啟動和關閉,所以秒鐘寄存器的配置都是留在最後才操作。因為變更秒寄存器如同啟動DS1302晶片)

如果我要在地址20, RAM空間寫入 0xff的資料,那麼我需要如下的操作:

{ 2'b11, 5'd 20, 1'b0 }

{ 8'hff }

如果我要在時寄存器讀出的“十位和個位”( 如果以24小時進位 ),那麼我需要如下的操作:

{ 2'b10, 5'd2, 1'b1 }

{ 4'h讀出時十位, 4'h讀出時個位 }

如果我要在秒寄存器讀出“十位和個位”,那麼我需要的操作如下:

{ 2'b10, 5'd1, 1'b1 }

{ 4'h讀出秒十位, 4'h讀出秒個位}

如果我要在地址20, RAM空間讀出資料,那麼我需要如下的操作:

{ 2'b11, 5'd 20, 1'b1}

{ 8'h讀出資料 }

我們要建立的組合模組 ds1302_module.v 基本上如。首先我們先把焦點放在 function_module.v 。我們知道如果以“命令式仿順序操作”,函數模組,必須包含“兩個最基本的函數”,亦即“寫位元組函數”和“讀位元組函數”。

在我們可見 函數模組 的開始訊號 Access_Start_Sig 的位寬有兩位,它們分別是:

Access_Start_Sig [ 1..0 ]

位命令

功能

10

寫位元組操作

01

讀位元組操作

此外,還有由上層模組輸入的 Words_Addr 和 Write_Data ,亦即“寫一位元組操作”所要求的“第一位元組”和“第二位元組”資料。Read_Data 和 Access_Done_Sig 分別是返回的“讀出資料”和“完成訊號”。

具體的操作,我們還是直接看代碼吧!

function_module.v

第1~23行表示了該模組輸入輸出口,注意 SIO 是IO口(11行)。說道IO,

左圖是一個IO的硬體設計。如果要該IO輸出,這時候 isOut必須拉高,同時間 Data_Out 的資料就會輸出。如果要該IO為輸入,這時候我需要拉低 isOut,然而三態門會輸出高阻態將“輸出”載止 , 從IO口輸入的資料就會經向Data_In。如果使用 Verilog HDL來表示:

assign IO = isOut ? Data_Out : 1'bz;

assign Data_In = IO;

在142行,定義了 SDA 這個 IO口,是由 isOut 這個寄存器控制著“輸入輸出”。

當 isOut為邏輯1時,該IO口是輸出狀態,反之是輸入狀態。然而輸入只直接在操作中調用(122行)。當然我們也可以這樣:

wire SIO_In;

assign SIO_In = SIO;

assign SIO = isOut ? rSIO : 1'bz;

然後在調用的地方,可以這樣寫, 結果也是一樣。

rData[ ( i >> 1 ) - 9 ] = SDA_In;

在45~51行定義了相關的寄存器,i是指示著執行步驟,rData用來暫存資料,rSCLK用來驅動 SCLK ,rRST用來驅動 RST , rSIO 用來驅動 SIO的輸出,isOut用來控制 IO口的方向,最後的 isDone 是完成標誌,亦即用來反饋完成資訊。

在65~98行也是Start_Sig 為 2'b10 的時候,亦即是“寫位元組操作”。在這段內容之中,代碼完全是按照時序圖執行。

在步驟0的時候,對rData,rSCLK,rRST(CE),isOut等寄存器進行初始化,這一點很重要(68行)。

然後在步驟1~16之中,將“第一個位元組資料”,亦即“訪問寄存器地址位元組”發送出去。傳輸規則和SPI有點相似,都是時間下降沿設定資料,時間上升沿鎖存資料。(70~76行)此外在步驟17再一次對rData設定為“第二個位元組資料”。(79行)

然後重複如同步驟 1~16那樣(81~87行),將“第二位元組資料”發送出去。在步驟34,對rRST (CE) 拉低,以示“寫位元組操作”已經結束。最後在步驟35~36反饋完成訊號。

在99~133行也是Start_Sig 為 2'b01 的時候,亦即是“讀位元組操作”。在讀操作中,第一位元組和第二位元組資料顯然,對時間沿的敏感不同。

在步驟0的時候,對rData,rSCLK,rRST(CE),isOut等寄存器進行初始化,這一點很重要(103行)。

然後在步驟1~16之中,將“第一個位元組資料”,亦即“訪問寄存器地址位元組”發送出去。這時的資料鎖存發生在時間的上升沿。(105~111行)在步驟17對IO口的方向,改變為輸入,亦即將isOut設定為邏輯0。(114行)

在步驟18~33之間是“讀取一個位元組資料的操作”,該動作時時間的下降沿,對SIO信後讀取資料(116~122行)。在這裡我再強調一下,DS1302晶片,資料的傳輸都是從LSB開始到MSB結束。

最後在步驟35對rRST的拉低,以示“讀位元組資料”操作已經結束。然後恢複IO口為輸出,亦即拉高isOut寄存器(125行),然後產生一個完成訊號(127~131行)。

在122行,從DS1302晶片讀取的資料會暫存在rData這個寄存器,然後該寄存器會驅動Read_Data 這個訊號線(137行)。

接下來我們要探討的就是 cmd_control_module.v, 從“圖形”看來 cmd_control_module.v 是 function_module.v 的上層模組。從順序操作上看來, cmd_control_module.v的功能如下(以下只是虛擬碼,希望讀者不要太認真,為了給讀者一個感知的認識):

Function_Module( Command, Addr, Data )

{

case( Command )

{

2'b10 : Write_Function( Addr, Data ); // Write operation

2'b11 : Read_Fucntion( Addr ) { return Data; } // Read operation

}

}

CMD_Control_Module( Command )

{

case( Command )

{

8'b10000000 : Function_module( 2'b10, {2'b10,5'd0,1'b0}, 8'h00 ); // Unprotect

8'b01000000 : Function_module( 2'b10, {2'b10,5'd2,1'b0}, 8'h00 ); // Write hour

8'b00100000 : Function_module( 2'b10, {2'b10,5'd1,1'b0}, 8'h00 ); // Write minit

8'b00010000 : Function_module( 2'b10, {2'b10,5'd0,1'b0}, 8'h00 ); // Write second

8'b00001000 : Function_module( 2'b10, {2'b10,5'd0,1'b0}, 8'h80 ); // Protect

8'b00000100 : Function_module( 2'b01, {2'b10,5'd2,1'b1} ); // Read hour

8'b00000010 : Function_module( 2'b01, {2'b10,5'd1,1'b1} ); // Read minit

8'b00000001 : Function_module( 2'b01, {2'b10,5'd0,1'b1} ); // Read second

}

}

從上面的虛擬碼看來 CMD_Control_Module 反應出 cmd_control_module 是利用 Start_Sig 的8位位寬來定義8中不同的操作。而且在這8個不同的操作之中,都對function_module.v 都有不同的操作。

(位寬對命令分配如下)

Start_Sig[ 7..0 ]

位命令

功能

1000_0000

關閉防寫保護

0100_0000

變更時寄存器

0010_0000

變更分寄存器

0001_0000

變更秒寄存器

0000_1000

開啟防寫保護

0000_0100

讀取時寄存器

0000_0010

讀取分寄存器

0000_0001

讀取秒寄存器

cmd_control_module.v

第2~34行的介面定義和“圖形”是一致的。在38~39行定義了針對Words_Addr, 和 Write_Data 的rAddr 和 rData 暫存的寄存器。換句話說,rAddr寄存器是用來驅動 Words_Addr訊號,rData寄存器是用來驅動 Write_Data訊號。

我們知道在8位 Start_Sig 的位寬之中,Start_Sig[7..3] 是寫操作,反之 Start_Sig[2..0]是讀操作。在DS1302晶片的時序中“寫操作”的第一個位元組需要“訪問寄存器的地址”,第二個位元組是“寫資料”。

然而在48~74行之中,針對這一內容對於rAddr 和 rData寄存器執行賦值。如在8'b1000_0000 的時候,是“關閉防寫保護”的操作,換句話說就是要往“控制寄存器”寫入“資料8'h00”。故對 rAddr和 rData 賦值 {2'b10, 5'd7, 1'b0},8'h00。再舉一個例子,當Start_Sig 等價於 8'b0100_0000的時候,即表示對“時寄存器”,“寫入資料”。這時候對 rAddr 賦予早已經預定好的值,亦即 { 2'b10, 5'd2, 1'b0 }。然而不同的是,rData被賦予的值,是從上層發來的 Time_Write_Data。

至於 Start_Sig[2..0] 是表示“讀操作”,在DS1302晶片的時序中,讀操作只需要寫入“第一位元組資料”,第二位元組資料是從DS1302讀來的。舉個例子,如當 Start_Sig 等價於 8’b0000_0001 是表示從“秒寄存器讀出資料”,所以關於這個操作rAddr被賦予{ 2'b10, 5'd0, 1'b1 }。

在76~120行,是該模組的具體操作。i寄存器表示執行步驟,rRead寄存器是讀出資料的暫存寄存器,isStart寄存器是用於驅動 Access_Start_Sig ,亦即是對 function_module.v 的控制寄存器(78~80行)。

在這裡我再重申一下 Start_Sig[7..3] 是“寫操作”,Start_Sig[2..0]是“讀操作”。為了避免跟多無謂的資源浪費,在91~118行採用了複用的寫法。

假設一個請款,當Start_Sig 等價於 8'b1000_0000 的時候,我們知道這是“關閉防寫保護”的操作。在同一時間rAddr和rData都會被賦值(51行)。然後91行的if條件就會成立。那麼一次性行為的寫操作就會發生(94~102行),當一次性的寫操作完成後,它會反饋完成訊號。

我們再假設一個情況,當Start_Sig 等價於 8'b0000_0001的時候,這表示“從秒寄存器讀取資料”。在同一個瞬間 rAddr 會被賦予相關的值(72行),然後在 105行 if條件就會成立,在108~116行就會完成一次的“讀位元組資料”的操作。

當完成一次性的“讀位元組資料”,讀取到的資料就會被暫存在 rRead寄存器(109行),最後反饋一個完成訊號。以示上一層模組“一次性的讀資料操作”已經完成。

嗯!終於完成對 function_module.v 和 cmd_control_module.v 的解釋了。最後的工作就是把它們組合成為 ds1302_module.v。

ds1302_module.v

組合模組ds1302_module.v 基本和“圖形”沒有什麼大不同,自己看著辦吧。

實驗十三說明:

在實驗十三中 function_module.v 包含了底層的操作,如果從順序操作的角度看來 function_module.v 包含了底層函數。然而 cmd_control_module.v 不是以“函數的形式”,基於底層函數去建立更高層的函數,相反的 cmd_control_module.v 是以“位命令的形式”去“控制著每一個更高層函數的執行步驟和操作”。

完成後的擴充圖:

實驗十三結論:

這個實驗和以往的實驗很不同,主要是混合了Verilog HDL語言本身的位操作和仿順序操作。實驗十三重點不是在於 DS1302晶片的驅動,而是“命令式仿順序操作”的設計。

筆者為了使筆記精簡僅僅為 cmd_control_module.v 配置8個命令而已,實際上可以達到更多,這要讀者自己看著辦。

實驗十三示範:

這個示範主要是示範對 ds1302_module.v 的調用。控制模組具體操作如下

一、關閉防寫保護,亦即發送命令 8'b1000_0000;

二、變更時寄存器,亦即發送命令 8'b0100_0000;

三、變更分寄存器,亦即發送命令 8'b0010_0000;

四、變更秒寄存器,亦即發送命令 8'b0001_0000;

五、最後永遠讀取秒寄存器的值,亦即發送命令 8'b0000_0001。然後將秒個位往

四位LED資源發送。

exp13_demo.v

在步驟0(35~37行),該模組向 ds1302_module.v 發送關閉防寫保護的命令,已經8'b1000_000。然後步驟1~3分別對,時寄存器,分寄存器和秒寄存器寫入資料,分別是寫入12時,22分,22秒(39~49行)。在步驟4,會一直從秒寄存器讀取,系統時鐘的秒值,換句話說該模組會一直對 ds1302_module.v 發送 8'b0000_0001的命令。每當完成“一次讀位元組操作”,就會對rLED賦予“秒個位”的值。最後由rLED寄存器驅動LED訊號。

實驗十三示範說明:

筆者開始懶惰了,所以只是讀取“秒個位”往LED輸出。啊哈哈!

實驗十三示範結論:

ds1302_module.v 的調用示範。

總結:

當你把筆記看到這裡,筆者只能說恭喜你了。因為經第二章到第四章,讀者已經瞭解都是“低級建模”所敘述的概念。筆記第二章的內容是表示“低級建模”的結構和Verilog HDL語言特性的概念。筆記的第三章是表示“低級建模”的基礎建模執行個體。然而筆記的第四章是說“仿順序操作”這一概念。

無論是筆記的那一章,都是“低級建模”重要的一部分,誰也不可缺少誰。可能讀者會在第二章瞭解到 Verilog HDL 語言容易被忽略的小細節。讀者又有可從第三章瞭解到“低級建模”一直強調的“準則”和“模組性質”的重要性等細節。筆記第四章中的“仿順序操作”作為“低級建模”的一部分,是不可或缺的。

因為“仿順序操作”作為“步驟概念”是 Verilog HDL語言不可缺少的一個部分,就像筆者在第二章中的說所,Verilog HDL是一個擁有並行性質的語言,多少對於“順序操作”都會有點不足。筆者所強調的“仿順序操作”,就是有效“利用Verilog HDL本身的特質”去“模仿順序操作”,在同一時間將設計的效果推向更高,既有可能超出“順序操作”本身的極限。

估計當讀者完成13個實驗後,讀者基本上已經掌握筆者所說的“低級建模”的Verilog HDL的建模技巧了。但是有一點筆者必須強調的說:“低級建模的精彩,不僅為前期建模的帶來結構性的優勢,而且還為後期的建模帶來許多方便。”,換句話說“低級建模”真正精彩的部分是在後期的建模。

在第一章中,筆者不是說了嗎,在筆者的眼中Verilog HDL語言 和 FPGA 是一堆樂高積木,不知道多少讀到這裡的筆者能瞭解其中的含義?筆者還說過,對於 Verilog HDL 和 FPGA 語言的學習,必須有形狀!?然而幾乎從第一個實驗到第十三個實驗,筆者完全把 FPGA 和 Verilog HDL語言當成“控制器”來使用。

還有一點,筆者一直很在意的就是“代碼風格”和“建模結構”,這就是筆者在第一章提及的“建模手段”,而對於這個所謂的“建模手段”亦即這本筆記的重點 -“低級建模”。可能讀者經筆者這樣一提,似乎可能明白第一章中筆者所言的“FPGA+Verilog HDL語言是一堆樂高積木”這一回事了吧!

至於什麼是“後期的建模”,這一點筆者還是停留在實驗的階段。畢竟還存在許多不成熟的地方。好了,筆者也不再說什麼了!但是,別忘了“低級建模”還沒有結束,只是目前告一段落!

下一章筆記開始又是一個新的旅程!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.