Sequential Restoring Divider

Hard · Arithmetic · Finite State Machines · Sequential Logic

Implement an unsigned sequential divider that computes one quotient bit per clock cycle using the restoring division algorithm.

Division is far too large to do in one cycle for wide operands, so real CPUs and DSP blocks iterate. Your divider accepts an operation with a start pulse, works for exactly WIDTH cycles, and then pulses done with the result.

Parameters and ports

module seq_divider #(
    parameter int WIDTH = 8
) (
    input  logic             clk,
    input  logic             rst,
    input  logic             start,
    input  logic [WIDTH-1:0] dividend,
    input  logic [WIDTH-1:0] divisor,
    output logic             busy,
    output logic             done,
    output logic [WIDTH-1:0] quotient,
    output logic [WIDTH-1:0] remainder
);
PortDirWidthMeaning
clkinput1Clock. Everything happens on the rising edge.
rstinput1Synchronous, active-high reset.
startinput1Request a division (sampled on the rising edge).
dividendinputWIDTHUnsigned dividend, sampled together with start.
divisorinputWIDTHUnsigned divisor, sampled together with start.
busyoutput11 while a division is in progress.
doneoutput1One-cycle pulse: the result is ready.
quotientoutputWIDTHdividend / divisor (unsigned, rounded toward zero).
remainderoutputWIDTHdividend % divisor.

WIDTH is any value ≥ 2 (default 8). The judge tests WIDTH = 8.

Reset

rst is synchronous and active high: on a rising edge with rst = 1, the divider aborts any division in progress and afterwards busy = 0, done = 0, quotient = 0, remainder = 0. Reset is checked only at rising clock edges: a rst pulse that rises and falls between two edges has no effect (do not use always_ff @(posedge clk or posedge rst)).

rst has priority over everything else on the same edge:

division is accepted, busy stays 0);

division is aborted: done does not pulse, and quotient/remainder become 0.

Timing (exact)

Call the rising edge at which start = 1 is sampled while busy = 0 the accepting edge E0, and the following rising edges E1, E2, ....

  1. At E0 the divider captures dividend and divisor. After E0, busy = 1.
  2. busy stays 1 after E1 … E(WIDTH−1): that is WIDTH cycles of busy.
  3. After E(WIDTH): busy = 0, done = 1, and quotient/remainder hold the result.

So done rises exactly WIDTH clock cycles after the accepting edge.

  1. After E(WIDTH+1): done = 0 again. done is high for exactly one cycle per division.

Other rules:

E0: the running division uses the captured values and finishes on time.

edge is the next division's E0. So with start held high continuously, a new division begins every WIDTH + 1 cycles.

most recent completed division (or 0 if none has completed since reset), and they hold that value until the next division is accepted. While busy = 1 their values are not checked.

WIDTH cycles and pulses done, with quotient = all ones (2**WIDTH − 1) and remainder = the dividend. (This is what the restoring algorithm naturally produces, so you need no special case.)

Timing diagram

WIDTH = 8, computing 100 / 7 = 14 remainder 2:

Examples (WIDTH = 8)

dividenddivisorquotientremainder
1007142
25512550
7907
20020010
0500
42025542

The restoring algorithm

Keep a partial remainder R (start at 0) and shift the dividend in from its MSB, one bit per cycle. In each of the WIDTH steps:

  1. R = {R, next dividend bit} (shift left by one, bring in the next bit, MSB first).
  2. If R >= divisor: R = R - divisor and the next quotient bit is 1; otherwise the

quotient bit is 0 (the subtraction is "restored", i.e. not applied).

After WIDTH steps the quotient bits (MSB first) form the quotient and R is the remainder. A common trick is to keep the dividend in a shift register and shift quotient bits into its LSB as the dividend bits leave its MSB.

Watch the widths: a plain >= comparison is safest. If you instead compute R - divisor and use its top bit as the "negative" flag, the subtraction must be one bit wider than the operands ({1'b0, R} - {1'b0, divisor}, then test bit WIDTH). The MSB of a WIDTH-bit difference is not a borrow: that version fails for divisors of 2**(WIDTH-1) or more (for example 0 / 129).

Sign up free to solve Sequential Restoring Divider in your browser.

More Arithmetic problems