강좌 & 팁
대게의 경우 FPU를 사용하기 위해서는
gcc 옵션 --fpu=vfp2 이렇게 해서 옵션을 준다. (--fpu 뒤에 붙는 옵션을 상당히 많다)
neon 어셈블러을 컴파일 하기위해 Makefile 에 따로 옵션을 주지 않고
소스에서 아래와 같이 추가하면 된다. (흠 초간단)
asm volatile (
".fpu neon\n"
아래의 소스를 보고 단지 쓴지 알아보자
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 ); }
vld1.u8, vst1.u8 명령어를 볼수 있다.
ld, st 의 neon 확장판이라고 생각하고 보면
load A <-- B
store A --> B
vld1.u8 {d0, d1, d2, d3}, [%[fsrc],:256]!
을 해석하면
double-register D0,D1,D2,D3 에 fsrc 메모리 256비트 불러온 후 해당하는 만큼 메모리를 증가시킨다.
vst1.u8 {d0, d1, d2, d3}, [%[fdst],:256]!
을 해석하면
double-register D0,D1,D2,D3 의 내용을 fdst 메모리에 256비트 저장한 후 해당하는 만큼 메모리를 증가시킨다.
우리가 알고 있는 일반적인 ARM 어셈블러와 동일하다.
다만 레이지스터의 크기가 다르것만 조심하자
위의 코드중에서 루프를 돌리는 " subs" 명령어 라인과 분기명령 "bgt" 라인이 떨어져 있다.
일반적인 경우 아래와 같이 작성한다
loop:
...
...
subs r0, r0, #1
bgt loop
하지만 ARM 코어의 파이프라인을 가만한다면 아래의 코드가 좀더 효율적이다.
loop:
subs r0, r0, #1
...
...
bgt loop
ARM 컴파일 옵션등은 아래의 파일을 참고하자
PS.
neon 으로 작성된 math-neon 프로젝트가 있다.
sqrt 함수를 컴파일한 후 math 라이브러리와 비교하였다.
이런 의외의 결과가...
커널에서 지원하는 fpu 통한 계산이 많이 빨랐다... ㅎㄷ
firmware 작성할 때 도움을 주기 위한 프로젝트가 아닐까..