当前位置:   article > 正文

固定除数整除的 FPGA 实现_固定除数除法

固定除数除法

除法在 FPGA 开发与应用中是一种重要的运算,按照被除数和除数是否为定值,分三种情况:(1)被除数固定,除数变化;(2)除数固定,被除数变化;(3)被除数和除数都不固定。本文讨论如何用 FPGA 实现除数固定,被除数变化的整数除法。

目录

1 问题分类

2 实现方法

2.1 比较器加编码器法

2.2 乘积右移截位法

3 仿真验证


1 问题分类

        由于除数是固定的,先根据除数本身的性质对问题进行分类。

        对于 2 的指数次幂的除数,例如 2,4,8...,用逻辑右移就可以很方便地实现除法运算,右移 1 位等价于除以 2,右移 2 位等价于除以 4,...,右移 N 位等价于除以 2 的 N 次幂。

150645d049cb44cf90161f0157356f1e.jpeg

        对于非 2 的指数次幂的除数,上述方法就不适用了,下面讨论两种实现方法。

2 实现方法

2.1 比较器加编码器法

        这种方法的原理是,根据被除数与除数的关系,划分若干区间,并对这些区间进行编码。把除法运算转换为,判断被除数落在哪个区间,然后输出区间的编码。

        例如,在处理 1920x1080p 视频画面时,假如需要计算 video_col ÷ 480,可以把 video_col 的取值范围划分为 [0,479], [480,959], [960,1439] 和 [1440,1919] 四个区间,并将这四个区间依次编码为 00, 01, 10, 11。

        以下是用 VHDL 语言实现 video_col ÷ 480 的代码:

  1. process(video_col)
  2. begin
  3. if video_col < 480 then
  4. q <= "00";
  5. elsif video_col < 960 then
  6. q <= "01";
  7. elsif video_col < 1440 then
  8. q <= "10";
  9. else
  10. q <= "11";
  11. end if;
  12. end process;

        这种方法的优点是易于理解,容易修改;缺点是对于数值小的除数,需要编码的区间数量较多,这会消耗大量 LUT 资源用于数值比较。

2.2 乘积右移截位法

        对于除数较小的情况,第一种方法可能出现很多选择分支。为了节约 LUT 资源,可以采用第二种方法,即被除数先乘以一个固定的数,然后将结果进行逻辑右移,截掉低位部分。

        如果用 x, y, z, a 分别表示被除数,除数,商和余数,它们满足

gif.latex?x%20%5Cdiv%20y%20%3D%20z%20%5C%3B%20%5Ccdots%20%5Ccdots%20%5C%3B%20a

改写成

gif.latex?x%20%5Ccdot%20%5Cfrac%7B1%7D%7By%7D%20%3D%20z%20&plus;%20%5Cdelta_1%20%5C%3B%20%2C%20%5C%3B%20%5Cdelta_1%20%5Cin%20%5B0%2C1%29

gif.latex?x%20%5Ccdot%20%5Cfrac%7Bm%7D%7B2%5En%7D%20%3D%20z%20&plus;%20%5Cdelta_2%20%5C%3B%20%2C%20%5C%3B%20%5Cdelta_2%20%5Cin%20%5B0%2C1%29

令 \delta = \delta_2 - \delta_1 ,有

gif.latex?x%20%5Ccdot%20%5Cfrac%7B1%7D%7By%7D%20%3D%20x%20%5Ccdot%20%5Cfrac%7Bm%7D%7B2%5En%7D%20&plus;%20%5Cdelta%20%5C%3B%20%2C%20%5C%3B%20%5Cdelta%20%5Cin%20%5B0%2C1%29

        容易知道,n 的取值范围相对 m 较小,因此在寻找满足要求的 m 和 n 时,可以先给定 n,再寻找 m 的最优值。 

        令

 gif.latex?f%28%5Cbold%20x%29%20%3D%20%5Clfloor%20%5Cbold%20x%20%5Ccdot%20%5Cfrac%7B1%7D%7By%7D%20%5Crfloor%20%5C%20%2C%20%5Cquad%20g%28%5Cbold%20x%29%20%3D%20%5Clfloor%20%5Cbold%20x%20%5Ccdot%20%5Cfrac%7Bm%7D%7B2%5En%7D%20%5Crfloor

其中 gif.latex?%5Cbold%20x%20%3D%20%5Cleft%5C%7B%20x_1%2C%20x_2%2C%20%5Ccdots%20%5Cright%5C%7D,于是,m 的最优值由以下整数规划问题给出:

gif.latex?%5Cbegin%7Bmatrix%7D%20min.%20%5Cquad%20%5CVert%20f%28%5Cbold%20x%29-g%28%5Cbold%20x%20%3Bn_0%2Cm%29%5CVert%20_2%5E2%5C%5C%20%5C%5C%20s.t.%20%5Cquad%20m%20%5Cin%20%5Cmathbb%7BZ%7D%20%5C%3B%5C%3B%20%5Cqquad%20%5Cqquad%20%5Cquad%20%5Cend%7Bmatrix%7D

m 有两个可能的最优解,分别是

gif.latex?m%5E*_1%20%3D%20%5Clfloor%20%5Cfrac%7B2%5En%7D%7By%7D%20%5Crfloor%20%5C%3B%20%2C%20%5Cquad%20m%5E*_2%20%3D%20%5Clfloor%20%5Cfrac%7B2%5En%7D%7By%7D%20%5Crfloor%20&plus;%201

        有了 m 和 n 的关系之后,只要在一定范围内遍历 n 的取值,再代入并验证 gif.latex?f%28%5Cbold%20x%29%20%5Cequiv%20g%28%5Cbold%20x%29 是否成立即可。

3 仿真验证

        用乘积右移截位法实现求 x 整除 5 的运算电路,x 的位宽取 8 bit。在 [3,12] 的范围内遍历 n,计算发现当 n = 10, m = 205 时,误差已经为 0。

        取 m = 205, n = 10,VHDL 代码如下:

  1. library ieee;
  2. use ieee.std_logic_1164.all;
  3. use ieee.std_logic_arith.all;
  4. use ieee.std_logic_unsigned.all;
  5. entity top is
  6. generic(
  7. M : integer := 205;
  8. N : integer := 10;
  9. W : integer := 6
  10. );
  11. port(
  12. ina : in std_logic_vector;
  13. y : out std_logic_vector
  14. );
  15. end entity;
  16. architecture behav of top is
  17. -- 常量与信号定义
  18. constant Y_HIGH: integer := W + N - 1;
  19. constant D_WIDTH: integer := ina'LENGTH + 32;
  20. signal Prod: std_logic_vector(D_WIDTH-1 downto 0);
  21. signal A_buf: bit_vector(D_WIDTH-1 downto 0) := (others => '0');
  22. signal M_buf: std_logic_vector(31 downto 0);
  23. begin
  24. -- 信号初始化
  25. A_buf(ina'HIGH downto 0) <= to_bitvector(ina);
  26. M_buf <= conv_std_logic_vector(M,32);
  27. -- 循环移位乘法器
  28. process(A_buf,M_buf)
  29. variable tmp: std_logic_vector(D_WIDTH-1 downto 0);
  30. begin
  31. tmp := (others => '0');
  32. for i in M_buf'REVERSE_RANGE loop
  33. if M_buf(i) = '1' then
  34. tmp := tmp + to_stdlogicvector(A_buf SLL i);
  35. end if;
  36. end loop;
  37. Prod <= tmp;
  38. end process;
  39. -- 截掉结果的低位部分
  40. y <= Prod(Y_HIGH downto N);
  41. end architecture;

        仿真激励代码如下:

  1. library ieee;
  2. use ieee.std_logic_1164.all;
  3. use ieee.std_logic_arith.all;
  4. use ieee.std_logic_unsigned.all;
  5. entity top_tb is
  6. end entity;
  7. architecture behav of top_tb is
  8. signal sys_rst: std_logic := '1';
  9. signal sys_clk: std_logic := '1';
  10. signal A: std_logic_vector(7 downto 0);
  11. signal A_div5: std_logic_vector(5 downto 0);
  12. begin
  13. -- Todo
  14. sys_rst <= '1', '0' after 100 ns;
  15. sys_clk <= not sys_clk after 2500 ps;
  16. process(sys_rst,sys_clk)
  17. begin
  18. if sys_rst = '1' then
  19. A <= (others => '0');
  20. elsif rising_edge(sys_clk) then
  21. if A = 255 then
  22. A <= A;
  23. else
  24. A <= A + 1;
  25. end if;
  26. end if;
  27. end process;
  28. top_inst: entity work.top
  29. port map(
  30. ina => A,
  31. y => A_div5
  32. );
  33. end architecture;

        仿真波形如下:

37006a3061d04a59b87352f1c72e45bc.png

58e61b0bb9cc44fa8168bf77115069b0.png  366f8c8f00b2449f973d79447ffdd817.png

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/671260
推荐阅读
相关标签
  

闽ICP备14008679号