HDLBits 是一組小型電路設(shè)計(jì)習(xí)題集,使用 Verilog/SystemVerilog 硬件描述語言 (HDL) 練習(xí)數(shù)字硬件設(shè)計(jì)~
網(wǎng)址如下:
https://hdlbits.01xz.net/
關(guān)于HDLBits的Verilog實(shí)現(xiàn)可以查看下面專欄:
https://www.zhihu.com/column/c_1131528588117385216
縮略詞索引:
SV:SystemVerilog
Problem 28-Alwaysblock1
從這一題開始我們將進(jìn)行過程塊的學(xué)習(xí),也就是時(shí)序和組合邏輯的一些知識(shí),下面簡單介紹一下這方面知識(shí):
由于數(shù)字電路是由用導(dǎo)線連接的邏輯門組成的,因此任何電路都可以表示為module和assign語句的某種組合。然而,有時(shí)這并不是描述電路的最方便的方式。過程塊(比如always塊)提供了一種用于替代assign語句描述電路的方法。
對于可綜合硬件,有兩種類型的 always :
組合邏輯:always@(*) 時(shí)序邏輯:always@(posedgeclk)
組合always塊相當(dāng)于assign語句,因此組合電路存在兩種表達(dá)方法。選擇使用哪個(gè)主要是哪個(gè)語法更方便的問題。程序塊內(nèi)部代碼的語法與外部代碼不同。程序塊具有更豐富的語句集(例如,if-then、case),不能包含連續(xù)賦值,但是卻引入了許多新的非直觀的出錯(cuò)方式。 (程序連續(xù)賦值確實(shí)存在,但與連續(xù)賦值有些不同,并且不可綜合。)
例如,assign和組合always塊描述相同的電路。兩者都創(chuàng)建了相同的組合邏輯塊。每當(dāng)任何輸入(右側(cè))更改值時(shí),兩者都會(huì)重新計(jì)算輸出。
assignout1=a&b|c^d; always@(*)out2=a&b|c^d;圖片來自 HDLBits
對于組合always塊,敏感變量列表總是使用(*)。如果把所有的輸入都列出來也是可以的,但容易出錯(cuò)的(可能少列出了一個(gè)),并且在硬件綜合時(shí)會(huì)忽略您少列了一個(gè),仍按原電路綜合。 但仿真器將會(huì)按少列一個(gè)來仿真,這導(dǎo)致了仿真與硬件不匹配。(在SystemVerilog中,使用always_comb)
關(guān)于 wire 與 reg 的注意事項(xiàng):assign 語句的左側(cè)必須是net類型(例如,wire),而過程賦值(在 always 塊中)的左側(cè)必須是變量類型(例如,reg)。這些類型(wire vs. reg)與合成的硬件無關(guān),只是 Verilog 用作硬件模擬語言時(shí)留下的語法。
題目說明
使用 assign 語句和組合 always 塊構(gòu)建 AND 門。
圖片來自 HDLBits
模塊端口聲明
//synthesisverilog_input_versionverilog_2001 moduletop_module( inputa, inputb, outputwireout_assign, outputregout_alwaysblock );
題目解析
這個(gè)題目重點(diǎn)是使用assign和always兩種方式描述一個(gè)AND門,整體難度不大。
moduletop_module( inputlogica, inputlogicb, outputwirelogicout_assign, outputvarlogicout_alwaysblock ); assignout_assign=a&b; always_comb begin out_alwaysblock=a&b; end endmodule
always_comb程序有很多好處,其中之一便是能自動(dòng)推斷出完整的敏感列表。該列表是完全完整的,避免了@*推斷不完整敏感列表的極端情況。
點(diǎn)擊Submit,等待一會(huì)就能看到下圖結(jié)果:
注意圖中的Ref是參考波形,Yours是你的代碼生成的波形,網(wǎng)站會(huì)對比這兩個(gè)波形,一旦這兩者不匹配,仿真結(jié)果會(huì)變紅。
這一題就結(jié)束了。
Problem 29-Alwaysblock2
阻塞性賦值和非阻塞性賦值
在Verilog中有以下三種賦值方法:
連續(xù)賦值(assign x=y;):不能在過程塊內(nèi)使用;
過程阻塞性賦值(x=y;):只能在過程塊中使用;
過程費(fèi)阻塞性復(fù)制(x<=y):只能在過程塊內(nèi)使用。
在組合always塊中,使用阻塞性賦值。在時(shí)序always塊中,使用非阻塞性賦值。具體為什么對設(shè)計(jì)硬件用處不大,還需要理解Verilog模擬器如何跟蹤事件(的確是這樣,記住組合用阻塞性,時(shí)序用非阻塞性就可以了)。不遵循此規(guī)則會(huì)導(dǎo)致極難發(fā)現(xiàn)非確定性錯(cuò)誤,并且在仿真和綜合出來的硬件之間存在差異。
題目說明
以三種方式構(gòu)建異或門,使用assign語句、組合always塊和時(shí)序always塊。請注意,時(shí)序always塊產(chǎn)生的電路與其他兩個(gè)不同:有一個(gè)觸發(fā)器,因此輸出被延遲。
圖片來自 HDLBits
模塊端口聲明
//synthesisverilog_input_versionverilog_2001 moduletop_module( inputclk, inputa, inputb, outputwireout_assign, outputregout_always_comb, outputregout_always_ff);
題目解析
這道題難度不大,主要時(shí)區(qū)分三種方式。
moduletop_module( inputlogicclk, inputlogica, inputlogicb, outputwirelogicout_assign, outputlogicout_always_comb, outputlogicout_always_ff); assignout_assign=a^b; always_combbegin out_always_comb=a^b; end always_ff@(posedgeclk)begin out_always_ff<=?a?^?b; ????end endmodule
點(diǎn)擊Submit,等待一會(huì)就能看到下圖結(jié)果:
從仿真的波形圖可以看出,out_always_ff比其他兩個(gè)輸出延遲了一個(gè)時(shí)鐘周期,這就是非阻塞性賦值帶來的。
注意圖中的Ref是參考波形,Yours是你的代碼生成的波形,網(wǎng)站會(huì)對比這兩個(gè)波形,一旦這兩者不匹配,仿真結(jié)果會(huì)變紅。
這一題就結(jié)束了。
Problem 30-Always if
if語句通常創(chuàng)建一個(gè)2 對 1 多路復(fù)用器,如果條件為真則選擇一個(gè)輸入,如果條件為假則選擇另一個(gè)輸入。
下面給出了一個(gè)基本的if語句和其綜合出來的電路。
always@(*)begin if(condition)begin out=x; end elsebegin out=y; end end
這與下面使用條件運(yùn)算符連續(xù)賦值的語句是等價(jià)的:
assignout=(condition)?x:y;
但是,過程if語句使用不當(dāng)可能會(huì)引入新的錯(cuò)誤,只有out在所有的條件下都被賦值才會(huì)生成正確的組合電路。
題目說明
構(gòu)建一個(gè)在a和b之間進(jìn)行選擇的 2 對 1 多路復(fù)用器。如果sel_b1和sel_b2都為真,則選擇b 。其他情況輸出a。請使用兩種方法作答,一次使用assign賦值,一次使用if語句。
模塊端口聲明
moduletop_module( inputa, inputb, inputsel_b1, inputsel_b2, outputwireout_assign, outputregout_always);
題目解析
本題考查的是if語句的簡單用法,使用條件運(yùn)算符作為對比,入門練習(xí)題。
moduletop_module( inputlogica,b, inputsel_b1,sel_b2, outputwirelogicout_assign, outputlogicout_always); assignout_assign=(sel_b1&sel_b2)?b:a; always_comb begin if(sel_b1&sel_b2) out_always=b; else out_always=a; end endmodule
點(diǎn)擊Submit,等待一會(huì)就能看到下圖結(jié)果:
注意圖中的Ref是參考波形,Yours是你的代碼生成的波形,網(wǎng)站會(huì)對比這兩個(gè)波形,一旦這兩者不匹配,仿真結(jié)果會(huì)變紅。
這一題就結(jié)束了。
Problem 31-Always_if2
常見的錯(cuò)誤來源:如何避免引入鎖存器
在設(shè)計(jì)電路時(shí),必須首先具體考慮電路:
1、我想實(shí)現(xiàn)一個(gè)邏輯門;
2、我想實(shí)現(xiàn)一個(gè)具有輸入并產(chǎn)生輸出的組合邏輯塊;
3、我想實(shí)現(xiàn)一組組合邏輯,緊接著一組觸發(fā)器。
不要上來就寫代碼,這樣往往與你想象的電路相差很遠(yuǎn)。
if(cpu_overheated)thenshut_off_computer=1; if(~arrived)thenkeep_driving=~gas_tank_empty;
除了你指定的情況以外,會(huì)發(fā)生些什么,答案是什么也不會(huì)發(fā)生,輸出保持不變。而這往往就導(dǎo)致了電路的錯(cuò)誤,所以說語法正確的代碼不一定能產(chǎn)生合理的電路(組合邏輯+觸發(fā)器)。
輸出保持不變,這就意味著電路需要記住當(dāng)前狀態(tài),從而產(chǎn)生鎖存器。組合邏輯(比如邏輯門)不能記住任何狀態(tài)。
題目說明
以下代碼包含創(chuàng)建鎖存器的不正確行為。修復(fù)錯(cuò)誤~
always@(*)begin if(cpu_overheated) shut_off_computer=1; end always@(*)begin if(~arrived) keep_driving=~gas_tank_empty; end圖片來自 HDLBits
模塊端口聲明
moduletop_module( inputcpu_overheated, outputregshut_off_computer, inputarrived, inputgas_tank_empty, outputregkeep_driving);
題目解析
這個(gè)題目的核心是修復(fù)由于各種原因在組合電路中引入的鎖存器代碼,理解了前面說的產(chǎn)生鎖存器的原因,看這個(gè)代碼還是比較好找出問題的,盡量補(bǔ)全if語句的條件。
moduletop_module( inputlogiccpu_overheated, outputlogicshut_off_computer, inputlogicarrived, inputlogicgas_tank_empty, outputlogickeep_driving ); always_combbegin if(cpu_overheated) shut_off_computer=1; else shut_off_computer=0; end always_combbegin if(~arrived) keep_driving=~gas_tank_empty; else keep_driving=0; end endmodule
點(diǎn)擊Submit,等待一會(huì)就能看到下圖結(jié)果:
注意圖中的Ref是參考波形,Yours是你的代碼生成的波形,網(wǎng)站會(huì)對比這兩個(gè)波形,一旦這兩者不匹配,仿真結(jié)果會(huì)變紅。
這一題就結(jié)束了。
總結(jié)
今天的幾道題就結(jié)束了,整體難度不大,逐漸的在學(xué)習(xí)新知識(shí)~
最后我這邊做題的代碼也是個(gè)人理解使用,有錯(cuò)誤歡迎大家批評指正,祝大家學(xué)習(xí)愉快~
-
FPGA
+關(guān)注
關(guān)注
1629文章
21729瀏覽量
603029 -
硬件
+關(guān)注
關(guān)注
11文章
3315瀏覽量
66203 -
Verilog
+關(guān)注
關(guān)注
28文章
1351瀏覽量
110077 -
HDL
+關(guān)注
關(guān)注
8文章
327瀏覽量
47378
原文標(biāo)題:HDLBits: 在線學(xué)習(xí) SystemVerilog(七)-Problem 28-31
文章出處:【微信號(hào):Open_FPGA,微信公眾號(hào):OpenFPGA】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論