參考:
https://blog.csdn.net/vivid117/article/details/101427302
http://wscentity.lofter.com/post/1d00edbd_6476453
Verilog中有符號與無符號的加法和乘法運算
無符號乘法和加法
對於無符號的乘法和加法,沒有什么好說的,就是直接用‘*’和‘+’。
有符號乘法和加法
有符號和無符號運算
verilog里如果有符號數和無符號數做運算,會強制當作無符號運算
這就涉及verilog處理運算時的法則:
例如 c = a + b; 其中a和b都是四位數,c是五位。在計算時,verilog會將a和b都擴展到5位,然后再做加法,而如果a和b中有無符號數,則位寬擴展就按照無符號數來,也就是高位補0。所以如果a和b中既有無符號又有有符號,結果就不正確了。
解決方法是用 \$signed()來修飾:c = a + $signed(b)這樣在c = a + b,這個運算開始的擴位就會按照有符號數的方式進行擴位,在高位補符號位,加法得出的結果就是a、b視為有符號數的結果。
例子:






可見結果是不是signed倒是無所謂的。但是最好還是加上。
有符號數乘法
例如有符號數[3:0]a * [3:0]b. 其中a=-5,b=7。a用補碼表示為1011,b用補碼表示是0111,對於這個例子,乘法過程如下:


可以看到上面最后一行的結果需要對a進行\(\color{red}{取反加一}\)才正確,並且此時\(\color{red}{取反加一也包括a的符號位}\)。
另外,還需要注意的是所有部分積都要補符號位補到乘法輸出值的位數。
其實乘法器就是由加法組成,所以b中的每一位跟a做乘法(異或)之后把部分積累加時,仍然需要遵從加法的原則,擴展符號位直到達到輸出位寬,然后再加。
所以有符號乘法跟無符號乘法的區別就在這,無符號乘法不需要考慮符號位擴展問題,而有符號乘法在累加部分積的時候需要做符號位擴展,並且還要考慮符號位參與乘法時的含義不同,也就是說符號位的0表示0,但1卻表示-1,所以符號位的1做乘法就不是異或而是\(\color{red}{對所有位取反再加一}\)了。
有符號乘法器的實現
上面說的是對於補碼形式的有符號數如何計算乘法,而實際上上面這種方法是將符號位也參與到運算中,這種方式實際上需要區分符號位的乘法,所以在設計帶符號乘法器時可能需要修改傳統無符號乘法器中的加法器類型,可以參考:
https://blog.csdn.net/iteye_3619/article/details/82282317
在verilog中,一般有符號乘法器的做法是先將補碼的輸入都轉成原碼,再將符號位單獨拿出來進行異或,然后其余部分當作無符號數乘起來,最后再對結果取補碼轉回原碼結果。