|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
经常有人问, FPGA里小数乘法怎么搞?
1 x4 ^1 u& o: p' T/ Y( l* b' \/ m! M% J# A7 s
) Y. m3 T3 n1 C" \
如果你乐意, 按照IEEE754标准做"浮点"型运算的ip当然最好(虽然面积上不太好).2 I* ]9 }( R% Q9 L7 y
不过,很多情况下,没有这个必要. c+ b/ t" G, {8 r
; C- s O; _- z6 b! i- [
# G; h z" X9 Q& b+ H一般我们就用"定点"了.
) a: _$ p1 ^; R6 v) v- [5 \你得自己"定个点", 比如用16位, 分成8位整数8位小数(后面记为"(8.8)"), 即"定点"在第8位.. g6 e+ H) y' B
那么:
/ b+ o1 @6 h. o! _# L' {1 -> 16'h0100;
! W, V; B2 B8 x2 n: D1.5 -> 16'h0180;7 ~) F+ E3 J% y8 M+ P
-1.5 -> -1.5*256 + 65536(补码) -> 16'hFE80(其实就是-16'sh0180, 让综合器给我们算补码去~~);
4 Z8 A1 i x, Q4 q2 W d9 U( k2 m; K...# r2 j% T- v* @0 v, {) T1 k
1.164 -> 1.164*256 = 298 = 16'h012A;
9 C; j/ d7 z; N' f! o- D% O) n. _# h& i' O7 B5 C3 E) s% M
8 u' r W8 s( ~% V `+ k
所以 signed input [15:0] a (也是"8整.8小")和 1.164相乘给 signed output [15:0] mul (也是"8整.8小"), 直接写:. I! n1 u/ d* e( Q5 x0 O, U
assign mul = (a * 16'sh012A) >>>8;1 Y: G9 G7 K& J* }
就行了, 当然, 你的fpga里有DSP block最好, 不然也要几百个LE的.# S$ _/ d! ?3 d$ a( x0 t3 R
6 O; ~9 f& n0 G; ~6 i8 r q9 `$ p4 Z6 k, s1 x) D) n' [# J8 U
因为 (8.8) 乘 (8.8) 得到 (16.16), 为了恢复成 (8.8), 所以帯符号右移8位即可.' Y9 x( \) n7 A+ ^( F7 l, w, f
把低8位小数舍掉, 高8位整数也丢了, 所以你得保证你的16位(8.8)的"定点小数"乘积不能超过范围, 多数数字信号处理系数都是区间[-1.0, 1.0]的,多半不存在问题, 积分什么的, 还有其它可能有问题的自己想清楚就行, 当然你要保留16位整.16位小也可以~~~% [9 ?4 f0 O3 h% h! g
( D) b; R, y! B8 Q; z
* Z* A. o+ ]$ H2 Y0 M4 t
总结:
1 Q5 e. ~5 ?) k- ~2 }" B, Bmodule fixpmul7 M+ U2 R" M- x
#(7 `# G- c% u6 F& ~3 x& N
parameter IW = 8,) t! N( X- W$ U
parameter FW = 8
4 Q* w. ~8 ^! i9 E8 v5 l)() f, E+ y9 G# z. ]* U- C k
input signed [IW+FW-1 : 0] a," Q$ p/ I6 r5 F" X1 v7 F7 u% w" B
input signed [IW+FW-1 : 0] b,
3 T: b7 r5 s: }6 i output signed [IW+FW-1 : 0] o. J# F/ |& V/ j6 a4 b- M
);- T j3 X. O) M) C) ]
(* multstyle = "dsp" *) wire signed [IW*2+FW*2-1 : 0] long;
% t& | `) I/ | ], L* M- @0 ]( m# O% K assign long = a * b;6 [, k8 V- O! F. R
assign o = long >>> FW;/ j& J1 E2 w* `2 l
endmodule
! e% ?9 Q. P- x; t4 t) x
# [4 F" g+ }1 q2 d* h
" @3 i% u: | @, ~PS: 作为一个完美主义者的想法: 以8位整型为例, 其实 8位有符号 乘 8位有符号得到的 16位有符号, 中的第14位(权2^14的位, 符号位右边的位), 很讨厌, 它只有在 -128 * -128时才等于1, 其它65535种情况, 全是0, 很浪费.
; |( g6 p- ]6 N0 c9 j, P6 H# S% R所以我们一般在数字信号处理系统中, 永远把[-1,1]映射到[-127,127], 这样那个讨厌的第14位永远用不到, 然后就可以: wire signed [15:0] mul = a * b; wire signed [14:0] out = {wire[15], wire[13:0]}, 8位有符号 乘 8位有符号 得到 15位有符号, 节约一位.
: q" R: N' X0 s% G3 V) G& A
6 |- V; x/ t- U Y
$ N. \2 a, q! l' f/ a
7 S% K, u }2 `' z+ R# X* e$ n, l/ e* x
|
|