移位運算符
本節(jié)的文檔編號:001100000061
需要看對應的視頻,請點擊視頻編號:001100000064
1、本節(jié)主要進行組合邏輯的介紹,包括:程序語句(assign語句、always語句),數字進制(二進制、不定態(tài)、高阻態(tài)),算數運算符(加、減、乘、除運算符),邏輯運算符(邏輯與、或、非運算符),按位邏輯運算符(單目按位與、或、非運算符,雙目按位與、或、異或運算符),關系運算符,移位運算符(左移、右移運算符),條件運算符(三目運算符、if語句、case語句、選擇語句等),拼接運算符;
2、ALTERA和VIVADO文檔
5.7?移位運算符
在Verilog HDL中有兩種移位運算符,分別為“<<”(左移位運算符)和“>>”(右移位運算符)。
下面分別介紹兩者的用法:

5.7.1左移運算符
在Verilog HDL中,用“<<”表示左移運算符。其一般表達式為:
A<< n;
其中,A代表要進行移位的操作數,n代表要左移多少位。此表達式的意義是把操作數A左移n位。
左移操作屬于邏輯移位,需要用0來填補移出的空位,即在低位補0。左移n位,就要補n個0。

以上代碼由于左移了2位,所以在低位補2個零,所以上面代碼運行結果是:a = 4’b1100。
左移操作中有以下三點值得注意的地方:
(1)左移操作是不消耗邏輯資源的,甚至連與門、非門都不需要,它只是線的連接。

上面代碼是將信號b左移兩位并賦給c,其所對應的硬件電路如下圖:

(2)左移操作需根據位寬儲存結果
讀者在學習過程中可能看到過如下代碼:
4’b1001<<1=4’b0010與4’b1001<<1=5’b10010
為什么操作數同樣是4’b1001,都是左移一位,但結果一個是4’b0010,一個是5’b10010呢?
這是因為左移操作后,要看用多少位來存儲結果。

上面代碼中由于a是4比特,只能保存4位結果,所以b左移1位賦給4 bit的a,
用0填補移出的位后結果為a = 4’b0010?;

而上面代碼中由于a是5比特,能保存5位結果,所以b左移1位賦給5 bit的a,
用0填補移出的位后結果為a = 5’b10010?;
(3)左移操作的操作數可以是常數,也可以是信號。同樣,左移操作的移位數、常數也可以是信號。

上面代碼中cnt每個時鐘加1,由于是3比特,所以值為0~2。a則是4’b1左移cnt位。
當cnt等于0時左移0位,a等于4’b1;當cnt等于1時左移1位,a等于4’b10。以此類推,a的每個時鐘變化情況如下所示:??

需要注意的是,當移位數是信號時,其綜合的電路并不是簡單的連線,可能會綜合出如下圖所示的選擇器。
然而即便如此,這種硬件電路所消耗的資源依然比較少。

5.7.2右移運算符
在Verilog HDL中,用“>>”表示右移運算符。其一般表達式為:A >>n;
其中,A代表要進行移位的操作數,n代表要右移多少位。此代碼表示的意義是把操作數A右移n位。
在右移操作中有以下三點值得注意的地方:
(1)右移操作屬于邏輯移位,需要用0來填補移出的空位,即在高位補0,補多少個0,
取決于保存結果的信號的位寬。

4’b0111右移兩位后的結果為2’b01,由于a是6位的,2位賦值給6位需要在高位補0,
因此需要補4個0。所以上面代碼運行結果是:
a = 6’b0001
(2)與左移操作相似,右移操作是不消耗邏輯資源的,甚至連與門、非門都不需要,其只是線的連接。

上面代碼是將信號b左移兩位并賦給a,其所對應的硬件電路如下圖所示。

(3)左移操作的操作數可以是常數,也可以是信號。同樣,右移操作的移位數可以是常數,也可以是信號。

上面代碼中,cnt每個時鐘加1,由于是3比特,所以值為0~2。a則是4’b1000右移cnt位。
當cnt等于0時右移0位,a等于4’b1000;當cnt等于1時右移1位,a等于4’b0100。以此類推,
a的每個時鐘變化情況如下圖所示。

與左移操作類似,在右移操作中,如果移位數是信號時,其綜合的電路就不是簡單的連線,
而是有可能會綜合出如下圖所示的選擇器。然而同樣在這一情況下,這種硬件電路所消耗的資源依然比較
少。

5.7.3經驗總結
通過左移乘法運算
FPGA中要盡量避免乘法運算,因為這種計算需要占用較大的硬件資源,并且運算速度較慢。
當不得不使用乘法的時候,盡量乘以2的N次方,這樣在設計中可以利用左移運算來實現(xiàn)該乘法運算,
從而大大減少硬件資源。
當乘數是2的N次方的常數時可以用移位運算來實現(xiàn)乘法。例如:a*2,
等價于?a<<1;a*4等價于a<<2;a*8等價于a<<3,依此類推。
即使乘數不是2的N次方的常數,也可以通過移位運算來簡化實現(xiàn)。例如:

上面代碼中b和c都可以實現(xiàn)a*127,但第1行消耗了一個乘法,而第2行則只用到一個減法器。

上面代碼中,b和c都可以實現(xiàn)a*67,但第1行消耗了一個乘法,而第2行則只用到兩個加法器,
從而節(jié)省了資源。
有讀者可能注意到,上面兩個例子中的乘數都是常數,那么在設計時這種乘法也要花時間和精力來考慮優(yōu)化嗎?
其實是不必要的,因為現(xiàn)在綜合工具都很強大,當工具發(fā)現(xiàn)乘數是常數時會自動按上述過程進行優(yōu)化,
也就是說乘以常數在實質上并不消耗乘法器資源,讀者可以放心使用。
但當出現(xiàn)乘數不是常數的情況時,讀者就要注意乘法的使用了。盡量將信號轉換為與2的N次方相關的形式。
例如當數據要擴大后來計算時,不要按照慣有思維將數據擴大100倍,而是應該直接將其擴大128倍。
利用右移實現(xiàn)除法運算
FPGA設計中要極力避免除法,在筆者眼中甚至是嚴禁使用“ /”來用于除法計算。
這是由于除法器會占用極大的資源,其占用資源量要多于乘法器,而且很多時候不能在一個時鐘周期內得出結果。
而當不得不使用除法的時候,讀者應盡量使除法轉化為除以2的N次方形式,
這樣便可以利用右移運算來實現(xiàn)該除法運算,從而大大減少硬件資源。
當除數是2的N次方的常數時,就可以用移位運算來實現(xiàn)除法。
例如:a/2,等價于?a>>1;a/4等價于a>>2;a/8等價于a>>3,依此類推。
與左移不同的是,當除數不是2的N次方的常數時,不能簡單地通過移位運算來簡化實現(xiàn)。
總而言之,在FPGA設計中應盡力避免除法。
利用左移位產生獨熱碼
獨熱碼,也叫one-hot code,就是只有1個比特為1,其他全為0的一種碼制。
例如8’b00010000,8’b1000000等。
獨熱碼在設計時非常有用,可以用來表示狀態(tài)機的狀態(tài)使狀態(tài)機更健壯,
也可以用于多選一的電路中,表示選擇其中的一個。
利用左移位操作,可以方便地產生獨熱碼,例如產生4’b0010,可以是4’b1 << 1。
類似地,也可以產生1個比特為0,其他為1的碼制。例如產生4’b1011,可以是~(4’b1<<2)。
利用左移操作,還可以產生其他需要的數字結果:
例如,產生5’b00111,可以是(5’b1<<3)-1。
例如,產生5’b11100,可以是~((5’b1<<2)-1)。
相關視頻:https://www.bilibili.com/video/BV1yf4y1R7gH?p=18