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