Welcome guest. Before posting on our computer help forum, you must register. Click here it's easy and free.

Author Topic: Division in a FPGA  (Read 4457 times)

0 Members and 1 Guest are viewing this topic.

kokowang5699

    Topic Starter


    Rookie

    • Experience: Experienced
    • OS: Other
    Division in a FPGA
    « on: November 21, 2016, 01:36:23 PM »
    I'm trying to synthesize a module to run division as support for a DAQ filter.
    This was my original plan:

    module divide (clk, num, den, out);
    parameter bit = 64;
    input clk;
    input [bit-1:0] den, num;
    output [13:0] out;
    reg signed [bit-1:0] x, y;
    reg [13:0] count;
    assign out = count;
    always @ (posedge clk) begin
    x = num;
    count = 0;
    y = den;
    while (x > (y*256)) begin
    x = x - (y*256);
    count = count + 256;
    end
    while (x < 0) begin
    x = x + (y*16);
    count = count - 16;
    end
    while (x > 0) begin
    x = x - y;
    count = count + 1;
    end
    end
    endmodule


    However, I'm running across a major problem. Vivado (the software used to synthesize FPGA circuit) does not work with loops determined by dynamic variables. Any suggestions on how to make a module to divide? Thanks in advance!

    Geek-9pm


      Mastermind
    • Geek After Dark
    • Thanked: 1026
      • Gekk9pm bnlog
    • Certifications: List
    • Computer: Specs
    • Experience: Expert
    • OS: Windows 10
    Re: Division in a FPGA
    « Reply #1 on: November 21, 2016, 01:52:31 PM »
    First of all, what language is this?
    You said:
    Quote
    Vivado (the software used to synthesize FPGA circuit) does not work with loops determined by dynamic variables.
    What experience do you have?
    Why would you need to use a dynamic variable to control a loop?
    In programming, a dynamic variable is a variable whose address is determined when the program is run. In contrast, a static variable has memory reserved for it at compilation time.
    Please explain.

    kokowang5699

      Topic Starter


      Rookie

      • Experience: Experienced
      • OS: Other
      Re: Division in a FPGA
      « Reply #2 on: November 21, 2016, 06:52:10 PM »
      Geek-9pm
      First of all, what language is this?
      What experience do you have?

      This is VHDL - verilog.
      I am a highschool student programming a DAQ to filter nuclear spectrometer data in real time (before you ask, there's no teacher in my school that knows anything about HDL or FPGAs). I have moderate experience with verilog and have a decent understanding of FPGAs. I've written the entire filter consisting of this logic:
      aK,L[n] = x[n] − x[n − K] − x[n − L] + x[n − K − L]
      b[n] = b[n − 1] + aK,L[n], n ≥ 0
      c[n] = b[n] + MaK,L[n]
      y[n] = y[n − 1] + c[n], n ≥ 0

      Where x[n] is digitized input and y[n] is output. k, l, and M are user defined variables.
      This equation outputs a y[n] that is m*(l or k +1) times larger than x[n]'s peak. I need to reduce y[n] by dividing it by m*(l+1). Because M and L are changing variables, I can't simply hard code a multiplication + bitshift into the FPGA.

      I don't necessary need a dynamic variable to control a loop, here is a slightly altered version (Note, 7 iterations of the loop is the minimum number to ensure the correct value (truncated) being outputted given output is 14 bits unsigned or 15 bits signed):

      module dividez (clk, num, den, out);
      parameter bit = 64;
      input clk;
      input [bit-1:0] den, num;
      output [13:0] out;
      reg signed [bit-1:0] x, y;
      reg [24:0] count;
      assign out = $signed(count);
      integer i;
      always @ (posedge clk) begin
      x = $signed(num);
      count = 0;
      y = den;
      for (i = 0; i <= 6; i = i+1) begin
      if (x >= 0) begin
      if (x > (y*4096)) begin
      x = x - (y*4096);
      count = count + 4096;
      end
      if (x >= (y*1024)) begin
      x = x - (y*1024);
      count = count + 1024;
      end
      if (x >= (y*256)) begin
      x = x - (y*256);
      count = count + 256;
      end
      if (x >= (y*64)) begin
      x = x - (y*64);
      count = count + 64;
      end
      if (x >= (y*16)) begin
      x = x - (y*16);
      count = count + 16;
      end
      if (x >= (y*4)) begin
      x = x - (y*4);
      count = count + 4;
      end
      if (x >= (y)) begin
      x = x - (y);
      count = count + 1;
      end
      end

      if (x < 0) begin
      if (x <= -y*4096) begin
      x = x + (y*4096);
      count = count - 4096;
      end
      if (x <= -y*1024) begin
      x = x + (y*1024);
      count = count - 1024;
      end
      if (x <= -y*256) begin
      x = x + (y*256);
      count = count - 256;
      end
      if (x <= -y*64) begin
      x = x + (y*64);
      count = count - 64;
      end
      if (x <= -y*16) begin
      x = x + (y*16);
      count = count - 16;
      end
      if (x <= -y*4) begin
      x = x + (y*4);
      count = count - 4;
      end
      if (x <= -y) begin
      x = x + (y);
      count = count - 1;
      end
      end
      end
      end
      endmodule


      This works logically and can be synthesized, although it takes up quite a bit of LUTs (over 10000). The entire loop also takes more than 0.5 clock cycles (4ns) to run, I need it under that for the rest of the hardware logic to function. The FPGA I currently have access to is the one on the Zynq-7000 SOC. I have 17,000 LUTs to work with and 4ns between pos-neg edges of clock.
      The goal is to have a module that can do division of very large numbers very quickly. The first version can not be synthesized, this version above is too resource heavy and too slow. In case you aren't familiar with verilog, division is not possible natively. This is my attempt at division that I threw together in 20 minutes; the code won't be very organized. If you know of any other methods to do division using only +, -, * by integers, <<, >>, or logic, please let me know. Thanks!
      « Last Edit: November 21, 2016, 07:09:21 PM by kokowang5699 »

      Geek-9pm


        Mastermind
      • Geek After Dark
      • Thanked: 1026
        • Gekk9pm bnlog
      • Certifications: List
      • Computer: Specs
      • Experience: Expert
      • OS: Windows 10
      Re: Division in a FPGA
      « Reply #3 on: November 21, 2016, 07:08:53 PM »
      Hope you get it to work soon. There is some stuff in the IEEE archives you will want to look at. You might have to ask a friend for a password to get into some of it. Sometimes the IEEE is stingy.

      Division is the hard part in the basic math functions. Multiplication is easy. Division is not. A common solution is to use hardware division, not software.
      Did you already tread this?
      http://www.eetimes.com/author.asp?section_id=36&doc_id=1321047
      Doing Math in FPGAs, Part 5 (Binary Division)
      Quote
      If you thought binary multiplication was "interesting," just wait until you try to wrap your brain around fixed-point binary division!

      What some programmers do is have a look-up table to help start the division recursion chain. This can reduce the number iterations a lot.

      This link above has a nice video about fixed point division.  Take a look. 8)

      EDIT: Another reference:
      https://en.wikipedia.org/wiki/Division_algorithm
      Quote
      Division algorithms fall into two main categories: slow division and fast division. Slow division algorithms produce one digit of the final quotient per iteration. Examples of slow division include restoring, non-performing restoring, non-restoring, and SRT division. Fast division methods start with a close approximation to the final quotient and produce twice as many digits of the final quotient on each iteration. Newton–Raphson and Goldschmidt fall into this category.
      « Last Edit: November 21, 2016, 07:21:31 PM by Geek-9pm »

      kokowang5699

        Topic Starter


        Rookie

        • Experience: Experienced
        • OS: Other
        Re: Division in a FPGA
        « Reply #4 on: November 21, 2016, 07:12:56 PM »
        Hope you get sit to work.

        Division is the hard part in the basic math functions. Multiplication is easy. Division is not. A common solution is to use hardware division, not software.
        Did you already tread this?
        http://www.eetimes.com/author.asp?section_id=36&doc_id=1321047
        Doing Math in FPGAs, Part 5 (Binary Division)
        What some programmers do is have a look-up table to help start the division recursion chain. This can reduce the number iterations a lot.


        I'll throw something together using the method in the link in a few minutes or hours. Thanks for the reference.
        I can't test it right away though since some hardware stopped working, I'll replace it tomorrow.

        kokowang5699

          Topic Starter


          Rookie

          • Experience: Experienced
          • OS: Other
          Re: Division in a FPGA
          « Reply #5 on: November 21, 2016, 09:03:02 PM »
          Geek-9pm I've implemented the method used in the link you sent me. It works fine in simulations but on the actual FPGA, it exhibits spikes in the output at random intervals. This suggests that the logic for it takes longer than 4ns and can not be used with this setup. It seems to be doing no better than Vivado's division modules (auto generated logic during synthesis).

          At this point, I may just give up on this and have the CPU handle division after initial filtering. One last thing I can think of to try is initiating 2-4 of the division module and running them in parallel processing, each on every 2nd, 3rd, or 4th clock cycle. Hopefully I'll have room on the FPGA for that many. Either that or I could run division on edges of each of the variables to recalibrate FPGA upon change of user defined variables to output a constant that I could multiply y[n] by then bitshift. That will add considerably more work though as I'll need to ignore data and triggers during recalibration to avoid interference from that. Although it would also be the cheapest - resource wise - method.

          I could use the CASE method in verilog as something similar to a lookup table, but I need all values to work at all times for accurate spectroscopy measurements. Simply mapping common values won't work and mapping the all possible values will result in several gigabytes of data needing to be loaded into RAM.

          Geek-9pm


            Mastermind
          • Geek After Dark
          • Thanked: 1026
            • Gekk9pm bnlog
          • Certifications: List
          • Computer: Specs
          • Experience: Expert
          • OS: Windows 10
          Re: Division in a FPGA
          « Reply #6 on: November 21, 2016, 10:34:29 PM »
          Yes, latency is an issue in this kind of thing.
          Quote
          I could use the CASE method in verilog as something similar to a lookup table, but I need all values to work at all times for accurate spectroscopy measurements. Simply mapping common values won't work and mapping the all possible values will result in several gigabytes of data needing to be loaded into RAM.
          Give it some thought. There is a middle ground where you get initial values that are very good and then work down to very good value. That is how division is done in the Intel CPU. The concept can be applied with other hardware.
          Here is another reference:
          https://graphics.stanford.edu/~seander/bithacks.html
          By Sean Eron Anderson, Stanford University. His work has been peer reviewed.