OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [or1200/] [rtl/] [verilog/] [or1200_fpu_intfloat_conv.v] - Rev 588

Go to most recent revision | Compare with Previous | Blame | View Log

/////////////////////////////////////////////////////////////////////
////                                                             ////
////  or1200_fpu_intfloat_conv                                   ////
////  Only conversion between 32-bit integer and single          ////
////  precision floating point format                            ////
////                                                             ////
////  Author: Rudolf Usselmann                                   ////
////          rudi@asics.ws                                      ////
////                                                             ////
//// Modified by Julius Baxter, July, 2010                       ////
////             julius.baxter@orsoc.se                          ////
////                                                             ////
//// TODO: Fix bug where 1.0f in round up goes to integer 2      ////
////                                                             ////
/////////////////////////////////////////////////////////////////////
////                                                             ////
//// Copyright (C) 2000 Rudolf Usselmann                         ////
////                    rudi@asics.ws                            ////
////                                                             ////
//// 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 SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
//// POSSIBILITY OF SUCH DAMAGE.                                 ////
////                                                             ////
/////////////////////////////////////////////////////////////////////
 
`timescale 1ns / 100ps
 
/*
 
 FPU Operations (fpu_op):
 ========================
 
 0 = 
 1 = 
 2 = 
 3 = 
 4 = int to float
 5 = float to int
 6 =
 7 =
 
 Rounding Modes (rmode):
 =======================
 
 0 = round_nearest_even
 1 = round_to_zero
 2 = round_up
 3 = round_down
 
 */
 
 
module or1200_fpu_intfloat_conv
  ( 
    clk, rmode, fpu_op, opa, out, snan, ine, inv,
    overflow, underflow, zero
    );
   input		clk;
   input [1:0] 		rmode;
   input [2:0] 		fpu_op;
   input [31:0] 	opa;
   output [31:0] 	out;
   output		snan;   
   output		ine;
   output 		inv;   
   output 		overflow;
   output 		underflow;   
   output		zero;
 
 
   parameter	INF  = 31'h7f800000,
		  QNAN = 31'h7fc00001,
		  SNAN = 31'h7f800001;
 
   ////////////////////////////////////////////////////////////////////////
   //
   // Local Wires
   //
   reg 			zero;
   reg [31:0] 		opa_r;	// Input operand registers
   reg [31:0] 		out;		// Output register
   reg 			div_by_zero;	// Divide by zero output register
   wire [7:0] 		exp_fasu;	// Exponent output from EQU block
   reg [7:0] 		exp_r;		// Exponent output (registerd)
   wire 		co;		// carry output
   wire [30:0] 		out_d;		// Intermediate final result output
   wire 		overflow_d, underflow_d;// Overflow/Underflow
   reg 			inf, snan, qnan;// Output Registers for INF, S/QNAN
   reg 			ine;		// Output Registers for INE
   reg [1:0] 		rmode_r1, rmode_r2,// Pipeline registers for round mode
			rmode_r3;
   reg [2:0] 		fpu_op_r1, fpu_op_r2,// Pipeline registers for fp 
			                     // operation
			fpu_op_r3;
 
   ////////////////////////////////////////////////////////////////////////
     //
   // Input Registers
   //
 
   always @(posedge clk)
     opa_r <=  opa;
 
 
   always @(posedge clk)
     rmode_r1 <=  rmode;
 
   always @(posedge clk)
     rmode_r2 <=  rmode_r1;
 
   always @(posedge clk)
     rmode_r3 <=  rmode_r2;
 
   always @(posedge clk)
     fpu_op_r1 <=  fpu_op;
 
   always @(posedge clk)
     fpu_op_r2 <=  fpu_op_r1;
 
   always @(posedge clk)
     fpu_op_r3 <=  fpu_op_r2;
 
   ////////////////////////////////////////////////////////////////////////
   //
   // Exceptions block
   //
   wire 		inf_d, ind_d, qnan_d, snan_d, opa_nan;
   wire 		opa_00;   
   wire 		opa_inf;
   wire 		opa_dn;
 
   or1200_fpu_intfloat_conv_except u0
     (	.clk(clk),
	.opa(opa_r), 
	.opb(),
	.inf(inf_d), 
	.ind(ind_d),
	.qnan(qnan_d), 
	.snan(snan_d),
	.opa_nan(opa_nan), 
	.opb_nan(),
	.opa_00(opa_00),   
	.opb_00(),
	.opa_inf(opa_inf), 
	.opb_inf(),
	.opa_dn(opa_dn), 
	.opb_dn()
	);
 
   ////////////////////////////////////////////////////////////////////////
   //
   // Pre-Normalize block
   // - Adjusts the numbers to equal exponents and sorts them
   // - determine result sign
   // - determine actual operation to perform (add or sub)
   //
 
   wire 		nan_sign_d, result_zero_sign_d;
   reg 			sign_fasu_r;
   wire [1:0] 		exp_ovf;
   reg [1:0] 		exp_ovf_r;
 
   // This is all we need from post-norm module for int-float conversion
   reg 			opa_sign_r;
   always @(posedge clk)
     opa_sign_r <= opa_r[31];
 
   always @(posedge clk)
     sign_fasu_r <=  opa_sign_r; //sign_fasu;
 
 
   ////////////////////////////////////////////////////////////////////////
   //
   // Normalize Result
   //
   wire 		ine_d;
   wire 		inv_d;   
   wire 		sign_d;
   reg 			sign;
   reg [30:0] 		opa_r1;
   reg [47:0] 		fract_i2f;
   reg 			opas_r1, opas_r2;
   wire 		f2i_out_sign;
   wire [47:0] 		fract_denorm;
 
   always @(posedge clk)  // Exponent must be once cycle delayed
     case(fpu_op_r2)
       //4:	exp_r <=  0;
       5:	exp_r <=  opa_r1[30:23];
       default: exp_r <=  0;
     endcase
 
   always @(posedge clk)
     opa_r1 <=  opa_r[30:0];
 
   always @(posedge clk)
     fract_i2f <=  (fpu_op_r2==5) ?
		   (sign_d ?  1-{24'h00, (|opa_r1[30:23]), opa_r1[22:0]}-1 : 
		    {24'h0, (|opa_r1[30:23]), opa_r1[22:0]})
       : (sign_d ? 1 - {opa_r1, 17'h01} : {opa_r1, 17'h0});
 
   assign fract_denorm = fract_i2f;
 
   always @(posedge clk)
     opas_r1 <=  opa_r[31];
 
   always @(posedge clk)
     opas_r2 <=  opas_r1;
 
   assign sign_d = opa_sign_r; //sign_fasu;
 
   always @(posedge clk)
     sign <=  (rmode_r2==2'h3) ? !sign_d : sign_d;
 
 
   // Special case of largest negative integer we can convert to - usually
   // gets picked up as invalid, but really it's not, so deal with it as a
   // special case.
   wire 		f2i_special_case_no_inv;
   assign f2i_special_case_no_inv = (opa == 32'hcf000000);
 
 
   or1200_fpu_post_norm_intfloat_conv u4
     (
      .clk(clk),			// System Clock
      .fpu_op(fpu_op_r3),		// Floating Point Operation
      .opas(opas_r2),			// OPA Sign
      .sign(sign),			// Sign of the result
      .rmode(rmode_r3),		// Rounding mode
      .fract_in(fract_denorm),	// Fraction Input
 
      .exp_in(exp_r),			// Exponent Input
      .opa_dn(opa_dn),		// Operand A Denormalized
      .opa_nan(opa_nan),
      .opa_inf(opa_inf),
 
      .opb_dn(),		// Operand B Denormalized
      .out(out_d),		// Normalized output (un-registered)
      .ine(ine_d),		// Result Inexact output (un-registered)
      .inv(inv_d),            // Invalid input for f2i operation
      .overflow(overflow_d),	// Overflow output (un-registered)
      .underflow(underflow_d),// Underflow output (un-registered)
      .f2i_out_sign(f2i_out_sign)	// F2I Output Sign
      );
 
   ////////////////////////////////////////////////////////////////////////
     //
   // FPU Outputs
   //
   reg 			fasu_op_r1, fasu_op_r2;
   wire [30:0] 		out_fixed;
   wire 		output_zero_fasu;
   wire 		overflow_fasu;
   wire 		out_d_00;
   wire 		ine_fasu;
   wire 		underflow_fasu;   
 
 
   /*
    always @(posedge clk)
    fasu_op_r1 <=  fasu_op;
 
    always @(posedge clk)
    fasu_op_r2 <=  fasu_op_r1;
    */
   // Force pre-set values for non numerical output
 
   assign out_fixed = (	(qnan_d | snan_d) |
			(ind_d /*& !fasu_op_r2*/))  ? QNAN : INF;
 
   always @(posedge clk)
     out[30:0] <=  /*((inf_d & (fpu_op_r3!=3'b101)) | snan_d | qnan_d) 
		    & fpu_op_r3!=3'b100 ? out_fixed :*/ out_d;
 
   assign out_d_00 = !(|out_d);
 
 
   always @(posedge clk)
     out[31] <= (fpu_op_r3==3'b101) ? 
		f2i_out_sign : sign_fasu_r; 
 
 
 
   // Exception Outputs
   assign ine_fasu = (ine_d | overflow_d | underflow_d) & 
		     !(snan_d | qnan_d | inf_d);
 
   always @(posedge  clk)
     ine <= 	 fpu_op_r3[2] ? ine_d : ine_fasu;
 
   assign overflow = overflow_d & !(snan_d | qnan_d | inf_d);
   assign underflow = underflow_d & !(inf_d | snan_d | qnan_d);
 
   always @(posedge clk)
     snan <=  snan_d & (fpu_op_r3==3'b101);  // Only signal sNaN when ftoi
 
   // Status Outputs   
   assign output_zero_fasu = out_d_00 & !(inf_d | snan_d | qnan_d);
 
   always @(posedge clk)
     zero <= 	fpu_op_r3==3'b101 ? out_d_00 & !(snan_d | qnan_d) :
	     output_zero_fasu ;
   assign inv = inv_d & !f2i_special_case_no_inv;
 
endmodule // or1200_fpu_intfloat_conv
 
 
module or1200_fpu_intfloat_conv_except
  (	
	clk, opa, opb, inf, ind, qnan, snan, opa_nan, opb_nan,
	opa_00, opb_00, opa_inf, opb_inf, opa_dn, opb_dn
	);
   input		clk;
   input [31:0] 	opa, opb;
   output		inf, ind, qnan, snan, opa_nan, opb_nan;
   output		opa_00, opb_00;
   output		opa_inf, opb_inf;
   output		opa_dn;
   output		opb_dn;
 
   ////////////////////////////////////////////////////////////////////////
   //
   // Local Wires and registers
   //
 
   wire [7:0] 		expa, expb;		// alias to opX exponent
   wire [22:0] 		fracta, fractb;		// alias to opX fraction
   reg 			expa_ff, infa_f_r, qnan_r_a, snan_r_a;
   reg 			expb_ff, infb_f_r, qnan_r_b, snan_r_b;
   reg 			inf, ind, qnan, snan;	// Output registers
   reg 			opa_nan, opb_nan;
   reg 			expa_00, expb_00, fracta_00, fractb_00;
   reg 			opa_00, opb_00;
   reg 			opa_inf, opb_inf;
   reg 			opa_dn, opb_dn;
 
   ////////////////////////////////////////////////////////////////////////
   //
   // Aliases
   //
 
   assign   expa = opa[30:23];
   assign   expb = opb[30:23];
   assign fracta = opa[22:0];
   assign fractb = opb[22:0];
 
   ////////////////////////////////////////////////////////////////////////
   //
   // Determine if any of the input operators is a INF or NAN or any other 
   // special number
   //
 
   always @(posedge clk)
     expa_ff <=  &expa;
 
   always @(posedge clk)
     expb_ff <=  &expb;
 
   always @(posedge clk)
     infa_f_r <=  !(|fracta);
 
   always @(posedge clk)
     infb_f_r <=  !(|fractb);
 
   always @(posedge clk)
     qnan_r_a <=   fracta[22];
 
   always @(posedge clk)
     snan_r_a <=  !fracta[22] & |fracta[21:0];
 
   always @(posedge clk)
     qnan_r_b <=   fractb[22];
 
   always @(posedge clk)
     snan_r_b <=  !fractb[22]; // & |fractb[21:0];
 
   always @(posedge clk)
     ind  <=  (expa_ff & infa_f_r); // & (expb_ff & infb_f_r);
 
   always @(posedge clk)
     inf  <=  (expa_ff & infa_f_r); // | (expb_ff & infb_f_r);
 
   always @(posedge clk)
     qnan <=  (expa_ff & qnan_r_a); // | (expb_ff & qnan_r_b);
 
   always @(posedge clk)
     snan <=  (expa_ff & snan_r_a); // | (expb_ff & snan_r_b);
 
   always @(posedge clk)
     opa_nan <=  &expa & (|fracta[22:0]);
 
   always @(posedge clk)
     opb_nan <=  &expb & (|fractb[22:0]);
 
   always @(posedge clk)
     opa_inf <=  (expa_ff & infa_f_r);
 
   always @(posedge clk)
     opb_inf <=  (expb_ff & infb_f_r);
 
   always @(posedge clk)
     expa_00 <=  !(|expa);
 
   always @(posedge clk)
     expb_00 <=  !(|expb);
 
   always @(posedge clk)
     fracta_00 <=  !(|fracta);
 
   always @(posedge clk)
     fractb_00 <=  !(|fractb);
 
   always @(posedge clk)
     opa_00 <=  expa_00 & fracta_00;
 
   always @(posedge clk)
     opb_00 <=  expb_00 & fractb_00;
 
   always @(posedge clk)
     opa_dn <=  expa_00;
 
   always @(posedge clk)
     opb_dn <=  expb_00;
 
endmodule // or1200_fpu_intfloat_conv_except
 
 
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.