将整数sqrt算法转换为verilog中的固定点

时间:2014-11-05 06:50:41

标签: verilog square-root

我有这个代码确定32位数的整数平方根。

output = floor(sqrt(input))

我希望得到一个定点结果,例如{8 bit integer ,8 bit fractionary}但是在8位输入上。因此wire[7:0]输入而不是[31:0]

我的问题是我不知道如何修改算法以确定我之前说过的内容。您可以在下面找到代码。

module sqrt32(clk, rdy, reset, x, .y(acc));
   input  clk;
   output rdy;
   input  reset;

   input [31:0] x;
   output [15:0] acc;


   // acc holds the accumulated result, and acc2 is the accumulated
   // square of the accumulated result.
   reg [15:0] acc;
   reg [31:0] acc2;

   // Keep track of which bit I'm working on.
   reg [4:0]  bitl;
   wire [15:0] bit = 1 << bitl;
   wire [31:0] bit2 = 1 << (bitl << 1);

   // The output is ready when the bitl counter underflows.
   wire rdy = bitl[4];

   // guess holds the potential next values for acc, and guess2 holds
   // the square of that guess. The guess2 calculation is a little bit
   // subtle. The idea is that:
   //
   //      guess2 = (acc + bit) * (acc + bit)
   //             = (acc * acc) + 2*acc*bit + bit*bit
   //             = acc2 + 2*acc*bit + bit2
   //             = acc2 + 2 * (acc<<bitl) + bit
   //
   // This works out using shifts because bit and bit2 are known to
   // have only a single bit in them.
   wire [15:0] guess  = acc | bit;
   wire [31:0] guess2 = acc2 + bit2 + ((acc << bitl) << 1);

   task clear;
      begin
     acc = 0;
     acc2 = 0;
     bitl = 15;
      end
   endtask

   initial clear;

   always @(reset or posedge clk)
      if (reset)
       clear;
      else begin
     if (guess2 <= x) begin
        acc  <= guess;
        acc2 <= guess2;
     end
     bitl <= bitl - 1;
      end

endmodule

module main;

   reg clk, reset;
   reg [31:0] value;
   wire [15:0] result;
   wire rdy;

   sqrt32 root(.clk(clk), .rdy(rdy), .reset(reset), .x(value), .y(result));

   always #5 clk = ~clk;

   always @(posedge rdy) begin
      $display("sqrt(%d) --> %d", value, result);
      $finish;
   end


   initial begin
      clk = 0;
      reset = 1;
      $monitor($time,,"%m.acc = %b", root.acc);
      #100 value = 63;
      reset = 0;
   end
endmodule /* main */

改进版本:

根据Matt的建议,我已经设法使算法部分工作。 仍有这个问题:

for input = 70 the result should be output = 8.366

我得到了

 for input = 70 the result is output = 8.5

是否有可能获得正确的小数部分?

我没有得到正确的小部分,我不知道为什么或是否可能:这是改进的算法:

    module sqrt32(clk, rdy, reset, x, .y(acc));
       input  clk;
       output rdy;
       input  reset;

       input [7:0] x;
       output [15:0] acc;
        reg [15:0] xholder;



       // acc holds the accumulated result, and acc2 is the accumulated
       // square of the accumulated result.
       reg [15:0] acc;
       reg [15:0] acc2;

       // Keep track of which bit I'm working on.
       reg [4:0]  bitl;
       wire [15:0] bit = 1 << bitl;
       wire [15:0] bit2 = 1 << (bitl << 1);

       // The output is ready when the bitl counter underflows.
       wire rdy = bitl[4];

       // guess holds the potential next values for acc, and guess2 holds
       // the square of that guess. The guess2 calculation is a little bit
       // subtle. The idea is that:
       //
       //      guess2 = (acc + bit) * (acc + bit)
       //             = (acc * acc) + 2*acc*bit + bit*bit
       //             = acc2 + 2*acc*bit + bit2
       //             = acc2 + 2 * (acc<<bitl) + bit
       //
       // This works out using shifts because bit and bit2 are known to
       // have only a single bit in them.
       wire [15:0] guess  = acc | bit;
       wire [15:0] guess2 = acc2 + bit2 + ((acc << bitl) << 1);

       task clear;
          begin
         acc = 0;
         acc2 = 0;
         //bitl = 15;
            bitl = 7;
             assign xholder = x << 8;
          end
       endtask

       initial clear;

       always @(reset or posedge clk)
          if (reset)
           clear;
          else begin
            $display("xholder is %b", xholder);
         if (guess2 <= xholder) begin
            acc  <= guess;
            acc2 <= guess2;
         end
         bitl <= bitl - 1;
          end

    endmodule

module sqrtest;

   reg  clk, reset;
   reg  [7:0]  value;
   wire [15:0] result;
   wire rdy;

   sqrt32 root(.clk(clk), .rdy(rdy), .reset(reset), .x(value), .y(result));

   always #5 clk = ~clk;

   always @(posedge rdy) begin
      $display("sqrt(%d) --> %d,%d", value, result[7:4], result[3:0]);
      $finish;
   end


   initial begin
      clk = 0;
      reset = 1;
      $monitor($time,"%m.acc = %b", root.acc);
      #100 value = 70;
      reset = 0;
   end
endmodule /* main */

1 个答案:

答案 0 :(得分:1)

只是使用一些值运行代码模拟,并提出了一个简单的解决方案。

注意:问题中的代码可能无法成功编译,因为bit是Verilog保留字。此外,wire在同一行(例如wire [31:0] bit2 = 1 << (bitl << 1);)上具有作业的实例化应该真正分成两行(wire [15:0] bit2; assign bit2 = 1 << (bitl << 1);)。

无论如何,你的输入有8位表示整数部分,8位表示小数部分,实际上与16位数相同,唯一的区别是它乘以2 ^ 8。因此,一种可能的解决方案是将“16”位整数提供给sqrt32模块的输入。

通过这样做,你真的在​​解决sqrt(X * 2^8)。函数的输出为sqrt(X) * 2^4。答案是输出的8个LSB,其中[7:4]是整数部分,[3:0]是小数部分。