Class Methods, Operators, and Data Members - 2023.2 English

Vitis High-Level Synthesis User Guide (UG1399)

Document ID
UG1399
Release Date
2023-12-18
Version
2023.2 English

In general, any valid operation that can be done on a native C/C++ integer data type is supported (using operator overloading) for ap_[u]fixed types. In addition to these overloaded operators, some class specific operators and methods are included to ease bit-level operations.

Binary Arithmetic Operators

Addition

ap_[u]fixed::RType ap_[u]fixed::operator + (ap_[u]fixed op)

Adds an arbitrary precision fixed-point with a given operand op.

The operands can be any of the following integer types:

  • ap_[u]fixed
  • ap_[u]int
  • C/C++

The result type ap_[u]fixed::RType depends on the type information of the two operands.

ap_fixed<76, 63> Result;

ap_fixed<5, 2> Val1 = 1.125;
ap_fixed<75, 62> Val2 = 6721.35595703125;

Result = Val1 + Val2; //Yields 6722.480957

Because Val2 has the larger bit-width on both integer part and fraction part, the result type has the same bit-width and plus one to be able to store all possible result values.

Specifying the data's width controls resources by using the power functions, as shown below. In similar cases, AMD recommends specifying the width of the stored result instead of specifying the width of fixed point operations.

ap_ufixed<16,6> x=5; 
ap_ufixed<16,7>y=hl::rsqrt<16,6>(x+x); 

Subtraction

ap_[u]fixed::RType ap_[u]fixed::operator - (ap_[u]fixed op)

Subtracts an arbitrary precision fixed-point with a given operand op.

The result type ap_[u]fixed::RType depends on the type information of the two operands.

ap_fixed<76, 63> Result;

ap_fixed<5, 2> Val1 = 1625.153;
ap_fixed<75, 62> Val2 = 6721.355992351;

Result = Val2 - Val1; // Yields 6720.23057

Because Val2 has the larger bit-width on both integer part and fraction part, the result type has the same bit-width and plus one to be able to store all possible result values.

Multiplication

ap_[u]fixed::RType ap_[u]fixed::operator * (ap_[u]fixed op)

Multiplies an arbitrary precision fixed-point with a given operand op.

ap_fixed<80, 64> Result;

ap_fixed<5, 2> Val1 = 1625.153;
ap_fixed<75, 62> Val2 = 6721.355992351;

Result = Val1 * Val2; // Yields 7561.525452

This shows the multiplication of Val1 and Val2. The result type is the sum of their integer part bit-width and their fraction part bit width.

Division

ap_[u]fixed::RType ap_[u]fixed::operator / (ap_[u]fixed op)

Divides an arbitrary precision fixed-point by a given operand op.

ap_fixed<84, 66> Result;

ap_fixed<5, 2> Val1 = 1625.153;
ap_fixed<75, 62> Val2 = 6721.355992351;

Val2 / Val1; // Yields 5974.538628

This shows the division of Val2 and Val1. To preserve enough precision:

  • The integer bit-width of the result type is sum of the integer bit-width of Val2 and the fraction bit-width of Val1.
  • The fraction bit-width of the result type is equal to the fraction bit-width of Val2.

Bitwise Logical Operators

Bitwise OR

ap_[u]fixed::RType ap_[u]fixed::operator | (ap_[u]fixed op)

Applies a bitwise operation on an arbitrary precision fixed-point and a given operand op.

ap_fixed<75, 62> Result;

ap_fixed<5, 2> Val1 = 1625.153;
ap_fixed<75, 62> Val2 = 6721.355992351;

Result = Val1 | Val2; // Yields 6271.480957

Bitwise AND

ap_[u]fixed::RType ap_[u]fixed::operator & (ap_[u]fixed op)

Applies a bitwise operation on an arbitrary precision fixed-point and a given operand op.

ap_fixed<75, 62> Result;

ap_fixed<5, 2> Val1 = 1625.153;
ap_fixed<75, 62> Val2 = 6721.355992351;

Result = Val1 & Val2;  // Yields 1.00000

Bitwise XOR

ap_[u]fixed::RType ap_[u]fixed::operator ^ (ap_[u]fixed op)

Applies an xor bitwise operation on an arbitrary precision fixed-point and a given operand op.

ap_fixed<75, 62> Result;

ap_fixed<5, 2> Val1 = 1625.153;
ap_fixed<75, 62> Val2 = 6721.355992351;

Result = Val1 ^ Val2; // Yields 6720.480957

Increment and Decrement Operators

Pre-Increment

ap_[u]fixed ap_[u]fixed::operator ++ ()

This operator function prefix increases an arbitrary precision fixed-point variable by 1.

ap_fixed<25, 8> Result;
ap_fixed<8, 5> Val1 = 5.125;

Result = ++Val1; // Yields 6.125000

Post-Increment

ap_[u]fixed ap_[u]fixed::operator ++ (int)

This operator function postfix:

  • Increases an arbitrary precision fixed-point variable by 1.
  • Returns the original val of this arbitrary precision fixed-point.
    ap_fixed<25, 8> Result;
    ap_fixed<8, 5> Val1 = 5.125;
    
    Result = Val1++; // Yields 5.125000

Pre-Decrement

ap_[u]fixed ap_[u]fixed::operator -- ()

This operator function prefix decreases this arbitrary precision fixed-point variable by 1.

ap_fixed<25, 8> Result;
ap_fixed<8, 5> Val1 = 5.125;

Result = --Val1; // Yields 4.125000

Post-Decrement

ap_[u]fixed ap_[u]fixed::operator -- (int)

This operator function postfix:

  • Decreases this arbitrary precision fixed-point variable by 1.
  • Returns the original val of this arbitrary precision fixed-point.
    ap_fixed<25, 8> Result;
    ap_fixed<8, 5> Val1 = 5.125;
    
    Result = Val1--; // Yields 5.125000

Unary Operators

Addition

ap_[u]fixed ap_[u]fixed::operator + ()

Returns a self copy of an arbitrary precision fixed-point variable.

ap_fixed<25, 8> Result;
ap_fixed<8, 5> Val1 = 5.125;

Result = +Val1;  // Yields 5.125000

Subtraction

ap_[u]fixed::RType ap_[u]fixed::operator - ()

Returns a negative value of an arbitrary precision fixed-point variable.

ap_fixed<25, 8> Result;
ap_fixed<8, 5> Val1 = 5.125;

Result = -Val1; // Yields -5.125000

Equality Zero

bool ap_[u]fixed::operator ! ()

This operator function:

  • Compares an arbitrary precision fixed-point variable with 0,
  • Returns the result.
    bool  Result;
    ap_fixed<8, 5> Val1 = 5.125;
    
    Result = !Val1; // Yields false

Bitwise Inverse

ap_[u]fixed::RType ap_[u]fixed::operator ~ ()

Returns a bitwise complement of an arbitrary precision fixed-point variable.

ap_fixed<25, 15> Result;
ap_fixed<8, 5> Val1 = 5.125;

Result = ~Val1; // Yields -5.25

Shift Operators

Unsigned Shift Left

ap_[u]fixed ap_[u]fixed::operator << (ap_uint<_W2> op) 

This operator function:

  • Shifts left by a given integer operand.
  • Returns the result.

The operand can be a C/C++ integer type:

  • char
  • short
  • int
  • long

The return type of the shift left operation is the same width as the type being shifted.

Note: Shift does not support overflow or quantization modes.
ap_fixed<25, 15> Result;
ap_fixed<8, 5> Val = 5.375;

ap_uint<4> sh = 2;

Result = Val << sh; // Yields -10.5

The bit-width of the result is (W = 25, I = 15). Because the shift left operation result type is same as the type of Val:

  • The high order two bits of Val are shifted out.
  • The result is -10.5.

If a result of 21.5 is required, Val must be cast to ap_fixed<10, 7> first -- for example, ap_ufixed<10, 7>(Val).

Signed Shift Left

ap_[u]fixed ap_[u]fixed::operator << (ap_int<_W2> op)

This operator:

  • Shifts left by a given integer operand.
  • Returns the result.

The shift direction depends on whether the operand is positive or negative.

  • If the operand is positive, a shift right is performed.
  • If the operand is negative, a shift left (opposite direction) is performed.

The operand can be a C/C++ integer type:

  • char
  • short
  • int
  • long

The return type of the shift right operation is the same width as the type being shifted.

ap_fixed<25, 15,  false> Result;
ap_uint<8, 5> Val = 5.375;

ap_int<4> Sh = 2;
Result = Val << sh; // Shift left, yields -10.25

Sh = -2;
Result = Val << sh; // Shift right, yields 1.25

Unsigned Shift Right

ap_[u]fixed ap_[u]fixed::operator >> (ap_uint<_W2> op) 

This operator function:

  • Shifts right by a given integer operand.
  • Returns the result.

The operand can be a C/C++ integer type:

  • char
  • short
  • int
  • long

The return type of the shift right operation is the same width as the type being shifted.

ap_fixed<25, 15> Result;
ap_fixed<8, 5> Val = 5.375;

ap_uint<4> sh = 2;

Result = Val >> sh; // Yields 1.25

If it is necessary to preserve all significant bits, extend fraction part bit-width of the Val first, for example ap_fixed<10, 5>(Val).

Signed Shift Right

ap_[u]fixed ap_[u]fixed::operator >> (ap_int<_W2> op) 

This operator:

  • Shifts right by a given integer operand.
  • Returns the result.

The shift direction depends on whether operand is positive or negative.

  • If the operand is positive, a shift right performed.
  • If operand is negative, a shift left (opposite direction) is performed.

The operand can be a C/C++ integer type (char, short, int, or long).

The return type of the shift right operation is the same width as type being shifted. For example:

ap_fixed<25, 15,  false> Result;
ap_uint<8, 5> Val = 5.375;

ap_int<4> Sh = 2;
Result = Val >> sh; // Shift right, yields 1.25

Sh = -2;
Result = Val >> sh; // Shift left,  yields -10.5

1.25

Relational Operators

Equality

bool ap_[u]fixed::operator == (ap_[u]fixed op)

This operator compares the arbitrary precision fixed-point variable with a given operand.

Returns true if they are equal and false if they are not equal.

The type of operand op can be ap_[u]fixed, ap_int or C/C++ integer types. For example:

bool Result;

ap_ufixed<8, 5> Val1 = 1.25;
ap_fixed<9, 4> Val2 = 17.25;
ap_fixed<10, 5> Val3 = 3.25;

Result = Val1 == Val2; // Yields  true
Result = Val1 == Val3; // Yields  false

Inequality

bool ap_[u]fixed::operator != (ap_[u]fixed op)

This operator compares this arbitrary precision fixed-point variable with a given operand.

Returns true if they are not equal and false if they are equal.

The type of operand op can be:

  • ap_[u]fixed
  • ap_int
  • C or C++ integer types

For example:

bool Result;

ap_ufixed<8, 5> Val1 = 1.25;
ap_fixed<9, 4> Val2 = 17.25;
ap_fixed<10, 5> Val3 = 3.25;

Result = Val1 != Val2; // Yields false
Result = Val1 != Val3; // Yields true

Greater than or equal to

bool ap_[u]fixed::operator >= (ap_[u]fixed op)

This operator compares a variable with a given operand.

Returns true if they are equal or if the variable is greater than the operator and false otherwise.

The type of operand op can be ap_[u]fixed, ap_int or C/C++ integer types.

For example:

bool Result;

ap_ufixed<8, 5> Val1 = 1.25;
ap_fixed<9, 4> Val2 = 17.25;
ap_fixed<10, 5> Val3 = 3.25;

Result = Val1 >= Val2; // Yields true
Result = Val1 >= Val3; // Yields false

Less than or equal to

bool ap_[u]fixed::operator <= (ap_[u]fixed op)

This operator compares a variable with a given operand, and return true if it is equal to or less than the operand and false if not.

The type of operand op can be ap_[u]fixed, ap_int or C/C++ integer types.

For example:

bool Result;

ap_ufixed<8, 5> Val1 = 1.25;
ap_fixed<9, 4> Val2 = 17.25;
ap_fixed<10, 5> Val3 = 3.25;

Result = Val1 <= Val2; // Yields true
Result = Val1 <= Val3; // Yields true

Greater than

bool ap_[u]fixed::operator > (ap_[u]fixed op)

This operator compares a variable with a given operand, and return true if it is greater than the operand and false if not.

The type of operand op can be ap_[u]fixed, ap_int, or C/C++ integer types.

For example:

bool Result;

ap_ufixed<8, 5> Val1 = 1.25;
ap_fixed<9, 4> Val2 = 17.25;
ap_fixed<10, 5> Val3 = 3.25;

Result = Val1 > Val2; // Yields false
Result = Val1 > Val3; // Yields false

Less than

bool ap_[u]fixed::operator < (ap_[u]fixed op)

This operator compares a variable with a given operand, and return true if it is less than the operand and false if not.

The type of operand op can be ap_[u]fixed, ap_int, or C/C++ integer types. For example:

bool Result;

ap_ufixed<8, 5> Val1 = 1.25;
ap_fixed<9, 4> Val2 = 17.25;
ap_fixed<10, 5> Val3 = 3.25;

Result = Val1 < Val2; // Yields false
Result = Val1 < Val3; // Yields true

Bit Operator

Bit-Select and Set

af_bit_ref ap_[u]fixed::operator [] (int bit) 

This operator selects one bit from an arbitrary precision fixed-point value and returns it.

The returned value is a reference value that can set or clear the corresponding bit in the ap_[u]fixed variable. The bit argument must be an integer value and it specifies the index of the bit to select. The least significant bit has index 0. The highest permissible index is one less than the bit-width of this ap_[u]fixed variable.

The result type is af_bit_ref with a value of either 0 or 1. For example:

ap_int<8, 5> Value = 1.375;

Value[3]; // Yields  1
Value[4]; // Yields  0

Value[2] = 1; // Yields 1.875
Value[3] = 0; // Yields 0.875

Bit Range

af_range_ref af_(u)fixed::range (unsigned Hi, unsigned Lo)
af_range_ref af_(u)fixed::operator [] (unsigned Hi, unsigned Lo) 

This operation is similar to bit-select operator [] except that it operates on a range of bits instead of a single bit.

It selects a group of bits from the arbitrary precision fixed-point variable. The Hi argument provides the upper range of bits to be selected. The Lo argument provides the lowest bit to be selected. If Lo is larger than Hi the bits selected are returned in the reverse order.

The return type af_range_ref represents a reference in the range of the ap_[u]fixed variable specified by Hi and Lo. For example:

ap_uint<4> Result = 0;
ap_ufixed<4, 2> Value = 1.25;
ap_uint<8> Repl = 0xAA;

Result = Value.range(3, 0); // Yields: 0x5
Value(3, 0) = Repl(3, 0); // Yields: -1.5

// when Lo > Hi, return the reverse bits string
Result = Value.range(0, 3); // Yields: 0xA

Range Select

af_range_ref af_(u)fixed::range ()
af_range_ref af_(u)fixed::operator []

This operation is the special case of the range select operator []. It selects all bits from this arbitrary precision fixed-point value in the normal order.

The return type af_range_ref represents a reference to the range specified by Hi = W - 1 and Lo = 0. For example:

ap_uint<4> Result = 0;

ap_ufixed<4, 2> Value = 1.25;
ap_uint<8> Repl = 0xAA;

Result = Value.range(); // Yields: 0x5
Value() = Repl(3, 0); // Yields: -1.5

Length

int ap_[u]fixed::length ()

This function returns an integer value that provides the number of bits in an arbitrary precision fixed-point value. It can be used with a type or a value. For example:

ap_ufixed<128, 64> My128APFixed;

int bitwidth = My128APFixed.length(); // Yields 128

Explicit Conversion Methods

Fixed to Double

double ap_[u]fixed::to_double ()

This member function returns this fixed-point value in form of IEEE double precision format. For example:

ap_ufixed<256, 77> MyAPFixed = 333.789;
double Result;

Result = MyAPFixed.to_double(); // Yields 333.789

Fixed to Float

float ap_[u]fixed::to_float()

This member function returns this fixed-point value in form of IEEE float precision format. For example:

ap_ufixed<256, 77> MyAPFixed = 333.789;
float Result;

Result = MyAPFixed.to_float();  // Yields 333.789

Fixed to Half-Precision Floating Point

half ap_[u]fixed::to_half()

This member function return this fixed-point value in form of HLS half-precision (16-bit) float precision format. For example:

ap_ufixed<256, 77> MyAPFixed = 333.789;
half Result;

Result = MyAPFixed.to_half();  // Yields 333.789

Fixed to ap_int

ap_int ap_[u]fixed::to_ap_int ()

This member function explicitly converts this fixed-point value to ap_int that captures all integer bits (fraction bits are truncated). For example:

ap_ufixed<256, 77> MyAPFixed = 333.789;
ap_uint<77> Result;

Result = MyAPFixed.to_ap_int(); //Yields 333

Fixed to Integer

int ap_[u]fixed::to_int ()
unsigned ap_[u]fixed::to_uint ()
ap_slong ap_[u]fixed::to_int64 ()
ap_ulong ap_[u]fixed::to_uint64 ()

This member function explicitly converts this fixed-point value to C built-in integer types. For example:

ap_ufixed<256, 77> MyAPFixed = 333.789;
unsigned int  Result;

Result = MyAPFixed.to_uint(); //Yields 333

unsigned long long Result;
Result = MyAPFixed.to_uint64(); //Yields 333

Compile Time Access to Data Type Attributes

The ap_[u]fixed<> types are provided with several static members that allow the size and configuration of data types to be determined at compile time. The data type is provided with the static const members: width, iwidth, qmode and omode:

static const int width = _AP_W;
static const int iwidth = _AP_I;
static const ap_q_mode qmode = _AP_Q;
static const ap_o_mode omode = _AP_O;

You can use these data members to extract the following information from any existing ap_[u]fixed<> data type:

width
The width of the data type.
iwidth
The width of the integer part of the data type.
qmode
The quantization mode of the data type.
omode
The overflow mode of the data type.

For example, you can use these data members to extract the data width of an existing ap_[u]fixed<> data type to create another ap_[u]fixed<> data type at compile time.

The following example shows how the size of variable Res is automatically defined as 1-bit greater than variables Val1 and Val2 with the same quantization modes:

// Definition of basic data type
#define INPUT_DATA_WIDTH 12
#define IN_INTG_WIDTH 6
#define IN_QMODE AP_RND_ZERO
#define IN_OMODE AP_WRAP
typedef ap_fixed<INPUT_DATA_WIDTH, IN_INTG_WIDTH, IN_QMODE, IN_OMODE> data_t;
// Definition of variables 
data_t Val1, Val2;
// Res is automatically sized at run-time to be 1-bit greater than INPUT_DATA_WIDTH 
// The bit growth in Res will be in the integer bits
ap_int<data_t::width+1, data_t::iwidth+1, data_t::qmode, data_t::omode> Res = Val1 + 
Val2;

This ensures that Vitis HLS correctly models the bit-growth caused by the addition even if you update the value of INPUT_DATA_WIDTH, IN_INTG_WIDTH, or the quantization modes for data_t.