From f47eba7d7d4c6a1d9501e027b63bbab04bb7d417 Mon Sep 17 00:00:00 2001 From: Takamichi Horikawa Date: Thu, 30 Mar 2017 23:31:39 +0000 Subject: add NEON optimization --- libopna/opna.c | 5 +- libopna/opnassg-sinc-c.c | 13 +++++ libopna/opnassg-sinc-neon.s | 118 ++++++++++++++++++++++++++++++++++++++++++++ libopna/opnassg.c | 81 +++++++++++++++++++++++------- libopna/opnassg.h | 13 ++++- 5 files changed, 210 insertions(+), 20 deletions(-) create mode 100644 libopna/opnassg-sinc-c.c create mode 100644 libopna/opnassg-sinc-neon.s (limited to 'libopna') diff --git a/libopna/opna.c b/libopna/opna.c index 1b0aa6c..567c913 100644 --- a/libopna/opna.c +++ b/libopna/opna.c @@ -37,8 +37,9 @@ void opna_mix_oscillo(struct opna *opna, int16_t *buf, unsigned samples, struct } } unsigned offset = OSCILLO_SAMPLE_COUNT - samples; - opna_fm_mix(&opna->fm, buf, samples, &oscillo[0], offset); - opna_ssg_mix_55466(&opna->ssg, &opna->resampler, buf, samples, &oscillo[6], offset); + opna_fm_mix(&opna->fm, buf, samples, oscillo ? &oscillo[0] : 0, offset); + opna_ssg_mix_55466(&opna->ssg, &opna->resampler, buf, samples, + oscillo ? &oscillo[6] : 0, offset); opna_drum_mix(&opna->drum, buf, samples); opna_adpcm_mix(&opna->adpcm, buf, samples); } diff --git a/libopna/opnassg-sinc-c.c b/libopna/opnassg-sinc-c.c new file mode 100644 index 0000000..bf93039 --- /dev/null +++ b/libopna/opnassg-sinc-c.c @@ -0,0 +1,13 @@ +#include "libopna/opnassg.h" + +void opna_ssg_sinc_calc_c(unsigned resampler_index, const int16_t *inbuf, int32_t *outbuf) { + for (int c = 0; c < 3; c++) { + int32_t chsample = 0; + for (int j = 0; j < OPNA_SSG_SINCTABLELEN; j++) { + unsigned sincindex = j; + if (!(resampler_index&1)) sincindex += OPNA_SSG_SINCTABLELEN; + chsample += inbuf[(((resampler_index)>>1)+j)*3+c] * opna_ssg_sinctable[sincindex]; + } + outbuf[c] = chsample; + } +} diff --git a/libopna/opnassg-sinc-neon.s b/libopna/opnassg-sinc-neon.s new file mode 100644 index 0000000..19dc3c6 --- /dev/null +++ b/libopna/opnassg-sinc-neon.s @@ -0,0 +1,118 @@ +@ neon register map: +@ 0, 3, 6, 9, 12, 15 ssg1 +@ 1, 4, 7, 10, 13, 16 ssg2 +@ 2, 5, 8, 11, 14, 17 ssg3 +@ 18, 19, 20, 21, 22, 23 sinc +@ 24-25 (q12): ssg1 out +@ 26-27 (q13): ssg2 out +@ 28-29 (q14): ssg3 out + +.global opna_ssg_sinc_calc_neon +@ r0: resampler_index +@ r1: const int16_t *inbuf +@ r2: int32_t *outbuf + +opna_ssg_sinc_calc_neon: + push {r4-r10,lr} +@ sinc table to r3 + movw r3, #:lower16:opna_ssg_sinctable + movt r3, #:upper16:opna_ssg_sinctable + tst r0, #1 + addeq r3, #256 + +@ add offset to ssg input buffer address + bic r0, #1 + add r0, r0, lsl #1 + add r1, r0 + +@ initialize output register + vmov.i64 q12, #0 + vmov.i64 q13, #0 + vmov.i64 q14, #0 + +@ sinc sample length + mov r0, #128 + +.loop: +@ + subs r0, #24 + blo .end + +@ load SSG channel data + vld3.16 {d0-d2}, [r1]! + vld3.16 {d3-d5}, [r1]! + vld3.16 {d6-d8}, [r1]! + vld3.16 {d9-d11}, [r1]! + vld3.16 {d12-d14}, [r1]! + vld3.16 {d15-d17}, [r1]! + +@ load sinc data + vld1.16 {d18-d21}, [r3]! + vld1.16 {d22-d23}, [r3]! + +@ multiply and accumulate + vmlal.s16 q12, d0, d18 + vmlal.s16 q13, d1, d18 + vmlal.s16 q14, d2, d18 + vmlal.s16 q12, d3, d19 + vmlal.s16 q13, d4, d19 + vmlal.s16 q14, d5, d19 + vmlal.s16 q12, d6, d20 + vmlal.s16 q13, d7, d20 + vmlal.s16 q14, d8, d20 + vmlal.s16 q12, d9, d21 + vmlal.s16 q13, d10, d21 + vmlal.s16 q14, d11, d21 + vmlal.s16 q12, d12, d22 + vmlal.s16 q13, d13, d22 + vmlal.s16 q14, d14, d22 + vmlal.s16 q12, d15, d23 + vmlal.s16 q13, d16, d23 + vmlal.s16 q14, d17, d23 + b .loop + +.end: +@ 8 samples left + vld3.16 {d0-d2}, [r1]! + vld3.16 {d3-d5}, [r1] + vld1.16 {d18-d19}, [r3] + + vmlal.s16 q12, d0, d18 + vmlal.s16 q13, d1, d18 + vmlal.s16 q14, d2, d18 + vmlal.s16 q12, d3, d19 + vmlal.s16 q13, d4, d19 + vmlal.s16 q14, d5, d19 + +@ extract data from result SIMD registers + + vmov.32 r0, d24[0] + vmov.32 r1, d24[1] + vmov.32 r3, d25[0] + vmov.32 r12, d25[1] + + vmov.32 r14, d26[0] + vmov.32 r4, d26[1] + vmov.32 r5, d27[0] + vmov.32 r6, d27[1] + + vmov.32 r7, d28[0] + vmov.32 r8, d28[1] + vmov.32 r9, d29[0] + vmov.32 r10, d29[1] + + add r0, r1 + add r3, r12 + + add r14, r4 + add r5, r6 + + add r7, r8 + add r9, r10 + + add r4, r0, r3 + add r5, r14 + add r6, r7, r9 + + stmia r2, {r4-r6} + pop {r4-r10,pc} diff --git a/libopna/opnassg.c b/libopna/opnassg.c index ec03437..4a12f76 100644 --- a/libopna/opnassg.c +++ b/libopna/opnassg.c @@ -1,5 +1,6 @@ #include "opnassg.h" #include "oscillo/oscillo.h" +#include /* static const float voltable[32] = { 0.0f, 0.0f, 0x1.ae89f9p-8f, 0x1.000000p-7f, @@ -27,9 +28,6 @@ static const int16_t voltable[32] = { 6494, 7723, 9185, 10922 }; -#define SINCTABLEBIT 7 -#define SINCTABLELEN (1<ch[i].tone_counter = 0; @@ -78,7 +130,7 @@ void opna_ssg_reset(struct opna_ssg *ssg) { } void opna_ssg_resampler_reset(struct opna_ssg_resampler *resampler) { - for (int i = 0; i < SINCTABLELEN; i++) { + for (int i = 0; i < OPNA_SSG_SINCTABLELEN; i++) { resampler->buf[i] = 0; } resampler->index = 0; @@ -215,7 +267,7 @@ void opna_ssg_generate_raw(struct opna_ssg *ssg, int16_t *buf, int samples) { } } -#define BUFINDEX(n) ((((resampler->index)>>1)+n)&(SINCTABLELEN-1)) +#define BUFINDEX(n) ((((resampler->index)>>1)+n)&(OPNA_SSG_SINCTABLELEN-1)) void opna_ssg_mix_55466( struct opna_ssg *ssg, struct opna_ssg_resampler *resampler, @@ -246,18 +298,13 @@ void opna_ssg_mix_55466( resampler->index += 9; } int32_t sample = 0; + resampler->index &= (1u<<(OPNA_SSG_SINCTABLEBIT+1))-1; + memcpy(resampler->buf + OPNA_SSG_SINCTABLELEN*3, resampler->buf, OPNA_SSG_SINCTABLELEN*3*sizeof(*resampler->buf)); + int32_t outbuf[3]; + opna_ssg_sinc_calc_func(resampler->index, resampler->buf, outbuf); for (int ch = 0; ch < 3; ch++) { - int32_t chsample = 0; - for (int j = 0; j < SINCTABLELEN; j++) { - unsigned sincindex = j*2; - if (!(resampler->index&1)) sincindex++; - bool sincsign = sincindex & (1<<(SINCTABLEBIT)); - unsigned sincmask = ((1<<(SINCTABLEBIT))-1); - sincindex = (sincindex & sincmask) ^ (sincsign ? sincmask : 0); - chsample += (resampler->buf[BUFINDEX(j)*3+ch] * sinctable[sincindex])>>2; - } - if (oscillo) oscillo[ch].buf[offset+i] = chsample >> 13; - if (!(ssg->mask & (1<> 15; + if (!(ssg->mask & (1<> 2; } sample >>= 16; sample *= 13000; diff --git a/libopna/opnassg.h b/libopna/opnassg.h index 0321163..231db4d 100644 --- a/libopna/opnassg.h +++ b/libopna/opnassg.h @@ -8,6 +8,9 @@ extern "C" { #endif +#define OPNA_SSG_SINCTABLEBIT 7 +#define OPNA_SSG_SINCTABLELEN (1<