《電子技術(shù)應(yīng)用》
您所在的位置:首頁(yè) > 可編程邏輯 > 業(yè)界動(dòng)態(tài) > 零基礎(chǔ)教你學(xué)FPGA之Verilog語法基礎(chǔ)(中)

零基礎(chǔ)教你學(xué)FPGA之Verilog語法基礎(chǔ)(中)

2015-02-09
關(guān)鍵詞: FPGA Verilog 基礎(chǔ)

我們接著上篇文章繼續(xù)學(xué)習(xí),上次提到了兩種賦值語句,讓我們接著往下學(xué)。

  1、塊語句

  塊語句包括兩種,一個(gè)是順序塊,一個(gè)是并行塊。

  (1)順序快

  順序快就好比C語言里的大括號(hào)“{ }”,在語法中,用begin…end代替。這里只需要知道,在begin…end中間的語句是順序執(zhí)行的就行了。

  (2)并行塊

  并行塊可以算是一個(gè)新的知識(shí)點(diǎn),與順序塊最大的不同就是并行塊中的語句是同時(shí)開始執(zhí)行的,要想控制語句的先后順序,可以加延時(shí)語句控制。這種并行塊是用fork…join語句描述。

  2、條件語句

  條件語句這里不說,和C語言一樣。就說一點(diǎn)主意事項(xiàng)。

  在使用條件語句時(shí),要注意語句的嚴(yán)整與封閉性。和C語言不同,舉個(gè)例子

  always @(al or d)

  begin

  if(al==1) q=d;

  end

  這個(gè)例子是說,當(dāng)al上升沿到來時(shí),d的值賦給q,那么當(dāng)al=0時(shí)又是什么情況呢,事實(shí)上,在always塊中,如果沒有給變量賦值,這個(gè)變量就會(huì)保持原值,也就是生成了一個(gè)鎖存器。為了避免這種情況的發(fā)生,我們一般這樣寫

  always @(al or d)

  begin

  if(al==1) q=d;

  else q=0;

  end

  同樣在case語句中也要加上default語句避免鎖存器的生成,這樣可以使設(shè)計(jì)者更加明確的設(shè)計(jì)目標(biāo),也提高了程序的可讀性。

  3、case語句

  

360桌面截圖20140226225540.jpg

 

  case語句要注意幾點(diǎn),只挑幾點(diǎn)重要的,其他的不說了

  (1)case語句分項(xiàng)后的表達(dá)式的值必須相同,否則就會(huì)出現(xiàn)問題,例如上面圖片上的result。

  (2)與C語言不同,與某一項(xiàng)case語句匹配后,就會(huì)跳出case語句,這里沒有break語句。

  (3)case語句的所有表達(dá)式位寬必須相等,例如上圖都是16位整型,如果不加以說明,系統(tǒng)會(huì)以默認(rèn)值32位控制表達(dá)式位寬。

  下面是case,casez,case語句的真值表

  

360桌面截圖20140226230246.jpg

 

  這個(gè)表其實(shí)還是很好記的

  case語句,只有匹配才出“1”

  casez語句除了匹配出“1”之外,另外只要遇到“z”就出“1”

  case語句除了匹配出“1”之外,另外只要遇到“z”或“x”就出“1”

  

360桌面截圖20140226231114.jpg

 

  上圖就用到了casez語句來處理不必要考慮的值,這樣就可以靈活的設(shè)置對(duì)信號(hào)的默寫位進(jìn)行比較。

  下面寫了一個(gè)小例子來練習(xí)一下

  使用case語句實(shí)現(xiàn)一個(gè)四選一多路選擇器

  module xiaomo(a1,a2,a3,a4,out,s1,s2);

  input a1,a2,a3,a4;

  input s1,s2;

  reg out; //把輸出變量聲明為寄存器類型

  always @(s1 or s2 or a1 or a2 or a3 or a4 or out) //任何信號(hào)的變化都會(huì)引起輸出變量的重新計(jì)算

  begin

  case ({s1,s2}) //位拼接運(yùn)算

  2'b00: out=a1;

  2'b01: out=a2;

  2'b10: out=a3;

  2'b11: out=a4;

  default: out=1'bx; //保持語句的嚴(yán)整性

  endcase

  end

  endmodule

4、循環(huán)語句

  語法**有4中循環(huán)語句,這里只簡(jiǎn)單說一下C語言里沒有的兩種

  (1) forever語句

  連續(xù)執(zhí)行語句,這種語句主要用在產(chǎn)生周期性的波形,用來做仿真信號(hào)。個(gè)人理解和always語句差不多的功能,但是,forever語句只能用在initial塊中。

  (2)repeat 語句后面接常量表達(dá)式,可以指定循環(huán)次數(shù),例如;

  repeat (8)

  begin

  …

  end

  表示循環(huán)8次相應(yīng)語句。

  5、順序塊和并行塊

  所謂順序塊就是前面說的begin…end,他的作用就是把多條語句組合到一起執(zhí)行,在順序塊里面,語句是一條一條順序執(zhí)行的,如果遇到#10延遲語句,延遲也是相對(duì)于上一條語句的延遲,這一點(diǎn)比較重要。

  相對(duì)于順序塊的就是并行塊,用fork…end語句表示,并行塊里的語句是同時(shí)執(zhí)行的。

  順序塊和并行塊可以嵌套使用。

  如果在begin或者fork語句后面加上名字,這個(gè)塊語句就成了命名塊,例如

  begin :xiaomo

  ……

  end

  命名塊有什么好處呢?有了命名塊,我們就可以用verilog提供的disable語句來隨時(shí)終止命名塊,例如disable xiaomo;這樣,當(dāng)程序運(yùn)行到此時(shí),就會(huì)禁用命名塊,就會(huì)直接跳出塊語句,相當(dāng)于C語言里面的break語句一樣,看下面這個(gè)例子:

  

360桌面截圖20140308132040.jpg

 

  6、生成塊

  生成塊語句可以動(dòng)態(tài)的生成代碼,這一聲明語句方面了參數(shù)化模塊的生成。黨對(duì)矢量中的多個(gè)位進(jìn)行重復(fù)操作時(shí),或者進(jìn)行多個(gè)模塊的實(shí)力引用時(shí),或者在根據(jù)參數(shù)的定義來確定程序中是否應(yīng)該包括末端代碼的時(shí)候,使用生成語句能夠大大簡(jiǎn)化程序的編寫過程。

  生成語句可以控制變量的聲明、任務(wù)或函數(shù)的調(diào)用,還能對(duì)實(shí)力引用進(jìn)行全面的控制。編寫代碼時(shí)必須在模塊中說明生成塊的實(shí)例范圍,關(guān)鍵字 generate…endgenerate用來指定該范圍。

  Verilog中有三種生成語句的方法,分別是循環(huán)生成,條件生成和case生成。

  (1)循環(huán)生成

  

360桌面截圖20140308142337.jpg

 

  

360桌面截圖20140308142446.jpg

 

  注:genvar 是關(guān)鍵詞,用于生成生成變量,生成變量只存在于生成塊中,在確立后的方針代碼中,生成變量是不存在的。

  xor_loop是賦予生成語句的名字,目的在于溝通它對(duì)循環(huán)生成語句之中的變量進(jìn)行層次化引用。因此循環(huán)生成語句中的各個(gè)異或門的相對(duì)層次為:xor_loop[0].gl,xor_loop[1].gl…,xor_loop[31] 這句話什么意思啊

  這個(gè)例子中的 xor gl (out [ j ] , i0 [ j ], i1 [ j ] );什么意思??求大神指點(diǎn)

  當(dāng)然這個(gè)異或門還可用always塊實(shí)現(xiàn)

  生成塊程序

  generate

  for (j=0;j

  begin :xiaomo

  always @(i0[ j ] or i1[ j ]) out [ j ]=i0[ j ]^i1[ j ];

  end

  endgenerate

  (2)條件生成

  

360桌面截圖20140308145303.jpg

 

  下面是一段生成語句

  

360桌面截圖20140308145416.jpg

 

  (3)case生成

  

360桌面截圖20140308150117.jpg

 

  下面是一個(gè)例子使用case語句生成N位的加法器

  

360桌面截圖20140308150759.jpg

 

  

360桌面截圖20140308150809.jpg

 

  說實(shí)話上面這些東西我自己也是看的模模糊糊,好多地方不懂,只能先截個(gè)圖放這兒了。唉...基礎(chǔ)還是不行啊...

7、結(jié)構(gòu)語句

  (1)initial語句比較簡(jiǎn)單,這里就不多說了。

  (2)always語句

  always語句在仿真過程中是不斷活動(dòng)的,always語句后面的語句是否執(zhí)行,這要看always語句是否滿足觸發(fā)條件。因此,always語句只有和時(shí)序控制語句結(jié)合才能使用,否則就會(huì)被死鎖。例如:always areg=~areg;

  這個(gè)always語句生成一個(gè)0延遲的無限跳變過程這時(shí)會(huì)發(fā)生死鎖。但是一旦加上時(shí)序控制,這條語句就不一樣了,例如:

  always #10 areg=~areg;

  這樣的語句就描述的一個(gè)周期為20毫秒的跳變信號(hào)。所以我們常用這種方法來描述時(shí)鐘信號(hào),并作為激勵(lì)信號(hào)來測(cè)試硬件電路。

  看下面這個(gè)例子

  reg [7:0] counter;

  reg tick;

  always @(posedge areg)

  begin

  tick=~tick;

  counter=counter+1;

  end

  這個(gè)例子就是說每當(dāng)信號(hào)areg上升沿到來時(shí),信號(hào)tick取反,計(jì)數(shù)器counter加一,這種時(shí)間控制是always語句最常用的。

  always語句的時(shí)間控制模板

  

360桌面截圖20140308153256.jpg

 

  如果組合邏輯塊語句的輸入變量過多容易漏掉,例如:

  always @(a or b or c or d or e)

  這樣的情況下可以用always@ (*)語句來代替,*號(hào)自動(dòng)將所有輸入變量默認(rèn)為敏感信號(hào)。

  上面所討論的都是等待信號(hào)的值發(fā)生變化或者觸發(fā)時(shí)才執(zhí)行相應(yīng)語句,我們也可以用wait語句來用電平敏感來控制。例如

  always

  wait (count_enable) #20 count=count+1;

  意思就是說,當(dāng)count-enable的值為1時(shí),程序延遲20毫秒后計(jì)數(shù)。

  8、任務(wù)與函數(shù)

  書上寫了關(guān)于任務(wù)與函數(shù)的區(qū)別,寫了好多,我覺得區(qū)別這兩個(gè)概念主要看一點(diǎn)就夠了,就是看有沒有返回值,函數(shù)有,任務(wù)沒有。舉個(gè)例子

  switch_bytes (old_bytes,new_bytes);這是個(gè)任務(wù),沒有返回值,功能是把新舊兩個(gè)字節(jié)互換位置。

  new_bytes=switch_bytes(old_bytes);這是個(gè)函數(shù),功能是把舊字節(jié)轉(zhuǎn)換后賦值給新字節(jié)。有返回值。

  下面寫一個(gè)交通信號(hào)燈的程序來學(xué)習(xí)一下任務(wù)這個(gè)概念

  moudle xiaomo_traffic;

  reg clock,red,green,amber;

  //定義時(shí)鐘,紅燈,黃燈,綠燈

  parameter on=1,off=0,red_tics=350.amber_tics=30,green_ics=200;

  //定義紅燈等待350個(gè)時(shí)鐘,黃燈等待30個(gè)時(shí)鐘,綠燈等待200個(gè)時(shí)鐘

  initial red=0;

  initial green=0;

  initial amber=0;

  //初始化,這里用initial語句保證三條語句同時(shí)執(zhí)行

  always

  begin

  red=on; //紅燈亮

  light (red,red_tics); //這里用到任務(wù),功能是等待350個(gè)時(shí)鐘的時(shí)間,聲明看下面程序

  amber=on; //黃燈亮

  light (amber,amber_tics); //等待30個(gè)時(shí)鐘

  green=on; //綠燈亮

  light (green,green_tics); //等待200個(gè)時(shí)鐘

  end

  task:light; //命名任務(wù)

  output color;

  input [31:0] tics;

  //注意這里的兩個(gè)變量要與上面的一一對(duì)應(yīng),也就是說上面的light(red,red_tics);中的red對(duì)應(yīng)color,red_tics對(duì)應(yīng)tics

  begin

  repeat(tics); //重復(fù)執(zhí)行tics次下面的語句

  @(posedge clock); //等待上升沿,因?yàn)檫@里的tics對(duì)應(yīng)上面的red_tics幾個(gè),所以這里要等待相應(yīng)個(gè)上升沿

  color=off; //等到相應(yīng)個(gè)上升沿結(jié)束時(shí),相應(yīng)顏色的燈關(guān)閉

  end

  endtask

  //下面就是寫時(shí)鐘函數(shù)了,用always塊

  always

  begin

  #100 clock=0;

  #100 clock=1; //每100毫秒產(chǎn)生一次跳變

  end

  endmoudle

  注意:這個(gè)程序要找對(duì)一一對(duì)應(yīng)關(guān)系,例如脈沖模塊里的clock對(duì)應(yīng)posedge clock中的clock,程序行與行之間是有聯(lián)系的,不能隨便聲明

本站內(nèi)容除特別聲明的原創(chuàng)文章之外,轉(zhuǎn)載內(nèi)容只為傳遞更多信息,并不代表本網(wǎng)站贊同其觀點(diǎn)。轉(zhuǎn)載的所有的文章、圖片、音/視頻文件等資料的版權(quán)歸版權(quán)所有權(quán)人所有。本站采用的非本站原創(chuàng)文章及圖片等內(nèi)容無法一一聯(lián)系確認(rèn)版權(quán)者。如涉及作品內(nèi)容、版權(quán)和其它問題,請(qǐng)及時(shí)通過電子郵件或電話通知我們,以便迅速采取適當(dāng)措施,避免給雙方造成不必要的經(jīng)濟(jì)損失。聯(lián)系電話:010-82306118;郵箱:aet@chinaaet.com。