//
// This confidential and proprietary software may be used only as
// authorised by a licensing agreement from ARM Limited
// (C) COPYRIGHT 2021 ARM Limited
// ALL RIGHTS RESERVED
// The entire notice above must be reproduced on all authorised
// copies and copies may only be made to the extent permitted
// by a licensing agreement from ARM Limited.

== TOSA Pseudocode

The TOSA pseudocode provides precise descriptions of TOSA operations.
Each operator contains pseudocode describing the operator's functionality.
This section contains pseudocode functions shared across multiple operators in the specification.

=== Operator Validation Helpers


The following functions are used to define the valid conditions for TOSA operators.
The REQUIRE function defines the conditions required by the TOSA operator.
When a call to unpredictable() is made, processing defined in the pseudocode for this operator may or may not be executed.
Once unpredictable is called, the whole TOSA graph is considered unpredictable, even if the unpredictable result does not propagate to the graph output.

[source,c++]
----
void unpredictable() {
    // Behavior of this TOSA operator cannot be relied on if this is called.
    tosa_graph_result_unpredictable = true;
}

void REQUIRE(condition) {
    if (not condition) {
        unpredictable();
    }
}
----

=== General Pseudocode Helpers

This section contains general pseudocode utility functions used throughout the specification.

The following functions provide basic arithmetic while defining requirements such that values stay in the valid range.

[source,c++]
----
acc_t apply_add<acc_t>(acc_t a, acc_t b) {
    if (acc_t == float_t) return a + b;
    int64_t c = (int64_t)a + (int64_t)b;
    REQUIRE(c >= minimum<acc_t> && c <= maximum<acc_t>);
    return (acc_t)c;
}

acc_t apply_sub<acc_t>(acc_t a, acc_t b) {
    if (acc_t == float_t) return a - b;
    int64_t c = (int64_t)a - (int64_t)b;
    REQUIRE(c >= minimum<acc_t> && c <= maximum<acc_t>);
    return (acc_t)c;
}
----

The following functions are used in the pseudocode to take maximum,
minimum, clip values to a range, or count leading zeros.
[[count_leading_zeros]]
[source,c++]
----
<type> apply_max<type>(<type> a, <type> b) {
    if (a >= b) return a; else return b;
}

<type> apply_min<type>(<type> a, <type> b) {
    if (a < b) return a; else return b;
}

<type> apply_clip<type>(<type> value, <type> min_val, <type> max_val) {
    REQUIRE(min_val <= max_val);
    value = apply_max(value, min_val);
    value = apply_min(value, max_val);
    return value;
}

int32_t count_leading_zeros(int32_t a) {
    int32_t acc = 32;
    if (a != 0) {
        uint32_t mask;
        mask = 1 << (32 - 1); // width of int32_t - 1
        acc = 0;
        while ((mask & a) == 0) {
            mask = mask >> 1;
            acc = acc + 1;
        }
    }
    return acc;
}
----

The following definitions are used in pseudocode to do numeric conversions.

[source,c++]
----
int round_to_nearest_int(float_t f)
  Converts the floating-point value to f, with rounding to the nearest integer value.

float_t round_to_nearest_float(in_t f)
  Converts the input value into floating-point, rounding to the nearest representable value.
  The behavior for ties is implementation dependent.

out_t sign_extend(in_t input)
  Only valid for twos complement integer values where out_t has more bits than in_t.
  Output = input
  Replicate the top bit of input for all bits between the top bit of input and the top bit of output.

out_t truncate(in_t input)
  output is the sizeof(out_t) least significant bits in input.
----

The following definition is used to flatten a list of lists into a single list

[source,c++]
----
in_t* flatten(in_t lists[]) {
    in_t output = [];
    for_each(list in lists) {
        for_each(element in list) {
            output.append(element);
        }
    }
}
----
