123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- /*
- * 32-bit multicycle fixed-point divider
- */
- module FPDivider #(
- 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
|