前言
关于相关原理可以百度相关介绍或者参照我之前的文章。
加减法采用纯组合逻辑,没有做busy判定(后续可以加上)。
目前没有做符号位判定。
除法低32位为余数,33-64位为商。
加减乘除计算器(32位)verilog实现
加减法
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;
// Opcode is 1 means Operand_Y is negetive number
assign {Cout, Result} = Operand_X + B + Opcode;
always @(Operand_Y or Opcode) begin
if (Opcode) begin
B = ~Operand_Y;
end else begin
B = Operand_Y;
end
end
endmodule
32位乘法
module mul (
input rst ,
input clk ,
input [ 2:0] Opcode ,
// multiplication Opcode is 110
// add code is 100
// sub code is 101
input [31:0] Operand_X ,
input [31:0] Operand_Y ,
output reg Busy ,
output reg Cout ,
output reg [64:0] Result
);
// Complement one digit multiplication, the default input is already a complement!
reg [31:0] Add_A, Add_B, Add_Result ;
reg Add_Cin ;
reg [ 4:0] Mul_Counter ;
reg [31:0] Multiplicand, Operand_Y_inner;
// add 00; sub 01; mul 10;
reg [ 1:0] Opcode_inner ;
// reg [64:0] Product ;
// add or sub
always @(Add_A or Add_B or Add_Cin) begin
{Cout, Add_Result} = Add_A + Add_B + Add_Cin;
end
// Mul_Counter register
always @(posedge rst or posedge clk) begin
if (rst) begin
Mul_Counter <= 5'b00000;
end else if (Opcode == 3'b110) begin
Mul_Counter <= 5'b11111;
end else if (Busy) begin
Mul_Counter <= Mul_Counter - 1;
end
end
// Busy
always @(posedge rst or posedge clk) begin
if (rst) begin
Busy <= 1'b0;
end else if (Opcode == 3'b110 && ~Busy) begin
// multiplication Opcode is 110
// add Opcode is 100
// sub Opcode is 101
Busy <= 1'b1;
end else if (Busy == 1'b1 & Mul_Counter == 5'b00000) begin
// complete Multiplication operation
Busy <= 1'b0;
end
end
// Multiplicand register in_Y
always @(posedge rst or posedge clk) begin
if (rst) begin
Multiplicand <= 32'b0;
end else if (Opcode == 3'b110) begin
// if mul, multiplicand is Operand_Y
Multiplicand <= Operand_Y;
end
end
// Result register
always @(posedge rst or posedge clk) begin
if (rst) begin
Result <= 65'b0;
end else if (Opcode == 3'b110) begin
// initial Result
Result <= {32'b0, Operand_X, 1'b0};
end else begin
// shifter with symbol
Result <= {Add_Result[31], Add_Result, Result[32:1]};
end
end
// adder inA is Add_A
always @(Result or Operand_X or Operand_Y) begin
if (Busy) begin
Add_A <= Result[64:33];
end else begin
Add_A <= Operand_X ;
end
end
// Operand_Y_inner
always @(Busy or Multiplicand or Operand_Y) begin
if (Busy) begin
// if mul, inner is multiplicand
Operand_Y_inner <= Multiplicand;
end else begin
Operand_Y_inner <= Operand_Y ;
end
end
// Add_B
always @(Opcode_inner or Operand_Y_inner) begin
// add 10; sub 01;
if (Opcode_inner == 2'b10) begin
Add_B <= Operand_Y_inner;
end else if (Opcode_inner == 2'b01) begin
Add_B <= ~Operand_Y_inner;
end else begin
Add_B <= 32'b0;
end
end
always @(Opcode_inner) begin
begin
if (Opcode_inner == 2'b01) begin
Add_Cin <= 1'b1;
end else begin
Add_Cin <= 1'b0;
end
end
end
always @(Busy or Result or Opcode) begin
if (Busy) begin
if (Result[1:0] == 2'b00 || Result[1:0] == 2'b11) begin
Opcode_inner <= 2'b00;
end else if (Result[1:0] == 2'b10) begin
Opcode_inner <= 2'b01;
end else if (Result[1:0] == 2'b01) begin
Opcode_inner <= 2'b10;
end
end else begin
if (Opcode == 3'b100) begin
Opcode_inner <= 2'b10;
end else if (Opcode == 3'b101) begin
Opcode_inner <= 2'b11;
end else begin
Opcode_inner <= 2'b00;
end
end
end
endmodule
32位除法
module div (
input rst ,
input clk ,
input [ 2:0] Opcode ,
// multiplication Opcode is 110
// add code is 100
// sub code is 101
// div code is 110
input [31:0] Operand_X ,
input [31:0] Operand_Y ,
output reg Busy ,
output reg Cout ,
output reg [63:0] Result
);
// Complement one digit div
// the default input is already a complement!!!!
reg [31:0] Add_A ;
reg [31:0] Add_Result = 32'b0 ;
reg [ 4:0] Mul_Counter ;
reg [31:0] Dividend, Operand_Y_inner ;
// just sub
always @(Add_A) begin
{Cout, Add_Result} <= Add_A + ~Operand_Y_inner + 1'b1;
end
// Mul_Counter register
always @(posedge rst or posedge clk) begin
if (rst) begin
Mul_Counter <= 5'b00000;
end else if (Opcode == 3'b111) begin
Mul_Counter <= 5'b11111;
end else if (Busy) begin
Mul_Counter <= Mul_Counter - 1;
end
end
// Busy
always @(posedge rst or posedge clk) begin
if (rst) begin
Busy <= 1'b0;
end else if (Opcode == 3'b111 && ~Busy) begin
Busy <= 1'b1;
end else if (Busy == 1'b1 & Mul_Counter == 5'b00000) begin
Busy <= 1'b0;
end
end
// divisor register in_Y
always @(posedge rst or posedge clk) begin
if (rst) begin
Dividend <= 32'b0;
end else if (Opcode == 3'b111) begin
Dividend <= Operand_Y;
end
end
// Result register
always @(posedge rst or posedge clk) begin
if (rst) begin
Result <= 64'b0;
end else if (Opcode == 3'b111) begin
// initial Result
Result <= {31'b0, Operand_X, 1'b0};
end else if (~Add_Result[31]) begin
// if 0, quotient is 1
Result <= {Add_Result[30:0], Result[31:0], 1'b1};
end else begin
// if 1, just shift, quotient is 0
Result <= {Result[62:0], 1'b0};
end
end
// adder inA is Add_A
always @(Result or Operand_X or Operand_Y) begin
if (Busy) begin
Add_A <= Result[63:32];
end else begin
Add_A <= Operand_X ;
end
end
// Operand_Y_inner
always @(Busy or Dividend or Operand_Y) begin
if (Busy) begin
Operand_Y_inner <= Dividend;
end else begin
Operand_Y_inner <= Operand_Y ;
end
end
endmodule
顶层模块
module alu (
input rst ,
input clk ,
input [ 2:0] Opcode ,
// multiplication Opcode is 110
// add Opcode is 100
// sub Opcode is 101
// div Opcode is 110
input [31:0] Operand_X ,
input [31:0] Operand_Y ,
output reg Busy ,
output reg Cout ,
output reg [64:0] Result
);
wire [31:0] add_sub_result;
wire [64:0] mul_result ;
wire [63:0] div_result ;
wire Busy_mul ;
wire Busy_div ;
wire Cout_mul ;
wire Cout_div ;
wire Cout_add_sub ;
wire [2:0] inst_opcode ;
// always @(posedge clk or posedge rst) begin
// if (rst) begin
// Opcode <= 3'b000;
// end else if (Busy) begin
// Opcode <= 3'b000;
// end
// end
assign inst_opcode = Opcode!=3'b0 ? Opcode : inst_opcode;
add_sub u_add_sub (
// .rst ( rst ),
// .clk ( clk ),
.Opcode ( Opcode [ 0] ),
.Operand_X ( Operand_X [31:0] ),
.Operand_Y ( Operand_Y [31:0] ),
// .Busy ( Busy ),
.Cout ( Cout_add_sub ),
.Result ( add_sub_result )
);
mul u_mul (
.rst ( rst ),
.clk ( clk ),
.Opcode ( Opcode [ 2:0] ),
.Operand_X ( Operand_X [31:0] ),
.Operand_Y ( Operand_Y [31:0] ),
.Busy ( Busy_mul ),
.Cout ( Cout_mul ),
.Result ( mul_result )
);
div u_div (
.rst ( rst ),
.clk ( clk ),
.Opcode ( Opcode [ 2:0] ),
.Operand_X ( Operand_X [31:0] ),
.Operand_Y ( Operand_Y [31:0] ),
.Busy ( Busy_div ),
.Cout ( Cout_div ),
.Result ( div_result )
);
always @(*) begin
if (rst) begin
Result <= 65'b0;
end else if (inst_opcode == 3'b100 || inst_opcode == 3'b101) begin
Result <= {33'b0, add_sub_result};
Cout <= Cout_add_sub;
end else if (inst_opcode == 3'b110) begin
Result <= mul_result;
Busy <= Busy_mul;
Cout <= Cout_mul;
end else if (inst_opcode == 3'b111) begin
Result <= {1'b0, div_result[31:0], div_result[63:32]};
Busy <= Busy_div;
Cout <= Cout_div;
end
end
endmodule
仿真
TestBench
`timescale 1ns / 1ps
module tb_alu();
// alu Parameters
parameter PERIOD = 20;
// alu Inputs
reg rst = 0 ;
reg clk = 0 ;
reg [ 2:0] Opcode = 0 ;
reg [31:0] Operand_X = 0 ;
reg [31:0] Operand_Y = 0 ;
// alu Outputs
wire Busy ;
wire Cout ;
wire [64:0] Result ;
initial begin
forever #(PERIOD/2) clk=~clk;
end
initial begin
rst = 1'b1;
#25 rst = 1'b0;
Opcode = 3'b100;
Operand_X = 32'h0006;
Operand_Y = 32'h0002;
#20 Opcode = 3'b101;
#20 Opcode = 3'b110;
#10 Opcode = 3'b000;
#650 Opcode = 3'b111;
#10 Opcode = 3'b000;
#700 $finish ;
end
alu u_alu (
.rst ( rst ),
.clk ( clk ),
.Opcode ( Opcode [ 2:0] ),
.Operand_X ( Operand_X [31:0] ),
.Operand_Y ( Operand_Y [31:0] ),
.Busy ( Busy ),
.Cout ( Cout ),
.Result ( Result [64:0] )
);
endmodule
仿真结果