verilog乘法器以及booth编码改进
第一章 整數(shù)乘法器
1.1 整數(shù)的概念
整數(shù)在IEEE 的規(guī)定上有,短整數(shù)short integer , 中整數(shù)integer 和 長(zhǎng)整數(shù)long integer ,它們之間的關(guān)系如下:
?
?
整數(shù) | 字節(jié)空間 | 取值范圍 |
短整數(shù) | 一個(gè)字節(jié) | -127 ~ 127 |
中整數(shù) | 兩個(gè)字節(jié) | -32767~32767 |
長(zhǎng)整數(shù) | 和四個(gè)字節(jié) | -2147483647~2147483647 |
?
?
在這里筆者以短整數(shù)為筆記的主角。
?
?
短整數(shù)的最高位是符號(hào)位,符號(hào)位的正負(fù)表示了該值是“正還是負(fù)”?。正值的表示方法很簡(jiǎn)單,反之負(fù)值的表示方法是以補(bǔ)碼來(lái)表示。
?
?
+127 亦即8'b0111_1111;
+4 亦即8'b0000_0100;
-127 亦即8'b1000_0001;
-4 亦即8'b1111_1100;
?
?
補(bǔ)碼在英文又叫2nd?implementation?? , 其實(shí)是“正值的求反又加一”的操作。(哎~年輕時(shí)的筆者曾經(jīng)這個(gè)東西頭疼過(guò))。一個(gè)負(fù)值表示如-4 ,是由+4 求反由加一后而成。
?
?
8'b0000_0100;? // 正值4
8'b1111_1011;? // 求反
8'b1111_1100;? // 加1 , 負(fù)值4
那么符號(hào)位和正值,負(fù)值,補(bǔ)碼,取值由有什么關(guān)系呢?舉個(gè)例子 :A = 8'b0111_1111 (+127) 和B = 8'b1000_0001 ( -127 )。
當(dāng)我們?cè)谶M(jìn)行判斷一個(gè)短整數(shù)是正值還是負(fù)值的時(shí)候,我們可以這樣表示:
?if ( !A[7] ) ...? // A是正值
?if ( B[7] ) ...? // B是負(fù)值
在事實(shí)的事實(shí)上。我們知道短整數(shù) 28?,亦即取值范圍是0~255,但是符號(hào)位的出現(xiàn)吃掉了最高位,所以造成由28?的取值范圍變成27?= 0~127 。
你知道嗎?在短整數(shù)家族里面永遠(yuǎn)存在一個(gè)幽靈成員。該成員很神秘,它不是正值,即不是負(fù)值或者0值。而且它的能力也不可忽視,它劃分了正值和負(fù)值的邊界,它就是8'b1000_0000。
+127 ??? 8'b0111_1111;
劃分????? 8'b1000_0000;
-127 ???? 8'b1000_0001;
換句話(huà)說(shuō),在8'b1000_0000 之前的都是正值 ,然而在8'b1000_0000 之后是負(fù)值。如果讀者硬是要說(shuō)8'b1000_0000 是 “負(fù)0”,筆記也無(wú)話(huà)可說(shuō)......
從上述的內(nèi)容,我們可以知道:正值可以進(jìn)行求反又加一之后成為負(fù)值。那么負(fù)值如何變成正值?同樣的一個(gè)道理“負(fù)值求反又加一后,成為正值”。
8'b1111_1100;? // 負(fù)4
8'b0000_0011;? // 求反
8'b0000_0100;? // 加1 , 正4
?
1.2 傳統(tǒng)乘法的概念
筆者還記得筆者在上小學(xué)三年級(jí)的時(shí)候,老師在黑板上寫(xiě)上3 x 4 = 12。筆者對(duì)這神秘的數(shù)學(xué)公式迷糊了頭腦。后來(lái)老師解釋道: " 3粒蘋(píng)果重復(fù)加上4 次等于12粒蘋(píng)果",小時(shí)的筆者頓時(shí)恍然大悟!
當(dāng)筆者上了初中,老師在黑板上寫(xiě)上3 + -4 = -1。大伙們都明白那是整數(shù),但是初中的筆者,腦袋過(guò)很遲鈍。因?yàn)樵诂F(xiàn)實(shí)中,初中的筆者認(rèn)為沒(méi)有“-3粒蘋(píng)果”類(lèi)似實(shí)體的概念純?cè)?#xff0c;后來(lái)老師解釋道:“ 小明欠小黃4粒蘋(píng)果,后來(lái)小明還了小黃3粒蘋(píng)果,結(jié)果小明還欠小黃一粒蘋(píng)果 ”,初中的筆者又恍然大悟。
又在初中,當(dāng)老師又在黑板上寫(xiě)上如下的內(nèi)容。那時(shí)候的筆者,嘴巴長(zhǎng)得大大 ,有好一段時(shí)間說(shuō)不出話(huà)來(lái) 。好一段時(shí)間筆者都是自己在嘀咕....
?3 x 4 = 12;??? " 3粒蘋(píng)果重復(fù)疊加4次,等于12粒蘋(píng)果"
-3 x 4 = -12;? ? " 欠3粒蘋(píng)果,重復(fù)欠4次,等于欠12粒蘋(píng)果"
3 x -4 = -12;??? " 欠4粒蘋(píng)果,重復(fù)欠3次,等于欠12粒蘋(píng)果"
-3 x -4 = 12;??? " @#¥%#¥*!%……" ( 嘀咕中... )
讀者們不要笑,上述的故事確實(shí)是筆者的真實(shí)故事。那時(shí)候的筆者,真的拿不到整數(shù)的乘法的門(mén)兒,考試還常常滿(mǎn)江紅,真的悲劇的初衷時(shí)代......
在傳統(tǒng)的概念上乘法等價(jià)于“重復(fù)幾次”。打個(gè)比方:B = 4;A x B 亦即A要重復(fù)加四次才能得到答案。
然而在乘法中“負(fù)值正值的關(guān)系”就是“異或的關(guān)系”。
A值 | B值 | 結(jié)果 |
正(0) | 正(0) | 正(0) |
正(0) | 負(fù)(1) | 負(fù)(1) |
負(fù)(1) | 正(0) | 負(fù)(1) |
負(fù)(1) | 負(fù)(1) | 正(0) |
?A x B = C;
?3 x 4 = 12;???
-3 x 4 = -12;???
3 x -4 = -12;???
-3 x -4 = 12;?
從上面的內(nèi)容看來(lái),無(wú)論A值和B值是什么樣的“正值和負(fù)值的關(guān)系”,結(jié)果C都是一樣。
那么我們可以換一個(gè)想法:
“在作乘法的時(shí)候只是我們只要對(duì)正值進(jìn)行操作。然而“負(fù)值和正值的結(jié)果”,我們用“異或”關(guān)系來(lái)判斷... ”
實(shí)驗(yàn)一 :傳統(tǒng)的乘法器
該乘法器的大致操作如下:
(一)在初始化之際,取乘數(shù)和被乘數(shù)的正負(fù)關(guān)系,然后取被乘數(shù)和乘數(shù)的正值。
(二)每一次累加操作,遞減一次乘數(shù)。直到乘數(shù)的值為零,表示操作結(jié)束。
(三)輸出結(jié)果根據(jù)正負(fù)關(guān)系取得。
multiplier_module.v
第3~11行是該模塊的輸入輸出。看到Start_Sig 和Done_Sig 是仿順序操作的標(biāo)志性結(jié)構(gòu),不明白的去看筆者之前寫(xiě)的筆記。Multiplicand 和Multiplier (被乘數(shù)和乘數(shù)),都是8位位寬,所以輸出Product 是16位位寬。
第16~21行是該模塊所使用的寄存器,i寄存表示步驟,Mcand 用來(lái)暫存Multiplicand 的正值,Mer 用來(lái)暫存Multiplier 的正值,Temp 寄存器是操作空間。然而isNeg 標(biāo)志寄存器是用來(lái)寄存Multiplicand 和Multiplier 之間的正負(fù)關(guān)系。
在步驟0(36~45行)是初始化的步驟。第39行isNeg寄存“乘數(shù)和被乘數(shù)之間的正負(fù)關(guān)系”。第40行,Mcand寄存 Multiplicand 的正值,該行表示:如果被乘數(shù)的符號(hào)位是邏輯1的話(huà),就將負(fù)值轉(zhuǎn)換為正值,然后Mcand寄存該值,否則Mcand直接寄存Multiplicand 的值。第41行是用來(lái)寄存Multiplier 的正值,該行的操作和40行很相識(shí)。
在步驟1(47~49行),是“重復(fù)加幾次”的操作。Temp寄存器的每一次值的疊加,Mer寄存就遞減(49行)。直到Mer的值等于0(48行),就進(jìn)入下一個(gè)步驟。步驟2~3是產(chǎn)生完成信號(hào)。
在62行,Product輸出信號(hào)的輸出值是由isNeg寄存器作決定,如果isNeg是邏輯1,那么Temp的結(jié)果從負(fù)值轉(zhuǎn)換為正值。否則直接輸出Temp的值。
multiplier_module.vt
?
第16~22行是復(fù)位信號(hào)和時(shí)鐘信號(hào)的激勵(lì)。第26~35行是multiplier_module.v 的實(shí)例化。
第39行以下和普通的仿順序操作的寫(xiě)法一樣,不明白的話(huà)請(qǐng)看筆者以往寫(xiě)過(guò)的筆記。
步驟0~3, 會(huì)輸入不同的乘數(shù)和被乘數(shù)來(lái)激勵(lì)multiplier_module.v。
仿真結(jié)果:
?實(shí)驗(yàn)說(shuō)明:
其實(shí)傳統(tǒng)的乘法器是很容易的,但是短整數(shù)的出現(xiàn),負(fù)值和正值隨著出現(xiàn),使得設(shè)計(jì)上難以下手。但是只要掌握負(fù)值和正值的關(guān)系以后,乘法只作正值也“無(wú)問(wèn)題”。只要在輸出下一點(diǎn)手腳就行了。
實(shí)驗(yàn)結(jié)論:
傳統(tǒng)的乘法器雖然簡(jiǎn)單,但是它有一個(gè)致命的問(wèn)題。就是被乘數(shù)越大就越消耗時(shí)鐘。具體的原因在下一章節(jié)解釋......
1.3 傳統(tǒng)乘法器的改進(jìn)
Verilog HDL 語(yǔ)言所描述的乘法器的消耗是以“時(shí)鐘”作為時(shí)間單位。反之,組合邏輯所建立的乘法器是以“廣播時(shí)間”作為時(shí)間單位。說(shuō)簡(jiǎn)單點(diǎn)就是,Verilog HDL 語(yǔ)言所描述的乘法器“快不快”是根據(jù)“時(shí)鐘消耗”作為評(píng)估。
假設(shè)A = 10 , B = 20,? A x B ,那么時(shí)鐘的消耗至少需要20個(gè),因?yàn)锳值需要累加20次才能得到結(jié)果。到底有沒(méi)有什么辦法,改進(jìn)這個(gè)缺點(diǎn)呢?
有學(xué)過(guò)乘法的朋友都知道A ( B ) = B ( A )。如果以實(shí)驗(yàn)一的乘法器作為基礎(chǔ),那么A( B ) 和B( A ) 所消耗的時(shí)間就不一樣了。所以我們可以這樣改進(jìn):
如果被乘數(shù)小于乘數(shù),那么被乘數(shù)和乘數(shù)互換。
{ Multiplier , Multiplicand } = Multiplicand < Multiplier ? { Multiplicand ,Multiplier } :
???????????????????????? {Multiplier ,Multiplicand };
?
舉個(gè)例子:Multiplicand = 2 ,Multiplicand = 10 ;
更換之前 被乘數(shù)2 需要10次的累加,才能得到結(jié)果。 更換之后 被乘數(shù)為10 乘數(shù)為2,亦即被乘數(shù)10只要累加2次就能得到結(jié)果。
如此一來(lái),可以減少不少時(shí)鐘的消耗。
?
實(shí)驗(yàn)二: 傳統(tǒng)乘法器改進(jìn)
和實(shí)驗(yàn)一相比,在進(jìn)行累加操作之間,多了一個(gè)被乘數(shù)和乘數(shù)比較的步驟。
(一)在初始化之際,取乘數(shù)和被乘數(shù)的正負(fù)關(guān)系,然后取被乘數(shù)和乘數(shù)的正值。
(二)乘數(shù)和被乘數(shù)比較,如果被乘數(shù)小于乘數(shù),結(jié)果乘數(shù)和被乘數(shù)互換。
(三)每一次累加操作,遞減一次乘數(shù)。直到乘數(shù)的值為零,表示操作結(jié)束。
(四)輸出結(jié)果根據(jù)正負(fù)關(guān)系取得。
multiplier_module_2.v
和實(shí)驗(yàn)一先比,添加了一個(gè)比較的步驟(46~49行)。仿真結(jié)果:
仿真.vt 文件和實(shí)驗(yàn)一樣。
?
在仿真的結(jié)果上,10 x 2 和2 x 10 的時(shí)鐘消耗都一樣。
實(shí)驗(yàn)說(shuō)明:
與實(shí)驗(yàn)一的乘法器比較,關(guān)于時(shí)鐘的消耗多少都有改進(jìn)。
實(shí)驗(yàn)結(jié)論:
傳統(tǒng)的乘法器無(wú)論如何改進(jìn)也好,當(dāng)遇見(jiàn)如127 x 127 的乘數(shù)和被乘數(shù),咋也看不出什么優(yōu)化......
1.4 補(bǔ)碼君存在的意義
每一個(gè)人都有存在的意義,有的人用一生的時(shí)間去尋找自己的存在意義,有的人則是經(jīng)過(guò)生活的大反轉(zhuǎn),看到了自己存在意義,有的人則不聞不問(wèn)... 當(dāng)然補(bǔ)碼也有存在的意義,只是在前面的實(shí)驗(yàn)被筆者濫用而已。
補(bǔ)碼不僅可以執(zhí)行正值和負(fù)值轉(zhuǎn)換,其實(shí)補(bǔ)碼存在的意義,就是避免計(jì)算機(jī)去做減法的操作。
? ?? 1101 ??? -3補(bǔ)
+ ?? 1000??? 8
????? 0101??? 5
?
假設(shè)-3 + 8,只要將-3 轉(zhuǎn)為補(bǔ)碼形式,亦即0011 => 1101,然后和8,亦即1000相加
就會(huì)得到5,亦即0101。至于溢出的最高位可以無(wú)視掉。
1101 ??? -3補(bǔ)
+???? 1110???? -2補(bǔ)
?? 1011??? -5補(bǔ)
其實(shí)你知道嗎,如Quartus II 綜合器 ,當(dāng)我們使用“-”算術(shù)操作符的時(shí)候,其實(shí)就是使用補(bǔ)碼的形式,具體如下:
A = 8'd5;
B = 8'd9;
A -B 等價(jià)于A + ( ~B + 1'b1 );
在實(shí)際的操作中,綜合器都會(huì)如上優(yōu)化。
?
1.5:Booth算法乘法器
傳統(tǒng)的乘法器是有極限的,因此位操作乘法器就出現(xiàn)了。筆者在網(wǎng)上沖浪找資源的時(shí)候,還常常撞到許多稀奇古怪的位操作乘法器。但是有一種位操作乘法器,吸引了筆者的眼球,它就是Booth算法乘法器。實(shí)際上Booth 算法是一種“加碼”乘法運(yùn)算。
Booth 算法的概念也很簡(jiǎn)單,我們先從數(shù)學(xué)的角度去理解看看:
?
B[0] | B[-1] | 加碼結(jié)果 |
0 | 0 | 0(無(wú)操作) |
0 | 1 | 1(+被乘數(shù)) |
1 | 0 | 1(-被乘數(shù)) |
1 | 1 | 0(無(wú)操作) |
?
B[-1] 是什么?先假設(shè)B是2的,然而B(niǎo)的最低位的右邊后一個(gè)“負(fù)一位”那就是B[-1]。
0010 0? // LSB 右邊出現(xiàn)的就是-1位
那么上面那個(gè)加碼表和乘法又有什么關(guān)系呢?其實(shí)要加碼的目標(biāo)是“乘數(shù)”,假設(shè)乘數(shù)為2, 那么乘數(shù)2的加碼過(guò)程會(huì)是如下。
一開(kāi)始的時(shí)候在乘數(shù)2的“負(fù)一位”加上一個(gè)默認(rèn)0值 | 0010?0 |
先判斷[0: -1],結(jié)果是2'b00,表示“0”亦即沒(méi)有操作 | 0010 0 |
判斷[2: 1],結(jié)果是2'b01,表示“1”亦即“-被乘數(shù)”操作 | 0010 0 |
判斷[1: 0],結(jié)果是2'b10,表示“1”亦即“+被乘數(shù)”操作 | 0010 0 |
判斷[3: 2],結(jié)果是2'b00,表示“0”亦即沒(méi)有操作 | 0010 0 |
舉個(gè)例子,被乘數(shù)為7,0111; 乘數(shù)為2,0010;結(jié)果會(huì)是什么?
????? 0111? ???? - A被乘數(shù) ????? 0010?0? - B乘數(shù) ? ========== ????? 0110? ??? - 乘數(shù)加碼 ? ========== ????? 0000???? 0 ?? 111001??????1?(- 7) ??? 0111?????? 1 (+7) ?? 0000 ?????? 0 ? ========== ?? 0001110???? 14??? ? ==========???????? | ? ? ? ? 從左邊的操作過(guò)程中,我們可以看到乘數(shù)被加碼以后, 操作的結(jié)果是14。 |
從數(shù)學(xué)的角度看來(lái),確實(shí)Booth算法是麻煩的存在,但是在位操作的角度來(lái)看就不是這么一回事。實(shí)際上在千奇百怪的位操作乘法中,Booth算法其中可以容納“補(bǔ)碼”亦即“負(fù)數(shù)”來(lái)執(zhí)行操作。
B[0] | B[-1] | 加碼結(jié)果 |
0 | 0 | 無(wú)操作,右移一位 |
0 | 1 | +被乘數(shù),右移一位 |
1 | 0 | -被乘數(shù),右移一位 |
1 | 1 | 無(wú)操作,右移一位 |
?
上面的圖表是位操作時(shí)候的Booth 算法。Booth算法在位操作的時(shí)候,它使用一個(gè)很有個(gè)性的空間,就是P空間。
?
先假設(shè):被乘數(shù)A 為7 (0111),乘數(shù)B為2 (0010) ,它們n均為4位,所以P空間的容量是n x 2 + 1 , 亦即9 位。
_ _ _ _ _ _ _ _? _? // P空間
那么P空間如何實(shí)現(xiàn)乘法的位操作呢?
一開(kāi)始先求出-1 (被乘數(shù)) | ?A = 0111,A= 1001 |
然后初始化P 空間, 默認(rèn)為0 | ?P = 0000 0000 0 |
P空間的[4..1] 填入乘數(shù) | ?P = 0000 0010 0 |
判斷P[1:0],是2'b00 亦即“無(wú)操作” | ?P = 0000 0010 0 |
判斷P[8], 如果是邏輯0右移一位補(bǔ)0,反之補(bǔ)1。 | ?P = 0000 0001 0 |
判斷P[1:0],是2'b10 亦即“-被乘數(shù)”。 | ?P = 0000 0001 0 |
P空間的[8..5] 和 被乘數(shù)?A相加。 | ?P = 0000 0001 0 ?+? 1001????? ?P = 1001 0001 0 |
判斷P[8], 如果是邏輯0右移一位,補(bǔ)0,反之補(bǔ)1 | ?P = 1100 1000 1 |
判斷P[1:0],是2'b01 亦即“+被乘數(shù)”。 | ?P = 1100 1000 1 |
P空間的[8..5] 和 被乘數(shù) A 相加。 | ?p = 1100 1000 1 ?+? 0111????? ?P = 0011 1000 1?無(wú)視最高位溢出 |
判斷P[8], 如果是邏輯0右移一位補(bǔ)0,反之補(bǔ)1 | ?P = 0001 1100 0 |
判斷P[1:0],是2'b00 亦即“無(wú)操作” | ?P = 0001 1100 0 |
判斷P[8], 如果是邏輯0右移一位,補(bǔ)0,反之補(bǔ)1 | ?P = 0000 1110 0 |
最終P空間的[8..1] 就是最終答案。 | ?P =?0000 1110?0 |
從上面的操作看來(lái),由于乘數(shù)和被乘數(shù)均為n 位所以 “判斷P[1:0],后操作,之后移位”的操作僅執(zhí)行四次而已。
?
? 如左邊的循環(huán)圖。A為被乘數(shù),A為被乘數(shù)補(bǔ)碼形式(-1(A) ),B為乘數(shù),n為乘數(shù)和被乘數(shù)的位寬,P為操作空間。 ? 一開(kāi)始P空間會(huì)初始化,然后P空間的[4..1] 位會(huì)填入B。然后進(jìn)入P[1:0]的判斷。每一次的判斷過(guò)后的操作都會(huì)導(dǎo)致P空間右移一次,至于右移過(guò)后的最高位是補(bǔ)0還是補(bǔ)1,是由當(dāng)時(shí)P[8]說(shuō)了算。 ? ? 當(dāng)循環(huán)n 次以后,最終結(jié)果會(huì)是P[8:1]。 |
?
實(shí)驗(yàn)三:Booth算法乘法器
實(shí)驗(yàn)中建立的Booth算法乘法器大致的步驟正如1.5章節(jié)所描述的那樣。
booth_multiplier_module.v
第13~15行是仿真的輸出(S - Simulation , Q - Output)。第20~25行定義了該模塊所使用的寄存器。a寄存器用來(lái)寄存A 值,s寄存器用來(lái)寄存-1(A) 的值,p寄存器是P空間。輸入信號(hào)A和B均為8位位寬,所以p寄存器是17位位寬。至于X寄存器是用來(lái)表示n位,用來(lái)指示n 次循環(huán)。
步驟0(40~41行),初始化了a,s寄存器。p[8:1]填入B值,亦即乘數(shù),其余的位均為0值。
步驟1(43~51行)是用來(lái)判斷p[1:0] 的操作。步驟2(53~55行)是執(zhí)行右移一位,是補(bǔ)0還是補(bǔ)1,完全取決于p[16]。步驟1~2會(huì)重復(fù)交替執(zhí)行,直到X的值達(dá)到8次,就會(huì)進(jìn)入下一步步驟。
步驟3~4(57~61行)是用來(lái)產(chǎn)生完成信號(hào)。第68行輸出信號(hào)product 是由p空間的[16..1]來(lái)驅(qū)動(dòng)。第72~74行是仿真用的輸出信號(hào),功能如字面上的意思。
booth_multiplier_module.vt
?
在仿真中,從步驟0~3(59~73行),激勵(lì)了不同A和B的值(被乘和數(shù)乘數(shù))。
仿真結(jié)果:
P空間的詳細(xì)操作過(guò)程,自己代開(kāi)modelsim看吧,界面有限的關(guān)系。從仿真結(jié)果上可以看到,4次的乘法操作所使用的時(shí)間都一樣,尤其是-127 x -127 的情形,不像傳統(tǒng)乘法器那樣累加127次,才能得到結(jié)果。(p空間的[ Width :1]是用來(lái)填入乘數(shù)B,然而p空間的[Width * 2 : Width + 1 ] 是用來(lái)執(zhí)行和被乘數(shù)A的操作)
實(shí)驗(yàn)結(jié)論:
按常理來(lái)說(shuō)8位的乘數(shù)和被乘數(shù),位操作會(huì)是使用8個(gè)時(shí)鐘而已,但是實(shí)驗(yàn)3的乘法器,需要先操作后移位的關(guān)系,所以多出8個(gè)時(shí)鐘的消耗......
?
1.6 筆者情有獨(dú)鐘的步驟i
在筆者初學(xué)Verilog HDL語(yǔ)言,筆者老是捉不好Verilog HDL 語(yǔ)言和時(shí)序的關(guān)系,吃了不少苦頭。世界就是很巧妙,腦子里就忽然間冒出步驟i。
?
步驟i是什么?
有關(guān)《Verilog HDL 那些事兒》那本筆記,雖然筆者的實(shí)例都和“它”有關(guān)。但是在筆記中,筆者只是微微的帶過(guò)“步驟i是仿順序操作相關(guān)的寫(xiě)法... ”。但是要探討步驟i是什么,那不是初學(xué)Verilog HDL 的任務(wù)。步驟i的用法很簡(jiǎn)單,從概念上和“順序操作”很類(lèi)似,它可以補(bǔ)助初學(xué)者不必過(guò)度依賴(lài)功能仿真,也能“從代碼中看到時(shí)序”。
如果從低級(jí)建模的角度去探討步驟i,低級(jí)建模里面有一個(gè)準(zhǔn)則,就是“一個(gè)模塊一個(gè)功能”,步驟i好比這個(gè)準(zhǔn)則的支持者。步驟i從0開(kāi)始,表示了這個(gè)模塊開(kāi)始工作,直到i被清理,這也表示了這個(gè)模塊已經(jīng)結(jié)束工作。或者可以這樣說(shuō)“一個(gè)模塊不會(huì)出現(xiàn)兩個(gè)步驟i”。
?
具體上,步驟i的“值”是指示著“第幾個(gè)時(shí)鐘沿”發(fā)生,然而Verilog HDL語(yǔ)言里的“步驟”和C語(yǔ)言里的“步驟”是不一樣。C語(yǔ)言里的“步驟”就好比“把大象放進(jìn)冰箱需要幾個(gè)步驟... ”。相反的Verilog HDL 語(yǔ)言里的“步驟”,有如“時(shí)間點(diǎn)”的觀念。
如上面的示意圖所示, 在這個(gè)時(shí)間點(diǎn)里所發(fā)生的“決定”會(huì)產(chǎn)生不一樣的未來(lái)。然而在這個(gè)時(shí)間點(diǎn)里“可以允許不同的決定在這一刻存在”。舉一個(gè)例子:A的初值是4,B的初值是0。
?
case( i )
0:
begin A <= A + 2'd2; B <= B + 2'd3; i <= i + 1'b1; end
1:
if( A > 3 ) begin B <= A; A = 0; i <= i + 1'b1; end
else if i <= i + 1'b1;
?
咋看是一個(gè)簡(jiǎn)單的代碼,但是你知道里邊包含的秘密嗎?
在i = 0的時(shí)候,A 累加2,B 累加3。
在i = 1的時(shí)候,如果A大于3,就B寄存A的值將A清零。
無(wú)論是i等于0還是等于1,它們“只是這一時(shí)間點(diǎn)發(fā)生的決定”,結(jié)果會(huì)在這個(gè)時(shí)間點(diǎn)的過(guò)后發(fā)生。如果用“生動(dòng)”的話(huà)來(lái)描述的話(huà)。
在時(shí)間點(diǎn)0的時(shí)候,這個(gè)模塊決定A累加2,B累加3。然后在時(shí)間點(diǎn)0過(guò)后,結(jié)果就產(chǎn)生。直到迎來(lái)下一個(gè)時(shí)間點(diǎn),這個(gè)模塊才能再一次作決定。
在時(shí)間點(diǎn)1的時(shí)候,這個(gè)模塊判斷A是否大于3。那么,問(wèn)題來(lái)了“這個(gè)模塊是以什么作為基礎(chǔ),判斷A大于3呢?”。答案很簡(jiǎn)單就是“時(shí)間點(diǎn)1的過(guò)去的結(jié)果”或者說(shuō)“在時(shí)間點(diǎn)0過(guò)后所產(chǎn)生的結(jié)果”。
上圖完全將上述的內(nèi)容表達(dá)了出來(lái)。在這里筆者有一個(gè)很在意的問(wèn)題,那就是"<=" 賦值操作符。在眾多的參考書(shū)中“<=”賦值操作符被解釋為“時(shí)間沿有效的賦值操作符”。筆者初學(xué)的時(shí)候的,完全不知道它是蝦米... 如果換做時(shí)間點(diǎn)的概念來(lái)說(shuō)“<=”的操作符,表示了“在這個(gè)時(shí)間點(diǎn)下決定”專(zhuān)用的賦值操作符。
與“=”賦值操作符不一樣,它是沒(méi)有時(shí)間點(diǎn)的概念的賦值操作符。所以在always @ ( posedge CLK ... ) 有效區(qū)域內(nèi),它是不適合使用,因?yàn)樗鼤?huì)破壞這個(gè)模塊的時(shí)間和結(jié)果。
我們的人生,下錯(cuò)了決定只要知錯(cuò),吸取教訓(xùn)還有從來(lái)的機(jī)會(huì)。但是模塊下錯(cuò)了決定,就影響它的一生,所以我們?cè)诰庉嫷臅r(shí)候要特別小心,不然會(huì)可能因我們的疏忽,導(dǎo)致了這個(gè)模塊的一生悲劇。
小時(shí)候,筆者讀道德教育的時(shí)候,有一句話(huà)是筆者一生受用,那就是“先三思而后行”。
這個(gè)又和上述的內(nèi)容有什么關(guān)系呢?
我們知道“時(shí)間點(diǎn)”的概念就是“就是在這個(gè)時(shí)間點(diǎn)決定了什么,這個(gè)時(shí)間點(diǎn)的過(guò)后會(huì)產(chǎn)生什么”。難道模塊的世界就是那么現(xiàn)實(shí), 就連三思的機(jī)會(huì)也沒(méi)有嗎?這是一個(gè)很好的問(wèn)題......
舉個(gè)例子,有一個(gè)模塊他有A ,B和C三個(gè)寄存器,它們的初值都是0:
case( i )
?? 0:
?? begin A <= 3; B <= 4; C <= 0; i <= i + 1'b1; end
?? 1:
?? begin
?????? C <= A + B;
?????? if( C > 0 ) begin A <= 0; B <= 0 ; end
?????? else begin A <= 1; B <= 1; end
?????? i <= i + 1'b1;
?? end
從上面的代碼,我們可以知道。在時(shí)間點(diǎn)0,該模塊決定了A 等于3,B等于4,C等于0。然后到了時(shí)間1, 問(wèn)題來(lái)了“在時(shí)間點(diǎn)1,該模塊是以什么作為基礎(chǔ)去判斷C 的值呢?是時(shí)間點(diǎn)1過(guò)去的C值,還是在這一個(gè)瞬間A + B 所產(chǎn)生的值?”。
答案如上圖所示,if是以時(shí)間點(diǎn)1過(guò)去的C值作為判斷的基礎(chǔ)。所以說(shuō)模塊的現(xiàn)實(shí)是很殘忍的,它們不但沒(méi)有重來(lái)的機(jī)會(huì),就連“思考”的時(shí)間也不給它。它們"只能以當(dāng)前時(shí)間點(diǎn)過(guò)去的值,作為當(dāng)前時(shí)間點(diǎn)下決定的參考......? ( 寫(xiě)到這里, 筆者流淚了! )
實(shí)際上“=”不是不可以在always @ ( posedge CLK ... ) 里出現(xiàn),只不過(guò)它比較危險(xiǎn)。
case( i )
?? 0:
?? begin A <= 3; B <= 4; C <= 0; i <= i + 1'b1; end
?? 1:
?? begin
?????? C = A + B;
?????? if( C > 0 ) begin A <= 0; B <= 0 ; end
?????? else begin A <= 1; B <= 1; end
?????? i <= i + 1'b1;
?? end
筆者將上面的代碼稍微修改了一下, 在步驟1 變成了C = A + B。
如果把步驟i按照“時(shí)間點(diǎn)”的概念,結(jié)果會(huì)是如上圖。在時(shí)間點(diǎn)1,“=”造成了一個(gè)而外的時(shí)間停止空間,在這個(gè)空間里C 不但可以“作決定”,而且“即時(shí)得到結(jié)果”。在某種程度上,它的存在會(huì)破壞和諧,如果沒(méi)有步驟i的控制,它很容易暴走。筆者在設(shè)計(jì)模塊中,除非出現(xiàn)“不得已”的情況,否則筆者在always @ ( posedge CLK ... )區(qū)域內(nèi),絕對(duì)不會(huì)使用它。
?
1.7 Booth算法乘法器的改進(jìn)
在實(shí)驗(yàn)三中所建立的Booth算法乘法器,要完成一次乘法計(jì)算,至少要消耗16個(gè)時(shí)鐘,而且其中8個(gè)時(shí)間就是消耗在移位的方面上。那么有什么辦法改進(jìn) 實(shí)驗(yàn)三中的Booth算法乘法器呢?
在1.6章節(jié),筆者說(shuō)了步驟i有如時(shí)間點(diǎn)的概念,假設(shè)我這樣修改實(shí)驗(yàn)三的Booth乘法器 :
case ( i )
???
?? 0: ... 初始化
??
?? 1,2,3,4,5,6,7,8:
?? begin
?????? if( p[1:0] == 2'b01 ) p <= { p[16] , p[16:9] + a , p[8:1] };
?????? else if( p[1:0] == 2'b10 ) p <= { p[16] , p[16:9] + s , p[8:1]};
?????? else p <= { p[16] , p[16:1]};
?????? i <= i + 1'b1;
?? end
從上面的代碼,讀者能看出什么破綻嗎?我們嘗試回憶Booth算法的流程圖,先判斷p[1:0] 的操作,然后右移一位,最高位補(bǔ)0還是補(bǔ)1,是取決與 經(jīng)p[1:0]操作之后的p[16]。
那么問(wèn)題來(lái)了,從上面的代碼看來(lái)p <= { p[16] , p[16:9] + a , p[8:1]}; 其中的p[16] 是以當(dāng)前時(shí)間點(diǎn)的過(guò)去值作為基礎(chǔ),而不是p[1:0]操作過(guò)后的值, 所以上面的代碼不行!
case( i )
?
0: ... 初始化
?
1,2,3,4,5,6,7,8:
begin
??? Diff1 = p[16:9] + a;? Diff2 = p[16:9] +s;
???
??? if( p[1:0] == 2'b01 ) p <= { Diff1[7] , Diff1 , p[8:1]};
??? else if( p[1:0] == 2'b10 ) p <= { Diff2[7] , Diff2 , p[8:1]};
??? else p <= { p[16] , p[16:1]};
?
??? i <= i + 1'b1;
end
?
上面的代碼表示了,在步驟1~8里Diff1 寄存了p[16:9] + a 的結(jié)果,反之Diff2 寄存了p[16:9] + s的結(jié)果。然后判斷p[1:0] 再來(lái)決定p 的結(jié)果是取決于Diff1 ,Diff2 或者其他。和第一段的代碼不同,第二段代碼的p輸出值是一致的。在這里有一個(gè)重點(diǎn)是,Diff1 和Diff2 沒(méi)有使用“<=”而是使用“=”,換一句話(huà)說(shuō),Diff1 和Diff2 結(jié)果的產(chǎn)生在“該時(shí)間點(diǎn)作決定的時(shí)候”,亦即“取得即時(shí)的結(jié)果”,而不是該時(shí)間點(diǎn)過(guò)后,才產(chǎn)生結(jié)果。
實(shí)驗(yàn)四:Booth算法乘法器改進(jìn)
基于實(shí)驗(yàn)三的Booth算法乘法器,從原先的一次乘法需要16次、個(gè)時(shí)鐘,優(yōu)化至8個(gè)時(shí)鐘。
booth_multiplier_module_2.v
?
同樣是Booth 算法的原理,和實(shí)驗(yàn)三不同的是在55~67行,是步驟1~8的循環(huán)操作。不再使用X寄存器作為循環(huán)計(jì)數(shù),而是直接使用步驟來(lái)指示8個(gè)循環(huán)操作。在55~67行,這樣的寫(xiě)法有一個(gè)好處,就是可以使得p的值輸出一致,因此可以減少8個(gè)時(shí)鐘。
仿真結(jié)果:
實(shí)驗(yàn)四所使用的.vt 文件和實(shí)驗(yàn)三的一樣。
從仿真結(jié)果看來(lái),一次的乘法操作只消耗8個(gè)時(shí)鐘而已(步驟0初始化,和步驟9~10完成信號(hào)產(chǎn)生除外)。現(xiàn)在我們把上面的仿真結(jié)果切成一塊一塊的來(lái)看。
?
? ? | 00000000 10000001 0 值左邊上升沿開(kāi)始,即是第一個(gè)時(shí)間點(diǎn)i = 0,亦即步驟0。步驟0之后就是初始化的結(jié)果。S是取反過(guò)后的a值,并且填充在p空間的[8:1]。 |
? ? | 00000000 10000001 0 值右邊的上升沿,亦即步驟1。此時(shí): Diff1 寄存過(guò)去的p[16:9] + a ,亦即00000000 + 10000001, 結(jié)果為10000001。Diff2 寄存過(guò)去的p[16:9] + s,亦即00000000 + 01111111, 結(jié)果為01111111。經(jīng)步驟1的“決定”,過(guò)去p[1:0]是 2'b10 ,所以p值的未來(lái)是{ Diff2[7] , Diff2 , p過(guò)去[8:1] }, 亦即 0 01111111 10000001。 |
? ? | 00111111 11000000 1 值右邊的上升沿,亦即步驟2。此時(shí): Diff1 寄存過(guò)去的p[16:9] + a ,亦即00111111 + 10000001, 結(jié)果為11000000。Diff2 寄存過(guò)去的p[16:9] + s,亦即00111111 + 01111111, 結(jié)果為10111110。經(jīng)步驟2的“決定”,過(guò)去p[1:0]是 2'b01 ,所以p值的未來(lái)是{ Diff1[7] , Diff1 , p過(guò)去[8:1] }, 亦即 1 11000000 11000000。 |
? ? | 11100000 01100000 0 值右邊的上升沿,亦即步驟3。此時(shí): Diff1 寄存過(guò)去的p[16:9] + a ,亦即11100000 + 10000001, 結(jié)果為01100001。Diff2 寄存過(guò)去的p[16:9] + s,亦即11100000 + 01111111, 結(jié)果為01011111。經(jīng)步驟3的“決定”,過(guò)去p[1:0]是2'b00 ,所以p值的未來(lái)是{ p過(guò)去[16] , p過(guò)去[16:1] }, 亦即 1 11100000 01100000。 |
11110000 00110000 0 值右邊的上升沿,亦即步驟4。此時(shí): Diff1 寄存過(guò)去的p[16:9] + a ,亦即11110000 + 10000001, 結(jié)果為01110001。Diff2 寄存過(guò)去的p[16:9] + s,亦即11110000 + 01111111, 結(jié)果為01101111。經(jīng)步驟4的“決定”,過(guò)去p[1:0]是2'b00 ,所以p值的未來(lái)是{ p過(guò)去[16] , p過(guò)去[16:1] }, 亦即 1 11110000 00110000。 ? ? |
11111000 00011000 0 值右邊的上升沿,亦即步驟5。此時(shí): Diff1 寄存過(guò)去的p[16:9] + a ,亦即11111000 + 10000001, 結(jié)果為01111001。Diff2 寄存過(guò)去的p[16:9] + s,亦即11111000 + 01111111, 結(jié)果為01110111。經(jīng)步驟5的“決定”,過(guò)去p[1:0]是2'b00 ,所以p值的未來(lái)是{ p過(guò)去[16] , p過(guò)去[16:1] }, 亦即 1 11111000 00011000。 ? ? | |
11111100 00001100 0 值右邊的上升沿,亦即步驟6。此時(shí): Diff1 寄存過(guò)去的p[16:9] + a ,亦即11111100 + 10000001, 結(jié)果為01111101。Diff2 寄存過(guò)去的p[16:9] + s,亦即11111100 + 01111111, 結(jié)果為01111011。經(jīng)步驟6的“決定”,過(guò)去p[1:0]是2'b00 ,所以p值的未來(lái)是{ p過(guò)去[16] , p過(guò)去[16:1] }, 亦即 1 11111100 00001100。 ? ? | |
11111110 000001100 0 值右邊的上升沿,亦即步驟7。此時(shí): Diff1 寄存過(guò)去的p[16:9] + a ,亦即11111110 + 10000001, 結(jié)果為01111111。Diff2 寄存過(guò)去的p[16:9] + s,亦即11111110 + 01111111, 結(jié)果為01111101。經(jīng)步驟7的“決定”,過(guò)去p[1:0]是2'b00 ,所以p值的未來(lái)是{ p過(guò)去[16] , p過(guò)去[16:1] }, 亦即 1 11111110 00000110。 ? ? | |
11111111 00000011 0 值右邊的上升沿,亦即步驟8。此時(shí): Diff1 寄存過(guò)去的p[16:9] + a ,亦即11111111 + 10000001, 結(jié)果為10000000。Diff2 寄存過(guò)去的p[16:9] + s,亦即11111111 + 01111111, 結(jié)果為 01111110。經(jīng)步驟8的“決定”,過(guò)去p[1:0]是2'b10 ,所以p值的未來(lái)是{Diff2[7] , Diff2, p過(guò)去[8:1] }, 亦即 0 01111110 00000011。 ? ? 最終結(jié)果取值未來(lái)p[16:1] ,00111111 00000001 亦即16129。 |
實(shí)驗(yàn)說(shuō)明:
如果以“大象放進(jìn)冰箱”這樣的概念去理解步驟i,在實(shí)驗(yàn)四中可能會(huì)產(chǎn)生許多思考邏輯上的矛盾。換一個(gè)想法,如果以“時(shí)間點(diǎn)”的概念去理解步驟i的話(huà),從仿真圖看來(lái)是絕對(duì)邏輯的。(再?lài)Z叨的補(bǔ)充一下,p空間的[ Width :1]是用來(lái)填入乘數(shù)B,然而p空間的[Width * 2 : Width + 1 ] 是用來(lái)執(zhí)行和被乘數(shù)A的操作)
實(shí)驗(yàn)結(jié)論:
這一章節(jié)筆記的重點(diǎn)不是要“如何如何實(shí)現(xiàn)一個(gè)算法”,而是“以不同概念的理解去完成乘法器的改進(jìn)”。
1.8 LUT乘法器
從1.8章節(jié)以前的乘法器都可以歸納為“慢速乘法器”,當(dāng)然它們不是真正意義上的慢,只不過(guò)它們無(wú)法達(dá)到急性一族人的任性而已。LUT乘法器,又成為查表乘法器。用傻瓜的話(huà)來(lái)說(shuō),就是先吧各種各樣的結(jié)果儲(chǔ)存在一個(gè)表中,然后將輸入資源以“查表”的方式,許對(duì)比“等于的結(jié)果”。
舉個(gè)例子,筆者先建立一個(gè)16 x 16 正值的查表:
?
? ? | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
2 | 0 | 2 | 4 | 6 | 8 | 10 | 12 | 14 | 16 | 18 | 20 | 22 | 24 | 26 | 28 | 30 |
3 | 0 | 3 | 6 | 9 | 12 | 15 | 18 | 21 | 24 | 27 | 30 | 33 | 36 | 39 | 42 | 45 |
4 | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 |
5 | 0 | 5 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 |
6 | 0 | 6 | 12 | 18 | 24 | 30 | 36 | 42 | 48 | 54 | 60 | 66 | 72 | 78 | 84 | 90 |
7 | 0 | 7 | 14 | 21 | 28 | 35 | 42 | 49 | 56 | 63 | 70 | 77 | 84 | 91 | 98 | 105 |
8 | 0 | 8 | 16 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80 | 88 | 96 | 104 | 112 | 120 |
9 | 0 | 9 | 18 | 27 | 36 | 45 | 54 | 63 | 72 | 81 | 90 | 99 | 108 | 117 | 126 | 135 |
10 | 0 | 10 | 20 | 30 | 40 | 50 | 60 | 70 | 80 | 90 | 100 | 110 | 120 | 130 | 140 | 150 |
11 | 0 | 11 | 22 | 33 | 44 | 55 | 66 | 77 | 88 | 99 | 110 | 121 | 132 | 143 | 154 | 165 |
12 | 0 | 12 | 24 | 36 | 48 | 60 | 72 | 84 | 96 | 108 | 120 | 132 | 144 | 156 | 168 | 180 |
13 | 0 | 13 | 26 | 39 | 52 | 65 | 78 | 91 | 104 | 117 | 130 | 143 | 156 | 169 | 182 | 195 |
14 | 0 | 14 | 28 | 42 | 56 | 70 | 84 | 98 | 112 | 126 | 140 | 154 | 168 | 182 | 196 | 210 |
15 | 0 | 15 | 30 | 45 | 60 | 75 | 90 | 105 | 120 | 135 | 150 | 165 | 180 | 195 | 210 | 225 |
假設(shè)A x B,它們均為4位,A為10,B為2,那么結(jié)果會(huì)是20。查表乘法器之所以被稱(chēng)為快速乘法器,就是上面的原因( 實(shí)際上許多硬件乘法器都是使用查表的方式)。
如果A x B ,它們均為8位,那么應(yīng)該如何呢?難道再建立一個(gè)256 x 256 乘法器!?這樣會(huì)死人的。
不知道讀者有沒(méi)有聽(tīng)過(guò)Quarter square 乘法查表呢?
上邊是該算法的公式,在公式的結(jié)束得到ab = ( ( a + b )2?)/4 - ( ( a - b )2?)/4 。
如果再進(jìn)一步細(xì)分的話(huà),無(wú)論是( a + b )2/4? 或者( a - b )2/4,經(jīng)過(guò)冪運(yùn)算后,得到的結(jié)果都是正值。
假設(shè)a 和b的位寬都是8 位的短整數(shù)話(huà)( 127 + 127 )2?/ 4 = ( -127 - 127 )2?/ 4。那么我們可以得到一個(gè)結(jié)論“( a + b )2/4? 或者( a - b )2/4? 使用同樣的(C)2/4 查表”。
那么我們建立一個(gè)C = 0 ~ 255 ,并且內(nèi)容是(C)2/4 的查表。
?
這個(gè)查表的尋址雖然是0~255,但是實(shí)際上下限是254而已。因?yàn)槲覀冎纼蓚€(gè)短整數(shù)最大值相加僅有-127 + -127 = -254 或者127 + 127 = 254 。
那么問(wèn)題來(lái)了, 短整數(shù)的最大取值范圍是-127 ~ 127 而已,何來(lái)寄存-254 ~ 254 呢?
這里我們就涉及了“不同容量空間的相互賦值”。假設(shè)C 是9位位寬的不正規(guī)整數(shù)
,然而A 和B 都是8位位寬的正規(guī)整數(shù),那么C = A + B ?
?
??? C = A + B | 等價(jià)于 | ??? C = { A[7], A } + { B[7], B } |
??? A = 127 (0111 1111) ??? B = 127 (0111 1111) ? ?A? ?? 0111 1111 ?B? ? ?0111 1111? + ?C? ? 01111 1110 | 等價(jià)于 | ??? ??? A = 127 (00111 1111) ??? B = 127 (00111 1111) ? ?A? ? 00111 1111 ?B? ? 00111 1111? + ?C? ? 01111 1110 ? ? |
??? ??? A = -127 (1000 0001) ??? B = -127 (1000 0001) ??? ?A? ?? 1000 0001 ?B? ?? 1000 0001? + ?C? ? 10000 0010 ? ? | ? ? ? ? ? ? 等價(jià)于 | ? ? ??? A = -127 (11000 0001) ??? B = -127 (11000 0001) ??? ?A? ? 11000 0001 ?B? ? 11000 0001? + ?C? ? 10000 0010 ? ? |
接下來(lái),我們來(lái)看一看下面的代碼:
reg [8:0]I1,I2;
case( i )
0:
begin
??? I1 <= { A[7], A } + { B[7], B };??????????? // C =A + B;
??? I2 <= { A[7], A } + { ~B[7], ( ~B + 1'b1 ) };? // C = A - B;
??? i <= i + 1'b1;
end
1:? // 取正值
begin
??? I1 <= I1[8] ? ( ~I1 + 1'b1 ) : I1;
??? I2 <= I2[8] ? ( ~I2 + 1'b1 ) : I2;
??? i <= i + 1'b1;
end
?
上面的I1 和I2 均為9位位寬。在步驟0,I1表示了C = A + B,相反的I2 表示了C = A - B。由于短整數(shù)的賦值采用補(bǔ)碼的表示方式,所以大大簡(jiǎn)化了正負(fù)轉(zhuǎn)換的操作。
假設(shè)A = -1 ( 1111 1111 ) , B = -3 ( 1111 1101 ), 經(jīng)過(guò)上面步驟0的操作:
I1 = { 1 11111111 } + { 1 1111 1101 } = 1 1111 1100 (-4) 等價(jià)于I1 = -1 + -3 = -4
I2 = { 1 11111111 } + { 0 0000 0011 } = 0 0000 0010 ( 2) 等價(jià)于I2 = -1 - (-3) = -1 + 3 = 2
步驟1是I1 和I2 從負(fù)值轉(zhuǎn)換為正值。
假設(shè)I1 = -4 (1 111 1100) ,I2 = 2 (0 0000 0010), 經(jīng)過(guò)步驟1的操作:
I1 = 0 0000 0011 + 1 = 0 0000 0100;
I2 = 0 0000 0010;
為什么在步驟1中,要特意將負(fù)值轉(zhuǎn)換為正值呢?筆者在前面已經(jīng)說(shuō)過(guò),無(wú)論是(-C)2?還是(C)2?取得的結(jié)果都是一至。為了兩者I1 和I2 共用相同的查表這是必須的步驟。
如果用I1和I2 來(lái)表達(dá)Quarter square 公式,那么:
?( | I1 |2?/ 4 ) - ( | I2 |2?/ 4 )
實(shí)驗(yàn)五:基于Quarter square 的查表乘法器
首先筆者手動(dòng)建立0~255 關(guān)于(C)2/4 結(jié)果的lut_module.v ,因?yàn)橛肣uartus II建立的rom 仿真不給力,很別扭。
?
lut_module.v
這是我目前,貼過(guò)最長(zhǎng)的.v 文件了...
lut_multiplier_module.v
這個(gè)模塊的功能很簡(jiǎn)單。首先取得I1 = A + B ,I2 = A - B,然后I1 和I2 都正值值,將I1 和I2 送至各自的查表,然后將得出的結(jié)果Q1_Sig (I1的結(jié)果) 和Q2_Sig
(I2的結(jié)果) , 執(zhí)行相減。實(shí)際上是補(bǔ)碼形式的相加,Q1_Sig + ( ~Q2_Sig + 1'b1 ) ,以致符合Quarter square的公式:
?( a + b )2/4? - ( a - b )2/4 = ( |I1| )2/4? + [ ( |I2| )2/4]補(bǔ)
???????????? ????????????????? = Q1_Sig + [Q2_Sig]補(bǔ)
?
?
第15~18行是仿真的輸出。第26~27行建立Q1_Sig 和Q2_Sig ,實(shí)際上這兩個(gè)線型數(shù)據(jù)是U1(81~87行)和U2(91~97行) 實(shí)例前申明的,可是modelsim 那么混蛋,偏偏就不給我通過(guò)。
從37~77行是該模塊的主功能。步驟0(49~54行)是取I1 和I2 的值。步驟1(56~61行)是I1和I2的正值化操作。步驟2(63~64行)是延遲一個(gè)時(shí)鐘,給予足夠的時(shí)間從lut_module.v讀出結(jié)果。步驟3(66~67行),是Quarter square公式操作的最后一步。
89~99行是lut_module.v 的實(shí)例化 ,U1是給I1使用 ,U2是給I2使用,它們的輸出連線分別是Q1_Sig 和Q2_Sig 。102行的Product 輸出信號(hào)由Data寄存器驅(qū)動(dòng)。然而106~109行是仿真輸出的驅(qū)動(dòng),分別有I1 , I2 ,Q1_Sig 和Q2_Sig 的仿真輸出。
?
lut_multiplier_module.vt
.vt 文件的寫(xiě)法和之前的實(shí)驗(yàn)都一樣,如果真的不知道筆者在寫(xiě)什么,就得好好看筆者之前寫(xiě)的筆記。
仿真結(jié)果:
看吧!一次的乘法操作僅需4個(gè)時(shí)鐘的而已。比起改進(jìn)的Booth算法減少了一半的時(shí)鐘消耗。真不愧是查表式的乘法器,佩服佩服。
實(shí)驗(yàn)結(jié)論:
說(shuō)實(shí)話(huà)查表式的乘法器是“以空間換時(shí)間”的乘法器,所以說(shuō)查表式的乘法器是很消耗空間。到底有什么乘法器“可以節(jié)約空間,又節(jié)省時(shí)鐘”呢?
你知道嗎?傳統(tǒng)查表的乘法器都有一個(gè)僵局,假設(shè)A(B),那么其中一個(gè)變量需要是“恒數(shù)”,否則建立查表的工作是非常的勞動(dòng)。但是Quarter square 公式的出現(xiàn)把這個(gè)僵局給打破。感謝前人的努力吧,我們后人才能乘涼......
1.9 Modified Booth 算法乘法器
事先聲明modified booth 算法 和 改進(jìn)的booth 算法乘法器(實(shí)驗(yàn)四)是沒(méi)有任何關(guān)系的。如字面上的意思modified booth 算法是booth 算法的升級(jí)版。我們稍微來(lái)回味一下booth 算法。
?
假設(shè)B是4位位寬的乘數(shù),那么booth 算法會(huì)對(duì)B[0: -1] , B[1:0], B[2:1], B[3:2] 加碼,而使得乘法運(yùn)算得到簡(jiǎn)化。booth 算法有典型數(shù)學(xué)做法,也有位操作的做法。Modified booth 算法比起booth 算法,對(duì)于4位位寬B乘數(shù)的加碼返回會(huì)更廣,而使得n/2 乘法運(yùn)算的優(yōu)化。再假設(shè)B是4微微款的倍數(shù),那么modified booth 算法會(huì)對(duì)B[1:-1] , B[3:1] 執(zhí)行加碼。
如果站在位操作的角度上:
?
B[1] | B[0] | B[-1] | 操作結(jié)果 |
0 | 0 | 0 | 無(wú)操作,右移兩位 |
0 | 0 | 1 | +被乘數(shù),右移兩位 |
0 | 1 | 0 | +被乘數(shù),右移兩位 |
0 | 1 | 1 | 右移一位,+被乘數(shù),右移一位 |
1 | 0 | 0 | 右移一位,-被乘數(shù),右移一位 |
1 | 0 | 1 | -被乘數(shù),右移兩位 |
1 | 1 | 0 | -被乘數(shù),右移兩位 |
1 | 1 | 1 | 無(wú)操作,右移兩位 |
?
Modified booth 算法同樣也有使用p空間,假設(shè)乘數(shù)A,和被乘數(shù)B,均為4位,那么p空間的大小n x 2 + 1 ,亦即9位。乘數(shù)A為7 (0111),被乘數(shù)B為2 (0010)。
?
先求出+被乘數(shù) 和 -被乘數(shù),亦即A 和?A。 | ?? A = 0111 ,?A= 1001 |
P空間初始化為0,然后P空間的[4..1] 填入乘數(shù) 亦即B。 | ?? P = 0000 0000 0 ?? P = 0000 0010 0 |
先判斷p[2:0],結(jié)果是3'b100 亦即“右移一位,-被乘數(shù),右移一位”。 | ?? P = 0000 0010 0 |
右移一位 ? ? | ?? P = 0000 0001 0 ?? |
p[8:5] 加上?A | ?? P = 0000 0001 0 ???+? 1001????? ???P = 1001 0001 0 |
右移一位 | ?? p = 1100 1000 1 |
判斷p[2:0],結(jié)果是3'b001 亦即“+被乘數(shù),右移二位”。 | ?? p = 1100 1000 1 |
?
p[8:5] 加上 A | ?? P = 1100 1000 1 ???+? 0111????? ???P = 0011 1000 1 |
右移二位 | ?? P = 0000 1110 0 |
最終取出p[8:1] 就是最終答案8'b00001110 ?,亦即14。 | ?? P =?0000 1110?0 |
?
關(guān)于4 位為位寬的乘數(shù)和被乘數(shù)操作流程圖如下:
說(shuō)實(shí)話(huà)modified booth 算法的位操作是很不規(guī)則,從上面的流程圖可以看到,不同的p[2:0]操作都有“不同的步驟次數(shù)”,這也使得它非常不適合作為運(yùn)用。
?
實(shí)驗(yàn)六:Modified Booth 乘法器
?
這個(gè)模塊大致的操作如上述的流程圖。
modified_booth_module.v
?
15~17行是仿真輸出。43~94行是該模塊的主功能。在步驟0(45~51行)取得被乘數(shù)A并且寄存在a寄存器,此外取得-1(被乘數(shù)A) 并且寄存在s寄存器。在初始化p空間的同時(shí),將乘數(shù)B填入p[8:1]。
(由于被乘數(shù)A和乘數(shù)B的位寬為8,所以p空間是n x 2 + 1 亦即9。我知道我很長(zhǎng)氣,但是還是容許筆者補(bǔ)充一下:p空間的[ Width :1]是用來(lái)填入乘數(shù)B,然而p空間的[Width * 2 : Width + 1 ] 是用來(lái)執(zhí)行和被乘數(shù)A的操作)。
步驟1和2(53~62行)是p[2:0] 等于3'b000 | 111 | 001 | 010 | 101 | 110 的操作。相反的,由于modified booth 算法當(dāng)p[2:0] 等于3'b011 和3'b100 所執(zhí)行的步驟次數(shù)是不一樣(56~57行)。
所以在步驟3~5(66~73行)針對(duì) p[2:0] 等于3'b011 的操作(56行)。反之步驟6~8 (77~84行)針對(duì)p[2:0] 3'b100 的操作(57行)。
?
步驟9~10產(chǎn)生完成信號(hào)。第102行的product輸出信號(hào)是由p[16:1]來(lái)驅(qū)動(dòng)。第106~109的仿真輸出信號(hào),分別由寄存器a ,s 和p來(lái)驅(qū)動(dòng)。
modified_booth_multiplier_module.v
?
這是激勵(lì)文件,在寫(xiě)這個(gè)文件的時(shí)候,筆者心情很糟糕,所以在步驟5加入了類(lèi)似for嵌套循環(huán)的東西。其他的和之前的.vt 文件都是大同小異~ 自己看著吧。
?
仿真結(jié)果:
在仿真結(jié)果中,可以很明顯的看到當(dāng)2(4) 和127(-127)有明顯的時(shí)鐘消耗差異。
實(shí)驗(yàn)結(jié)論:
如果Modified booth 算法用在“位操作”,雖然它是快速的乘法操作,但是很多時(shí)候它還是很別扭。換句話(huà)說(shuō),用它還要圖運(yùn)氣,因?yàn)椴煌某藬?shù)和被乘數(shù)都有不同的時(shí)鐘消耗......
?
1.10 Modified Booth 乘法器·改
如果要把Modified Booth 乘法器別扭的性格去掉,我們不得站在“數(shù)學(xué)的角度”去看modified booth 算法。下表是從數(shù)學(xué)的角度去看modified booth 針對(duì)乘數(shù)B的加碼。
?
B[1] | B[0] | B[n-1] | 操作結(jié)果 |
0 | 0 | 0 | 無(wú)操作 |
0 | 0 | 1 | +被乘數(shù) |
0 | 1 | 0 | +被乘數(shù) |
0 | 1 | 1 | +2(被乘數(shù)) |
1 | 0 | 0 | -2(被乘數(shù)) |
1 | 0 | 1 | -被乘數(shù) |
1 | 1 | 0 | -被乘數(shù) |
1 | 1 | 1 | 無(wú)操作 |
?
我們假設(shè)A被乘數(shù)和乘數(shù)B均為4位位寬 :A=7(0111),B=2(0010)。
?
A = (7) 0000 0111;2A = (14) 0000 1110;-2A = (-14) 1111 0010。
?
在這里我們必須注意一下當(dāng)B[1:-1] 等于011 或者100 的時(shí)候,4位的被乘數(shù)A的取值范圍最大是-7 ~ 7 然而,+2(被乘數(shù)) 或者 -2(被乘數(shù)) 都會(huì)使得A的最大值突破取值范圍。所以需要從4位位寬的空間向更大的位位寬哦空間轉(zhuǎn)換。這里就選擇向8位位寬的空間轉(zhuǎn)換吧。
?
B乘數(shù)加碼為B[1:-1] = 3'b100?,亦即 -2(被乘數(shù)) 和B[3:1] = 3'b100 ,亦即 +被乘數(shù)。
?
??? A????? 0 1 1 1
?? ?B????? 0 0 1 0??0
??? ==============
?????????? +1? -2?????? B乘數(shù)加碼
??? ==============
? 1 1 1 1 0 0 1 0
?+ 0 0 0 0 0 1 1 1????????? << 2 左移兩位
?? ===============
??? 10 0 0 0 1 1 1 0????? 無(wú)視超過(guò)8位最高位的益處
?? ===============
?
還記得booth算法在數(shù)學(xué)角度上的運(yùn)算嗎?4位的乘數(shù)和被乘數(shù)相乘,乘數(shù)必須加碼n次,而且乘積也是n 位的次數(shù),亦即4次哦加碼操作,和4次的乘積操作。相反的modified booth 算法在數(shù)學(xué)的角度上運(yùn)算的話(huà),4位的乘數(shù)和被乘數(shù)相乘,乘數(shù)加碼為n位/ 2 次,而且乘積也是n位/2 的次數(shù),亦即2次加碼操作,和2次的乘積操作
實(shí)驗(yàn)七:Modified Booth 乘法器·改
modified_booth_multiplier_module_2.v
?
第29~27行是該模塊所使用的寄存器。a是用來(lái)寄存A,a2是用來(lái)寄存2A,s是用來(lái)寄存-A,s2是用來(lái)寄存-2A。M是用來(lái)表示每次乘積的偏移量。
由于這個(gè)實(shí)驗(yàn)不是站在位操作的角度上,所以P空間僅是作為累加空間的存在。作為補(bǔ)償寄存器N用來(lái)判別booth 加碼操作,所以寄存器N用于寄存乘數(shù)B的值。乘數(shù)B是8位位寬,所以N空間的大小是 “乘數(shù)B的大小+ 1”。多出來(lái)的1個(gè)空間是用來(lái)寄存B[-1]的值。”
在步驟0(54~65行),是用來(lái)初始化所有相關(guān)的寄存器。寄存器a,a2,s,s2 在初始化的同時(shí)也進(jìn)行8位 向16位 空間轉(zhuǎn)換。寄存器p和M都清零,至于寄存器N[8:1]是用來(lái)填充乘數(shù)B,N[0] 填入零值。
步驟1~4(67~79),也就是4次的乘積次數(shù),因?yàn)槭艿絥/2 的關(guān)系。每一次的乘積操作都是先判別N[2:0],然后累加相關(guān)的值。
我們知道傳統(tǒng)的乘法,每一次的乘積操作,都有偏移量 ,打個(gè)比方。
?? 123
?? 111
=====
?? 123? <= 十進(jìn)制的第一個(gè)乘積是 偏移0,沒(méi)有左移位操作。
? 123?? <= 十進(jìn)制的第二個(gè)乘積是 偏移10,也就是左移1位。
?123??? <= 十進(jìn)制的第三個(gè)乘積是 偏移100,也就是左移2位。
=====
???????? ?
同樣的道理寄存器M 是用于記錄二進(jìn)制的每一次乘積偏移量,但是modified booth乘法的乘積偏移量是普通2進(jìn)制乘法乘積偏移量的2被。所以每一次乘積操作結(jié)束都左移+2。
至于寄存器N它寄存了B[7:1] + B[-1] 的值。然而每一次用于的判別都是N[2:0],所以每一次的乘積之后,N都需要右移兩位。
假設(shè)B = 1101 0010 ,N 必然是1101 0010 0。
乘積1 ? ? B[1:-1] = 100 N = 1101 0010 0 | 乘積2 ? ? B[3:1] = 001 N = 0011 0100 1 | 乘積3 ? ? B[5:3] = 010 N = 0000 1101 0 | 乘積4 ? ? B[7:5] = 110 N = 0000 0011 0 |
為什么說(shuō)8 位位寬的數(shù)據(jù)相乘,乘積運(yùn)算次數(shù)是n / 2 ,亦即4。這是Modified booth算法的一個(gè)特點(diǎn)。如果站在數(shù)學(xué)的角度上,他可以節(jié)省“乘積次數(shù)/ 2”。
第92行的product 輸出是由寄存器p驅(qū)動(dòng)。前面筆者說(shuō)過(guò)了,如果站在數(shù)學(xué)的角度,p空間只是累加空間的作用而已。然而p空間的大小是“乘數(shù)和被乘數(shù)位寬大小的相加”。
第96~101行是仿真輸出信號(hào)的被驅(qū)動(dòng)。有一點(diǎn)很特別,除了寄存a, a2, s, s2 和N 以外,筆者還故意將該模塊的i 引出,這是為了觀察 “Modified booth 乘法使得乘積次數(shù)減半”這一事實(shí)。在仿真中,SQ_i 從1~4經(jīng)過(guò),如果輸出的結(jié)果是真確,那么可以證明Modified booth 算法確實(shí)何以減少一半的乘積。
modified_booth_multiplier_module_2.vt
?
仿真結(jié)果:
?
?
從仿真結(jié)果上,我們可以看到,每一個(gè)乘法操作都消耗同樣數(shù)目的時(shí)鐘。此外還有一點(diǎn), 當(dāng)SQ_i 等于4 之后,就會(huì)得到正確的答案。
實(shí)驗(yàn)結(jié)論:
實(shí)驗(yàn)七和實(shí)驗(yàn)六相比,不僅每一次乘法操作時(shí)鐘消耗都一致,而且這樣結(jié)果帶來(lái)一個(gè)好處,就是- 實(shí)驗(yàn)七和實(shí)驗(yàn)六相比比起乘法運(yùn)算更快。此外,從SQ_i信號(hào)等于4之后,product 就輸出正確的結(jié)果,所以我們可以證明modified booth算法是可以減半乘積的次數(shù)。
總結(jié):
從實(shí)驗(yàn)一到實(shí)驗(yàn)七當(dāng)中,筆者詳細(xì)描述出四種乘法器的各有千秋,其中還有幾種乘法器筆者還特意去優(yōu)化和提升它們。從四種乘法器之中,傳統(tǒng)乘法器,Booth 乘法器,LUT查表乘法器,和Modified Booth乘法器。LUT乘法器擁有最少的時(shí)鐘消耗(最快的運(yùn)算速度),但是LUT乘法器卻暴露出消耗資源的弱點(diǎn)。
如果將LUT乘法器排外,自然而然Modified Booth 乘法器成為第二候選人,但是要建立Modified Booth 乘法器需要很好的理論基礎(chǔ),故很多新手都很怕它。至于Booth乘法和是最受歡迎的,如果設(shè)計(jì)的要求不像DSP那么任性,估計(jì)會(huì)有很多人喜歡它,因?yàn)樗杏?#xff0c;簡(jiǎn)單,容易親近。
剩 下的傳統(tǒng)的乘法器,它什么都不比上后者,難道我們就要鄙視它嗎?這個(gè)不然,筆者接觸各種各樣的乘法,還是托它的副,不然我是不可能如此深入研究整數(shù)乘法 器。傳統(tǒng)的乘法器,最主要的功能是傳達(dá)“乘法運(yùn)算”的概念。正如筆者贊同的一句話(huà):“前人造路,后人走路”,前者們的辛苦應(yīng)該受到尊敬。
整數(shù)乘法器所涉及的知識(shí)可真不小,Verilog HDL語(yǔ)言掌握的成熟性姑且不說(shuō),而且還涉及諸如補(bǔ)碼,整數(shù)的表示方法,不同位空間的整數(shù)轉(zhuǎn)換等等... 都是一些非常基礎(chǔ)的知識(shí)。我們所使用的高級(jí)語(yǔ)言,如C語(yǔ)言:
int C;
short int A,B;
C = A * B;
假設(shè)筆者輸入如同上述的代碼,實(shí)際上我們是不知道和不被允許窺看它里邊是如何操作(有傳言說(shuō),C語(yǔ)言的乘法就是傳統(tǒng)的乘法概念... (-_-!))。
雖然這本只有短短50多頁(yè)的筆記,故事也只是圍繞著著“整數(shù)乘法器”發(fā)展,顯然還有很多地方都不給力。但是你知道嗎,關(guān)于網(wǎng)上“Verilog HDL 整數(shù)乘法器”的求救貼已經(jīng)達(dá)到很恐怖的數(shù)量,此外還有很多源碼和實(shí)例都非常不給力,真是非常蛋疼!故筆者才有編輯這本筆記的初衷,雖然這本筆記不是什么非常給力的東西,但是作為參考已經(jīng)切切有余。
不知道讀者們看完這本筆記后又會(huì)萌出什么奇怪的想法呢?
總結(jié)
以上是生活随笔為你收集整理的verilog乘法器以及booth编码改进的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 麻将胡牌算法带癞子 python实现
- 下一篇: 半导体精密划片机行业介绍及市场分析