一般来说,FPGA厂商的EDA软件里都有除法器的IP核。以Xilinx为例,Core Generator 里就可以生成除法器,任意位数。不过生成的除法器是流水线形式的。也就是说,如果是有批量的数据做除法,那么肯定是非常快的,只要经过一个固定的Lantency之后,结果就源源不断地出来。
但是我在做图像压缩算法的时候,遇到了这样一个问题:我需要前一次除法的结果代入到下一次除法里去,这样看来,那个固定的Lantency就成了最大的障碍。所以没办法,就决定自己写一个除法器,以尽管减少时间延迟和FPGA内部资源。
除法器的思路是这样的,以8位除以4位为例。
设A=[a0,a1,a2,a3,a4,a5,a6,a7],B=[b0,b1,b2,b3](an,bn分别表示1bit位),商为C。
第一步,用A与(B<<4)进行比较,如果A比(B<<4)大,则从A中减去(B<<4),然后C+=(1<<4)。直到A小于(B<<4)。
第二步,用A与(B<<3)进行比较,如果A比(B<<3)大,则从A中减去(B<<3),然后C+=(1<<3)。直到A小于(B<<3)。
第三步,用A与(B<<2)进行比较,如果A比(B<<2)大,则从A中减去(B<<2),然后C+=(1<<2)。直到A小于(B<<2)。
第四步,用A与(B<<1)进行比较,如果A比(B<<1)大,则从A中减去(B<<3),然后C+=(1<<1)。直到A小于(B<<1)。
第五步,用A与B进行比较,如果A比B大,则从A中减去B,然后C+=1。直到A小于B。
最终C为商,A为余数。
关键算法的代码如下:
if (CONV_INTEGER(divisor_buf) = 0) then -- 除数为0 fra_buf <= (others => '0'); quo_buf <= (others => '0'); elsif (CONV_INTEGER(divisor_buf) = 1) then -- 除数为1 fra_buf <= (others => '0'); quo_buf <= dividend_buf; elsif (dividend_buf > (divisor_buf & "0000")) then --4 dividend_buf <= dividend_buf - (divisor_buf & "0000"); quo_cnt <= quo_cnt + "10000"; state <= st2; elsif (dividend_buf > (divisor_buf & "000")) then --3 dividend_buf <= dividend_buf - (divisor_buf & "000"); quo_cnt <= quo_cnt + "1000"; state <= st2; elsif (dividend_buf > (divisor_buf & "00")) then --2 dividend_buf <= dividend_buf - (divisor_buf & "00"); quo_cnt <= quo_cnt + "100"; state <= st2; elsif (dividend_buf > (divisor_buf & "0")) then --1 dividend_buf <= dividend_buf - (divisor_buf & "0"); quo_cnt <= quo_cnt + "10"; state <= st2; elsif (dividend_buf >= divisor_buf ) then --0 dividend_buf <= dividend_buf - divisor_buf; quo_cnt <= quo_cnt + '1'; state <= st2; else fra_buf <= dividend_buf(9 downto 0); quo_buf <= quo_cnt; end if;
实例仿真图如下:
完整VHDL代码: