Files
kernels/hw/rtl/fpu/VX_fpu_rounding.sv
Blaise Tine a08d3ebd42 minor update
2023-11-12 23:40:59 -08:00

79 lines
3.5 KiB
Systemverilog

// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the 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.
`include "VX_fpu_define.vh"
`ifdef FPU_DSP
/// Modified port of rouding module from fpnew Libray
/// reference: https://github.com/pulp-platform/fpnew
module VX_fpu_rounding #(
parameter DAT_WIDTH = 2 // Width of the abolute value, without sign bit
) (
// inputs
input wire [DAT_WIDTH-1:0] abs_value_i, // absolute value without sign
input wire sign_i,
// rounding information
input wire [1:0] round_sticky_bits_i, // round and sticky bits {RS}
input wire [2:0] rnd_mode_i,
input wire effective_subtraction_i, // sign of inputs affects rounding of zeroes
// outputs
output wire [DAT_WIDTH-1:0] abs_rounded_o, // absolute value without sign
output wire sign_o,
output wire exact_zero_o // output is an exact zero
);
reg 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 @(*) begin
case (rnd_mode_i)
`INST_FRM_RNE: // Decide accoring to round/sticky bits
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
endcase
`INST_FRM_RTZ: round_up = 1'b0; // always round down
`INST_FRM_RDN: round_up = (| round_sticky_bits_i) & sign_i; // to 0 if +, away if -
`INST_FRM_RUP: round_up = (| round_sticky_bits_i) & ~sign_i; // to 0 if -, away if +
`INST_FRM_RMM: round_up = round_sticky_bits_i[1]; // round down if < ulp/2 away, else up
default: round_up = 1'bx; // propagate x
endcase
end
// Perform the rounding, exponent change and overflow to inf happens automagically
assign abs_rounded_o = abs_value_i + DAT_WIDTH'(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 == `INST_FRM_RDN)
: sign_i;
endmodule
`endif