blob: 4e4b7c7f6a7a0a33b91d0edfcf6e4620b4c9b2f4 [file] [log] [blame]
// Copyright 2019 ETH Zurich and University of Bologna.
//
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Author: Stefan Mach <smach@iis.ee.ethz.ch>
module fpnew_rounding #(
parameter int unsigned AbsWidth=2 // Width of the abolute value, without sign bit
) (
// Input value
input logic [AbsWidth-1:0] abs_value_i, // absolute value without sign
input logic sign_i,
// Rounding information
input logic [1:0] round_sticky_bits_i, // round and sticky bits {RS}
input fpnew_pkg::roundmode_e rnd_mode_i,
input logic effective_subtraction_i, // sign of inputs affects rounding of zeroes
// Output value
output logic [AbsWidth-1:0] abs_rounded_o, // absolute value without sign
output logic sign_o,
// Output classification
output logic exact_zero_o // output is an exact zero
);
logic round_up; // Rounding decision
// Take the rounding decision according to RISC-V spec
// RoundMode | Mnemonic | Meaning
// :--------:|:--------:|:-------
// 000 | RNE | Round to Nearest, ties to Even
// 001 | RTZ | Round towards Zero
// 010 | RDN | Round Down (towards -\infty)
// 011 | RUP | Round Up (towards \infty)
// 100 | RMM | Round to Nearest, ties to Max Magnitude
// others | | *invalid*
always_comb begin : rounding_decision
unique case (rnd_mode_i)
fpnew_pkg::RNE: // Decide accoring to round/sticky bits
unique case (round_sticky_bits_i)
2'b00,
2'b01: round_up = 1'b0; // < ulp/2 away, round down
2'b10: round_up = abs_value_i[0]; // = ulp/2 away, round towards even result
2'b11: round_up = 1'b1; // > ulp/2 away, round up
//default: round_up = fpnew_pkg::DONT_CARE;
endcase
fpnew_pkg::RTZ: round_up = 1'b0; // always round down
fpnew_pkg::RDN: round_up = (| round_sticky_bits_i) ? sign_i : 1'b0; // to 0 if +, away if -
fpnew_pkg::RUP: round_up = (| round_sticky_bits_i) ? ~sign_i : 1'b0; // to 0 if -, away if +
fpnew_pkg::RMM: round_up = round_sticky_bits_i[1]; // round down if < ulp/2 away, else up
default: round_up = fpnew_pkg::DONT_CARE; // propagate x
endcase
end
// Perform the rounding, exponent change and overflow to inf happens automagically
assign abs_rounded_o = abs_value_i + round_up;
// True zero result is a zero result without dirty round/sticky bits
assign exact_zero_o = (abs_value_i == '0) && (round_sticky_bits_i == '0);
// In case of effective subtraction (thus signs of addition operands must have differed) and a
// true zero result, the result sign is '-' in case of RDN and '+' for other modes.
assign sign_o = (exact_zero_o && effective_subtraction_i)
? (rnd_mode_i == fpnew_pkg::RDN)
: sign_i;
endmodule