임베디드 시스템에 있어 응용 프로그램의 하드웨어 관련 부품의 액세스 기능은 필수적입니다. 임베디드 시스템에서 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

회원가입 후 이용바랍니다.
개의 댓글
0 / 400
댓글 정렬
BEST댓글
BEST 댓글 답글과 추천수를 합산하여 자동으로 노출됩니다.
댓글삭제
삭제한 댓글은 다시 복구할 수 없습니다.
그래도 삭제하시겠습니까?
댓글수정
댓글 수정은 작성 후 1분내에만 가능합니다.
/ 400
내 댓글 모음
저작권자 © 테크월드뉴스 무단전재 및 재배포 금지