
강좌 & 팁
글 수 2,412
2014.06.13 20:58:02 (*.134.169.166)
68282
ARM Cortex-A 를 적용한 MCU 데이타쉬트에는 모두 NEON 명령어를 내장했다는 문구가 있다.
NEON 이 먼데...
"float 연산을 지원하는 DSP 계열의 명령어" 라고 이해하자
우선 기본적인 지식(이전 글에 언급한것 같지만...)
4-byte 크기의 레지스터는 S0, S1 ...
8-byte 크기의 레지스터는 D0, D1 ...
16-byte 크기의 레지스터는 Q0, Q1 ...
참고로 Q0 는 D0, D1 으로 구성되었고 D0 는 S0, S1 으로 구성된다.
memcpy 함수를 neon 명령어로 작성하여 보자
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | void memcpy_neon_align32( char *dst, const char *src, int count ) { int remain; char * fdst; const char * fsrc; remain = count; fdst = dst; fsrc = src; while ( 32 <= remain ) { asm volatile ( ".fpu neon\n" "1: \n" "subs %[remain], %[remain], #32 \n" "vld1.u8 {d0, d1, d2, d3}, [%[fsrc],:256]! \n" "vst1.u8 {d0, d1, d2, d3}, [%[fdst],:256]! \n" "bgt 1b \n" : [fsrc] "+r" (fsrc), [fdst] "+r" (fdst), [remain] "+r" (remain) : : "d0" , "d1" , "d2" , "d3" , "cc" , "memory" ); } //printf( "fdst=%p:%p:%d fsrc=%p:%p:%d\n", fdst, dst, fdst-dst, fsrc, src, fsrc-src ); if ( 0 < remain ) memcpy ( dst, src, remain ); } |
위의 함수에서 인자로 넘어오는 포인터 *dst, *src 의 주소는 모두 32바이트 정렬이 되어야 한다.
0x41235678 이런주소가 아닌 0x41235680 이렇게 0x20 단위의 주소여야 한다.
위의 함수와 memcpy() 함수를 비교하는 프로그램은 아래와 같다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | void main( void ) { int tick, diff; char *dst, *src, *dst_sv, *src_sv; int size = 1024*1024*2; dst_sv = dst = malloc ( size + 32 ); src_sv = src = malloc ( size + 32 ); // 32byte align pointer dst = ( char *)((unsigned int )(dst + 32) & (~0x1f)); src = ( char *)((unsigned int )(src + 32) & (~0x1f)); printf ( " dst=%p:%p\n src=%p:%p\n" , dst, dst_sv, src, src_sv ); // fill memory memset ( dst, 0xaa, size ); memset ( src, 0x55, size ); tick = get_cur_usec(); memcpy_neon_align32( dst, src, size ); diff = get_cur_usec() - tick; printf ( " elasped=%d dst %02x %02x %02x %02x\n" , diff, dst[0], dst[1], dst[size-2], dst[size-1] ); // fill memory memset ( dst, 0x44, size ); memset ( src, 0x99, size ); tick = get_cur_usec(); memcpy ( dst, src, size ); diff = get_cur_usec() - tick; printf ( " elasped=%d dst %02x %02x %02x %02x\n" , diff, dst[0], dst[1], dst[size-2], dst[size-1] ); free ( dst_sv ); free ( src_sv ); } |
10MByte 의 메모리를 복사하는 루틴이다.
자 이제 결과를 공개하면...
1 2 3 4 5 6 7 8 | [root@falinux freefrug]$ . /test-neon dst=0x401f7020:0x401f7008 src=0x403f8020:0x403f8008 elasped=4093 dst 55 55 55 55 elasped=8333 dst 99 99 99 99 [root@falinux freefrug]$ |
4msec 와 8msec 되시겠다....
거의 2배 빠른 속도를 보여준다.
다음주에는 위에 소개된 memcpy_neon_align32() 함수를 탐구해보자