// designed by Sergey Suslov // // sequential integer divider with reminder correction // takes in 2 arguments of adjustable width (parameters op_A_width, op_B_width) // and divide the first one by the second treating them either signed or unsigned depending on op-type input // which takes op_A_width+1 clock cycles + 1 cycle for reminder correction, provided that stall_n signal is deasserted // rdy_n output indicates completion of operation with result(rez) and reminder containing valid results // the unit provides additionally an overflow and division by zero exception flags //`include "definitions.v" `ifndef SYNTHESYS timeunit `verification_time_unit; timeprecision `verification_time_resolution; `endif module div_signed_unsigned #( parameter op_A_width=32, parameter op_B_width=op_A_width ) ( input bit clk, input bit reset_n, // operands loading input bit op_type, // 1-signed, 0-unsigned input bit [op_A_width-1:0] op_A, input bit [op_B_width-1:0] op_B, output bit [op_A_width-1:0] rez,// result output bit [op_B_width-1:0] remainder,//ramainder output bit overflow, output bit exception_div_by_zero, output bit rdy_n, input bit stall_n ); localparam state_counter_width=$clog2(op_A_width+1); reg [op_A_width:0] Q; // quotient reg [op_B_width:0] R; //remainder shifted reg [op_B_width:0] D; //divisor reg [op_B_width:0] rem; //ramainder wire sign; //sign of result reg op_A_sign; reg op_B_sign; reg [state_counter_width-1:0] state_counter; wire [op_A_width:0] Q_corrected; wire [op_B_width:0] difference; wire [op_B_width:0] sum; wire [op_B_width:0] rem_correction_difference; wire rem_correction_diff_zero; wire [op_B_width:0] rem_correction_sum; wire rem_correction_sum_zero; wire op_A_sign_extension; wire op_B_sign_extension; assign remainder=rem[op_B_width-1:0]; assign Q_corrected=Q+1; assign difference=R-D; assign sum=R+D; assign rem_correction_difference=rem-D; assign rem_correction_diff_zero=~(|rem_correction_difference); assign rem_correction_sum=rem+D; assign rem_correction_sum_zero=~(|rem_correction_sum); assign op_B_sign_extension=(op_type)?op_B[op_B_width-1]:1'b0; assign op_A_sign_extension=(op_type)?op_A[op_A_width-1]:1'b0; wire rez_correction; reg block; wire opA_negative_opB_positive; wire opA_positive_opB_negative; wire opAopB_negative; wire opAopB_positive; assign sign=(op_A_sign)^(op_B_sign); assign opA_negative_opB_positive=(op_A_sign)&(~op_B_sign); assign opA_positive_opB_negative=(~op_A_sign)&(op_B_sign); assign opAopB_negative=(op_A_sign)&(op_B_sign); assign opAopB_positive=(op_A_sign)|(op_B_sign); wire rem_zero; assign rem_zero=|rem; assign rez_correction=(opA_negative_opB_positive&rem_zero)|(opA_positive_opB_negative)|(opAopB_negative&(~rem_zero)); always @(posedge clk) begin if (stall_n==1) begin if (~reset_n) begin state_counter<=op_A_width+1; Q[op_A_width:1]<=op_A[op_A_width-1:0]; Q[0]<=(op_A_sign_extension)^(op_B_sign_extension); op_A_sign<=op_A_sign_extension; op_B_sign<=op_B_sign_extension; for (int i=0;i<=op_B_width;i=i+1)R[i]<=op_A_sign_extension; for (int i=0;i<=op_B_width;i=i+1)rem[i]<=op_A_sign_extension; D[op_B_width-1:0]<=op_B; D[op_B_width]<=op_B_sign_extension; rdy_n<=1; rez<=0; block<=0; overflow<=op_type&op_A[op_A_width-1]&(~(|op_A[op_A_width-2:0]))&(&op_B);// if maximum negative value in op_A is divided by -1, it is an overflow exception exception_div_by_zero<=(|op_B); end else begin if (|state_counter) begin state_counter<=state_counter-1; if (rem[op_B_width]) begin if (D[op_B_width]) begin R[op_B_width:1]<=difference[op_B_width-1:0]; Q[0]<=~(D[op_B_width]^difference[op_B_width]); rem<=difference; end else begin R[op_B_width:1]<=sum[op_B_width-1:0]; Q[0]<=~(D[op_B_width]^sum[op_B_width]); rem<=sum; end end else begin if (D[op_B_width]) begin R[op_B_width:1]<=sum[op_B_width-1:0]; Q[0]<=~(D[op_B_width]^sum[op_B_width]); rem<=sum; end else begin R[op_B_width:1]<=difference[op_B_width-1:0]; Q[0]<=~(D[op_B_width]^difference[op_B_width]); rem<=difference; end end R[0]<=Q[op_A_width]; Q[op_A_width:1]<=Q[op_A_width-1:0]; end else begin if (block) rdy_n<=0; if (rez_correction) rez<=Q_corrected[op_A_width-1:0]; else rez<=Q[op_A_width-1:0]; block<=1; if ((~block)&&(rem_zero)) begin if (rem[op_B_width]) begin if (D[op_B_width]) begin if (~opAopB_negative|(opAopB_negative&rem_correction_diff_zero)) rem<=rem_correction_difference; end else begin if (~sign|(opA_negative_opB_positive&rem_correction_sum_zero))rem<=rem_correction_sum; end end else begin if (D[op_B_width]) begin if (~sign)rem<=rem_correction_sum; end //!! else if(opAopB_positive)rem<=rem_correction_difference; end end end end end end endmodule