Computes the signed quotient of the signed dividend and divisor, based on whether each Remainder addition/subtraction step is successful. Part of the Signed Integer Divider module. Not usable by itself.
`default_nettype none module Quotient_Integer_Signed #( parameter WORD_WIDTH = 0, parameter STEP_WORD_WIDTH = 0 ) ( input wire clock, input wire clear, input wire input_valid, output reg input_ready, input wire dividend_sign, input wire divisor_sign, output reg output_valid, input wire output_ready, output wire [WORD_WIDTH-1:0] quotient, input wire control_valid, output reg control_ready, input wire step_ok ); `include "clog2_function.vh" localparam WORD_ZERO = {WORD_WIDTH{1'b0}}; initial begin input_ready = 1'b0; output_valid = 1'b0; control_ready = 1'b0; end
Some basic definitions to establish our two's-complement signed representation.
localparam ADD = 1'b0; localparam SUB = 1'b1;
We have to internally compute with one extra bit of range to match the behaviour of the Remainder calculations.
localparam STEP_WORD_WIDTH_LONG = STEP_WORD_WIDTH + 1; localparam WORD_WIDTH_LONG = WORD_WIDTH + 1; localparam WORD_ZERO_LONG = {WORD_WIDTH_LONG{1'b0}}; localparam WORD_ONE_LONG = {{WORD_WIDTH_LONG-1{1'b0}},1'b1}; localparam WORD_ONES_LONG = {WORD_WIDTH_LONG{1'b1}};
reg divisor_sign_enable = 1'b0; wire divisor_sign_loaded; Register #( .WORD_WIDTH (1), .RESET_VALUE (1'b0) ) divisor_sign_storage ( .clock (clock), .clock_enable (divisor_sign_enable), .clear (1'b0), .data_in (divisor_sign), .data_out (divisor_sign_loaded) ); reg dividend_sign_enable = 1'b0; wire dividend_sign_loaded; Register #( .WORD_WIDTH (1), .RESET_VALUE (1'b0) ) dividend_sign_storage ( .clock (clock), .clock_enable (dividend_sign_enable), .clear (1'b0), .data_in (dividend_sign), .data_out (dividend_sign_loaded) );
The quotient increment is added/subtracted to/from the quotient each time we could remove the divisor from the remainder. Shift it right by 1 each calculation step, so we increment by decreasing multiples of 2 at each division step.
reg quotient_increment_enable = 1'b0; reg quotient_increment_load = 1'b0; wire [WORD_WIDTH_LONG-1:0] quotient_increment_reversed; Register_Pipeline #( .WORD_WIDTH (1), .PIPE_DEPTH (WORD_WIDTH_LONG), .RESET_VALUES (WORD_ZERO_LONG) ) quotient_increment_storage ( .clock (clock), .clock_enable (quotient_increment_enable), .clear (clear), .parallel_load (quotient_increment_load), .parallel_in (WORD_ONE_LONG), .parallel_out (quotient_increment_reversed), .pipe_in (1'b0), // verilator lint_off PINCONNECTEMPTY .pipe_out () // verilator lint_on PINCONNECTEMPTY );
The Register_Pipeline only shifts left, so let's reverse its parallel output.
wire [WORD_WIDTH_LONG-1:0] quotient_increment; Word_Reverser #( .WORD_WIDTH (1), .WORD_COUNT (WORD_WIDTH_LONG) ) quotient_increment_shift_direction ( .words_in (quotient_increment_reversed), .words_out (quotient_increment) );
reg quotient_enable = 1'b0; reg quotient_clear = 1'b0; wire [WORD_WIDTH_LONG-1:0] quotient_next; wire [WORD_WIDTH_LONG-1:0] quotient_loaded; Register #( .WORD_WIDTH (WORD_WIDTH_LONG), .RESET_VALUE (WORD_ZERO_LONG) ) quotient_storage ( .clock (clock), .clock_enable (quotient_enable), .clear (quotient_clear), .data_in (quotient_next), .data_out (quotient_loaded) ); Width_Adjuster #( .WORD_WIDTH_IN (WORD_WIDTH_LONG), .SIGNED (1), .WORD_WIDTH_OUT (WORD_WIDTH) ) quotient_shorten ( .original_input (quotient_loaded), .adjusted_output (quotient) );
Add or subtract depending on the signs of the inputs. We don't need to
handle backpressure at the input handshake of the
Adder_Subtractor_Binary_Multiprecision
since we don't try to start a new
operation until the previous one has completed and its results stored.
reg quotient_add_sub = 1'b0; always @(*) begin quotient_add_sub = (divisor_sign_loaded == dividend_sign_loaded) ? ADD : SUB; end reg quotient_input_valid = 1'b0; wire quotient_output_valid; // Veril*tor cannot quite anaylze this signals path across the hierarchy. // This is not a synthesis bug. // verilator lint_off UNOPTFLAT reg quotient_output_ready = 1'b0; // verilator lint_on UNOPTFLAT Adder_Subtractor_Binary_Multiprecision #( .WORD_WIDTH (WORD_WIDTH_LONG), .STEP_WORD_WIDTH (STEP_WORD_WIDTH_LONG) ) quotient_calc ( .clock (clock), .clock_enable (1'b1), .clear (clear), .input_valid (quotient_input_valid), //verilator lint_off PINCONNECTEMPTY .input_ready (), //verilator lint_on PINCONNECTEMPTY .add_sub (quotient_add_sub), // 0/1 -> A+B/A-B .A (quotient_loaded), .B (quotient_increment), .output_valid (quotient_output_valid), .output_ready (quotient_output_ready), .sum (quotient_next), // verilator lint_off PINCONNECTEMPTY .carry_out (), .carries (), .overflow () // verilator lint_on PINCONNECTEMPTY );
We denote state as two bits, with the following transitions: LOAD -> CALC -> DONE -> LOAD -> ... We don't handle the fourth, impossible case. The state encoding is arbitrary.
localparam STATE_WIDTH = 2; localparam [STATE_WIDTH-1:0] STATE_LOAD = 2'b00; localparam [STATE_WIDTH-1:0] STATE_CALC = 2'b10; localparam [STATE_WIDTH-1:0] STATE_DONE = 2'b11; localparam [STATE_WIDTH-1:0] STATE_ERROR = 2'b01; // Never reached
The state bits, from which we derive the control outputs and the internal control signals.
reg [STATE_WIDTH-1:0] state_next = STATE_LOAD; wire [STATE_WIDTH-1:0] state; Register #( .WORD_WIDTH (STATE_WIDTH), .RESET_VALUE (STATE_LOAD) ) state_storage ( .clock (clock), .clock_enable (1'b1), .clear (clear), .data_in (state_next), .data_out (state) );
Each division takes WORD_WIDTH_LONG
steps, from WORD_WIDTH_LONG-1
to
0
, plus one step to initially load the dividend and divisor. Thus, we
need a counter of the correct width.
localparam STEPS_WIDTH = clog2(WORD_WIDTH_LONG); localparam STEPS_INITIAL = WORD_WIDTH_LONG - 1; localparam STEPS_ZERO = {STEPS_WIDTH{1'b0}}; localparam STEPS_ONE = {{STEPS_WIDTH-1{1'b0}},1'b1};
Count down WORD_WIDTH_LONG-1 calculation steps. Stops at zero, and reloads when leaving STATE_LOAD.
reg calculation_step_clear = 1'b0; reg calculation_step_do = 1'b0; wire [STEPS_WIDTH-1:0] calculation_step; Counter_Binary #( .WORD_WIDTH (STEPS_WIDTH), .INCREMENT (STEPS_ONE), .INITIAL_COUNT (STEPS_INITIAL [STEPS_WIDTH-1:0]) ) calculation_steps ( .clock (clock), .clear (calculation_step_clear), .up_down (1'b1), // 0/1 -> up/down .run (calculation_step_do), .load (1'b0), .load_count (STEPS_ZERO), .carry_in (1'b0), // verilator lint_off PINCONNECTEMPTY .carry_out (), .carries (), .overflow (), // verilator lint_on PINCONNECTEMPTY .count (calculation_step) );
Accept inputs when empty (after results are read out) or frehsly reset/cleared). Declare outputs valid when calculation is done. Signal a new calculation step each time the addition/subtraction is complete.
always @(*) begin output_valid = (state == STATE_DONE); input_ready = (state == STATE_LOAD); control_ready = (state == STATE_CALC) && (quotient_output_valid == 1'b1); end
reg load_inputs = 1'b0; // When we load the dividend and divisor signs. reg read_outputs = 1'b0; // When we read out the quotient. reg read_control = 1'b0; // When we read in the calculation step status. reg calculating = 1'b0; // High while performing the division steps. reg step_done = 1'b0; // High when an add/sub completes and is ack'ed by other computations. reg last_calculation = 1'b0; // High during the last calculation step. always @(*) begin load_inputs = (input_ready == 1'b1) && (input_valid == 1'b1); read_outputs = (output_valid == 1'b1) && (output_ready == 1'b1); read_control = (control_valid == 1'b1) && (control_ready == 1'b1); calculating = (state == STATE_CALC); step_done = (read_control == 1'b1); last_calculation = (read_control == 1'b1) && (calculation_step == STEPS_ZERO); end
Past this point, we should not refer directly to the FSM states or inputs/outputs, but to these events which are combinations of states and signals.
There is no handling of erroneous states.
always @(*) begin state_next = (load_inputs == 1'b1) ? STATE_CALC : state; state_next = (last_calculation == 1'b1) ? STATE_DONE : state_next; state_next = (read_outputs == 1'b1) ? STATE_LOAD : state_next; end
always @(*) begin calculation_step_clear = (load_inputs == 1'b1) || (clear == 1'b1); calculation_step_do = (step_done == 1'b1); end
Let the Adder/Subtractor run independently, but read out its value only when the control handshake (from the Remainder module) completes. This then allows the Adder/Subtractor's input handshake to complete.
always @(*) begin quotient_input_valid = (calculating == 1'b1); quotient_output_ready = (control_valid == 1'b1); end
always @(*) begin divisor_sign_enable = (load_inputs == 1'b1); dividend_sign_enable = (load_inputs == 1'b1); end
Store only an updated Quotient if the division step from the Remainder module was OK (could successfully remove the divisor from the dividend).
always @(*) begin quotient_increment_enable = (load_inputs == 1'b1) || (step_done == 1'b1); quotient_increment_load = (load_inputs == 1'b1); quotient_enable = (load_inputs == 1'b1) || ((step_done == 1'b1) && (step_ok == 1'b1)); quotient_clear = (load_inputs == 1'b1) || (clear == 1'b1); end endmodule