在FPGA中能夠自定義數位寬,這帶來了極大的靈活性(相較於C語言等其餘語言),可是同時帶來的問題就是如何解讀這些數據,以及如何處理好他們的進位關係。(以前的某個項目中,就是由於計算位數錯誤,致使項目結果的錯誤,debug好久)所以寫下這篇blog,對這部分做出必定的總結。git
目前我經常使用的是unsigned int,signed int 以及 fixed-point三種。下面分別介紹。github
這種是最最簡單的表示方法。debug
一列數:code
\(a_n a_{n-1}... a_2 a_1a_0\)blog
他的大小等於get
\(D=\sum_{i=0}^{n} a_i 2^i\)it
如: b11100111module
其大小等於
\(2^7+2^6+2^5+2^2+2^1+2^0=231\)語法
很是常見的有符號整數的表示方法,一般的ADC的輸出就是這種形式。一般是用補碼錶示。bug
最高位爲符號位,剩下的部分表示數字
定義是這樣的:
- 正數的補碼等於原碼
- 負數的補碼=負數的反碼+1
- 負數的反碼=符號位爲1,剩下的部分爲正數的取反
若是暈了就看下面的例子
比方說-3用8位Signed int表示爲
# 3的Signed int 0000_0011 # 3的反碼 1111_1100 # 3的補碼 1111_1101 # 爲0xfd
驗證一下:
module invert( output signed [7:0] out, output signed [7:0] out1, ); assign out = -3; assign out1 = 3; `probe(out); // 這個是iverilog用於實現波形的語法 `probe(out1); endmodule
結果爲:
定點數顧名思義就是小數點的位置在二進制數中是固定的,一般須要本身定義。
如總位寬8位的,3位小數,1位符號位表示爲,其中\(\Delta\)表示小數點
\(S_4 a_3 a_2 a_1 a_0 \Delta a_{-1} a_{-2} a_{-3}\)
原碼的話,計算方式同Unsigned int
\(D=(-1)^{S_4}\sum_{i=-3}^{3} a_i 2^i\)
反碼、補碼都同Signed int,注意補碼在最低位+1
舉例: -1.75 Fixed point 總位寬8位的,3位小數,1位符號位表示爲
# 原碼 1 0001.110 # 反碼 1 1110.001 # 補碼 1 1110.010 # 0xf2
驗證:verilog自己不支持Fixed point,這裏採用更加高級的SpinalHDL來驗證,具體關於SpinalHDL的能夠本身看看
數的表示,特別是負數的表示,採用補碼的形式,這種方式更容易計算加減法,而採用原碼的表示,更容易計算乘法。
在運算的時候 位寬是會變化的,所以須要注意變化的規律
在兩個位寬爲B的加減運算中,要保證數據不溢出,結果的位寬應爲B+1
在SpinalHDL中,採用 +^ 或 -^ 來保證自動推斷位寬
乘法結果的位寬等於被乘數兩個位寬之和
除法儘可能使用IP覈實現