Привет!
ESP32-S3 - замечательный процессор с SIMD инструкциями. Оперирует 16-байтовыми векторами, умеет с комплексными числами работать и Фурье делать. Поэтому его часто используют в домашней аудиотехнике (всякие играйки музыки и set-top boxes)
Ну раз есть SIMD, значит самое время для быстрого memcpy
Ниже - файл, esp32-s3-memcpy.S. Кидаете его прямо в каталог с вашим скетчем и объявляете у себя где-нибудь
extern "C" void esps3_memcpy(void *, void *, size_t);
.. или так (если на Си пишите):
extern void esps3_memcpy(void *, void *, size_t);
Для копирования маленьких блоков, менее 16 байт, лучше использовать встроенный memcpy(). А если длиннее - то ассемблерный вариант дает прирост скорости от 2.4 до 3 раз. Тестировалось на буферах 15кб (чтобы в кэш влезло и cache miss не случались, а то будем измерять среднюю температуру по больнице)
Работает только на ESP32-S3. Не читал даташыт от ESP32-S2 - может быть будет работать и там.
.align 4
.text
.global esps3_memcpy
.type esps3_memcpy, @function
.section .iram1
esps3_memcpy:
.align 4
entry sp, 32
# void esps3_memcpy(store_ptr, load_ptr, length)
# a2 a3 a4
ee.ld.128.usar.ip q0, a3, 0
rur.sar_byte a13
movi a11, 16
sub a11, a11, a13 # head unaligned bytes 1 (a11, load_ptr)
ee.ld.128.usar.ip q1, a2, 0
rur.sar_byte a9
movi a12, 16
sub a12, a12, a9 # head unaligned bytes 2 (a12, store_ptr)
# is store buffer 16-byte aligned?
beqi a12, 16, 11f
# unaligned. calculate reminder and copy via l32/s32
min a12, a12, a4
srli a13, a12, 2 # a13 - words count
slli a14, a13, 2
sub a14, a12, a14 # a14 - bytes count
# esp32 zero-overhead hardware loop to copy the unaligned remainder
# this loop only takes place if remainder is non-zero
# copy 32 bits at a time
loopgtz a13, 9f
l32i a5, a3, 0
addi a3, a3, 4
s32i a5, a2, 0
addi a2, a2, 4
9:
# copy 1 byte at a time
loopgtz a14, 10f
l8ui a5, a3, 0
addi a3, a3, 1
s8i a5, a2, 0
addi a2, a2, 1
10:
# main machinery
sub a4, a4, a12
ee.ld.128.usar.ip q0, a3, 0
rur.sar_byte a13
11:
beqz a13, 1f
srli a5, a4, 4
slli a6, a5, 4
sub a6, a4, a6 # a6 = length % 16
srli a7, a5, 1 # len // 32
slli a8, a7, 1
sub a8, a5, a8 # odd_flag
srli a9, a6, 2 #remainder_4b
slli a10, a9, 2
sub a10, a6, a10 #remainder_1b
# 32-byte per cycle in a hardware loop
loopgtz a7, 12f
ee.ld.128.usar.ip q0, a3, 16
ee.ld.128.usar.ip q1, a3, 16
ee.ld.128.usar.ip q2, a3, 0
ee.src.q q0, q0, q1
ee.src.q q1, q1, q2
ee.vst.128.ip q0, a2, 16
ee.vst.128.ip q1, a2, 16
12:
beqz a8, 3f
ee.ld.128.usar.ip q0, a3, 16
ee.ld.128.usar.ip q1, a3, 0
ee.src.q q0, q0, q1
ee.vst.128.ip q0, a2, 16
bnez a8, 3f
1:
srli a5, a4, 4 # len // 16
slli a6, a5, 4
sub a6, a4, a6 # remainder
srli a7, a5, 1 # len // 32
slli a8, a7, 1
sub a8, a5, a8 # odd_flag
srli a9, a6, 2 #remainder_4b
slli a10, a9, 2
sub a10, a6, a10 #remainder_1b
loopgtz a7, 2f
ee.vld.128.ip q0, a3, 16
ee.vld.128.ip q1, a3, 16
ee.vst.128.ip q0, a2, 16
ee.vst.128.ip q1, a2, 16
2:
beqz a8, 3f
ee.vld.128.ip q0, a3, 16
ee.vst.128.ip q0, a2, 16
3:
loopgtz a9, 4f
l32i a5, a3, 0
addi a3, a3, 4
s32i a5, a2, 0
addi a2, a2, 4
4:
loopgtz a10, 5f
l8ui a5, a3, 0
addi a3, a3, 1
s8i a5, a2, 0
addi a2, a2, 1
5:
retw
На блоках чуть меньше килобайта прирост скорости составляет 2.4 раза. На блоках по 15кб прирост 3 раза.
На здоровье!

