固定除数整除的 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 的代码:

process(video_col)
begin
   if video_col < 480 then
      q <= "00";
   elsif video_col < 960 then
      q <= "01";
   elsif video_col < 1440 then
      q <= "10";
   else
      q <= "11";
   end if;
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 代码如下:

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

entity top is 
   generic(
      M : integer := 205;
      N : integer := 10;
      W : integer := 6
   );
   port(
      ina : in std_logic_vector;
      y   : out std_logic_vector
   );
end entity;
architecture behav of top is 
   -- 常量与信号定义
   constant Y_HIGH: integer := W + N - 1;
   constant D_WIDTH: integer := ina'LENGTH + 32;
   signal Prod: std_logic_vector(D_WIDTH-1 downto 0);
   signal A_buf: bit_vector(D_WIDTH-1 downto 0) := (others => '0');
   signal M_buf: std_logic_vector(31 downto 0);
begin
   -- 信号初始化
   A_buf(ina'HIGH downto 0) <= to_bitvector(ina);
   M_buf <= conv_std_logic_vector(M,32);

   -- 循环移位乘法器
   process(A_buf,M_buf)
      variable tmp: std_logic_vector(D_WIDTH-1 downto 0);
   begin
      tmp := (others => '0');
      for i in M_buf'REVERSE_RANGE loop
         if M_buf(i) = '1' then
            tmp := tmp + to_stdlogicvector(A_buf SLL i);
         end if;
      end loop;
      Prod <= tmp;
   end process;

   -- 截掉结果的低位部分
   y <= Prod(Y_HIGH downto N);
end architecture;

        仿真激励代码如下:

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

entity top_tb is
end entity;
architecture behav of top_tb is
   signal sys_rst: std_logic := '1';
   signal sys_clk: std_logic := '1';
   signal A: std_logic_vector(7 downto 0);
   signal A_div5: std_logic_vector(5 downto 0);
begin
   -- Todo
   sys_rst <= '1', '0' after 100 ns;
   sys_clk <= not sys_clk after 2500 ps;

   process(sys_rst,sys_clk)
   begin
      if sys_rst = '1' then
         A <= (others => '0');
      elsif rising_edge(sys_clk) then
         if A = 255 then
            A <= A;
         else
            A <= A + 1;
         end if;
      end if;
   end process;

   top_inst: entity work.top
   port map(
      ina => A,
      y   => A_div5
   );
end architecture;

        仿真波形如下:

37006a3061d04a59b87352f1c72e45bc.png

58e61b0bb9cc44fa8168bf77115069b0.png  366f8c8f00b2449f973d79447ffdd817.png

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

洋洋Young

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值