Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 20 additions & 12 deletions src/audio/asrc/asrc_farrow_generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,16 @@ void asrc_fir_filter16(struct asrc_farrow *src_obj, int16_t **output_buffers,
/* Initialise the accumulator */
prod = 0;

/* Iterate over the filter bins.
* Data is Q1.15, coefficients are Q1.30. Prod will be Qx.45.
*/
for (n = 0; n < src_obj->filter_length; n++)
/* 4-way unrolled convolution for ILP / RISC-V SIMD pipeline */
for (n = 0; n <= src_obj->filter_length - 4; n += 4) {
prod += (int64_t)buffer_p[0] * filter_p[0];
prod += (int64_t)buffer_p[1] * filter_p[1];
prod += (int64_t)buffer_p[2] * filter_p[2];
prod += (int64_t)buffer_p[3] * filter_p[3];
buffer_p += 4;
filter_p += 4;
}
for (; n < src_obj->filter_length; n++)
prod += (int64_t)(*buffer_p++) * (*filter_p++);

/* Shift left after accumulation, because interim
Expand Down Expand Up @@ -88,14 +94,16 @@ void asrc_fir_filter32(struct asrc_farrow *src_obj, int32_t **output_buffers,
/* Initialise the accumulator */
prod = 0;

/* Iterate over the filter bins. Data is Q1.31, coefficients
* are Q1.22. They are down scaled by 1 shift. In addition
* there C is implementation specific right shift by 8. It
* gives headroom to calculate up to 256 taps FIR. The use
* of 24 bits of 32 bits is not a practical limitation for
* quality. The product is Qx.54.
*/
for (n = 0; n < src_obj->filter_length; n++)
/* 4-way unrolled convolution for ILP / RISC-V SIMD pipeline */
for (n = 0; n <= src_obj->filter_length - 4; n += 4) {
prod += (int64_t)buffer_p[0] * (filter_p[0] >> 8);
prod += (int64_t)buffer_p[1] * (filter_p[1] >> 8);
prod += (int64_t)buffer_p[2] * (filter_p[2] >> 8);
prod += (int64_t)buffer_p[3] * (filter_p[3] >> 8);
buffer_p += 4;
filter_p += 4;
}
for (; n < src_obj->filter_length; n++)
prod += (int64_t)(*buffer_p++) * (*filter_p++ >> 8);

/* Shift left after accumulation, because interim
Expand Down
2 changes: 2 additions & 0 deletions src/audio/drc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ else()
drc_hifi3.c
drc_hifi4.c
drc_arm.c
drc_riscv.c
drc_math_generic.c
drc_math_hifi3.c
drc_math_arm.c
drc_math_riscv.c
)
endif()

Expand Down
8 changes: 8 additions & 0 deletions src/audio/drc/Kconfig.simd
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ choice "DRC_SIMD_LEVEL_SELECT"
depends on COMP_DRC
default DRC_HIFI_MAX if XTENSA
default DRC_ARM_SIMD if ARM
default DRC_RISCV_SIMD if RISCV
default DRC_HIFI_NONE

config DRC_ARM_SIMD
Expand Down Expand Up @@ -46,4 +47,11 @@ choice "DRC_SIMD_LEVEL_SELECT"
bool
help
This option used to build DRC generic code.

config DRC_RISCV_SIMD
prompt "choose RISC-V SIMD optimized DRC module"
bool
Comment thread
lgirdwood marked this conversation as resolved.
depends on RISCV
help
This option used to build RISC-V SIMD optimized DRC code
endchoice
4 changes: 2 additions & 2 deletions src/audio/drc/drc_generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ void drc_compress_output(struct drc_state *state,

#endif /* DRC_HIFI_NONE */

#if SOF_USE_HIFI(NONE, DRC) || SOF_USE_HIFI(3, DRC) || SOF_USE_ARM_SIMD(DRC)
#if SOF_USE_HIFI(NONE, DRC) || SOF_USE_HIFI(3, DRC) || SOF_USE_ARM_SIMD(DRC) || SOF_USE_RISCV_SIMD(DRC)
/* After one complete division of samples have been received (and one division of
* samples have been output), we calculate shaped power average
* (detector_average) from the input division, update envelope parameters from
Expand Down Expand Up @@ -806,4 +806,4 @@ const struct drc_proc_fnmap drc_proc_fnmap[] = {
};

const size_t drc_proc_fncount = ARRAY_SIZE(drc_proc_fnmap);
#endif
#endif /* SOF_USE_HIFI(NONE, DRC) || SOF_USE_HIFI(3, DRC) || SOF_USE_RISCV_SIMD(DRC) */
11 changes: 10 additions & 1 deletion src/audio/drc/drc_math.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ static inline int32_t drc_asin_fixed(int32_t x)
}
#endif /* DRC_USE_CORDIC_ASIN */

#elif SOF_USE_ARM_SIMD(DRC)
#elif SOF_USE_ARM_SIMD(DRC) || SOF_USE_RISCV_SIMD(DRC)

#define PI_OVER_TWO_Q30 1686629713 /* Q_CONVERT_FLOAT(1.57079632679489661923, 30); pi/2 */
#define TWO_OVER_PI_Q30 683565248 /* Q_CONVERT_FLOAT(0.63661977236758134, 30); 2/pi */
Expand Down Expand Up @@ -114,6 +114,15 @@ static inline int32_t drc_sin_fixed(int32_t x)
return sofm_lut_sin_fixed_16b(denorm_x) << 16;
}

#ifdef DRC_USE_CORDIC_ASIN
static inline int32_t drc_asin_fixed(int32_t x)
{
const int32_t lshift = drc_get_lshift(30, 30, 30);
int32_t asin_val = asin_fixed_16b(x);

return drc_mult_lshift(asin_val << 16, TWO_OVER_PI_Q30, lshift);
}
#endif /* DRC_USE_CORDIC_ASIN */
#else

/*
Expand Down
186 changes: 186 additions & 0 deletions src/audio/drc/drc_math_riscv.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
// SPDX-License-Identifier: BSD-3-Clause
//
// Copyright(c) 2026 Sound Open Firmware. All rights reserved.

#include <sof/audio/format.h>
#include <sof/math/decibels.h>
#include <sof/math/exp_fcn.h>
#include <sof/math/numbers.h>
#include <sof/math/trig.h>
#include <sof/common.h>

#include "drc_math.h"

#if SOF_USE_RISCV_SIMD(DRC)

#define ONE_OVER_SQRT2_Q30 759250112 /* Q_CONVERT_FLOAT(0.70710678118654752f, 30); 1/sqrt(2) */
#define SQRT2_Q30 1518500224 /* Q_CONVERT_FLOAT(1.4142135623730950488f, 30); sqrt(2) */
#define LOG10_FUNC_A5_Q26 75959200 /* Q_CONVERT_FLOAT(1.131880283355712890625f, 26) */
#define LOG10_FUNC_A4_Q26 -285795039 /* Q_CONVERT_FLOAT(-4.258677959442138671875f, 26) */
#define LOG10_FUNC_A3_Q26 457435200 /* Q_CONVERT_FLOAT(6.81631565093994140625f, 26) */
#define LOG10_FUNC_A2_Q26 -410610303 /* Q_CONVERT_FLOAT(-6.1185703277587890625f, 26) */
#define LOG10_FUNC_A1_Q26 244982704 /* Q_CONVERT_FLOAT(3.6505267620086669921875f, 26) */
#define LOG10_FUNC_A0_Q26 -81731487 /* Q_CONVERT_FLOAT(-1.217894077301025390625f, 26) */
#define HALF_Q25 16777216 /* Q_CONVERT_FLOAT(0.5, 25) */
#define LOG10_2_Q26 20201782 /* Q_CONVERT_FLOAT(0.301029995663981195214f, 26) */
#define NEG_1K_Q21 -2097151999 /* Q_CONVERT_FLOAT(-1000.0f, 21) */
#define LOG_10_Q29 1236190976 /* Q_CONVERT_FLOAT(2.3025850929940457f, 29) */
#define NEG_30_Q26 -2013265919 /* Q_CONVERT_FLOAT(-30.0f, 26) */
#define DRC_TWENTY_Q26 1342177280 /* Q_CONVERT_FLOAT(20, 26) */

#define ASIN_FUNC_A7L_Q30 126897672 /* Q_CONVERT_FLOAT(0.1181826665997505187988281f, 30) */
#define ASIN_FUNC_A5L_Q30 43190596 /* Q_CONVERT_FLOAT(4.0224377065896987915039062e-2f, 30) */
#define ASIN_FUNC_A3L_Q30 184887136 /* Q_CONVERT_FLOAT(0.1721895635128021240234375f, 30) */
#define ASIN_FUNC_A1L_Q30 1073495040 /* Q_CONVERT_FLOAT(0.99977016448974609375f, 30) */
#define ASIN_FUNC_A7H_Q26 948097024 /* Q_CONVERT_FLOAT(14.12774658203125f, 26) */
#define ASIN_FUNC_A5H_Q26 -2024625535 /* Q_CONVERT_FLOAT(-30.1692714691162109375f, 26) */
#define ASIN_FUNC_A3H_Q26 1441234048 /* Q_CONVERT_FLOAT(21.4760608673095703125f, 26) */
#define ASIN_FUNC_A1H_Q26 -261361631 /* Q_CONVERT_FLOAT(-3.894591808319091796875f, 26) */

#define INV_FUNC_A5_Q25 -92027983 /* Q_CONVERT_FLOAT(-2.742647647857666015625f, 25) */
#define INV_FUNC_A4_Q25 470207584 /* Q_CONVERT_FLOAT(14.01327800750732421875f, 25) */
#define INV_FUNC_A3_Q25 -998064895 /* Q_CONVERT_FLOAT(-29.74465179443359375f, 25) */
#define INV_FUNC_A2_Q25 1126492160 /* Q_CONVERT_FLOAT(33.57208251953125f, 25) */
#define INV_FUNC_A1_Q25 -713042175 /* Q_CONVERT_FLOAT(-21.25031280517578125f, 25) */
#define INV_FUNC_A0_Q25 239989712 /* Q_CONVERT_FLOAT(7.152250766754150390625f, 25) */

static inline int32_t rexp_fixed_riscv(int32_t x, int32_t precision_x, int32_t *e)
{
int32_t bit = 31 - norm_int32(x);

*e = bit - precision_x;

if (bit > 30)
return (x + (1 << (bit - 31))) >> (bit - 30);
if (bit < 30)
return x << (30 - bit);
return x;
}

static inline int32_t log10_fixed(int32_t x)
{
int32_t e;
int32_t exp;
int32_t acc;
const int32_t lshift = drc_get_lshift(26, 30, 26);

x = rexp_fixed_riscv(x, 26, &e);
exp = e << 25;

if (x > ONE_OVER_SQRT2_Q30) {
x = drc_mult_lshift(x, ONE_OVER_SQRT2_Q30, drc_get_lshift(30, 30, 30));
exp += HALF_Q25;
}

/* Horner's rule: A0 + x*(A1 + x*(A2 + x*(A3 + x*(A4 + x*A5)))) */
acc = drc_mult_lshift(LOG10_FUNC_A5_Q26, x, lshift) + LOG10_FUNC_A4_Q26;
acc = drc_mult_lshift(acc, x, lshift) + LOG10_FUNC_A3_Q26;
acc = drc_mult_lshift(acc, x, lshift) + LOG10_FUNC_A2_Q26;
acc = drc_mult_lshift(acc, x, lshift) + LOG10_FUNC_A1_Q26;
acc = drc_mult_lshift(acc, x, lshift) + LOG10_FUNC_A0_Q26;

acc += drc_mult_lshift(exp, LOG10_2_Q26, drc_get_lshift(25, 26, 26));
return acc;
}

int32_t drc_lin2db_fixed(int32_t linear)
{
int32_t log10_linear;

if (linear <= 0)
return NEG_1K_Q21;

log10_linear = log10_fixed(linear);
return drc_mult_lshift(DRC_TWENTY_Q26, log10_linear, drc_get_lshift(26, 26, 21));
}

int32_t drc_log_fixed(int32_t x)
{
int32_t log10_x;

if (x <= 0)
return NEG_30_Q26;

log10_x = log10_fixed(x);
return drc_mult_lshift(LOG_10_Q29, log10_x, drc_get_lshift(29, 26, 26));
}

#ifndef DRC_USE_CORDIC_ASIN
int32_t drc_asin_fixed(int32_t x)
{
int32_t lshift;
int32_t x_abs = x < 0 ? -x : x;
int32_t in2;
int32_t A7, A5, A3, A1;
int32_t qc;
int32_t acc;

in2 = drc_mult_lshift(x, x, drc_get_lshift(30, 30, 30));

if (x_abs <= ONE_OVER_SQRT2_Q30) {
A7 = ASIN_FUNC_A7L_Q30;
A5 = ASIN_FUNC_A5L_Q30;
A3 = ASIN_FUNC_A3L_Q30;
A1 = ASIN_FUNC_A1L_Q30;
qc = 30;
} else {
A7 = ASIN_FUNC_A7H_Q26;
A5 = ASIN_FUNC_A5H_Q26;
A3 = ASIN_FUNC_A3H_Q26;
A1 = ASIN_FUNC_A1H_Q26;
qc = 26;
}

lshift = drc_get_lshift(qc, 30, qc);
acc = drc_mult_lshift(A7, in2, lshift) + A5;
acc = drc_mult_lshift(acc, in2, lshift) + A3;
acc = drc_mult_lshift(acc, in2, lshift) + A1;
acc = drc_mult_lshift(acc, x, lshift);

return drc_mult_lshift(acc, TWO_OVER_PI_Q30, drc_get_lshift(qc, 30, 30));
}
#endif /* !DRC_USE_CORDIC_ASIN */

int32_t drc_inv_fixed(int32_t x, int32_t precision_x, int32_t precision_y)
Comment thread
lgirdwood marked this conversation as resolved.
{
int32_t e;
int32_t precision_inv;
int32_t sqrt2_extracted = 0;
int32_t acc;
const int32_t lshift = drc_get_lshift(25, 30, 25);

x = rexp_fixed_riscv(x, precision_x, &e);

if ((x < 0 ? -x : x) < ONE_OVER_SQRT2_Q30) {
x = drc_mult_lshift(x, SQRT2_Q30, drc_get_lshift(30, 30, 30));
sqrt2_extracted = 1;
}

/* Horner's rule for reciprocal */
acc = drc_mult_lshift(INV_FUNC_A5_Q25, x, lshift) + INV_FUNC_A4_Q25;
acc = drc_mult_lshift(acc, x, lshift) + INV_FUNC_A3_Q25;
acc = drc_mult_lshift(acc, x, lshift) + INV_FUNC_A2_Q25;
acc = drc_mult_lshift(acc, x, lshift) + INV_FUNC_A1_Q25;
acc = drc_mult_lshift(acc, x, lshift) + INV_FUNC_A0_Q25;

if (sqrt2_extracted)
acc = drc_mult_lshift(acc, SQRT2_Q30, lshift);

precision_inv = e + 25;
if (precision_inv > precision_y) {
int shift = precision_inv - precision_y;
return (acc + (1 << (shift - 1))) >> shift;
}
if (precision_inv < precision_y) {
int shift = precision_y - precision_inv;
int64_t val = ((int64_t)acc) << shift;
if (val > INT32_MAX)
return INT32_MAX;
if (val < INT32_MIN)
return INT32_MIN;
return (int32_t)val;
}
return acc;
}

#endif /* SOF_USE_RISCV_SIMD(DRC) */
Loading
Loading