1 /*
2  * SPDX-FileCopyrightText: <text>Copyright 2010-2020, 2022, 2024 Arm Limited and/or its affiliates
3  * <open-source-office@arm.com></text>
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  *
7  * Licensed under the Apache License, Version 2.0 (the License); you may
8  * not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an AS IS BASIS, WITHOUT
15  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 
20 /* ----------------------------------------------------------------------
21  * Project:      CMSIS NN Library
22  * Title:        arm_nn_activation_s16.c
23  * Description:  Q15 neural network activation function using direct table look-up
24  *
25  * $Date:        19 January 2024
26  * $Revision:    V.2.0.0
27  *
28  * Target Processor:  Cortex-M cores
29  *
30  * -------------------------------------------------------------------- */
31 
32 #include "arm_nn_tables.h"
33 #include "arm_nnfunctions.h"
34 
35 /**
36  *  @ingroup groupNN
37  */
38 
39 /**
40  * @addtogroup Acti
41  * @{
42  */
43 
44 /*
45  * @brief Neural network activation function using direct table look-up
46  *
47  * @note  Refer header file for details.
48  *
49  */
50 
arm_nn_activation_s16(const int16_t * input,int16_t * output,const int32_t size,const int32_t left_shift,const arm_nn_activation_type type)51 arm_cmsis_nn_status arm_nn_activation_s16(const int16_t *input,
52                                           int16_t *output,
53                                           const int32_t size,
54                                           const int32_t left_shift,
55                                           const arm_nn_activation_type type)
56 {
57     uint32_t abs_input_shift, max_saturation;
58     switch (type)
59     {
60     case ARM_SIGMOID:
61         abs_input_shift = 9;
62         max_saturation = 0x7FFF << 10;
63         break;
64     case ARM_TANH:
65     default:
66         abs_input_shift = 8;
67         max_saturation = 0xFFFF << 8;
68         break;
69     }
70 
71     const int32_t input_multiplier = (left_shift < 0) ? 3 : 3 << left_shift;
72     const int32_t abs_left_shift = (left_shift < 0) ? -left_shift : 0;
73     const int32_t rounding = (abs_left_shift > 0) ? 1 << (abs_left_shift - 1) : 0;
74     // Use the LUT for sigmoid and take into account, that
75     // tanh(x) = 2*sigmoid(2*x) - 1
76 
77     for (int i = 0; i < size; ++i, input++, output++)
78     {
79         const int32_t input_data = ((*input) * input_multiplier + rounding) >> abs_left_shift;
80         const uint32_t abs_input_data = input_data > 0 ? input_data : -input_data;
81         const uint32_t uh = abs_input_data >> abs_input_shift;
82         uint32_t result;
83 
84         if (uh >= 255)
85         {
86             result = max_saturation;
87         }
88         else
89         {
90             const uint32_t ua = sigmoid_table_uint16[uh];
91             const uint32_t ub = sigmoid_table_uint16[uh + 1];
92             uint32_t ut;
93             if (type == ARM_SIGMOID)
94             {
95                 ut = abs_input_data & 0x1ff;
96             }
97             else
98             {
99                 ut = abs_input_data & 0x0ff;
100             }
101             result = (ua << abs_input_shift) + ut * (ub - ua);
102         }
103         if (type == ARM_SIGMOID)
104         {
105             result = (input_data >= 0) ? (result + (1 << 9)) : ((1 << 25) - result + (1 << 9) - 1);
106             result >>= 10;
107         }
108         else
109         {
110             result = (input_data >= 0) ? (result - (1 << 23)) + (1 << 7) : ((-result + (1 << 23)) + (1 << 7) - 1);
111             result >>= 8;
112         }
113         *output = (int16_t)result;
114     }
115 
116     return ARM_CMSIS_NN_SUCCESS;
117 }
118 
119 /**
120  * @} end of Acti group
121  */
122