【发布时间】:2016-10-28 19:43:41
【问题描述】:
我一直在使用'/'运算符在verilog中执行除法。我能够得到正确的模拟结果,但问题是我的代码由于“/”运算符而无法合成。它显示错误“/ 的第二个操作数应该是 2 的幂”。我应该如何在 Verilog HDL 中执行除法?
【问题讨论】:
-
除法算法很少,基于移位和加法。您可以在数字电路或计算机设计书籍中找到它们。
标签: verilog xilinx-ise
我一直在使用'/'运算符在verilog中执行除法。我能够得到正确的模拟结果,但问题是我的代码由于“/”运算符而无法合成。它显示错误“/ 的第二个操作数应该是 2 的幂”。我应该如何在 Verilog HDL 中执行除法?
【问题讨论】:
标签: verilog xilinx-ise
如错误信息所指出的,除法运算符不可合成,它应该仅用于模拟。
你需要做什么取决于分区的条件。 您可以使用重复减法算法,这是最简单的解决方案。
缺点是您会在 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
在图像中正在执行 17/5 的除法,开始操作
start 线需要在 1 中至少 1 个时钟周期,当除法完成时,标志 done 设置为 1,此时结果在输出寄存器中。对于这个例子integer_part:3,提醒是2
【讨论】: