(写本文的目的仅源于记笔记的想法,好记性不如烂笔头~)
参考来源:https://blog.youkuaiyun.com/alangaixiaoxiao/article/details/81624946
1. 实现原理
对于16的无符号除法,被除数a除以除数b,他们的商和余数一定不会超过16位。首先将a转换成高16位为0,低16位为a的temp_a。把b转换成高16位为b,低16位为0的temp_b。在每个周期开始时,先将temp_a左移一位,末尾补0,然后与b比较,是否大于b,是则temp_a减去temp_b将且加上1,否则继续往下执行。上面的移位、比较和减法(视具体情况而定)要执行16次,执行结束后temp_a的高16位即为余数,低16位即为商。
手推说明无符号位4位除法的实现:
为啥要加1?????
即:
2组合逻辑实现代码
module chu2_CL_top(
a,b,shang,yushu,enable, rst
);
input rst,enable;
input [15:0] a,b;
output[15:0] shang,yushu;
reg [15:0] temp_a1,temp_b1;
reg [31:0] temp_a2,temp_b2;
integer i;
always@(*)
begin
if(!rst)
begin
temp_a1 = 16'h0;
temp_b1 = 16'h0;
end
else if(enable) //赋初值
begin
temp_a1 = a;
temp_b1 = b;
end
else
begin
temp_a1 = temp_a1;
temp_b1 = temp_b1;
end
end
always@(*)
begin
if(!rst)
begin
temp_a2 = 32'h0;
temp_b2 = 32'h0;
end
else
begin
temp_a2 = {16'h0,temp_a1};
temp_b2 = {temp_b1,16'h0};
for(i = 0; i < 16; i = i+1) //除数左移位16次
begin
temp_a2 = {temp_a2[30:0],1'b0} ;
if(temp_a2[31:16] >= temp_b2[31:16] )
temp_a2 = temp_a2 - temp_b2 + 1;
else
temp_a2 = temp_a2;
end
end
end
assign shang = temp_a2[15:0];//商在低位
assign yushu = temp_a2[31:16];//余数在高位
endmodule
3时序逻辑实现代码
`timescale 1ns / 1ps
module chu_top(
clk,rst,a,b,enable,shang,yushu
);
input clk;
input rst;
input enable;
input [15:0] a,b;
output[15:0] shang,yushu;
reg [15:0] temp_a1,temp_b1;
reg [31:0] temp_a2,temp_b2;
reg [4:0] counter;
reg [31:0] shang_yu_temp;
reg move_start;
always@ (posedge clk or negedge rst)
begin
if(!rst)
begin
temp_a1 <= 16'b0;
temp_b1 <= 16'b0;
end
else if(enable) //赋初值
begin
temp_a1 <= a;
temp_b1 <= b;
end
else
begin
temp_a1 <= temp_a1;
temp_b1 <= temp_b1;
end
end
always@ (posedge clk or negedge rst) //控制移位
begin
if(!rst)
move_start <= 1'b0;
else if(enable && move_start == 0)
move_start <= 1'b1;
else if(counter==5'd16)
move_start <= 0;
else
move_start <= move_start;
end
always@(posedge clk or negedge rst) //计数器,用于计移位次数
begin
if(!rst)
counter <= 5'd0;
else if(move_start)
counter <= counter+1;
else
counter <= 5'd0;
end
always@ (posedge clk or negedge rst)
begin
if(!rst)
begin
temp_a2 <= 32'b0;
temp_b2 <= 32'b0;
end
else if(counter==5'd0 && move_start) //赋初值
begin
temp_a2 <= {16'b0,temp_a1};
temp_b2 <= {temp_b1,16'b0};
end
else if(temp_a2[31:16] >= temp_b2[31:16])
temp_a2 <= (temp_a2-temp_b2+1'b1)<<1;
else
begin
temp_a2 <= temp_a2<<1;
temp_b2 <= temp_b2;
end
end
reg move_start_reg;
wire move_end;
reg[15:0] shang,yushu;
always@(posedge clk or negedge rst)
begin
if (!rst)
move_start_reg <= 1'b0;
else
move_start_reg <= move_start;
end
assign move_end = move_start_reg & (~move_start); //输出控制信号
always@(posedge clk or negedge rst) //输出结果
begin
if (!rst)
begin
shang <= 16'h0;
yushu <= 16'h0;
end
else if(move_end)
begin
shang <= temp_a2[15:0]; //低16位为商
yushu <= temp_a2[31:16]; //高16位为余数
end
else
begin
shang <= 16'h0;
yushu <= 16'h0;
end
end
endmodule