module SP_FPU (BCLK, START, OPCODE, SRC1, SRC2, FSR, MRESULT, BWD, FL, FP_OUT, I_OUT, TT_SP, SP_CMP, SP_MUX, LD_FSR, UP_SP);

	input			BCLK;		// is not used !
	input			START;
	input	 [7:0]	OPCODE;	
	input	[31:0]	SRC1,SRC2;	// Input data
	input	 [8:3]	FSR;		// Floating Point Status Register
	input	[47:0]	MRESULT;	// Multiplier result
	input	 [1:0]	BWD;		// Size of integer
	input			FL;

	output	[31:0]	FP_OUT,I_OUT;	// The results
	output	 [4:0]	TT_SP;		// Trap-Type
	output	 [2:0]	SP_CMP;		// CMPF result
	output			SP_MUX,LD_FSR;
	output	reg		UP_SP;

	reg		 [2:0]	tt;
	reg		 [3:0]	select;
	reg				nan;
	reg				car_ry;

	wire	[36:0]	mulout,addout,fpout;
	wire	 [2:1]	nzexp;
	wire	[34:2]	rund;		// Indexnumbers like xxxout
	wire			overflow,underflow,inexact;
	wire			op_cmp;
	wire			nan_1,nan_2;
	
	// Control of datapath 

	always @(OPCODE)
		casex (OPCODE)
		  8'b1011_0000 : select = 4'b1000;	// 0 0 0 :	ADDF	Shifter are reused
		  8'b1011_0100 : select = 4'b1001;	// 0 0 1 :	SUBF
		  8'b1001_000x : select = 4'b1010;	// 0 1 0 :	MOViF
		  8'b1001_100x : select = 4'b1011;	// 0 1 1 :	ROUNDFi
		  8'b1001_101x : select = 4'b1011;	// 0 1 1 :	TRUNCFi
		  8'b1001_111x : select = 4'b1011;	// 0 1 1 :	FLOORFi
		  8'b1011_0010 : select = 4'b1001;	// 0 0 1 :	CMPF
		  8'b1011_1100 : select = 4'b1100;	// 1 x x :	MULF
		  default      : select = 4'b0;
		endcase

	assign SP_MUX = select[3] & (select[1:0] != 2'b11) & FL;	// Output multiplexer
	
	assign LD_FSR = (OPCODE[7:4] == 4'h9) & (OPCODE[3:1] == 3'b001);	// LFSR does only Double (according datasheet NS32016)
	always @(posedge BCLK) UP_SP = select[3] & FL & START;				// All FPU opcodes of SP_FPU, all are using 2 Clock
	assign op_cmp = (OPCODE == 8'hB2) & FL;
	
	// SRCFLAGS
	
	assign nzexp[2]	= (SRC2[30:23] != 8'd0);		// only exponent 0 ,denormalized Number => NAN !
	assign nzexp[1] = (SRC1[30:23] != 8'd0);		// only exponent 0 ,denormalized Number => NAN !
	assign nan_2 	= (SRC2[30:23] == 8'hFF) | (~nzexp[2] & (SRC2[22:0] != 23'd0));	// NAN
	assign nan_1 	= (SRC1[30:23] == 8'hFF) | (~nzexp[1] & (SRC1[22:0] != 23'd0));	// NAN

	always @(posedge BCLK) nan <= (select[1:0] == 2'b11) ? nan_1 : (~select[1] & (nan_2 | nan_1));
	
	// 001 : ADDF,... + 011 : CMPF
	SFPU_ADDSUB IADDSUB	( .BCLK(BCLK), .SRC1(SRC1), .SRC2(SRC2), .NZEXP(nzexp), .BWD(BWD),
						  .SELECT({OPCODE[2:1],select[1:0]}), .OUT(addout), .IOUT(I_OUT), .CMPRES(SP_CMP[1:0]) );
					
	// 100 : MULF
	SFPU_MUL IMUL ( .BCLK(BCLK), .SRC1(SRC1), .SRC2(SRC2), .MRESULT(MRESULT), .OUT(mulout), .NZEXP(nzexp) );
					
	// FP - Pfad : selection of result and rounding :

	assign fpout = (OPCODE[5] & OPCODE[3]) ? mulout : addout;
	
	always @(FSR or fpout)	// calculate Carry according rounding mode, fpout[35] = sign bit
		casex (FSR[8:7])
		  2'b00 : car_ry = ((fpout[1:0] == 2'b10) & fpout[2]) | (fpout[1:0] == 2'b11);	// round to nearest
		  2'b10 : car_ry = ~fpout[35] & (fpout[1:0] != 2'b00);	// round to positiv infinity
		  2'b11 : car_ry =  fpout[35] & (fpout[1:0] != 2'b00);	// round to negativ infinity
		default : car_ry = 1'b0;								// round to zero
		endcase

	assign rund = {fpout[34:2]} + {32'h0,car_ry};
	
	// Detection of Overflow, Underflow and Inexact : epxonent is [34:25] = 10 Bits
	assign overflow  = ~rund[34] & (rund[33] | (rund[32:25] == 8'hFF));
	assign underflow = (rund[34] | (rund[33:25] == 9'h0)) & ~fpout[36];	// Zero-Flag
	assign inexact   = (fpout[1:0] != 2'b00);
	
	// CMPF can have no other error except NAN 
	always @(nan or op_cmp or overflow or underflow or inexact or FSR)
		casex ({nan,op_cmp,overflow,FSR[3],underflow,FSR[5],inexact})
			7'b1xxxxxx : tt = 3'b101;	// Invalid operation
			7'b001xxxx : tt = 3'b010;	// Overflow
			7'b00011xx : tt = 3'b001;	// Underflow
			7'b0000011 : tt = 3'b110;	// Inexact Result
			default	   : tt = 3'b000;	// no error
		endcase

	assign TT_SP = {(inexact & ~op_cmp),(underflow & ~op_cmp),tt};
	assign SP_CMP[2] = nan;	
	
	// Underflow Special case and force ZERO 
	assign FP_OUT = (underflow | fpout[36]) ? 32'd0 : {fpout[35],rund[32:2]};
	
endmodule