Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2012-15 Advanced Micro Devices, Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  * Authors: AMD
0023  *
0024  */
0025 
0026 #include "dm_services.h"
0027 #include "conversion.h"
0028 
0029 #define DIVIDER 10000
0030 
0031 /* S2D13 value in [-3.00...0.9999] */
0032 #define S2D13_MIN (-3 * DIVIDER)
0033 #define S2D13_MAX (3 * DIVIDER)
0034 
0035 uint16_t fixed_point_to_int_frac(
0036     struct fixed31_32 arg,
0037     uint8_t integer_bits,
0038     uint8_t fractional_bits)
0039 {
0040     int32_t numerator;
0041     int32_t divisor = 1 << fractional_bits;
0042 
0043     uint16_t result;
0044 
0045     uint16_t d = (uint16_t)dc_fixpt_floor(
0046         dc_fixpt_abs(
0047             arg));
0048 
0049     if (d <= (uint16_t)(1 << integer_bits) - (1 / (uint16_t)divisor))
0050         numerator = (uint16_t)dc_fixpt_round(
0051             dc_fixpt_mul_int(
0052                 arg,
0053                 divisor));
0054     else {
0055         numerator = dc_fixpt_floor(
0056             dc_fixpt_sub(
0057                 dc_fixpt_from_int(
0058                     1LL << integer_bits),
0059                 dc_fixpt_recip(
0060                     dc_fixpt_from_int(
0061                         divisor))));
0062     }
0063 
0064     if (numerator >= 0)
0065         result = (uint16_t)numerator;
0066     else
0067         result = (uint16_t)(
0068         (1 << (integer_bits + fractional_bits + 1)) + numerator);
0069 
0070     if ((result != 0) && dc_fixpt_lt(
0071         arg, dc_fixpt_zero))
0072         result |= 1 << (integer_bits + fractional_bits);
0073 
0074     return result;
0075 }
0076 /*
0077  * convert_float_matrix - This converts a double into HW register spec defined format S2D13.
0078  */
0079 void convert_float_matrix(
0080     uint16_t *matrix,
0081     struct fixed31_32 *flt,
0082     uint32_t buffer_size)
0083 {
0084     const struct fixed31_32 min_2_13 =
0085         dc_fixpt_from_fraction(S2D13_MIN, DIVIDER);
0086     const struct fixed31_32 max_2_13 =
0087         dc_fixpt_from_fraction(S2D13_MAX, DIVIDER);
0088     uint32_t i;
0089 
0090     for (i = 0; i < buffer_size; ++i) {
0091         uint32_t reg_value =
0092                 fixed_point_to_int_frac(
0093                     dc_fixpt_clamp(
0094                         flt[i],
0095                         min_2_13,
0096                         max_2_13),
0097                         2,
0098                         13);
0099 
0100         matrix[i] = (uint16_t)reg_value;
0101     }
0102 }
0103 
0104 static uint32_t find_gcd(uint32_t a, uint32_t b)
0105 {
0106     uint32_t remainder = 0;
0107     while (b != 0) {
0108         remainder = a % b;
0109         a = b;
0110         b = remainder;
0111     }
0112     return a;
0113 }
0114 
0115 void reduce_fraction(uint32_t num, uint32_t den,
0116         uint32_t *out_num, uint32_t *out_den)
0117 {
0118     uint32_t gcd = 0;
0119 
0120     gcd = find_gcd(num, den);
0121     *out_num = num / gcd;
0122     *out_den = den / gcd;
0123 }