分区算法

时间:2016-10-28 19:43:41

标签: verilog xilinx-ise

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

1 个答案:

答案 0 :(得分:0)

除法错误消息指出,除法运算符不可合成,它应该只用于模拟。

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

缺点是你在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进行模拟的结果: Division Simulation

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