|
作者:小墨同學 我們接著上篇文章繼續學習,上次提到了兩種賦值語句,讓我們接著往下學。 1、塊語句 塊語句包括兩種,一個是順序塊,一個是并行塊。 (1)順序快 順序快就好比C語言里的大括號“{ }”,在Verilog語法中,用begin…end代替。這里只需要知道,在begin…end中間的語句是順序執行的就行了。 (2)并行塊 并行塊可以算是一個新的知識點,與順序塊最大的不同就是并行塊中的語句是同時開始執行的,要想控制語句的先后順序,可以加延時語句控制。這種并行塊是用fork…join語句描述。 2、條件語句 條件語句這里不說,和C語言一樣。就說一點主意事項。 在使用條件語句時,要注意語句的嚴整與封閉性。和C語言不同,舉個例子 always @(al or d) begin if(al==1) q=d; end 這個例子是說,當al上升沿到來時,d的值賦給q,那么當al=0時又是什么情況呢,事實上,在always塊中,如果沒有給變量賦值,這個變量就會保持原值,也就是生成了一個鎖存器。為了避免這種情況的發生,我們一般這樣寫 always @(al or d) begin if(al==1) q=d; else q=0; end 同樣在case語句中也要加上default語句避免鎖存器的生成,這樣可以使設計者更加明確的設計目標,也提高了程序的可讀性。 3、case語句
case語句要注意幾點,只挑幾點重要的,其他的不說了 (1)case語句分項后的表達式的值必須相同,否則就會出現問題,例如上面圖片上的result。 (2)與C語言不同,與某一項case語句匹配后,就會跳出case語句,這里沒有break語句。 (3)case語句的所有表達式位寬必須相等,例如上圖都是16位整型,如果不加以說明,系統會以默認值32位控制表達式位寬。 下面是case,casez,case語句的真值表
這個表其實還是很好記的 case語句,只有匹配才出“1” casez語句除了匹配出“1”之外,另外只要遇到“z”就出“1” case語句除了匹配出“1”之外,另外只要遇到“z”或“x”就出“1”
上圖就用到了casez語句來處理不必要考慮的值,這樣就可以靈活的設置對信號的默寫位進行比較。 下面寫了一個小例子來練習一下 使用case語句實現一個四選一多路選擇器 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) //任何信號的變化都會引起輸出變量的重新計算 begin case ({s1,s2}) //位拼接運算 2'b00: out=a1; 2'b01: out=a2; 2'b10: out=a3; 2'b11: out=a4; default: out=1'bx; //保持語句的嚴整性 endcase end endmodule 4、循環語句 Verilog語法**有4中循環語句,這里只簡單說一下C語言里沒有的兩種 (1) forever語句 連續執行語句,這種語句主要用在產生周期性的波形,用來做仿真信號。個人理解和always語句差不多的功能,但是,forever語句只能用在initial塊中。 (2)repeat 語句后面接常量表達式,可以指定循環次數,例如; repeat (8) begin … end 表示循環8次相應語句。 5、順序塊和并行塊 所謂順序塊就是前面說的begin…end,他的作用就是把多條語句組合到一起執行,在順序塊里面,語句是一條一條順序執行的,如果遇到#10延遲語句,延遲也是相對于上一條語句的延遲,這一點比較重要。 相對于順序塊的就是并行塊,用fork…end語句表示,并行塊里的語句是同時執行的。 順序塊和并行塊可以嵌套使用。 如果在begin或者fork語句后面加上名字,這個塊語句就成了命名塊,例如 begin :xiaomo …… end 命名塊有什么好處呢?有了命名塊,我們就可以用verilog提供的disable語句來隨時終止命名塊,例如disable xiaomo;這樣,當程序運行到此時,就會禁用命名塊,就會直接跳出塊語句,相當于C語言里面的break語句一樣,看下面這個例子:
6、生成塊 生成塊語句可以動態的生成Verilog代碼,這一聲明語句方面了參數化模塊的生成。黨對矢量中的多個位進行重復操作時,或者進行多個模塊的實力引用時,或者在根據參數的定義來確定程序中是否應該包括末端Verilog代碼的時候,使用生成語句能夠大大簡化程序的編寫過程。 生成語句可以控制變量的聲明、任務或函數的調用,還能對實力引用進行全面的控制。編寫代碼時必須在模塊中說明生成塊的實例范圍,關鍵字 generate…endgenerate用來指定該范圍。 Verilog中有三種生成語句的方法,分別是循環生成,條件生成和case生成。 (1)循環生成
注:genvar 是關鍵詞,用于生成生成變量,生成變量只存在于生成塊中,在確立后的方針代碼中,生成變量是不存在的。 xor_loop是賦予生成語句的名字,目的在于溝通它對循環生成語句之中的變量進行層次化引用。因此循環生成語句中的各個異或門的相對層次為:xor_loop[0].gl,xor_loop[1].gl…,xor_loop[31] 這句話什么意思啊 這個例子中的 xor gl (out [ j ] , i0 [ j ], i1 [ j ] );什么意思??求大神指點 當然這個異或門還可用always塊實現 生成塊程序 generate for (j=0;j begin :xiaomo always @(i0[ j ] or i1[ j ]) out [ j ]=i0[ j ]^i1[ j ]; end endgenerate (2)條件生成
下面是一段生成語句
(3)case生成
下面是一個例子使用case語句生成N位的加法器
說實話上面這些東西我自己也是看的模模糊糊,好多地方不懂,只能先截個圖放這兒了。唉...基礎還是不行啊... 7、結構語句 (1)initial語句比較簡單,這里就不多說了。 (2)always語句 always語句在仿真過程中是不斷活動的,always語句后面的語句是否執行,這要看always語句是否滿足觸發條件。因此,always語句只有和時序控制語句結合才能使用,否則就會被死鎖。例如:always areg=~areg; 這個always語句生成一個0延遲的無限跳變過程這時會發生死鎖。但是一旦加上時序控制,這條語句就不一樣了,例如: always #10 areg=~areg; 這樣的語句就描述的一個周期為20毫秒的跳變信號。所以我們常用這種方法來描述時鐘信號,并作為激勵信號來測試硬件電路。 看下面這個例子 reg [7:0] counter; reg tick; always @(posedge areg) begin tick=~tick; counter=counter+1; end 這個例子就是說每當信號areg上升沿到來時,信號tick取反,計數器counter加一,這種時間控制是always語句最常用的。 always語句的時間控制模板
如果組合邏輯塊語句的輸入變量過多容易漏掉,例如: always @(a or b or c or d or e) 這樣的情況下可以用always@ (*)語句來代替,*號自動將所有輸入變量默認為敏感信號。 上面所討論的都是等待信號的值發生變化或者觸發時才執行相應語句,我們也可以用wait語句來用電平敏感來控制。例如 always wait (count_enable) #20 count=count+1; 意思就是說,當count-enable的值為1時,程序延遲20毫秒后計數。 8、任務與函數 書上寫了關于任務與函數的區別,寫了好多,我覺得區別這兩個概念主要看一點就夠了,就是看有沒有返回值,函數有,任務沒有。舉個例子 switch_bytes (old_bytes,new_bytes);這是個任務,沒有返回值,功能是把新舊兩個字節互換位置。 new_bytes=switch_bytes(old_bytes);這是個函數,功能是把舊字節轉換后賦值給新字節。有返回值。 下面寫一個交通信號燈的程序來學習一下任務這個概念 moudle xiaomo_traffic; reg clock,red,green,amber; //定義時鐘,紅燈,黃燈,綠燈 parameter on=1,off=0,red_tics=350.amber_tics=30,green_ics=200; //定義紅燈等待350個時鐘,黃燈等待30個時鐘,綠燈等待200個時鐘 initial red=0; initial green=0; initial amber=0; //初始化,這里用initial語句保證三條語句同時執行 always begin red=on; //紅燈亮 light (red,red_tics); //這里用到任務,功能是等待350個時鐘的時間,聲明看下面程序 amber=on; //黃燈亮 light (amber,amber_tics); //等待30個時鐘 green=on; //綠燈亮 light (green,green_tics); //等待200個時鐘 end task:light; //命名任務 output color; input [31:0] tics; //注意這里的兩個變量要與上面的一一對應,也就是說上面的light(red,red_tics);中的red對應color,red_tics對應tics begin repeat(tics); //重復執行tics次下面的語句 @(posedge clock); //等待上升沿,因為這里的tics對應上面的red_tics幾個,所以這里要等待相應個上升沿 color=off; //等到相應個上升沿結束時,相應顏色的燈關閉 end endtask //下面就是寫時鐘函數了,用always塊 always begin #100 clock=0; #100 clock=1; //每100毫秒產生一次跳變 end endmoudle 注意:這個程序要找對一一對應關系,例如脈沖模塊里的clock對應posedge clock中的clock,程序行與行之間是有聯系的,不能隨便聲明 |