硬件电路中实现除法操作一般基于两种方式:乘法操作和减法操作
基于减法的除法器
对于32位的无符号除法,被除数a除以除数b,他们的商和余数位数一定不超过32位。首先将a转换为32位,b也转换为32位。在每周期的开始,先将a左移一位,末尾补0,然后和b比较,如果大于b则a-b且加上1,否则继续往下执行移位、比较和减法。执行32次后结束,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位后左右两边分别就是余数和商。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210621144838942.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xpdHRsZV9veA==,size_16,color_FFFFFF,t_70)
最终:a的高四位为余数 低四位为商
module divisionV1
(
input[31:0] a,
input[31:0] b,
input enable,
output reg [31:0] yshang,
output reg [31:0] yyushu,
output reg done
);
reg[31:0] tempa;
reg[31:0] tempb;
reg[63:0] temp_a;
reg[63:0] temp_b;
integer i;
always @(a or b)
begin
tempa <= a;
tempb <= b;
end
always @(tempa or tempb)
begin
if(enable)
begin
temp_a = {32'h00000000,tempa};
temp_b = {tempb,32'h00000000};
done = 0;
for(i = 0;i < 32;i = i + 1)
begin
temp_a = {temp_a[62:0],1'b0};
if(temp_a[63:32] >= tempb)
temp_a = temp_a - temp_b + 1'b1;
else
temp_a = temp_a;
end
yshang = temp_a[31:0];
yyushu = temp_a[63:32];
done = 1;
end
end
endmodule
测试模块
module tb_division();
reg [31:0] a;
reg [31:0] b;
reg enable;
wire [31:0] yshang;
wire [31:0] yyushu;
wire done;
divisionV1 U1
(
.a (a),
.b (b),
.enable(enable),
.yshang (yshang),
.yyushu (yyushu),
.done(done)
);
initial
begin
enable=1;
#10 a = 443525;
b = 32;
end
endmodule
结果显示:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210621145108937.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xpdHRsZV9veA==,size_16,color_FFFFFF,t_70)
可以根据上述组合逻辑实现时序逻辑除法的操作。
`timescale 1ns / 1ps
module divisionV2(
input clk,rst_n,en, //en为使能信号,使能时进行除法操作
input [3:0] a,
input [3:0] b,
output [3:0] yushu,
output [3:0] shangshu
);
parameter S1 = 4'b0000;
parameter S2 = 4'b0001;
parameter S3 = 4'b0010;
parameter S4 = 4'b0100;
reg [3:0] Cstate;
reg [3:0] Nstate;
reg [7:0] temp_a;
reg [7:0] temp_b;
reg [5:0] i;
reg done; //除法计算结束后,产生done信号
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
Cstate <= S1;
end
else
Cstate <= Nstate;
end
always @(*) begin
case(Cstate)
S1:begin
if(en)
Nstate <= S2;
else
Nstate <= S1;
end
S2:begin
if(i<4)
Nstate <= S3;
else
Nstate <= S4;
end
S3:begin
Nstate <= S2;
end
S4:begin
Nstate <= S1;
end
endcase
end
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
i <= 6'd0;
done <= 0;
temp_a <= 8'd0;
temp_b <= 8'd0;
end
else begin
case(Cstate)
S1:begin
done <= 0;
temp_a <= {4'b0,a}; //初始值为 0000_1111
temp_b <= {b,4'b0};
end
S2:begin //0001
i <= i+1;
temp_a <= {temp_a[6:0],1'b0};
end
S3:begin //0010
if(temp_a > temp_b) begin
temp_a <= temp_a - temp_b + 1'b1;
end
else
temp_a <= temp_a;
end
S4:begin //11
i <= 6'd0;
done <= 1;
end
endcase
end
end
assign yushu=(Nstate == S4)?temp_a[7:4]:4'd0;
assign shangshu=(Nstate == S4)?temp_a[3:0]:4'd0;
endmodule
测试向量
`timescale 1ns / 1ps
module tb_divisionV2;
// Inputs
reg clk;
reg rst_n;
reg [3:0] a;
reg [3:0] b;
reg en;
// Outputs
wire [3:0] yushu;
wire [3:0] shangshu;
// Instantiate the Unit Under Test (UUT)
divisionV2 uut (
.clk(clk),
.rst_n(rst_n),
.en(en),
.a(a),
.b(b),
.yushu(yushu),
.shangshu(shangshu)
);
always #10 clk = ~clk;
initial begin
// Initialize Inputs
clk = 0;
rst_n = 0;
a = 0;
b = 0;
en = 0;
// Wait 100 ns for global reset to finish
#100 rst_n = 1;
en = 1;
a = 4'd14;
b = 4'd3;
#600 en = 0;
// Add stimulus here
end
endmodule
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210621220143448.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xpdHRsZV9veA==,size_16,color_FFFFFF,t_70)