You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

656 lines
19KB

  1. /*
  2. * Copyright (c) 2014 RISC OS Open Ltd
  3. * Author: Ben Avison <bavison@riscosopen.org>
  4. *
  5. * This file is part of Libav.
  6. *
  7. * Libav is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * Libav is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with Libav; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. */
  21. #include "libavutil/arm/asm.S"
  22. #define MAX_CHANNELS 8
  23. #define MAX_FIR_ORDER 8
  24. #define MAX_IIR_ORDER 4
  25. #define MAX_RATEFACTOR 4
  26. #define MAX_BLOCKSIZE (40 * MAX_RATEFACTOR)
  27. PST .req a1
  28. PCO .req a2
  29. AC0 .req a3
  30. AC1 .req a4
  31. CO0 .req v1
  32. CO1 .req v2
  33. CO2 .req v3
  34. CO3 .req v4
  35. ST0 .req v5
  36. ST1 .req v6
  37. ST2 .req sl
  38. ST3 .req fp
  39. I .req ip
  40. PSAMP .req lr
  41. // Some macros that do loads/multiplies where the register number is determined
  42. // from an assembly-time expression. Boy is GNU assembler's syntax ugly...
  43. .macro load group, index, base, offset
  44. .altmacro
  45. load_ \group, %(\index), \base, \offset
  46. .noaltmacro
  47. .endm
  48. .macro load_ group, index, base, offset
  49. ldr \group\index, [\base, #\offset]
  50. .endm
  51. .macro loadd group, index, base, offset
  52. .altmacro
  53. loadd_ \group, %(\index), %(\index+1), \base, \offset
  54. .noaltmacro
  55. .endm
  56. .macro loadd_ group, index0, index1, base, offset
  57. A .if \offset >= 256
  58. A ldr \group\index0, [\base, #\offset]
  59. A ldr \group\index1, [\base, #(\offset) + 4]
  60. A .else
  61. ldrd \group\index0, \group\index1, [\base, #\offset]
  62. A .endif
  63. .endm
  64. .macro multiply index, accumulate, long
  65. .altmacro
  66. multiply_ %(\index), \accumulate, \long
  67. .noaltmacro
  68. .endm
  69. .macro multiply_ index, accumulate, long
  70. .if \long
  71. .if \accumulate
  72. smlal AC0, AC1, CO\index, ST\index
  73. .else
  74. smull AC0, AC1, CO\index, ST\index
  75. .endif
  76. .else
  77. .if \accumulate
  78. mla AC0, CO\index, ST\index, AC0
  79. .else
  80. mul AC0, CO\index, ST\index
  81. .endif
  82. .endif
  83. .endm
  84. // A macro to update the load register number and load offsets
  85. .macro inc howmany
  86. .set LOAD_REG, (LOAD_REG + \howmany) & 3
  87. .set OFFSET_CO, OFFSET_CO + 4 * \howmany
  88. .set OFFSET_ST, OFFSET_ST + 4 * \howmany
  89. .if FIR_REMAIN > 0
  90. .set FIR_REMAIN, FIR_REMAIN - \howmany
  91. .if FIR_REMAIN == 0
  92. .set OFFSET_CO, 4 * MAX_FIR_ORDER
  93. .set OFFSET_ST, 4 * (MAX_BLOCKSIZE + MAX_FIR_ORDER)
  94. .endif
  95. .elseif IIR_REMAIN > 0
  96. .set IIR_REMAIN, IIR_REMAIN - \howmany
  97. .endif
  98. .endm
  99. // Macro to implement the inner loop for one specific combination of parameters
  100. .macro implement_filter mask_minus1, shift_0, shift_8, iir_taps, fir_taps
  101. .set TOTAL_TAPS, \iir_taps + \fir_taps
  102. // Deal with register allocation...
  103. .set DEFINED_SHIFT, 0
  104. .set DEFINED_MASK, 0
  105. .set SHUFFLE_SHIFT, 0
  106. .set SHUFFLE_MASK, 0
  107. .set SPILL_SHIFT, 0
  108. .set SPILL_MASK, 0
  109. .if TOTAL_TAPS == 0
  110. // Little register pressure in this case - just keep MASK where it was
  111. .if !\mask_minus1
  112. MASK .req ST1
  113. .set DEFINED_MASK, 1
  114. .endif
  115. .else
  116. .if \shift_0
  117. .if !\mask_minus1
  118. // AC1 is unused with shift 0
  119. MASK .req AC1
  120. .set DEFINED_MASK, 1
  121. .set SHUFFLE_MASK, 1
  122. .endif
  123. .elseif \shift_8
  124. .if !\mask_minus1
  125. .if TOTAL_TAPS <= 4
  126. // All coefficients are preloaded (so pointer not needed)
  127. MASK .req PCO
  128. .set DEFINED_MASK, 1
  129. .set SHUFFLE_MASK, 1
  130. .else
  131. .set SPILL_MASK, 1
  132. .endif
  133. .endif
  134. .else // shift not 0 or 8
  135. .if TOTAL_TAPS <= 3
  136. // All coefficients are preloaded, and at least one CO register is unused
  137. .if \fir_taps & 1
  138. SHIFT .req CO0
  139. .set DEFINED_SHIFT, 1
  140. .set SHUFFLE_SHIFT, 1
  141. .else
  142. SHIFT .req CO3
  143. .set DEFINED_SHIFT, 1
  144. .set SHUFFLE_SHIFT, 1
  145. .endif
  146. .if !\mask_minus1
  147. MASK .req PCO
  148. .set DEFINED_MASK, 1
  149. .set SHUFFLE_MASK, 1
  150. .endif
  151. .elseif TOTAL_TAPS == 4
  152. // All coefficients are preloaded
  153. SHIFT .req PCO
  154. .set DEFINED_SHIFT, 1
  155. .set SHUFFLE_SHIFT, 1
  156. .if !\mask_minus1
  157. .set SPILL_MASK, 1
  158. .endif
  159. .else
  160. .set SPILL_SHIFT, 1
  161. .if !\mask_minus1
  162. .set SPILL_MASK, 1
  163. .endif
  164. .endif
  165. .endif
  166. .endif
  167. .if SPILL_SHIFT
  168. SHIFT .req ST0
  169. .set DEFINED_SHIFT, 1
  170. .endif
  171. .if SPILL_MASK
  172. MASK .req ST1
  173. .set DEFINED_MASK, 1
  174. .endif
  175. // Preload coefficients if possible
  176. .if TOTAL_TAPS <= 4
  177. .set OFFSET_CO, 0
  178. .if \fir_taps & 1
  179. .set LOAD_REG, 1
  180. .else
  181. .set LOAD_REG, 0
  182. .endif
  183. .rept \fir_taps
  184. load CO, LOAD_REG, PCO, OFFSET_CO
  185. .set LOAD_REG, (LOAD_REG + 1) & 3
  186. .set OFFSET_CO, OFFSET_CO + 4
  187. .endr
  188. .set OFFSET_CO, 4 * MAX_FIR_ORDER
  189. .rept \iir_taps
  190. load CO, LOAD_REG, PCO, OFFSET_CO
  191. .set LOAD_REG, (LOAD_REG + 1) & 3
  192. .set OFFSET_CO, OFFSET_CO + 4
  193. .endr
  194. .endif
  195. // Move mask/shift to final positions if necessary
  196. // Need to do this after preloading, because in some cases we
  197. // reuse the coefficient pointer register
  198. .if SHUFFLE_SHIFT
  199. mov SHIFT, ST0
  200. .endif
  201. .if SHUFFLE_MASK
  202. mov MASK, ST1
  203. .endif
  204. // Begin loop
  205. 01:
  206. .if TOTAL_TAPS == 0
  207. // Things simplify a lot in this case
  208. // In fact this could be pipelined further if it's worth it...
  209. ldr ST0, [PSAMP]
  210. subs I, I, #1
  211. .if !\mask_minus1
  212. and ST0, ST0, MASK
  213. .endif
  214. str ST0, [PST, #-4]!
  215. str ST0, [PST, #4 * (MAX_BLOCKSIZE + MAX_FIR_ORDER)]
  216. str ST0, [PSAMP], #4 * MAX_CHANNELS
  217. bne 01b
  218. .else
  219. .if \fir_taps & 1
  220. .set LOAD_REG, 1
  221. .else
  222. .set LOAD_REG, 0
  223. .endif
  224. .set LOAD_BANK, 0
  225. .set FIR_REMAIN, \fir_taps
  226. .set IIR_REMAIN, \iir_taps
  227. .if FIR_REMAIN == 0 // only IIR terms
  228. .set OFFSET_CO, 4 * MAX_FIR_ORDER
  229. .set OFFSET_ST, 4 * (MAX_BLOCKSIZE + MAX_FIR_ORDER)
  230. .else
  231. .set OFFSET_CO, 0
  232. .set OFFSET_ST, 0
  233. .endif
  234. .set MUL_REG, LOAD_REG
  235. .set COUNTER, 0
  236. .rept TOTAL_TAPS + 2
  237. // Do load(s)
  238. .if FIR_REMAIN != 0 || IIR_REMAIN != 0
  239. .if COUNTER == 0
  240. .if TOTAL_TAPS > 4
  241. load CO, LOAD_REG, PCO, OFFSET_CO
  242. .endif
  243. load ST, LOAD_REG, PST, OFFSET_ST
  244. inc 1
  245. .elseif COUNTER == 1 && (\fir_taps & 1) == 0
  246. .if TOTAL_TAPS > 4
  247. load CO, LOAD_REG, PCO, OFFSET_CO
  248. .endif
  249. load ST, LOAD_REG, PST, OFFSET_ST
  250. inc 1
  251. .elseif LOAD_BANK == 0
  252. .if TOTAL_TAPS > 4
  253. .if FIR_REMAIN == 0 && IIR_REMAIN == 1
  254. load CO, LOAD_REG, PCO, OFFSET_CO
  255. .else
  256. loadd CO, LOAD_REG, PCO, OFFSET_CO
  257. .endif
  258. .endif
  259. .set LOAD_BANK, 1
  260. .else
  261. .if FIR_REMAIN == 0 && IIR_REMAIN == 1
  262. load ST, LOAD_REG, PST, OFFSET_ST
  263. inc 1
  264. .else
  265. loadd ST, LOAD_REG, PST, OFFSET_ST
  266. inc 2
  267. .endif
  268. .set LOAD_BANK, 0
  269. .endif
  270. .endif
  271. // Do interleaved multiplies, slightly delayed
  272. .if COUNTER >= 2
  273. multiply MUL_REG, COUNTER > 2, !\shift_0
  274. .set MUL_REG, (MUL_REG + 1) & 3
  275. .endif
  276. .set COUNTER, COUNTER + 1
  277. .endr
  278. // Post-process the result of the multiplies
  279. .if SPILL_SHIFT
  280. ldr SHIFT, [sp, #9*4 + 0*4]
  281. .endif
  282. .if SPILL_MASK
  283. ldr MASK, [sp, #9*4 + 1*4]
  284. .endif
  285. ldr ST2, [PSAMP]
  286. subs I, I, #1
  287. .if \shift_8
  288. mov AC0, AC0, lsr #8
  289. orr AC0, AC0, AC1, lsl #24
  290. .elseif !\shift_0
  291. rsb ST3, SHIFT, #32
  292. mov AC0, AC0, lsr SHIFT
  293. A orr AC0, AC0, AC1, lsl ST3
  294. T mov AC1, AC1, lsl ST3
  295. T orr AC0, AC0, AC1
  296. .endif
  297. .if \mask_minus1
  298. add ST3, ST2, AC0
  299. .else
  300. add ST2, ST2, AC0
  301. and ST3, ST2, MASK
  302. sub ST2, ST3, AC0
  303. .endif
  304. str ST3, [PST, #-4]!
  305. str ST2, [PST, #4 * (MAX_BLOCKSIZE + MAX_FIR_ORDER)]
  306. str ST3, [PSAMP], #4 * MAX_CHANNELS
  307. bne 01b
  308. .endif
  309. b 99f
  310. .if DEFINED_SHIFT
  311. .unreq SHIFT
  312. .endif
  313. .if DEFINED_MASK
  314. .unreq MASK
  315. .endif
  316. .endm
  317. .macro switch_on_fir_taps mask_minus1, shift_0, shift_8, iir_taps
  318. A ldr pc, [pc, a3, LSL #2] // firorder is in range 0-(8-iir_taps)
  319. T tbh [pc, a3, lsl #1]
  320. 0:
  321. A .word 0, 70f, 71f, 72f, 73f, 74f
  322. T .hword (70f - 0b) / 2, (71f - 0b) / 2, (72f - 0b) / 2, (73f - 0b) / 2, (74f - 0b) / 2
  323. .if \iir_taps <= 3
  324. A .word 75f
  325. T .hword (75f - 0b) / 2
  326. .if \iir_taps <= 2
  327. A .word 76f
  328. T .hword (76f - 0b) / 2
  329. .if \iir_taps <= 1
  330. A .word 77f
  331. T .hword (77f - 0b) / 2
  332. .if \iir_taps == 0
  333. A .word 78f
  334. T .hword (78f - 0b) / 2
  335. .endif
  336. .endif
  337. .endif
  338. .endif
  339. 70: implement_filter \mask_minus1, \shift_0, \shift_8, \iir_taps, 0
  340. 71: implement_filter \mask_minus1, \shift_0, \shift_8, \iir_taps, 1
  341. 72: implement_filter \mask_minus1, \shift_0, \shift_8, \iir_taps, 2
  342. 73: implement_filter \mask_minus1, \shift_0, \shift_8, \iir_taps, 3
  343. 74: implement_filter \mask_minus1, \shift_0, \shift_8, \iir_taps, 4
  344. .if \iir_taps <= 3
  345. 75: implement_filter \mask_minus1, \shift_0, \shift_8, \iir_taps, 5
  346. .if \iir_taps <= 2
  347. 76: implement_filter \mask_minus1, \shift_0, \shift_8, \iir_taps, 6
  348. .if \iir_taps <= 1
  349. 77: implement_filter \mask_minus1, \shift_0, \shift_8, \iir_taps, 7
  350. .if \iir_taps == 0
  351. 78: implement_filter \mask_minus1, \shift_0, \shift_8, \iir_taps, 8
  352. .endif
  353. .endif
  354. .endif
  355. .endif
  356. .endm
  357. .macro switch_on_iir_taps mask_minus1, shift_0, shift_8
  358. A ldr pc, [pc, a4, LSL #2] // irorder is in range 0-4
  359. T tbh [pc, a4, lsl #1]
  360. 0:
  361. A .word 0, 60f, 61f, 62f, 63f, 64f
  362. T .hword (60f - 0b) / 2, (61f - 0b) / 2, (62f - 0b) / 2, (63f - 0b) / 2, (64f - 0b) / 2
  363. 60: switch_on_fir_taps \mask_minus1, \shift_0, \shift_8, 0
  364. 61: switch_on_fir_taps \mask_minus1, \shift_0, \shift_8, 1
  365. 62: switch_on_fir_taps \mask_minus1, \shift_0, \shift_8, 2
  366. 63: switch_on_fir_taps \mask_minus1, \shift_0, \shift_8, 3
  367. 64: switch_on_fir_taps \mask_minus1, \shift_0, \shift_8, 4
  368. .endm
  369. /* void ff_mlp_filter_channel_arm(int32_t *state, const int32_t *coeff,
  370. * int firorder, int iirorder,
  371. * unsigned int filter_shift, int32_t mask,
  372. * int blocksize, int32_t *sample_buffer);
  373. */
  374. function ff_mlp_filter_channel_arm, export=1
  375. push {v1-fp,lr}
  376. add v1, sp, #9*4 // point at arguments on stack
  377. ldm v1, {ST0,ST1,I,PSAMP}
  378. cmp ST1, #-1
  379. bne 30f
  380. movs ST2, ST0, lsl #29 // shift is in range 0-15; we want to special-case 0 and 8
  381. bne 20f
  382. bcs 10f
  383. switch_on_iir_taps 1, 1, 0
  384. 10: switch_on_iir_taps 1, 0, 1
  385. 20: switch_on_iir_taps 1, 0, 0
  386. 30: movs ST2, ST0, lsl #29 // shift is in range 0-15; we want to special-case 0 and 8
  387. bne 50f
  388. bcs 40f
  389. switch_on_iir_taps 0, 1, 0
  390. 40: switch_on_iir_taps 0, 0, 1
  391. 50: switch_on_iir_taps 0, 0, 0
  392. 99: pop {v1-fp,pc}
  393. endfunc
  394. .unreq PST
  395. .unreq PCO
  396. .unreq AC0
  397. .unreq AC1
  398. .unreq CO0
  399. .unreq CO1
  400. .unreq CO2
  401. .unreq CO3
  402. .unreq ST0
  403. .unreq ST1
  404. .unreq ST2
  405. .unreq ST3
  406. .unreq I
  407. .unreq PSAMP
  408. /********************************************************************/
  409. PSA .req a1 // samples
  410. PCO .req a2 // coeffs
  411. PBL .req a3 // bypassed_lsbs
  412. INDEX .req a4
  413. CO0 .req v1
  414. CO1 .req v2
  415. CO2 .req v3
  416. CO3 .req v4
  417. SA0 .req v5
  418. SA1 .req v6
  419. SA2 .req sl
  420. SA3 .req fp
  421. AC0 .req ip
  422. AC1 .req lr
  423. NOISE .req SA0
  424. LSB .req SA1
  425. DCH .req SA2 // dest_ch
  426. MASK .req SA3
  427. // INDEX is used as follows:
  428. // bits 0..6 index2 (values up to 17, but wider so that we can
  429. // add to index field without needing to mask)
  430. // bits 7..14 i (values up to 160)
  431. // bit 15 underflow detect for i
  432. // bits 25..31 (if access_unit_size_pow2 == 128) \ index
  433. // bits 26..31 (if access_unit_size_pow2 == 64) /
  434. .macro implement_rematrix shift, index_mask, mask_minus1, maxchan
  435. .if \maxchan == 1
  436. // We can just leave the coefficients in registers in this case
  437. ldrd CO0, CO1, [PCO]
  438. .endif
  439. 1:
  440. .if \maxchan == 1
  441. ldrd SA0, SA1, [PSA]
  442. smull AC0, AC1, CO0, SA0
  443. .elseif \maxchan == 5
  444. ldr CO0, [PCO, #0]
  445. ldr SA0, [PSA, #0]
  446. ldr CO1, [PCO, #4]
  447. ldr SA1, [PSA, #4]
  448. ldrd CO2, CO3, [PCO, #8]
  449. smull AC0, AC1, CO0, SA0
  450. ldrd SA2, SA3, [PSA, #8]
  451. smlal AC0, AC1, CO1, SA1
  452. ldrd CO0, CO1, [PCO, #16]
  453. smlal AC0, AC1, CO2, SA2
  454. ldrd SA0, SA1, [PSA, #16]
  455. smlal AC0, AC1, CO3, SA3
  456. smlal AC0, AC1, CO0, SA0
  457. .else // \maxchan == 7
  458. ldr CO2, [PCO, #0]
  459. ldr SA2, [PSA, #0]
  460. ldr CO3, [PCO, #4]
  461. ldr SA3, [PSA, #4]
  462. ldrd CO0, CO1, [PCO, #8]
  463. smull AC0, AC1, CO2, SA2
  464. ldrd SA0, SA1, [PSA, #8]
  465. smlal AC0, AC1, CO3, SA3
  466. ldrd CO2, CO3, [PCO, #16]
  467. smlal AC0, AC1, CO0, SA0
  468. ldrd SA2, SA3, [PSA, #16]
  469. smlal AC0, AC1, CO1, SA1
  470. ldrd CO0, CO1, [PCO, #24]
  471. smlal AC0, AC1, CO2, SA2
  472. ldrd SA0, SA1, [PSA, #24]
  473. smlal AC0, AC1, CO3, SA3
  474. smlal AC0, AC1, CO0, SA0
  475. .endif
  476. ldm sp, {NOISE, DCH, MASK}
  477. smlal AC0, AC1, CO1, SA1
  478. .if \shift != 0
  479. .if \index_mask == 63
  480. add NOISE, NOISE, INDEX, lsr #32-6
  481. ldrb LSB, [PBL], #MAX_CHANNELS
  482. ldrsb NOISE, [NOISE]
  483. add INDEX, INDEX, INDEX, lsl #32-6
  484. .else // \index_mask == 127
  485. add NOISE, NOISE, INDEX, lsr #32-7
  486. ldrb LSB, [PBL], #MAX_CHANNELS
  487. ldrsb NOISE, [NOISE]
  488. add INDEX, INDEX, INDEX, lsl #32-7
  489. .endif
  490. sub INDEX, INDEX, #1<<7
  491. adds AC0, AC0, NOISE, lsl #\shift + 7
  492. adc AC1, AC1, NOISE, asr #31
  493. .else
  494. ldrb LSB, [PBL], #MAX_CHANNELS
  495. sub INDEX, INDEX, #1<<7
  496. .endif
  497. add PSA, PSA, #MAX_CHANNELS*4
  498. mov AC0, AC0, lsr #14
  499. orr AC0, AC0, AC1, lsl #18
  500. .if !\mask_minus1
  501. and AC0, AC0, MASK
  502. .endif
  503. add AC0, AC0, LSB
  504. tst INDEX, #1<<15
  505. str AC0, [PSA, DCH, lsl #2] // DCH is precompensated for the early increment of PSA
  506. beq 1b
  507. b 98f
  508. .endm
  509. .macro switch_on_maxchan shift, index_mask, mask_minus1
  510. cmp v4, #5
  511. blo 51f
  512. beq 50f
  513. implement_rematrix \shift, \index_mask, \mask_minus1, 7
  514. 50: implement_rematrix \shift, \index_mask, \mask_minus1, 5
  515. 51: implement_rematrix \shift, \index_mask, \mask_minus1, 1
  516. .endm
  517. .macro switch_on_mask shift, index_mask
  518. cmp sl, #-1
  519. bne 40f
  520. switch_on_maxchan \shift, \index_mask, 1
  521. 40: switch_on_maxchan \shift, \index_mask, 0
  522. .endm
  523. .macro switch_on_au_size shift
  524. .if \shift == 0
  525. switch_on_mask \shift, undefined
  526. .else
  527. teq v6, #64
  528. bne 30f
  529. orr INDEX, INDEX, v1, lsl #32-6
  530. switch_on_mask \shift, 63
  531. 30: orr INDEX, INDEX, v1, lsl #32-7
  532. switch_on_mask \shift, 127
  533. .endif
  534. .endm
  535. /* void ff_mlp_rematrix_channel_arm(int32_t *samples,
  536. * const int32_t *coeffs,
  537. * const uint8_t *bypassed_lsbs,
  538. * const int8_t *noise_buffer,
  539. * int index,
  540. * unsigned int dest_ch,
  541. * uint16_t blockpos,
  542. * unsigned int maxchan,
  543. * int matrix_noise_shift,
  544. * int access_unit_size_pow2,
  545. * int32_t mask);
  546. */
  547. function ff_mlp_rematrix_channel_arm, export=1
  548. push {v1-fp,lr}
  549. add v1, sp, #9*4 // point at arguments on stack
  550. ldm v1, {v1-sl}
  551. teq v4, #1
  552. itt ne
  553. teqne v4, #5
  554. teqne v4, #7
  555. bne 99f
  556. teq v6, #64
  557. it ne
  558. teqne v6, #128
  559. bne 99f
  560. sub v2, v2, #MAX_CHANNELS
  561. push {a4,v2,sl} // initialise NOISE,DCH,MASK; make sp dword-aligned
  562. movs INDEX, v3, lsl #7
  563. beq 98f // just in case, do nothing if blockpos = 0
  564. subs INDEX, INDEX, #1<<7 // offset by 1 so we borrow at the right time
  565. adc lr, v1, v1 // calculate index2 (C was set by preceding subs)
  566. orr INDEX, INDEX, lr
  567. // Switch on matrix_noise_shift: values 0 and 1 are
  568. // disproportionately common so do those in a form the branch
  569. // predictor can accelerate. Values can only go up to 15.
  570. cmp v5, #1
  571. beq 11f
  572. blo 10f
  573. A ldr pc, [pc, v5, lsl #2]
  574. T tbh [pc, v5, lsl #1]
  575. 0:
  576. A .word 0, 0, 0, 12f, 13f, 14f, 15f, 16f, 17f, 18f, 19f, 20f, 21f, 22f, 23f, 24f, 25f
  577. T .hword 0, 0, (12f - 0b) / 2, (13f - 0b) / 2, (14f - 0b) / 2, (15f - 0b) / 2
  578. T .hword (16f - 0b) / 2, (17f - 0b) / 2, (18f - 0b) / 2, (19f - 0b) / 2
  579. T .hword (20f - 0b) / 2, (21f - 0b) / 2, (22f - 0b) / 2, (23f - 0b) / 2, (24f - 0b) / 2, (25f - 0b) / 2
  580. 10: switch_on_au_size 0
  581. 11: switch_on_au_size 1
  582. 12: switch_on_au_size 2
  583. 13: switch_on_au_size 3
  584. 14: switch_on_au_size 4
  585. 15: switch_on_au_size 5
  586. 16: switch_on_au_size 6
  587. 17: switch_on_au_size 7
  588. 18: switch_on_au_size 8
  589. 19: switch_on_au_size 9
  590. 20: switch_on_au_size 10
  591. 21: switch_on_au_size 11
  592. 22: switch_on_au_size 12
  593. 23: switch_on_au_size 13
  594. 24: switch_on_au_size 14
  595. 25: switch_on_au_size 15
  596. 98: add sp, sp, #3*4
  597. pop {v1-fp,pc}
  598. 99: // Can't handle these parameters, drop back to C
  599. pop {v1-fp,lr}
  600. b X(ff_mlp_rematrix_channel)
  601. endfunc
  602. .unreq PSA
  603. .unreq PCO
  604. .unreq PBL
  605. .unreq INDEX
  606. .unreq CO0
  607. .unreq CO1
  608. .unreq CO2
  609. .unreq CO3
  610. .unreq SA0
  611. .unreq SA1
  612. .unreq SA2
  613. .unreq SA3
  614. .unreq AC0
  615. .unreq AC1
  616. .unreq NOISE
  617. .unreq LSB
  618. .unreq DCH
  619. .unreq MASK