강좌 & 팁
글 수 2,412
2014.06.13 20:58:02 (*.134.169.166)
69138
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() 함수를 탐구해보자


