강좌 & 팁
글 수 2,412
2014.06.13 20:58:02 (*.134.169.166)
41586
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 명령어로 작성하여 보자
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() 함수를 비교하는 프로그램은 아래와 같다.
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 의 메모리를 복사하는 루틴이다.
자 이제 결과를 공개하면...
[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() 함수를 탐구해보자