Half-Up Rounder (rounding_halfup)

Half-up rounding and truncation for a variable-width signed input.

Design

The processing of the input stream is dependent on the value of binary_point.

The process is as follows:

  • A ‘0’ bit is appended after the least significant bit. This allows the rounding operation to be performed when binary_point \(= 0\).

  • A sign appropriate bit is prepended before the most significant bit. This prevents the rounding operation from overflowing.

  • A value of 1 (effectively adding 0.5) is added to the input before rounding.

  • The result is then truncated by right-shifting by binary_point. This causes any fractional value above 0.5 to round up and values below 0.5 to round down.

  • Finally, the most-significant bits of the input data are discarded down to the output width.

The mathematical representation of the implementation (assuming that the discarding of the most significant bits will not affect the value) is given in (130).

(130)\[y[n] = \left \lfloor \frac{\left \lfloor \frac{2 * x[n]}{2^{binary\_point}} \right \rfloor + 1.0}{2} \right \rfloor\]

In (130):

  • \(y[n]\) is the output values.

  • \(x[n]\) is the input values.

To prevent overflow when discarding down to the output width, saturation can be enabled. This will set the output to either the maximum or minimum value possible for the output width if the rounded value can’t be expressed within the output’s width.

Implementation

The primitive is pipelined so that a new sample can be inserted into the primitive on every rising edge of clk. The data_valid_in signal allows each input sample to be marked as valid or not. The pipeline advances every rising edge of clk regardless of if valid data is passed to the primitive or not. The data_valid_out signal is a delayed version of data_valid_in that indicates which outputs were calculated based on valid inputs.

The clk_en signal provides a clock enable for the primitive. When set low no data will enter or leave the primitive and all calculations are stopped. When set high the module will operate normally.

The data and valid can be delayed by 1 to 4 clock cycles based on the registers_g generic. Increasing the value improves timing closure by adding registers in the positions shown in the table below, refer to the HDL for further clarification. Note, multiple registers may be added in the same position to keep the latency the same between all rounding primitives.

registers_g

Register location

\(\geq 1\)

Output

\(\geq 2\)

Between binary point alignment and rounding

\(\geq 3\)

Input

4

Between rounding and saturation

Interface

Generics

  • input_width_g (integer): Sets width of data_in signal.

  • output_width_g (integer): Sets width of data_out signal.

  • saturation_en_g (boolean): Enables saturation on data when rounding and/or truncation to a reduced output resolution has caused an overflow.

  • registers_g (positive): Enable between 1 to 4 register stages in the data and valid paths.

Ports

  • clk (std_logic), in: Clock. Inputs and outputs registered on rising edge.

  • reset (std_logic), in: Reset. Active high, synchronous with rising edge of clock.

  • clk_en (std_logic), in: Clock Enable. If low the module will not operate.

  • data_in (signed, input_width_g bits), in: Input value for primitive.

  • data_valid_in (std_logic), in: data_in is valid when data_valid_in is high.

  • binary_point (integer), in: Number of fractional bits in the least significant bits of the data_in signal.

  • data_out (signed, output_width_g bits), out: Output value for primitive.

  • data_valid_out (std_logic), out: data_out is valid when data_valid_out is high.

Dependencies

The dependencies to other elements in OpenCPI are:

  • None.

There is also a dependency on:

  • ieee.std_logic_1164

  • ieee.numeric_std

Limitations

Limitations of rounding_halfup are:

  • A small positive bias will be introduced when using this primitive.

  • If this causes an issue convergent rounding may be used instead using the Half Even Rounder Primitive.