【问题标题】:Algorithm for Divison除法算法
【发布时间】:2016-10-28 19:43:41
【问题描述】:

我一直在使用'/'运算符在verilog中执行除法。我能够得到正确的模拟结果,但问题是我的代码由于“/”运算符而无法合成。它显示错误“/ 的第二个操作数应该是 2 的幂”。我应该如何在 Verilog HDL 中执行除法?

【问题讨论】:

  • 除法算法很少,基​​于移位和加法。您可以在数字电路或计算机设计书籍中找到它们。

标签: verilog xilinx-ise


【解决方案1】:

如错误信息所指出的,除法运算符不可合成,它应该仅用于模拟。

你需要做什么取决于分区的条件。 您可以使用重复减法算法,这是最简单的解决方案。

缺点是您会在 N 个时钟周期内得到除法的结果,其中 N 是除法的整数部分,但您可以设置一个标志位以表示除法完成时。

这是算法的描述,来自维基百科:

while  N ≥ D do
  N := N − D
end
return N

编辑:为了完整起见,任何人都会遇到这个问题。这是该算法的可综合实现。 (这不是最好的实现,也没有经过全面测试)

module mod_div(
    input clk,
    input rst,
    input start,
    input  [7:0] num,
    input  [7:0] den,
    output [7:0] res,
    output [7:0] rem,
    output reg done
);
/* Registers to store the input arguments */
reg [7:0] num_r;
reg [7:0] den_r;
/* counts the number of times denominator fits in numerator */
reg [7:0] result_integer;
/* True if the algorithm is running */
reg working;


always @(posedge clk) begin
    if(rst == 1'b1)begin
        /* setting the working registers to 0 */
        num_r <= 8'b0;
        den_r <= 8'b0;
        working <= 1'b0;
        result_integer <= 'b0;
        done <= 'b0;
    end else if(start == 1'b1) begin
        /* Captures the parameters and starts the operation */
        num_r <= num;
        den_r <= den;
        working <= 1'b1;
        done <= 1'b0;
    end
    /* The actual algorithm */
    if (working == 1'b1 && start == 1'b0)begin
        if(num_r >= den_r) begin
            /* The division will give a proper fraction */
            num_r <= num_r - den_r;
            result_integer <= result_integer + 8'b1;
        end else begin
            working <= 'b0;
            done <= 1'b1;
        end
    end
end



/* The reminder of the division  */
assign rem = num_r;
/*The integer part is the number of times the divisor was substracted from the
* numerator*/
assign res = result_integer;

endmodule 

这里也是这个模块的测试平台:

module division_tb();

reg clk;
reg rst;
reg [7:0] numerator;
reg [7:0] denominator;
reg start;

wire [7:0] integer_result;
wire [7:0] reminder_result;
wire done_flag;

mod_div DUT (
     .clk(clk),
     .rst(rst),
     .start(start),
     .num(numerator),
     .den(denominator),
     .res(integer_result),
     .rem(reminder_result),
     .done(done_flag)
 );


always begin
    #10 clk = ~clk;
end

initial begin
    clk = 1'b0;
    rst = 1'b1;
#15 rst = 1'b0;
    numerator = 17;
    denominator = 5;
#1  start = 1;
#20 start = 0;
#200 $finish;
end

/* FOR GTK WAVE */
initial
  begin
    $dumpfile("shift.vcd");
    $dumpvars(0, division_tb);
  end

endmodule 

这是使用 GTK-Wave 模拟的结果:

在图像中正在执行 17/5 的除法,开始操作 start 线需要在 1 中至少 1 个时钟周期,当除法完成时,标志 done 设置为 1,此时结果在输出寄存器中。对于这个例子integer_part3,提醒是2

【讨论】:

  • 我已经在 verilog 中实现了相同的功能。它显示错误:“Set_interation_limit XX”
猜你喜欢
  • 2011-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-24
  • 1970-01-01
  • 2017-12-02
  • 1970-01-01
相关资源
最近更新 更多