笔算除法
第一个版本的除法器
缺点
第二个版本的除法器
实现代码
module alu (
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) 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
虽然代码能跑通,结果也对,但是感觉写的不是很好。
我的理解是,不要在移位时控制是否要加回原码和上商为1或0,最好能和移位控制分离。
仿真
`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 [63:0] Result ;
initial begin
forever #(PERIOD/2) clk=~clk;
end
initial begin
rst = 1'b1;
#25 rst = 1'b0;
Opcode = 3'b111;
Operand_X = 32'h0006;
Operand_Y = 32'h0002;
#10 Opcode = 3'b000;
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 [63:0] )
);
endmodule