.section .data
.align 16; // on aligne les buffers sur 128bits (load/store SSE alignés)
buffer_mono1: .space 256*1024*2; // buffer de 256K échantillons en 16bits signés mono(PCM classique)
.align 16; // on aligne les buffers sur 128bits (load/store SSE alignés)
buffer_mono2: .space 256*1024*2; // buffer de 256K échantillons en 16bits signés mono(PCM classique)
.align 16; // on aligne les buffers sur 128bits (load/store SSE alignés)
buffer_stereo: .space 256*1024*2*2; // buffer de 256K échantillons en 16bits signés stéréo entrelacé (PCM classique)
nb_echantillons: .long 256*1024; // nombre d'échantillons (attention: 1 échantillon = 2 octets !)
// attention aussi a avoir un multiple de 8 echantillons !!
.section .text
;// PARTIE ENTRELACEMENT
entrelace:
mov $buffer_mono1,%eax; // on charge le pointeur du 1er buffer mono dans EAX
mov $buffer_mono2,%ebx; // on charge le pointeur du 2ème buffer mono dans EBX
mov $buffer_stereo,%edx; // on charge le pointeur du buffer stéréo dans EDX
mov nb_echantillons,%ecx; // on charge le contenu de nb_echantillons dans ECX
sar $3,%ecx; // on divise le nombre d'echantillons par 8
// car on les traite 8 par 8
boucle1:
movdqa (%eax),%xmm0; // XMM0.W = [Md0 Md1 Md2 Md3 Md4 Md5 Md6 Md7] (Mono Droite)
movdqa (%ebx),%xmm1; // XMM1.W = [Mg0 Mg1 Mg2 Mg3 Mg4 Mg5 Mg6 Mg7] (Mono Gauche)
pshufd $0xE4,%xmm0,%xmm2; // Recopie XMM0 dans XMM2 sans passer par l'unité de chargement SSE
punpcklwd %xmm1,%xmm2; // XMM2.W = [Md0 Mg0 Md1 Mg1 Md2 Mg2 Md3 Mg3]
movdqa %xmm2,(%edx); // on écrit la première partie d'entrelacement
punpckhwd %xmm1,%xmm0; // XMM0.W = [Md4 Mg4 Md5 Mg5 Md6 Mg6 Md7 Mg7]
movdqa %xmm0,16(%edx); // on écrit la deuxième partie d'entrelacement 16 octets plus loin
add $16,%eax; // on se decale de 8 echantillons (16 octets) pour mono1
add $16,%ebx; // on se decale de 8 echantillons (16 octets) pour mono2
add $32,%edx; // on se decale de 8 echantillons (32 octets) pour stéréo
dec %ecx; // on decremente le nombre de paquet de 8 echantillons a traiter
jnz boucle1; // si ce n'est pas null, on continue a traiter
fin_entrelace: // c'est fini ... on peut faire ce qu'on veut ensuite
;// PARTIE DESENTRELACEMENT
desentrelace:
mov $buffer_mono1,%eax; // on charge le pointeur du 1er buffer mono dans EAX
mov $buffer_mono2,%ebx; // on charge le pointeur du 2ème buffer mono dans EBX
mov $buffer_stereo,%edx; // on charge le pointeur du buffer stéréo dans EDX
mov nb_echantillons,%ecx; // on charge le contenu de nb_echantillons dans ECX
sar $3,%ecx; // on divise le nombre d'echantillons par 8
// car on les traite 8 par 8
boucle2:
movdqa (%edx),%xmm0; // XMM0.W = [Md0 Mg0 Md1 Mg1 Md2 Mg2 Md3 Mg3]
movdqa 16(%edx),%xmm1; // XMM1.W = [Md4 Mg4 Md5 Mg5 Md6 Mg6 Md7 Mg7]
pshufd $0xE4,%xmm0,%xmm2; // Recopie XMM0 dans XMM2 sans passer par l'unite de chargement SSE
pslld $16,%xmm2; // XMM2.W = [Mg0 0 Mg1 0 Mg2 0 Mg3 0]
psrad $16,%xmm2; // XMM2.W = [0 Mg0 0 Mg1 0 Mg2 0 Mg3]
movdqa %xmm1,%xmm3; // Recopie XMM1 dans XMM3
pslld $16,%xmm3; // XMM3.W = [Mg4 0 Mg5 0 Mg6 0 Mg7 0]
psrad $16,%xmm3; // XMM3.W = [0 Mg4 0 Mg5 0 Mg6 0 Mg7]
packssdw %xmm3,%xmm2; // on packetise de double (32bits) vers word (16bits)
// XMM2.W = [Mg0 Mg1 Mg2 Mg3 Mg4 Mg5 Mg6 Mg7]
movdqa %xmm2,(%eax); // on stocke le resultat dans le 1er buffer mono
psrad $16,%xmm0; // XMM0.W = [0 Md0 0 Md1 0 Md2 0 Md3]
psrad $16,%xmm1; // XMM1.W = [0 Md4 0 Md5 0 Md6 0 Md7]
packssdw %xmm1,%xmm0; // on packetise de double (32bits) vers word (16bits)
// XMM0.W = [Md0 Md1 Md2 Md3 Md4 Md5 Md6 Md7]
movdqa %xmm0,(%ebx); // on stocke le resultat dans le 2eme flux mono
add $16,%eax; // on se deplace vers les 8 echantillons suivants (16 octets)
add $16,%ebx; // on se deplace vers les 8 echantillons suivants (16 octets)
add $32,%edx; // on se deplace vers les 8 echantillons suivants (32 octets)
dec %ecx; // on decremente le nombre de paquet de 8 echantillons a traiter
jnz boucle1; // si ce n'est pas null, on continue a traiter
fin_desentrelace: // c'est fini ... on peut faire ce qu'on veut ensuite