马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?注册
x
在Verilog HDL语言中虽然有除的运算指令,但是除运算符中的除数必须是2的幂,因此无法实现除数为任意整数的除法,很大程度上限制了它的使用领域。并且多数综合工具对于除运算指令不能综合出令人满意的结果,有些甚至不能给予综合。即使可以综合,也需要比较多的资源。对于这种情况,一般使用相应的算法来实现除法,分为两类:基于减法操作和基于乘法操作的算法; 实现算法基于减法的除法器的算法:
对于32的无符号除法,被除数a除以除数b,他们的商和余数一定不会超过32位。首先将a转换成高32位为0,低32位为a的temp_a。把b转换成高32位为b,低32位为0的temp_b。在每个周期开始时,先将temp_a左移一位,末尾补0,然后与b比较,是否大于b,是则temp_a减去temp_b将且加上1,否则继续往下执行。上面的移位、比较和减法(视具体情况而定)要执行32次,执行结束后temp_a的高32位即为余数,低32位即为商; 算法推倒(非原创):
假设4bit的两数相除 a/b,商和余数最多只有4位 (假设1101/0010也就是13除以2得6余1) 我们先自己做二进制除法,则首先看a的MSB,若比除数小则看前两位,大则减除数,然后看余数,以此类推直到最后看到LSB;而上述算法道理一样,a左移进前四位目的就在于从a本身的MSB开始看起,移4次则是看到LSB为止,期间若比除数大,则减去除数,注意减完以后正是此时所剩的余数。而商呢则加到了这个数的末尾,因为只要比除数大,商就是1,而商0则是直接左移了,因为会自动补0。这里比较巧因为商可以随此时的a继续左移,然后新的商会继续加到末尾。经过比对会发现移4位后左右两边分别就是余数和商。 画个简单的图: 1.时序逻辑除法
module div_timing_logic(
input I_clk,
input I_rst_p,
input I_data_valid,
input [7:0] I_data_a,
input [7:0] I_data_b,
output reg O_data_valid,
output reg [7:0] O_data_shang,
output reg [7:0] O_data_yushu
);
reg [7:0] tempa;
reg [7:0] tempb;
reg [15:0] temp_a;
reg [15:0] temp_b;
reg div_start;
reg div_start_d1;
wire div_start_neg;
reg [4:0] div_cnt;
always@(posedge I_clk or posedge I_rst_p)
begin
if(I_rst_p)
begin
tempa <= 8'h0;
tempb <= 8'h0;
end
else if(I_data_valid)
begin
tempa <= I_data_a;
tempb <= I_data_b;
end
else
begin
tempa <= tempa;
tempb <= tempb;
end
end
always@(posedge I_clk or posedge I_rst_p)
begin
if(I_rst_p)
div_start <= 1'b0;
else if(I_data_valid && div_start == 1'b0)
div_start <= 1'b1;
else if(div_cnt == 5'd16 )
div_start <= 1'b0;
else
div_start <= div_start;
end
//========================================================div_cnt
always@(posedge I_clk or posedge I_rst_p)
if(I_rst_p)
div_cnt <= 5'd0;
else if(div_start)
div_cnt <= div_cnt + 1;
else
div_cnt <= 5'd0;
//=======================================================
always@(posedge I_clk or posedge I_rst_p)
begin
if(I_rst_p)
begin
temp_a <= 16'h0;
temp_b <= 16'h0;
end
else if(div_start )
if(div_cnt == 4'd0)
begin
temp_a <= {8'h0,tempa};
temp_b <= {tempb,8'h0};
end
else if(div_cnt[0] == 1'b1)
begin
temp_a <= {temp_a[14:0],1'b0};
end
else
begin
temp_a <= (temp_a[15:8] >= temp_b[15:8])?(temp_a - temp_b + 1):temp_a;//如果比temp_b大,则减去temp_b然后加1
end
else
begin
temp_a <= 16'h0;
temp_b <= 16'h0;
end
end
always@(posedge I_clk)
begin
div_start_d1 <= div_start;
end
assign div_start_neg = div_start_d1 & (~div_start);//下降沿检测
always@(posedge I_clk or posedge I_rst_p)
begin
if(I_rst_p)
begin
O_data_valid <= 1'b0;
O_data_shang <= 1'b0;
O_data_yushu <= 1'b0;
end
else if(div_start_neg)
begin
O_data_valid <= 1'b1;
O_data_shang <= temp_a[7:0];
O_data_yushu <= temp_a[15:8];
end
else
begin
O_data_valid <= 1'b0;
O_data_shang <= 1'b0;
O_data_yushu <= 1'b0;
end
end
endmodule
2.纯组合逻辑
module div_combinatory_logic
(
input [7:0] a,//被除数
input [7:0] b,//除数
output reg [7:0] y_shang,//商
output reg [7:0] y_yushu//余数
);
reg [7:0] tempa;
reg [7:0] tempb;
reg [15:0] temp_a;
reg [15:0] temp_b;
integer i;
always@(*)
begin
tempa = a;
tempb = b;
end
always@(*)
begin
temp_a = {8'h0,tempa};
temp_b = {tempb,8'h0};
for(i = 0; i < 8; i = i+1) //注意是移动8次
begin:shift_left
// temp_a = temp_a << 1 ;
temp_a = {temp_a[14:0],1'b0} ;
if(temp_a[15:8] >= temp_b[15:8] )//temp_b的低8位都是0,所以只需要比较高八位
temp_a = temp_a - temp_b + 1;
else
temp_a = temp_a;
end
y_shang = temp_a[7:0];//商在低位
y_yushu = temp_a[15:8];//余数在高位
end
endmodule
|