mirror of
https://github.com/openhwgroup/cvw
synced 2025-02-11 06:05:49 +00:00
307 lines
15 KiB
Systemverilog
307 lines
15 KiB
Systemverilog
///////////////////////////////////////////
|
|
//
|
|
// Written: me@KatherineParry.com
|
|
// Modified: 7/5/2022
|
|
//
|
|
// Purpose: Rounder
|
|
//
|
|
// A component of the Wally configurable RISC-V project.
|
|
//
|
|
// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University
|
|
//
|
|
// MIT LICENSE
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
|
// software and associated documentation files (the "Software"), to deal in the Software
|
|
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
|
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
|
// to whom the Software is furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in all copies or
|
|
// substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
|
// OR OTHER DEALINGS IN THE SOFTWARE.
|
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
`include "wally-config.vh"
|
|
// what position is XLEN in?
|
|
// options:
|
|
// 1: XLEN > NF > NF1
|
|
// 2: NF > XLEN > NF1
|
|
// 3: NF > NF1 > XLEN
|
|
// single and double will always be smaller than XLEN
|
|
`define XLENPOS ((`XLEN>`NF) ? 1 : (`XLEN>`NF1) ? 2 : 3)
|
|
|
|
module round(
|
|
input logic [`FMTBITS-1:0] OutFmt, // precision 1 = double 0 = single
|
|
input logic [2:0] Frm, // rounding mode
|
|
input logic FmaOp,
|
|
input logic DivOp,
|
|
input logic CvtOp,
|
|
input logic ToInt,
|
|
input logic DivDone,
|
|
input logic [1:0] PostProcSel,
|
|
input logic CvtResDenormUf,
|
|
input logic CvtResUf,
|
|
input logic [`CORRSHIFTSZ-1:0] Mf,
|
|
input logic FmaZmS, // addend's sticky bit
|
|
input logic [`NE+1:0] FmaMe, // exponent of the normalized sum
|
|
input logic Ms, // the result's sign
|
|
input logic [`NE:0] CvtCe, // the calculated expoent
|
|
input logic [`NE+1:0] Qe, // the calculated expoent
|
|
input logic DivS, // sticky bit
|
|
output logic UfPlus1, // do you add or subtract on from the result
|
|
output logic [`NE+1:0] FullRe, // Re with bits to determine sign and overflow
|
|
output logic [`NF-1:0] Rf, // Result fraction
|
|
output logic [`NE-1:0] Re, // Result exponent
|
|
output logic S, // sticky bit
|
|
output logic [`NE+1:0] Me,
|
|
output logic Plus1,
|
|
output logic R, G // bits needed to calculate rounding
|
|
);
|
|
logic UfCalcPlus1;
|
|
logic NormS; // normalized sum's sticky bit
|
|
logic [`NF-1:0] RoundFrac;
|
|
logic FpRes, IntRes;
|
|
logic FpG, FpL, FpR;
|
|
logic L; // lsb of result
|
|
logic CalcPlus1, FpPlus1;
|
|
logic [`FLEN:0] RoundAdd; // how much to add to the result
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Rounding
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// round to nearest even
|
|
// {R, S}
|
|
// 0x - do nothing
|
|
// 10 - tie - Plus1 if result is odd (LSBNormSum = 1)
|
|
// - don't add 1 if a small number was supposed to be subtracted
|
|
// 11 - do nothing if a small number was supposed to subtracted (the sticky bit was set by the small number)
|
|
// - plus 1 otherwise
|
|
|
|
// round to zero - subtract 1 if a small number was supposed to be subtracted from a positive result with guard and round bits of 0
|
|
|
|
// round to -infinity
|
|
// - Plus1 if negative unless a small number was supposed to be subtracted from a result with guard and round bits of 0
|
|
// - subtract 1 if a small number was supposed to be subtracted from a positive result with guard and round bits of 0
|
|
|
|
// round to infinity
|
|
// - Plus1 if positive unless a small number was supposed to be subtracted from a result with guard and round bits of 0
|
|
// - subtract 1 if a small number was supposed to be subtracted from a negative result with guard and round bits of 0
|
|
|
|
// round to nearest max magnitude
|
|
// {Guard, R, S}
|
|
// 0x - do nothing
|
|
// 10 - tie - Plus1
|
|
// - don't add 1 if a small number was supposed to be subtracted
|
|
// 11 - do nothing if a small number was supposed to subtracted (the sticky bit was set by the small number)
|
|
// - Plus 1 otherwise
|
|
|
|
assign IntRes = CvtOp & ToInt;
|
|
assign FpRes = ~IntRes;
|
|
|
|
// sticky bit calculation
|
|
if (`FPSIZES == 1) begin
|
|
|
|
// 1: XLEN > NF
|
|
// | XLEN |
|
|
// | NF |1|1|
|
|
// ^ ^ if floating point result
|
|
// ^ if not an FMA result
|
|
if (`XLENPOS == 1)assign NormS = (|Mf[`CORRSHIFTSZ-`NF-2:`CORRSHIFTSZ-`XLEN-1]&FpRes) |
|
|
(|Mf[`CORRSHIFTSZ-`XLEN-2:0]);
|
|
// 2: NF > XLEN
|
|
if (`XLENPOS == 2)assign NormS = (|Mf[`CORRSHIFTSZ-`XLEN-2:`CORRSHIFTSZ-`NF-1]&IntRes) |
|
|
(|Mf[`CORRSHIFTSZ-`NF-2:0]);
|
|
|
|
end else if (`FPSIZES == 2) begin
|
|
// XLEN is either 64 or 32
|
|
// so half and single are always smaller then XLEN
|
|
|
|
// 1: XLEN > NF > NF1
|
|
if (`XLENPOS == 1) assign NormS = (|Mf[`CORRSHIFTSZ-`NF1-2:`CORRSHIFTSZ-`NF-1]&FpRes&~OutFmt) |
|
|
(|Mf[`CORRSHIFTSZ-`NF-2:`CORRSHIFTSZ-`XLEN-1]&FpRes) |
|
|
(|Mf[`CORRSHIFTSZ-`XLEN-2:0]);
|
|
// 2: NF > XLEN > NF1
|
|
if (`XLENPOS == 2) assign NormS = (|Mf[`CORRSHIFTSZ-`NF1-2:`CORRSHIFTSZ-`XLEN-1]&FpRes&~OutFmt) |
|
|
(|Mf[`CORRSHIFTSZ-`XLEN-2:`CORRSHIFTSZ-`NF-1]&(IntRes|~OutFmt)) |
|
|
(|Mf[`CORRSHIFTSZ-`NF-2:0]);
|
|
// 3: NF > NF1 > XLEN
|
|
if (`XLENPOS == 3) assign NormS = (|Mf[`CORRSHIFTSZ-`XLEN-2:`CORRSHIFTSZ-`NF1-1]&IntRes) |
|
|
(|Mf[`CORRSHIFTSZ-`NF1-2:`CORRSHIFTSZ-`NF-1]&(~OutFmt|IntRes)) |
|
|
(|Mf[`CORRSHIFTSZ-`NF-2:0]);
|
|
|
|
end else if (`FPSIZES == 3) begin
|
|
// 1: XLEN > NF > NF1
|
|
if (`XLENPOS == 1) assign NormS = (|Mf[`CORRSHIFTSZ-`NF2-2:`CORRSHIFTSZ-`NF1-1]&FpRes&(OutFmt==`FMT1)) |
|
|
(|Mf[`CORRSHIFTSZ-`NF1-2:`CORRSHIFTSZ-`NF-1]&FpRes&~(OutFmt==`FMT)) |
|
|
(|Mf[`CORRSHIFTSZ-`NF-2:`CORRSHIFTSZ-`XLEN-1]&FpRes) |
|
|
(|Mf[`CORRSHIFTSZ-`XLEN-2:0]);
|
|
// 2: NF > XLEN > NF1
|
|
if (`XLENPOS == 2) assign NormS = (|Mf[`CORRSHIFTSZ-`NF2-2:`CORRSHIFTSZ-`NF1-1]&FpRes&(OutFmt==`FMT1)) |
|
|
(|Mf[`CORRSHIFTSZ-`NF1-2:`CORRSHIFTSZ-`XLEN-1]&FpRes&~(OutFmt==`FMT)) |
|
|
(|Mf[`CORRSHIFTSZ-`XLEN-2:`CORRSHIFTSZ-`NF-1]&(IntRes|~(OutFmt==`FMT))) |
|
|
(|Mf[`CORRSHIFTSZ-`NF-2:0]);
|
|
// 3: NF > NF1 > XLEN
|
|
if (`XLENPOS == 3) assign NormS = (|Mf[`CORRSHIFTSZ-`NF2-2:`CORRSHIFTSZ-`XLEN-1]&FpRes&(OutFmt==`FMT1)) |
|
|
(|Mf[`CORRSHIFTSZ-`XLEN-2:`CORRSHIFTSZ-`NF1-1]&((OutFmt==`FMT1)|IntRes)) |
|
|
(|Mf[`CORRSHIFTSZ-`NF1-2:`CORRSHIFTSZ-`NF-1]&(~(OutFmt==`FMT)|IntRes)) |
|
|
(|Mf[`CORRSHIFTSZ-`NF-2:0]);
|
|
|
|
end else if (`FPSIZES == 4) begin
|
|
// Quad precision will always be greater than XLEN
|
|
// 2: NF > XLEN > NF1
|
|
if (`XLENPOS == 2) assign NormS = (|Mf[`CORRSHIFTSZ-`H_NF-2:`CORRSHIFTSZ-`S_NF-1]&FpRes&(OutFmt==`H_FMT)) |
|
|
(|Mf[`CORRSHIFTSZ-`S_NF-2:`CORRSHIFTSZ-`D_NF-1]&FpRes&((OutFmt==`S_FMT)|(OutFmt==`H_FMT))) |
|
|
(|Mf[`CORRSHIFTSZ-`D_NF-2:`CORRSHIFTSZ-`XLEN-1]&FpRes&~(OutFmt==`Q_FMT)) |
|
|
(|Mf[`CORRSHIFTSZ-`XLEN-2:`CORRSHIFTSZ-`Q_NF-1]&(~(OutFmt==`Q_FMT)|IntRes)) |
|
|
(|Mf[`CORRSHIFTSZ-`Q_NF-2:0]);
|
|
// 3: NF > NF1 > XLEN
|
|
// The extra XLEN bit will be ored later when caculating the final sticky bit - the ufplus1 not needed for integer
|
|
if (`XLENPOS == 3) assign NormS = (|Mf[`CORRSHIFTSZ-`H_NF-2:`CORRSHIFTSZ-`S_NF-1]&FpRes&(OutFmt==`H_FMT)) |
|
|
(|Mf[`CORRSHIFTSZ-`S_NF-2:`CORRSHIFTSZ-`XLEN-1]&FpRes&((OutFmt==`S_FMT)|(OutFmt==`H_FMT))) |
|
|
(|Mf[`CORRSHIFTSZ-`XLEN-2:`CORRSHIFTSZ-`D_NF-1]&((OutFmt==`S_FMT)|(OutFmt==`H_FMT)|IntRes)) |
|
|
(|Mf[`CORRSHIFTSZ-`D_NF-2:`CORRSHIFTSZ-`Q_NF-1]&(~(OutFmt==`Q_FMT)|IntRes)) |
|
|
(|Mf[`CORRSHIFTSZ-`Q_NF-2:0]);
|
|
|
|
end
|
|
|
|
|
|
|
|
// only add the Addend sticky if doing an FMA opperation
|
|
// - the shifter shifts too far left when there's an underflow (shifting out all possible sticky bits)
|
|
assign S = FmaZmS&FmaOp | NormS | CvtResUf&CvtOp | FmaMe[`NE+1]&FmaOp | DivS&DivOp;
|
|
|
|
// determine round and LSB of the rounded value
|
|
// - underflow round bit is used to determint the underflow flag
|
|
if (`FPSIZES == 1) begin
|
|
assign FpG = Mf[`CORRSHIFTSZ-`NF-1];
|
|
assign FpL = Mf[`CORRSHIFTSZ-`NF];
|
|
assign FpR = Mf[`CORRSHIFTSZ-`NF-2];
|
|
|
|
end else if (`FPSIZES == 2) begin
|
|
assign FpG = OutFmt ? Mf[`CORRSHIFTSZ-`NF-1] : Mf[`CORRSHIFTSZ-`NF1-1];
|
|
assign FpL = OutFmt ? Mf[`CORRSHIFTSZ-`NF] : Mf[`CORRSHIFTSZ-`NF1];
|
|
assign FpR = OutFmt ? Mf[`CORRSHIFTSZ-`NF-2] : Mf[`CORRSHIFTSZ-`NF1-2];
|
|
|
|
end else if (`FPSIZES == 3) begin
|
|
always_comb
|
|
case (OutFmt)
|
|
`FMT: begin
|
|
FpG = Mf[`CORRSHIFTSZ-`NF-1];
|
|
FpL = Mf[`CORRSHIFTSZ-`NF];
|
|
FpR = Mf[`CORRSHIFTSZ-`NF-2];
|
|
end
|
|
`FMT1: begin
|
|
FpG = Mf[`CORRSHIFTSZ-`NF1-1];
|
|
FpL = Mf[`CORRSHIFTSZ-`NF1];
|
|
FpR = Mf[`CORRSHIFTSZ-`NF1-2];
|
|
end
|
|
`FMT2: begin
|
|
FpG = Mf[`CORRSHIFTSZ-`NF2-1];
|
|
FpL = Mf[`CORRSHIFTSZ-`NF2];
|
|
FpR = Mf[`CORRSHIFTSZ-`NF2-2];
|
|
end
|
|
default: begin
|
|
FpG = 1'bx;
|
|
FpL = 1'bx;
|
|
FpR = 1'bx;
|
|
end
|
|
endcase
|
|
end else if (`FPSIZES == 4) begin
|
|
always_comb
|
|
case (OutFmt)
|
|
2'h3: begin
|
|
FpG = Mf[`CORRSHIFTSZ-`Q_NF-1];
|
|
FpL = Mf[`CORRSHIFTSZ-`Q_NF];
|
|
FpR = Mf[`CORRSHIFTSZ-`Q_NF-2];
|
|
end
|
|
2'h1: begin
|
|
FpG = Mf[`CORRSHIFTSZ-`D_NF-1];
|
|
FpL = Mf[`CORRSHIFTSZ-`D_NF];
|
|
FpR = Mf[`CORRSHIFTSZ-`D_NF-2];
|
|
end
|
|
2'h0: begin
|
|
FpG = Mf[`CORRSHIFTSZ-`S_NF-1];
|
|
FpL = Mf[`CORRSHIFTSZ-`S_NF];
|
|
FpR = Mf[`CORRSHIFTSZ-`S_NF-2];
|
|
end
|
|
2'h2: begin
|
|
FpG = Mf[`CORRSHIFTSZ-`H_NF-1];
|
|
FpL = Mf[`CORRSHIFTSZ-`H_NF];
|
|
FpR = Mf[`CORRSHIFTSZ-`H_NF-2];
|
|
end
|
|
endcase
|
|
end
|
|
|
|
assign G = ToInt&CvtOp ? Mf[`CORRSHIFTSZ-`XLEN-1] : FpG;
|
|
assign L = ToInt&CvtOp ? Mf[`CORRSHIFTSZ-`XLEN] : FpL;
|
|
assign R = ToInt&CvtOp ? Mf[`CORRSHIFTSZ-`XLEN-2] : FpR;
|
|
|
|
|
|
always_comb begin
|
|
// Determine if you add 1
|
|
case (Frm)
|
|
3'b000: CalcPlus1 = G & (R|S|L);//round to nearest even
|
|
3'b001: CalcPlus1 = 0;//round to zero
|
|
3'b010: CalcPlus1 = Ms;//round down
|
|
3'b011: CalcPlus1 = ~Ms;//round up
|
|
3'b100: CalcPlus1 = G;//round to nearest max magnitude
|
|
default: CalcPlus1 = 1'bx;
|
|
endcase
|
|
// Determine if you add 1 (for underflow flag)
|
|
case (Frm)
|
|
3'b000: UfCalcPlus1 = R & (S|G);//round to nearest even
|
|
3'b001: UfCalcPlus1 = 0;//round to zero
|
|
3'b010: UfCalcPlus1 = Ms;//round down
|
|
3'b011: UfCalcPlus1 = ~Ms;//round up
|
|
3'b100: UfCalcPlus1 = R;//round to nearest max magnitude
|
|
default: UfCalcPlus1 = 1'bx;
|
|
endcase
|
|
|
|
end
|
|
|
|
// If an answer is exact don't round
|
|
assign Plus1 = CalcPlus1 & (S|R|G);
|
|
assign FpPlus1 = Plus1&~(ToInt&CvtOp);
|
|
assign UfPlus1 = UfCalcPlus1 & (S|R);
|
|
|
|
// Compute rounded result
|
|
if (`FPSIZES == 1) begin
|
|
assign RoundAdd = {{`FLEN{1'b0}}, FpPlus1};
|
|
|
|
end else if (`FPSIZES == 2) begin
|
|
// \/FLEN+1
|
|
// | NE+2 | NF |
|
|
// '-NE+2-^----NF1----^
|
|
// `FLEN+1-`NE-2-`NF1 = FLEN-1-NE-NF1
|
|
assign RoundAdd = {(`NE+1+`NF1)'(0), FpPlus1&~OutFmt, (`NF-`NF1-1)'(0), FpPlus1&OutFmt};
|
|
|
|
end else if (`FPSIZES == 3) begin
|
|
assign RoundAdd = {(`NE+1+`NF2)'(0), FpPlus1&(OutFmt==`FMT2), (`NF1-`NF2-1)'(0), FpPlus1&(OutFmt==`FMT1), (`NF-`NF1-1)'(0), FpPlus1&(OutFmt==`FMT)};
|
|
|
|
end else if (`FPSIZES == 4)
|
|
assign RoundAdd = {(`Q_NE+1+`H_NF)'(0), FpPlus1&(OutFmt==`H_FMT), (`S_NF-`H_NF-1)'(0), FpPlus1&(OutFmt==`S_FMT), (`D_NF-`S_NF-1)'(0), FpPlus1&(OutFmt==`D_FMT), (`Q_NF-`D_NF-1)'(0), FpPlus1&(OutFmt==`Q_FMT)};
|
|
|
|
// determine the result to be roundned
|
|
assign RoundFrac = Mf[`CORRSHIFTSZ-1:`CORRSHIFTSZ-`NF];
|
|
|
|
always_comb
|
|
case(PostProcSel)
|
|
2'b10: Me = FmaMe; // fma
|
|
2'b00: Me = {CvtCe[`NE], CvtCe}&{`NE+2{~CvtResDenormUf|CvtResUf}}; // cvt
|
|
2'b01: Me = DivDone ? Qe : '0; // divide
|
|
default: Me = '0;
|
|
endcase
|
|
|
|
// round the result
|
|
// - if the fraction overflows one should be added to the exponent
|
|
assign {FullRe, Rf} = {Me, RoundFrac} + RoundAdd;
|
|
assign Re = FullRe[`NE-1:0];
|
|
|
|
|
|
endmodule |