|
@@ -0,0 +1,172 @@
|
|
|
+/*
|
|
|
+* 32-bit multicycle divider
|
|
|
+*/
|
|
|
+
|
|
|
+/*
|
|
|
+module Divider(
|
|
|
+ input clk,
|
|
|
+ input reset,
|
|
|
+ input start,
|
|
|
+ input [31:0] data,
|
|
|
+
|
|
|
+ output done,
|
|
|
+ output [31:0] q
|
|
|
+);
|
|
|
+*/
|
|
|
+
|
|
|
+module Divider #(
|
|
|
+ parameter WIDTH=32, // width of numbers in bits (integer and fractional)
|
|
|
+ parameter FBITS=16 // fractional bits within WIDTH
|
|
|
+ ) (
|
|
|
+ input clk, // clock
|
|
|
+ input rst, // reset
|
|
|
+ input start, // start calculation
|
|
|
+ input write_a,
|
|
|
+ output reg busy = 1'b0, // calculation in progress
|
|
|
+ output reg done = 1'b0, // calculation is complete (high for one tick)
|
|
|
+ output reg valid = 1'b0, // result is valid
|
|
|
+ output reg dbz = 1'b0, // divide by zero
|
|
|
+ output reg ovf = 1'b0, // overflow
|
|
|
+ input signed [WIDTH-1:0] a_in, // dividend (numerator)
|
|
|
+ input signed [WIDTH-1:0] b, // divisor (denominator)
|
|
|
+ output reg signed [WIDTH-1:0] val = 32'd0 // result value: quotient
|
|
|
+ );
|
|
|
+
|
|
|
+
|
|
|
+ reg signed [WIDTH-1:0] a = 0;
|
|
|
+
|
|
|
+ always @(posedge clk)
|
|
|
+ begin
|
|
|
+ if (write_a)
|
|
|
+ begin
|
|
|
+ a <= a_in;
|
|
|
+ end
|
|
|
+
|
|
|
+ end
|
|
|
+
|
|
|
+ localparam WIDTHU = WIDTH - 1; // unsigned widths are 1 bit narrower
|
|
|
+ localparam FBITSW = (FBITS == 0) ? 1 : FBITS; // avoid negative vector width when FBITS=0
|
|
|
+ localparam SMALLEST = {1'b1, {WIDTHU{1'b0}}}; // smallest negative number
|
|
|
+
|
|
|
+ localparam ITER = WIDTHU + FBITS; // iteration count: unsigned input width + fractional bits
|
|
|
+ reg [$clog2(ITER):0] i; // iteration counter (allow ITER+1 iterations for rounding)
|
|
|
+
|
|
|
+ reg a_sig = 1'b0;
|
|
|
+ reg b_sig = 1'b0;
|
|
|
+ reg sig_diff = 1'b0; // signs of inputs and whether different
|
|
|
+
|
|
|
+ reg [WIDTHU-1:0] au = 0;
|
|
|
+ reg [WIDTHU-1:0] bu = 0; // absolute version of inputs (unsigned)
|
|
|
+
|
|
|
+ reg [WIDTHU-1:0] quo = 0;
|
|
|
+ reg [WIDTHU-1:0] quo_next = 0; // intermediate quotients (unsigned)
|
|
|
+
|
|
|
+ reg [WIDTHU:0] acc = 0;
|
|
|
+ reg [WIDTHU:0] acc_next = 0; // accumulator (unsigned but 1 bit wider)
|
|
|
+
|
|
|
+ // input signs
|
|
|
+ always @(*)
|
|
|
+ begin
|
|
|
+ a_sig = a[WIDTH-1+:1];
|
|
|
+ b_sig = b[WIDTH-1+:1];
|
|
|
+ end
|
|
|
+
|
|
|
+ // division algorithm iteration
|
|
|
+ always @(*)
|
|
|
+ begin
|
|
|
+ if (acc >= {1'b0, bu}) begin
|
|
|
+ acc_next = acc - bu;
|
|
|
+ {acc_next, quo_next} = {acc_next[WIDTHU-1:0], quo, 1'b1};
|
|
|
+ end else begin
|
|
|
+ {acc_next, quo_next} = {acc, quo} << 1;
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+ // calculation state machine
|
|
|
+ parameter IDLE = 5'd0;
|
|
|
+ parameter INIT = 5'd1;
|
|
|
+ parameter CALC = 5'd2;
|
|
|
+ parameter ROUND = 5'd3;
|
|
|
+ parameter SIGN = 5'd4;
|
|
|
+ parameter DONE = 5'd5;
|
|
|
+
|
|
|
+ reg [2:0] state = IDLE;
|
|
|
+
|
|
|
+ always @(posedge clk) begin
|
|
|
+ done <= 0;
|
|
|
+ case (state)
|
|
|
+ INIT: begin
|
|
|
+ state <= CALC;
|
|
|
+ ovf <= 0;
|
|
|
+ i <= 0;
|
|
|
+ {acc, quo} <= {{WIDTHU{1'b0}}, au, 1'b0}; // initialize calculation
|
|
|
+ end
|
|
|
+ CALC: begin
|
|
|
+ if (i == WIDTHU-1 && quo_next[WIDTHU-1:WIDTHU-FBITSW] != 0) begin // overflow
|
|
|
+ state <= DONE;
|
|
|
+ busy <= 0;
|
|
|
+ done <= 1;
|
|
|
+ ovf <= 1;
|
|
|
+ end else begin
|
|
|
+ if (i == ITER-1) state <= ROUND; // calculation complete after next iteration
|
|
|
+ i <= i + 1;
|
|
|
+ acc <= acc_next;
|
|
|
+ quo <= quo_next;
|
|
|
+ end
|
|
|
+ end
|
|
|
+ ROUND: begin // Gaussian rounding
|
|
|
+ state <= SIGN;
|
|
|
+ if (quo_next[0] == 1'b1) begin // next digit is 1, so consider rounding
|
|
|
+ // round up if quotient is odd or remainder is non-zero
|
|
|
+ if (quo[0] == 1'b1 || acc_next[WIDTHU:1] != 0) quo <= quo + 1;
|
|
|
+ end
|
|
|
+ end
|
|
|
+ SIGN: begin // adjust quotient sign if non-zero and input signs differ
|
|
|
+ state <= DONE;
|
|
|
+ if (quo != 0) val <= (sig_diff) ? {1'b1, -quo} : {1'b0, quo};
|
|
|
+ busy <= 0;
|
|
|
+ done <= 1;
|
|
|
+ valid <= 1;
|
|
|
+ end
|
|
|
+ DONE: begin
|
|
|
+ done <= 1;
|
|
|
+ state <= IDLE;
|
|
|
+ end
|
|
|
+ default: begin // IDLE
|
|
|
+ if (start) begin
|
|
|
+ valid <= 0;
|
|
|
+ if (b == 0) begin // divide by zero
|
|
|
+ state <= DONE;
|
|
|
+ busy <= 0;
|
|
|
+ done <= 1;
|
|
|
+ dbz <= 1;
|
|
|
+ ovf <= 0;
|
|
|
+ end else if (a == SMALLEST || b == SMALLEST) begin // overflow
|
|
|
+ state <= DONE;
|
|
|
+ busy <= 0;
|
|
|
+ done <= 1;
|
|
|
+ dbz <= 0;
|
|
|
+ ovf <= 1;
|
|
|
+ end else begin
|
|
|
+ state <= INIT;
|
|
|
+ au <= (a_sig) ? -a[WIDTHU-1:0] : a[WIDTHU-1:0]; // register abs(a)
|
|
|
+ bu <= (b_sig) ? -b[WIDTHU-1:0] : b[WIDTHU-1:0]; // register abs(b)
|
|
|
+ sig_diff <= (a_sig ^ b_sig); // register input sign difference
|
|
|
+ busy <= 1;
|
|
|
+ dbz <= 0;
|
|
|
+ ovf <= 0;
|
|
|
+ end
|
|
|
+ end
|
|
|
+ end
|
|
|
+ endcase
|
|
|
+ if (rst) begin
|
|
|
+ state <= IDLE;
|
|
|
+ busy <= 0;
|
|
|
+ done <= 0;
|
|
|
+ valid <= 0;
|
|
|
+ dbz <= 0;
|
|
|
+ ovf <= 0;
|
|
|
+ val <= 0;
|
|
|
+ end
|
|
|
+ end
|
|
|
+endmodule
|