URL
https://opencores.org/ocsvn/theia_gpu/theia_gpu/trunk
Subversion Repositories theia_gpu
[/] [theia_gpu/] [branches/] [icarus_version/] [rtl/] [Module_FixedPointDivision.v] - Rev 191
Go to most recent revision | Compare with Previous | Blame | View Log
/* Fixed point Multiplication Module Qm.n C = (A << n) / B */ `timescale 1ns / 1ps `include "aDefinitions.v" //--------------------------------------------------------------------------- // serial_divide_uu.v -- Serial division module // // // Description: See description below (which suffices for IP core // specification document.) // // Copyright (C) 2002 John Clayton and OPENCORES.ORG (this Verilog version) // // This source file may be used and distributed without restriction provided // that this copyright statement is not removed from the file and that any // derivative work contains the original copyright notice and the associated // disclaimer. // // This source file is free software; you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation; either version 2.1 of the License, or // (at your option) any later version. // // This source is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public // License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this source. // If not, download it from http://www.opencores.org/lgpl.shtml // //----------------------------------------------------------------------------- // // Author: John Clayton // Date : Jan. 30, 2003 // Update: Jan. 30, 2003 Copied this file from "vga_crosshair.v" // Stripped out extraneous stuff. // Update: Mar. 14, 2003 Added S_PP parameter, made some simple changes to // implement quotient leading zero "skip" feature. // Update: Mar. 24, 2003 Updated comments to improve readability. // //----------------------------------------------------------------------------- // Description: // // This module performs a division operation serially, producing one bit of the // answer per clock cycle. The dividend and the divisor are both taken to be // unsigned quantities. The divider is conceived as an integer divider (as // opposed to a divider for fractional quantities) but the user can configure // the divider to divide fractional quantities as long as the position of the // binary point is carefully monitored. // // The widths of the signals are configurable by parameters, as follows: // // M_PP = Bit width of the dividend // N_PP = Bit width of the divisor // R_PP = Remainder bits desired // S_PP = Skipped quotient bits // // The skipped quotient bits parameter provides a way to prevent the divider // from calculating the full M_PP+R_PP output bits, in case some of the leading // bits are already known to be zero. This is the case, for example, when // dividing two quantities to obtain a result that is a fraction between 0 and 1 // (as when measuring PWM signals). In that case the integer portion of the // quotient is always zero, and therefore it need not be calculated. // // The divide operation is begun by providing a pulse on the divide_i input. // The quotient is provided (M_PP+R_PP-S_PP) clock cycles later. // The divide_i pulse stores the input parameters in registers, so they do // not need to be maintained at the inputs throughout the operation of the module. // If a divide_i pulse is given to the serial_divide_uu module during the time // when it is already working on a previous divide operation, it will abort the // operation it was doing, and begin working on the new one. // // The user is responsible for treating the results correctly. The position // of the binary point is not given, but it is understood that the integer part // of the result is the M_PP most significant bits of the quotient output. // The remaining R_PP least significant bits are the fractional part. // // This is illustrated graphically: // // [ M_PP bits ][ R_PP bits] // [ S_PP bits ][quotient_o] // // The quotient will consist of whatever bits are left after removing the S_PP // most significant bits from the (M_PP+R_PP) result bits. // // Attempting to divide by zero will simply produce a result of all ones. // This core is so simple, that no checking for this condition is provided. // If the user is concerned about a possible divide by zero condition, he should // compare the divisor to zero and flag that condition himself! // // The COUNT_WIDTH_PP parameter must be sized so that 2^COUNT_WIDTH_PP-1 is >= // M_PP+R_PP-S_PP-1. The unit terminates the divide operation when the count // is equal to M_PP+R_PP-S_PP-1. // // The HELD_OUTPUT_PP parameter causes the unit to keep its output result in // a register other than the one which it uses to compute the quotient. This // is useful for applications where the divider is used repeatedly and the // previous divide result (quotient) must be stable during the computation of the // next divide result. Using the additional output register does incur some // additional utilization of resources. // //----------------------------------------------------------------------------- module serial_divide_uu ( clk_i, clk_en_i, rst_i, divide_i, dividend_i, divisor_i, quotient_o, done_o ); /* M_PP => 21, N_PP => 21, R_PP => 0, S_PP => 0, HELD_OUTPUT_PP => 1 */ parameter M_PP = 21; // Size of dividend parameter N_PP = 21; // Size of divisor parameter R_PP = 0; // Size of remainder parameter S_PP = 0; // Skip this many bits (known leading zeros) parameter COUNT_WIDTH_PP = 5; // 2^COUNT_WIDTH_PP-1 >= (M_PP+R_PP-S_PP-1) parameter HELD_OUTPUT_PP = 1; // Set to 1 if stable output should be held // from previous operation, during current // operation. Using this option will increase // the resource utilization (costs extra // d-flip-flops.) // I/O declarations input clk_i; // input clk_en_i; input rst_i; // synchronous reset input divide_i; // starts division operation input [M_PP-1:0] dividend_i; // input [N_PP-1:0] divisor_i; // output [M_PP+R_PP-S_PP-1:0] quotient_o; // output done_o; // indicates completion of operation //reg [M_PP+R_PP-1:0] quotient_o; reg done_o; // Internal signal declarations reg [M_PP+R_PP-1:0] grand_dividend; reg [M_PP+N_PP+R_PP-2:0] grand_divisor; reg [M_PP+R_PP-S_PP-1:0] quotient; reg [M_PP+R_PP-1:0] quotient_reg; // Used exclusively for the held output reg [COUNT_WIDTH_PP-1:0] divide_count; wire [M_PP+N_PP+R_PP-1:0] subtract_node; // Subtract node has extra "sign" bit wire [M_PP+R_PP-1:0] quotient_node; // Shifted version of quotient wire [M_PP+N_PP+R_PP-2:0] divisor_node; // Shifted version of grand divisor //-------------------------------------------------------------------------- // Module code // Serial dividing module always @(posedge clk_i) begin if (rst_i) begin grand_dividend <= 0; grand_divisor <= 0; divide_count <= 0; quotient <= 0; done_o <= 0; end else if (clk_en_i) begin done_o <= 0; if (divide_i) // Start a new division begin quotient <= 0; divide_count <= 0; // dividend placed initially so that remainder bits are zero... grand_dividend <= dividend_i << R_PP; // divisor placed initially for a 1 bit overlap with dividend... // But adjust it back by S_PP, to account for bits that are known // to be leading zeros in the quotient. /* verilator lint_off WIDTH */ grand_divisor <= divisor_i << (N_PP+R_PP-S_PP-1); /* verilator lint_on WIDTH */ end /* verilator lint_off WIDTH */ else if (divide_count == M_PP+R_PP-S_PP-1) /* verilator lint_on WIDTH */ begin if (~done_o) quotient <= quotient_node; // final shift... if (~done_o) quotient_reg <= quotient_node; // final shift (held output) done_o <= 1; // Indicate done, just sit end else // Division in progress begin // If the subtraction yields a positive result, then store that result /* verilator lint_off WIDTH */ if (~subtract_node[M_PP+N_PP+R_PP-1]) grand_dividend <= subtract_node; /* verilator lint_on WIDTH */ // If the subtraction yields a positive result, then a 1 bit goes into // the quotient, via a shift register quotient <= quotient_node; // shift the grand divisor to the right, to cut it in half next clock cycle grand_divisor <= divisor_node; // Advance the counter divide_count <= divide_count + 1; end end // End of else if clk_en_i end // End of always block /* verilator lint_off WIDTH */ assign subtract_node = {1'b0,grand_dividend} - {1'b0,grand_divisor}; /* verilator lint_on WIDTH */ assign quotient_node = {quotient[M_PP+R_PP-S_PP-2:0],~subtract_node[M_PP+N_PP+R_PP-1]}; assign divisor_node = {1'b0,grand_divisor[M_PP+N_PP+R_PP-2:1]}; assign quotient_o = (HELD_OUTPUT_PP == 0)?quotient:quotient_reg; endmodule module SignedIntegerDivision ( input wire Clock, input wire Reset, output wire [`WIDTH-1:0] oQuotient, input wire [`WIDTH-1:0] iDividend, input wire [`WIDTH-1:0] iDivisor, input wire iInputReady, output wire OutputReady ); wire wInputReadyDelay1,wInputReadyPulse; FFD_POSEDGE_SYNCRONOUS_RESET # ( 1 ) FF_DELAY1 ( .Clock( Clock ), .Reset( Reset ), .Enable( 1'b1 ), .D( iInputReady ), .Q(wInputReadyDelay1) ); assign wInputReadyPulse = iInputReady ^ wInputReadyDelay1; wire [`LONG_WIDTH-1:0] wDividend,wDivisor,wScaledDividend; wire [`WIDTH-1:0] wNegDividend,wNegDivisor; assign wNegDividend = ~iDividend+1'b1; assign wNegDivisor = ~iDivisor + 1'b1; wire [`LONG_WIDTH-1:0] wQuotient; //Assign the sign extended signed value assign wDividend = (iDividend[`WIDTH-1] == 1'b1) ? {{32{wNegDividend[31]}},wNegDividend[31:0]} : {{32{iDividend[31]}},iDividend[31:0]} ; assign wDivisor = (iDivisor[`WIDTH-1] == 1'b1) ? {{32{wNegDivisor[31]}},wNegDivisor[31:0]} : {{32{iDivisor[31]}},iDivisor[31:0]} ; wire wNegativeOutput; assign wNegativeOutput = iDividend[`WIDTH-1] ^ iDivisor[`WIDTH-1]; wire wNegativeOutput_Latched; FFD_POSEDGE_SYNCRONOUS_RESET # ( 1 ) FF_NEG ( .Clock( Clock ), .Reset( Reset ), .Enable( iInputReady ), .D( wNegativeOutput ), .Q(wNegativeOutput_Latched) ); assign oQuotient = (wNegativeOutput_Latched) ? ~wQuotient[`WIDTH-1:0]+1'b1 : wQuotient[`WIDTH-1:0]; wire wOutputReady,wOutputReadyDelay1; FFD_POSEDGE_SYNCRONOUS_RESET # ( 1 ) FF_DELAY2 ( .Clock( Clock ), .Reset( Reset | iInputReady), .Enable( 1'b1 ), .D( wOutputReady ), .Q(wOutputReadyDelay1) ); assign OutputReady = wOutputReady ^ wOutputReadyDelay1; assign wScaledDividend = (wDividend << `SCALE); serial_divide_uu # ( 64,64,0,0,6,1 ) uu_div( .clk_i(Clock), .clk_en_i(1'b1), .rst_i(Reset), .divide_i(iInputReady), .dividend_i(wScaledDividend), .divisor_i(wDivisor), .quotient_o(wQuotient), .done_o(wOutputReady) ); endmodule
Go to most recent revision | Compare with Previous | Blame | View Log