임베디드 시스템에 있어 응용 프로그램의 하드웨어 관련 부품의 액세스 기능은 필수적입니다. 임베디드 시스템에서 C프로그래밍 언어는 일반적으로 좋은 선택이며, 이는 하드웨어와 밀접한 관계를 가지며, 상대적으로 쉽게 디바이스의 주변장치들을 제어할 수 있기 때문입니다.
하지만 때때로 C언어로는 충분하지 않아, 예제처럼 C함수에 인라인 어셈블러 명령어를 사용하여 C와 어셈블러 모듈을 혼용하여 사용하게 됩니다.
인라인 어셈블러는 직접적으로 C또는 C++함수에 어셈블러 명령어를 삽입하기 위해 사용됩니다. 일반적으로 이 기능은 C에서 직접 액세스할 수 없는 하드웨어 자원을 액세스 하거나 C로 작성하는 경우 정확한 타이밍을 만들지 못할 때와 같이 타이밍에 민감한 경우에 작성합니다.
인라인 어셈블러 문장은 C함수와 유사합니다. 입력 인수(입력 피연산자)를 취할 수 있으며 반환 값(출력 피연산자) 이 있고, C심볼(피연산자를 통해)에 입력 또는 출력할 수 있습니다. 또한 인라인 어셈블러 문장은 레지스터 또는 메모리에 대한 값을 선언할 수 도 있습니다.
피연산자와 레지스터/메모리 자원이 없는 경우에는, 인라인 어셈블러는 C소스 코드와의 인터페이스가 없습니다. 이것은 인라인 어셈블러 코드를 취약하게 만드며, 미래에 컴파일러를 업데이트하면 유지보수에 있어 문제를 발생할지 모릅니다.
인라인 어셈블러를 사용하는 제약 사항은 컴파일러의 다양한 최적화 기능이 인라인 문장의 영향에 대해 고려하지 않는 다는 점이며, 인라인 문장들은 최적화되지 않습니다. 그래서 결과적으로 인라인 어셈블러는 가능한 한 사용을 피하야 하며, 함수 또는 모듈에서 분리해야 합니다.
하드웨어의 저수준(lower levels) 제어를 보다 효율적으로 하기위해서는 대신에 내장 함수를 사용하는 것입니다. IAR Embedded Workbench의 컴파일러는 어셈블러 언어를 사용하지 않고 저수준 프로세서 동작에 직접 액세스할 수 있는 미리 정의된 함수를 제공하고 있습니다.
이 함수들은 내장 함수(intrinsic functions)로 알려져 있습니다. 예를 들어, 이러한 함수들은 타이밍에 민감한 루틴에서 유용하게 사용될 수 있습니다.
내장 함수는 일반 함수 호출과 유사하게 보입니다. 그러나, 컴파일러가 인식하는 진정한 내장 함수 입니다. 내장 함수는 하나의 명령어로 또는 짧은 명령어들로 인라인 코드가 번역되며, 그리고 두개의 밑줄(double underscore, __)로 표시됩니다.
애플리케이션에서 내장 함수를 사용하기 위해서는 intrinsics.h 헤더 파일을 포함해야 합니다.
컴파일러 매뉴얼에서 컴파일러에 사용할 수 있는 내장 기능과 어떻게 동작하는지에 대한 설명을 찾을 수 있습니다.
IAR Embedded Workbench for ARM(이하 EWARM)에서 지원되는 내장 함수에 대해 살펴 보겠습니다. 자세한 내용은 EWARM C/C++ Development Guide, Intrinsic functions 항목을 참조하십시오.
다음 항목들은 함수명, 구문 형식, 그리고 요약 설명 순으로 나열되어 있습니다.
사용하고 있는 디바이스에서 해당 내장 함수를 지원하는지를 확인하시기 바랍니다.
__CLREX void __CLREX(void); CLREX 명령어를 삽입합니다.
__CLZ unsigned char __CLZ(unsigned long); CLZ 명령어를 삽입합니다.
__disable_fiq void __disable_fiq(void); fast interrupt requests (fiq)를 비활성화합니다.
__disable_interrupt void __disable_interrupt(void); interrupts를 비활성화합니다.
__disable_irq void __disable_irq(void); interrupt requests (irq)를 비활성화합니다.
__DMB void __DMB(void); DMB 명령어를 삽입합니다.
__DSB void __DSB(void); DSB 명령어를 삽입합니다.
__enable_fiq void __enable_fiq(void); Description Enables fast interrupt requests (fiq).
__enable_interrupt void __enable_interrupt(void); interrupts를 활성화 합니다.
__enable_irq void __enable_irq(void); interrupt requests (irq)를 활성화합니다.
__get_BASEPRI unsigned long __get_BASEPRI(void); BASEPRI 레지스터 값을 반환합니다.
__get_CONTROL unsigned long __get_CONTROL(void); CONTROL 레지스터 값을 반환합니다.
__get_CPSR unsigned long __get_CPSR(void); CPSR 값을 반환합니다.
__get_FAULTMASK unsigned long __get_FAULTMASK(void); FAULTMASK 레지스터 값 반환
__get_FPSCR unsigned long __get_FPSCR(void);
FPSCR (floating-point status and control register) 값을 반환합니다.
__get_interrupt_state __istate_t __get_interrupt_state(void); global interrupt state를 반환합니다.
__get_IPSR unsigned long __get_IPSR(void);
IPSR register (Interrupt Program Status Register)의 값을 반환합니다.
__get_LR unsigned long __get_LR(void); link register (R14) 값을 반환합니다.
__get_MSP unsigned long __get_MSP(void); MSP register (Main Stack Pointer) 값을 반환합니다.
__get_PRIMASK unsigned long __get_PRIMASK(void); PRIMASK register 값을 반환합니다.
__get_PSP unsigned long __get_PSP(void); PSP register (Process Stack Pointer) 값을 반환합니다.
__get_PSR unsigned long __get_PSR(void);
PSR register (combined Program Status Register) 값을 반환합니다.
__get_SB unsigned long __get_SB(void); static base register (R9) 값을 반환합니다.
__get_SP unsigned long __get_SP(void); stack pointer register (R13) 값을 반환합니다.
__ISB void __ISB(void); ISB 명령어를 삽입합니다.
__LDC __LDCL __LDC2 __LDC2L
void __LDCxxx(__ul coproc, __ul CRn, __ul const *src);
coprocessor load instruction LDC 또는 유사 명령어를 추가합니다.
__LDC_noidx __LDCL_noidx __LDC2_noidx __LDC2L_noidx
void __LDCxxx_noidx(__ul coproc, __ul CRn, __ul const *src, __ul option);
coprocessor load instruction LDC 또는 유사 명령어를 추가합니다.
__LDREX __LDREXB __LDREXD __LDREXH unsigned long __LDREX(unsigned long *);
unsigned char __LDREXB(unsigned char *);
unsigned long long __LDREXD(unsigned long long *);
unsigned short __LDREXH(unsigned short *);
지정된 명령어를 삽입합니다.
__MCR __MCR2
void __MCR(__ul coproc, __ul opcode_1, __ul src, __ul CRn, __ul CRm, __ul opcode_2);
void __MCR2(__ul coproc, __ul opcode_1, __ul src, __ul CRn, __ul CRm, __ul opcode_2);
coprocessor write instruction (MCR or MCR2) 삽입
__MRC __MRC2
unsigned long __MRC(__ul coproc, __ul opcode_1, __ul CRn, __ul CRm, __ul opcode_2);
unsigned long __MRC2(__ul coproc, __ul opcode_1, __ul CRn, __ul CRm, __ul opcode_2);
coprocessor read instruction (MRC or MRC2)을 삽입합니다.
__no_operation void __no_operation(void);
NOP 명령어를 삽입합니다.
__PKHBT unsigned long __PKHBT(unsigned long x, unsigned long y, unsigned long count);
PKHBT 명령어를 삽입합니다. 선택적으로 count만큼 shifted operand (LSL)를 추가합니다.
__PKHTB unsigned long __PKHTB(unsigned long x, unsigned long y, unsigned long count);
PKHTB 명령어를 삽입합니다. 선택적으로 count만큼 shifted operand (ASR)를 추가합니다.
__PLD __PLDW void __PLD(void const *);
void __PLDW(void const *);
preload data instruction (PLD or PLDW)을 삽입합니다.
__PLI void __PLI(void const *);
PLI 명령어를 삽입
__QADD __QDADD __QDSUB __QSUB signed long __Qxxx(signed long, signed long);
지정된 명령어를 삽입합니다.
__QADD8 __QADD16 __QASX __QSAX __QSUB8 __QSUB16
unsigned long __Qxxx(unsigned long, unsigned long);
지정된 명령어를 삽입합니다.
__QCFlag unsigned long __QCFlag(void);
cumulative saturation flag QC of the FPSCR register (Floating-point Status and Control Register) 값을 반환합니다.
Neon (Advanced SIMD)이 필요합니다.
__QDOUBLE signed long __QDOUBLE(signed long);
QADD 명령어를 삽입합니다.
__QFlag int __QFlag(void);
Q flag (overflow/saturation) 값을 반환합니다.
__RBIT unsigned long __RBIT(unsigned long);
RBIT 명령어를 삽입합니다. 32-bit register의 비트 순서를 반전합니다.
__reset_Q_flag void __reset_Q_flag(void);
Q flag (overflow/saturation)를 지움니다(clear).
__reset_QC_flag
void __reset_QC_flag(void);
cumulative saturation flag QC of the FPSCR register (Floating-point Status and Control Register)의 값을 지웁니다.
Neon (Advanced SIMD)이 필요합니다.
__REV __REV16 __REVSH unsigned long __REV16(unsigned long);
unsigned long __REV(unsigned long);
signed long __REVSH(short);
지정된 명령어를 삽입합니다.
__SADD8 __SADD16 __SASX __SSAX __SSUB8 __SSUB16
unsigned long __Sxxx(unsigned long, unsigned long);
지정된 명령어를 삽입합니다.
__SEL unsigned long __SEL(unsigned long, unsigned long);
SEL 명령어를 삽입합니다.
__set_BASEPRI void __set_BASEPRI(unsigned long);
BASEPRI 레지스터 값을 설정합니다.
__set_CONTROL void __set_CONTROL(unsigned long);
CONTROL 레지스터 값을 설정합니다.
__set_CPSR void __set_CPSR(unsigned long);
ARM CPSR (Current Program Status Register) 값을 설정합니다.
__set_FAULTMASK void __set_FAULTMASK(unsigned long);
FAULTMASK register의 값을 설정합니다.
__set_FPSCR void __set_FPSCR(unsigned long);
FPSCR (floating-point status and control register)의 값을 설정합니다.
__set_interrupt_state
void __set_interrupt_state(__istate_t);
__get_interrupt_state 함수로 가져온 값을 interrupt state에 재설정합니다.
__set_LR void __set_LR(unsigned long);
link register (R14)에 새로운 주소를 지정합니다.
__set_MSP void __set_MSP(unsigned long);
MSP register (Main Stack Pointer) 값을 설정합니다.
__set_PRIMASK void __set_PRIMASK(unsigned long);
PRIMASK register 값을 설정합니다.
__set_PSP void __set_PSP(unsigned long);
PSP register (Process Stack Pointer) 값을 설정합니다.
__set_SB void __set_SB(unsigned long);
static base register (R9)에 새로운 주소를 지정합니다.
__set_SP void __set_SP(unsigned long);
stack pointer register (R13)에 새로운 주소를 지정합니다.
__SEV void __SEV(void);
SEV 명령어를 삽입합니다.
__SHADD8 __SHADD16 __SHASX __SHSAX __SHSUB8 __SHSUB16
unsigned long __SHxxx(unsigned long, unsigned long);
지정된 명령어를 삽입합니다.
__SMLABB __SMLABT __SMLATB __SMLATT __SMLAWB __SMLAWT
unsigned long __SMLAxxx(unsigned long, unsigned long, unsigned long);
지정된 명령어를 삽입합니다.
__SMLAD __SMLADX __SMLSD __SMLSDX
unsigned long __SMLxxx(unsigned long, unsigned long, unsigned long);
지정된 명령어를 삽입합니다.
__SMLALBB __SMLALBT __SMLALTB __SMLALTT
unsigned long long __SMLALxxx(unsigned long, unsigned long,unsigned long long);
지정된 명령어를 삽입합니다.
__SMLALD __SMLALDX __SMLSLD __SMLSLDX
unsigned long long __SMLxxx(unsigned long, unsigned long, unsigned long long);
지정된 명령어를 삽입합니다.
__SMMLA __SMMLAR __SMMLS __SMMLSR
unsigned long __SMMLxxx(unsigned long, unsigned long, unsigned long);
지정된 명령어를 삽입합니다.
__SMMUL __SMMULR
unsigned long __SMMULxxx(unsigned long, unsigned long);
지정된 명령어를 삽입합니다.
__SMUAD __SMUADX __SMUSD __SMUSDX
unsigned long __SMUxxx(unsigned long, unsigned long);
지정된 명령어를 삽입합니다.
__SMUL signed long __SMUL(signed short, signed short);
signed 16-bit multiplication 삽입합니다.
__SMULBB __SMULBT __SMULTB __SMULTT __SMULWB __SMULWT
unsigned long __SMULxxx(unsigned long, unsigned long);
지정된 명령어를 삽입합니다.
__SSAT
unsigned long __SSAT(unsigned long, unsigned long);
SSAT 명령어를 삽입합니다.
__SSAT16
unsigned long __SSAT16(unsigned long, unsigned long);
SSAT16 명령어를 삽입합니다.
__STC __STCL __STC2 __STC2L
void __STCxxx(__ul coproc, __ul CRn, __ul const *dst);
coprocessor store instruction STC 또는 유사 명령어를 삽입합니다.
__STC_noidx __STCL_noidx __STC2_noidx __STC2L_noidx
void __STCxxx_noidx(__ul coproc, __ul CRn, __ul const *dst, __ul option);
coprocessor store instruction STC 또는 유사 명령어를 삽입합니다.
__STREX __STREXB __STREXD __STREXH
unsigned long __STREX(unsigned long, unsigned long *);
unsigned long __STREXB(unsigned char, unsigned char *);
unsigned long __STREXD(unsigned long long, unsigned long long*);
unsigned long __STREXH(unsigned short, unsigned short *);
지정된 명령어를 삽입합니다.
__SWP __SWPB
unsigned long __SWP(unsigned long, unsigned long *);
char __SWPB(unsigned char, unsigned char *);
지정된 명령어를 삽입합니다.
__SXTAB __SXTAB16 __SXTAH __SXTB16
unsigned long __SXTxxx(unsigned long, unsigned long);
지정된 명령어를 삽입합니다.
__UADD8 __UADD16 __UASX __USAX __USUB8 __USUB16
unsigned long __Uxxx(unsigned long, unsigned long);
지정된 명령어를 삽입합니다.
__UHADD8 __UHADD16 __UHASX __UHSAX __UHSUB8 __UHSUB16
unsigned long __UHxxx(unsigned long, unsigned long);
지정된 명령어를 삽입합니다.
__UMAAL
unsigned long long __UMAAL(unsigned long, unsigned long,unsigned long, unsigned long);
UMAAL 명령어를 삽입합니다.
__UQADD8 __UQADD16 __UQASX __UQSAX __UQSUB8 __UQSUB16
unsigned long __UQxxx(unsigned long, unsigned long);
지정된 명령어를 삽입합니다.
__USAD8 __USADA8
unsigned long __USADxxx(unsigned long, unsigned long);
지정된 명령어를 삽입합니다.
__USAT unsigned long __USAT(unsigned long, unsigned long);
USAT 명령어를 삽입합니다.
__USAT16 unsigned long __USAT16(unsigned long, unsigned long);
USAT16 명령어를 삽입합니다.
__UXTAB __UXTAB16 __UXTAH __UXTB16
unsigned long __UXTxxx(unsigned long, unsigned long);
지정된 명령어를 삽입합니다.
__WFE __WFI __YIELD
void long __xxx(void);
지정된 명령어를 삽입합니다.
맺음말
IAR EWARM에서 사용할 수 있는 내장 함수(Intrinsic function)에 대해 살펴 보았습니다.
이러한 함수들을 활용하여 보다 효율적이며 안정된 코드를 작성하시기 바랍니다.
감사합니다.
고성용 이사 / IAR 시스템즈
Sung-Yong.Ko@iar.com
그래도 삭제하시겠습니까?