URL
https://opencores.org/ocsvn/ft816float/ft816float/trunk
Subversion Repositories ft816float
[/] [ft816float/] [trunk/] [rtl/] [verilog/] [fpRound.v] - Rev 7
Go to most recent revision | Compare with Previous | Blame | View Log
// ============================================================================ // __ // \\__/ o\ (C) 2006-2016 Robert Finch, Stratford // \ __ / All rights reserved. // \/_// robfinch<remove>@finitron.ca // || // // 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 3 of the License, or // (at your option) any later version. // // This source file 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 General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // // fpRound.v // - floating point rounding unit // - parameterized width // - IEEE 754 representation // // This unit takes a normalized floating point number in an // expanded format and rounds it according to the IEEE-754 // standard. NaN's and infinities are not rounded. // This module has a single cycle latency. // // Mode // 0: round to nearest even // 1: round to zero (truncate) // 2: round towards +infinity // 3: round towards -infinity // ============================================================================ // module fpRound(rm, i, o); parameter WID = 32; localparam MSB = WID-1; localparam EMSB = WID==80 ? 14 : WID==64 ? 10 : WID==52 ? 10 : WID==48 ? 10 : WID==44 ? 10 : WID==42 ? 10 : WID==40 ? 9 : WID==32 ? 7 : WID==24 ? 6 : 4; localparam FMSB = WID==80 ? 63 : WID==64 ? 51 : WID==52 ? 39 : WID==48 ? 35 : WID==44 ? 31 : WID==42 ? 29 : WID==40 ? 28 : WID==32 ? 22 : WID==24 ? 15 : 9; input [2:0] rm; // rounding mode input [WID+3:0] i; // intermediate format input output [WID-1:0] o; // rounded output //------------------------------------------------------------ // variables wire so; wire [EMSB:0] xo; reg [FMSB:0] mo; wire [EMSB:0] xo1 = i[EMSB+FMSB+5:FMSB+5]; wire [FMSB+4:0] mo1 = i[FMSB+4:0]; wire xInf = &xo1; wire dn = !(|xo1); // denormalized input assign o = {so,xo,mo}; wire g = i[2]; // guard bit: always the same bit for all operations wire r = i[1]; // rounding bit wire s = i[0]; // sticky bit reg rnd; // Compute the round bit // Infinities and NaNs are not rounded! always @(xInf,rm,g,r,s,so) case ({xInf,rm}) 4'd0: rnd = (g & r) | (r & s); // round to nearest even 4'd1: rnd = 0; // round to zero (truncate) 4'd2: rnd = (r | s) & !so; // round towards +infinity 4'd3: rnd = (r | s) & so; // round towards -infinity default: rnd = 0; // no rounding if exponent indicates infinite or NaN endcase // round the number, check for carry // note: inf. exponent checked above (if the exponent was infinite already, then no rounding occurs as rnd = 0) // note: exponent increments if there is a carry (can only increment to infinity) // performance note: use the carry chain to increment the exponent wire [MSB+2:0] rounded = {xo1,mo1[FMSB+4:2]} + rnd; wire carry = mo1[FMSB+4] & !rounded[FMSB+2]; assign so = i[WID+3]; assign xo = rounded[MSB+2:FMSB+3]; always @(rnd or xo or carry or dn or rounded or mo1) casex({rnd,&xo,carry,dn}) 4'b0xx0: mo = mo1[FMSB+3:3]; // not rounding, not denormalized, => hide MSB 4'b0xx1: mo = mo1[FMSB+4:4]; // not rounding, denormalized 4'b1000: mo = rounded[FMSB+1:1]; // exponent didn't change, number was normalized, => hide MSB 4'b1001: mo = rounded[FMSB+2:2]; // exponent didn't change, but number was denormalized, => retain MSB 4'b1010: mo = rounded[FMSB+2:2]; // exponent incremented (new MSB generated), number was normalized, => hide 'extra (FMSB+2)' MSB 4'b1011: mo = rounded[FMSB+2:2]; // exponent incremented (new MSB generated), number was denormalized, number became normalized, => hide 'extra (FMSB+2)' MSB 4'b11xx: mo = 0; // number became infinite, no need to check carry etc., rnd would be zero if input was NaN or infinite endcase endmodule // Round and register the output module fpRoundReg(clk, ce, rm, i, o); parameter WID = 32; localparam MSB = WID-1; localparam EMSB = WID==80 ? 14 : WID==64 ? 10 : WID==52 ? 10 : WID==48 ? 10 : WID==44 ? 10 : WID==42 ? 10 : WID==40 ? 9 : WID==32 ? 7 : WID==24 ? 6 : 4; localparam FMSB = WID==80 ? 63 : WID==64 ? 51 : WID==52 ? 39 : WID==48 ? 35 : WID==44 ? 31 : WID==42 ? 29 : WID==40 ? 28 : WID==32 ? 22 : WID==24 ? 15 : 9; input clk; input ce; input [1:0] rm; // rounding mode input [WID+2:0] i; // expanded format input output reg [WID-1:0] o; // rounded output wire [WID-1:0] o1; fpRound #(WID) u1 (.rm(rm), .i(i), .o(o1) ); always @(posedge clk) if (ce) o <= o1; endmodule module fpRound_tb(); wire [31:0] o1,o2,o3,o4,o5,o6; fpRound u1 (3'd1, 36'h0, o1); // zero for zero fpRound u2 (3'd1, 36'h444444444, o2); // fpRound u3 (3'd1, 36'h444444444, o3); // endmodule
Go to most recent revision | Compare with Previous | Blame | View Log