aboutsummaryrefslogtreecommitdiff
`default_nettype none

module div
  #(
    parameter WIDTH = 16
    )
   (
    input wire 		      clock,
    input wire 		      start,

    input wire [WIDTH-1 : 0]  dividend,
    input wire [WIDTH-1 : 0]  divisor,

    output wire [WIDTH-1 : 0] quotient,
    output wire [WIDTH-1 : 0] remainder,

    output wire 	      done
    );

   reg [$clog2(WIDTH)-1 : 0]  steps;
   reg [2*WIDTH : 0] 	      work_reg;
   reg [WIDTH-1 : 0] 	      divisor_latched;

   wire [WIDTH+1 : 0] 	      work_remainder;
   wire 		      work_remainder_sign;
   assign work_remainder = work_reg[2*WIDTH : WIDTH-1];
   assign work_remainder_sign = work_remainder[WIDTH + 1];

   /*
    * The following variable represents quotient using digits 1 and -1,
    * where -1 is internally represented as 0
    */
`define MINUS_ONE 1'b0
`define PLUS_ONE 1'b1

   wire [WIDTH-1 : 0] 	      work_quotient;
   assign work_quotient = work_reg[WIDTH-1 : 0];

   reg 			      work_quotient_ready;

   always @ (posedge clock) begin
      if (start) begin
	 steps <= WIDTH - 1;
	 work_reg <= dividend;
	 divisor_latched <= divisor;
	 work_quotient_ready <= 0;
      end else begin
	 if (steps)
	   steps <= steps - 1;
	 else
	   work_quotient_ready <= 1;

	 if (!work_quotient_ready) begin
	    work_reg[WIDTH-1 : 1] <= work_reg[WIDTH-2 : 0];

	    if (work_remainder_sign) begin /* work remainder negative */
	       work_reg[0] <= `MINUS_ONE; /* Filling up quotient */
	       work_reg[2*WIDTH : WIDTH] <= work_remainder + divisor_latched;
	    end else begin /* work remainder equal 0 or positive */
	       work_reg[0] <= `PLUS_ONE; /* Filling up quotient */
	       work_reg[2*WIDTH : WIDTH] <= work_remainder - divisor_latched;
	    end
	 end
      end
   end // always @ (posedge clock)

   assign quotient = work_quotient - ~work_quotient - work_remainder_sign;
   assign remainder = (work_remainder >> 1) + (work_remainder_sign ? divisor_latched : 0);
   assign done = work_quotient_ready && !start;
endmodule // div