运算器
本运算器针对32位数的补码运算,以加法器为核心实现加、减、乘、除等运算。
基本模块
- 加/减法器
- 乘法器
- 除法器
加/减法器
源代码
module add_sub(
input [31:0]Operand_X,
input [31:0]Operand_Y,
input Opcode,
output [31:0]Result,
output Cout
);
reg [31:0]B;
assign {Cout,Result} = Operand_X + B + Opcode;
always@(Operand_Y or Opcode)
if(Opcode)
B = ~Operand_Y;
else
B = Operand_Y;
endmodule
原理
- 两个数相加,即为补码直接相加;
- 两个数相减,为被减数加上减数的相反数(各位取反,末位加1)。
乘法器
源代码
module alu(rst,clk,Opcode,Operand_X,Operand_Y,Busy,result,Cout);
input rst,clk;
input [2:0]Opcode;
/*Opcode 100:Add,101:Sub,110:Mul,111:reserved*/
input [31:0]Operand_X,Operand_Y;
output Busy,Cout;
output [63:0]result;
reg Busy,Cout;
reg [64:0]Result;
reg [31:0]Add_A,Add_B,Add_Result;
reg Add_Cin;
reg [4:0]Mul_Counter;
reg [31:0]Multiplicand,Operand_Y_inner;
reg [1:0]Opcode_inner;
/*00:add 0,01:sub multiplicand,10:multiplicand,11:reserved*/
always@(Add_A,Add_B,Add_Cin)
{Cout,Add_Result} = Add_A+Add_B+Add_Cin;
always@(posedge rst,posedge clk)
begin
if(rst)
Mul_Counter <= 5'b0;
else if(Opcode == 3'b110 && Busy == 1'b0)
Mul_Counter <= 5'b11111;//
else if(Busy)
Mul_Counter <= Mul_Counter - 1;
end
always@(posedge rst, posedge clk)
begin
if(rst)
Busy <= 1'b0;
else if(Opcode == 3'b110 && Busy == 1'b0)
Busy <= 1'b1;
else if(Busy == 1'b1 && Mul_Counter == 5'b0)
Busy <= 1'b0;
end
always@(posedge rst, posedge clk)
begin
if(rst)
Multiplicand <= 32'b0;
else if(Opcode == 3'b110 && Busy == 1'b0)
Multiplicand <= Operand_Y;
end
always@(posedge rst, posedge clk)
begin
if(rst)
Result <= 65'b0;
else if(Opcode == 3'b110 && Busy == 1'b0)
Result <= {32'b0,Operand_X,1'b0};
else
Result <= {Add_Result[31],Add_Result,Result[32:1]};
end
always@(Result)
begin
if(Busy)
Add_A <= Result[64:33];
else
Add_A <= Operand_X;
end
always@(Busy, Multiplicand, Operand_Y)
begin
if(Busy)
Operand_Y_inner <= Multiplicand;
else
Operand_Y_inner <= Operand_Y;
end
always@(Opcode_inner, Operand_Y_inner)
begin
if(Opcode_inner == 2'b10)
Add_B <= Operand_Y_inner;
else if(Opcode_inner == 2'b11)
Add_B <= ~Operand_Y_inner;
else
Add_B <= 32'b0;
end
always@(Opcode_inner)
begin
if(Opcode_inner == 2'b11)
Add_Cin = 1'b1;
else
Add_Cin = 1'b0;
end
always@(Busy, Result, Opcode)
begin
if(Busy)
begin
if(Result[1:0] == 2'b00 || Result[1:0] == 2'b11)
Opcode_inner <= 2'b00;
else if(Result[1:0] == 2'b01)
Opcode_inner <= 2'b10;
else
Opcode_inner <= 2'b11;
end
else
begin
if(Opcode == 3'b100)
Opcode_inner <= 2'b10;
else if(Opcode == 3'b101)
Opcode_inner <= 2'b11;
else
Opcode_inner <= 2'b00;
end
end
assign result = Result[64:1];
endmodule
原理
使用booth乘法的基本原理,根据乘积寄存器的后两位,选择适当的数放入加法器,计算出结果后,将其放在高32位上,再右移一位,如此往复32次;
除法器
源代码
module divider(rst,clk,Opcode,Operand_X,Operand_Y,Busy,Result,Cout);
input rst;
input clk;
input [2:0]Opcode;
input [31:0]Operand_X;
input [31:0]Operand_Y;
output reg Busy;
output [31:0]Result;
output reg Cout;
reg [31:0]Add_A,Add_B,Add_Result;
reg Add_Cin;
reg [4:0]Div_Counter;
reg [63:0]Remainder;
always@(Add_A,Add_B,Add_Cin)
{Cout,Add_Result} = Add_A+Add_B+Add_Cin;
always@(posedge rst,posedge clk)
begin
if(rst)
Div_Counter <= 5'b0;
else if(Opcode == 3'b111 && Busy == 1'b0)
Div_Counter <= 5'b11111;
else if(Busy)
Div_Counter <= Div_Counter - 1;
end
always@(posedge rst, posedge clk)
begin
if(rst)
Busy <= 1'b0;
else if(Opcode == 3'b111 && Busy == 1'b0)
Busy <= 1'b1;
else if(Busy == 1'b1 && Div_Counter == 5'b0)
Busy <= 1'b0;
end
always@(posedge rst, posedge clk)
begin
if(rst)
Remainder <= 64'b0;
else if(Opcode == 3'b111 && Busy == 1'b0)
begin
if(Operand_X[31])
Remainder[32:1] <= ~Operand_X + 1;
else
Remainder[32:1] <= Operand_X;
end
else
begin
if(Add_Result[31] == 0)
Remainder <= {Add_Result[30:0],Remainder[31:0],1'b1};
else
Remainder <= {Remainder[62:0],1'b0};
end
end
always@(Result)
begin
if(Busy)
Add_A <= Remainder[63:32];
else
Add_A <= Operand_X;
end
always@(Operand_Y)
begin
if(!Operand_Y[31])
begin
Add_B = ~Operand_Y;
Add_Cin = 1'b1;
end
else
begin
Add_B = Operand_Y;
Add_Cin = 1'b0;
end
end
assign Result = (Operand_X[31] ^ Operand_Y[31]) ? ~Remainder[31:0] + 1:Remainder[31:0];
endmodule
原理
补码除法运算运用恢复余数法,其执行流程如下:
- 将被除数与除数都转换成对应的无符号数;
- 使用恢复余数法,每次检测到高32位能够减去除数时,减去除数,左移一位,商1;否则恢复原来的余数寄存器,左移一位,商0;
- 用计数器记录到32位,即为最终的结果。