这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » MCU » RealView MDK中宏的使用方法

共1条 1/1 1 跳转至

RealView MDK中宏的使用方法

助工
2008-05-17 08:47:51     打赏

更多关于RealView MDK的技术文章,请点击此处!

RealView MDK中宏的使用方法

武汉理工大学  

更多关于RealView MDK的技术文章,请点击此处!

宏可以减少源代码长度,结构清晰,可以给宏起个与功能相关的名字,增加可读性。另外在RealView MDK中可以用宏来处理中断。即把一个普通函数作为中断服务子程序。例如AT91RM9200这块芯片采用的ARM9内核。ARM9核有多种模式,进入中断时需要进行模式切换。因此中断服务子程序时,除了保护现场之外还需要在进入中断之间保存当前模式,在中断子程序执行完时恢复到中断之前的模式。但是我们知道普通函数并不会保存进入之前的模式也不会恢复到进入之前的模式。为将一个普通函数改造为一个中断函数,我们需要在进入函数之前和退出函数之后加上一小段汇编代码来进行模式的保存和恢复。这就是ARM9核惯用的中断处理方法之一。下面介绍在MDK中如何使用宏。

宏的定义格式:

MACRO

{$label}  macroname   {$parameter}{$parameter }…

          ;宏定义体

MEND

其中  $label 宏指令被展开时,label可被替换成相应的符号,通常为一个标号在一个符号前使用$表示被汇编时使用相应的值替代$后的符号。

Macroname 所定义的宏的名称。

$parameter 宏指令的参数。当宏指令被展开时将被替换成相应的值,类似于函数中的形参。

更多关于RealView MDK的技术文章,请点击此处!

 

下面举个例子,这个例子中先定义一个宏,然后调用该宏,并显示调用该宏之后展开的汇编代码。让读者深刻理解宏的使用方法。

        MACRO

$Lab    DivMod  $Div,$Top,$Bot,$Temp

        ASSERT  $Top <> $Bot             ; Produce an error message if the

        ASSERT  $Top <> $Temp            ; registers supplied are

        ASSERT  $Bot <> $Temp            ; not all different

        IF      "$Div" <> ""

            ASSERT  $Div <> $Top         ; These three only matter if $Div

            ASSERT  $Div <> $Bot         ; is not null ("")

            ASSERT  $Div <> $Temp        ;

        ENDIF

$Lab

        MOV     $Temp, $Bot              ; Put divisor in $Temp

        CMP     $Temp, $Top, LSR #1      ; double it until

90      MOVLS   $Temp, $Temp, LSL #1     ; 2 * $Temp > $Top

        CMP     $Temp, $Top, LSR #1

        BLS     %b90                     ; The b means search backwards

        IF      "$Div" <> ""             ; Omit next instruction if $Div is null

            MOV     $Div, #0             ; Initialize quotient

        ENDIF

91      CMP     $Top, $Temp              ; Can we subtract $Temp?

        SUBCS   $Top, $Top,$Temp         ; If we can, do so

        IF      "$Div" <> ""             ; Omit next instruction if $Div is null

            ADC     $Div, $Div, $Div     ; Double $Div

        ENDIF

        MOV     $Temp, $Temp, LSR #1     ; Halve $Temp,

        CMP     $Temp, $Bot              ; and loop until

        BHS     %b91                     ; less than divisor

        MEND

更多关于RealView MDK的技术文章,请点击此处!

 

调用该宏语句:

ratio  DivMod  r0,r5,r4,r2

 

该宏展开后的汇编代码如下:

        ASSERT  r5 <> r4                   ; Produce an error if the

        ASSERT  r5 <> r2                   ; registers supplied are

        ASSERT  r4 <> r2                   ; not all different

        ASSERT  r0 <> r5                   ; These three only matter if $Div

        ASSERT  r0 <> r4                   ; is not null ("")

        ASSERT  r0 <> r2                   ;

ratio

        MOV     r2, r4                     ; Put divisor in $Temp

        CMP     r2, r5, LSR #1             ; double it until

90      MOVLS   r2, r2, LSL #1             ; 2 * r2 > r5

        CMP     r2, r5, LSR #1

        BLS     %b90                       ; The b means search backwards

        MOV     r0, #0                     ; Initialize quotient

91      CMP     r5, r2                     ; Can we subtract r2?

        SUBCS   r5, r5, r2                 ; If we can, do so

        ADC     r0, r0, r0                 ; Double r0

 

        MOV     r2, r2, LSR #1             ; Halve r2,

        CMP     r2, r4                     ; and loop until

        BHS     %b91                       ; less than divisor

看完以上例子,读者应该对MDK下宏的使用很清晰了。

下面以AT91RM9200为例,说明如何将一个普通函数用作中断服务子程序。

普通函数定义如下:

void AT91F_ST_HANDLER(void)

{

volatile int StStatus;

    // Read the system timer status register

    StStatus = *(AT91C_ST_SR);

    StTick++;

}

处理中断的宏为:

    MACRO

    IRQHandle $in_handle,$out_handle

    EXTERN $in_handle

    GLOBAL $out_handle

 

 

;#- Adjust and save LR_irq in IRQ stack

    sub         r14, r14, #4

    stmfd       sp!, {r14}

 

;#- Write in the IVR to support Protect Mode

;#- No effect in Normal Mode

;#- De-assert the NIRQ and clear the source in Protect Mode

    ldr         r14, =AT91C_BASE_AIC

    str         r14, [r14, #AT91C_AIC_IVR-AT91C_BASE_AIC]

 

;#- Save SPSR and r0 in IRQ stack

    mrs         r14, SPSR

    stmfd       sp!, {r0, r14}

 

;#- Enable Interrupt and Switch in SYS Mode

    mrs         r0, CPSR

    bic         r0, r0, #I_BIT

    orr         r0, r0, #ARM_MODE_SYS

    msr         CPSR_c, r0

   

;#- Save scratch/used registers and LR in User Stack

    stmfd       sp!, { r1-r3, r12, r14}

   

    ldr     r1,     =$in_handle

    mov     lr,     pc

    bx      r1

 

;#- Restore scratch/used registers and LR from User Stack

    ldmia       sp!, { r1-r3, r12, r14}

   

;#- Disable Interrupt and switch back in IRQ mode

    mrs         r0, CPSR

    bic         r0, r0, #ARM_MODE_SYS

    orr         r0, r0, #I_BIT|ARM_MODE_IRQ

    msr         CPSR_c, r0

 

;#- Mark the End of Interrupt on the AIC

    ldr         r0, =AT91C_BASE_AIC

    str         r0, [r0, #AT91C_AIC_EOICR-AT91C_BASE_AIC]

 

;#- Restore SPSR_irq and r0 from IRQ stack

    ldmia       sp!, {r0, r14}

    msr         SPSR_cxsf, r14

 

;#- Restore adjusted  LR_irq from IRQ stack directly in the PC

    ldmia       sp!, {pc}^

   

    MEND

    GLOBAL      AT91F_ST_ASM_HANDLER

AT91F_ST_ASM_HANDLER   

    IRQHandle AT91F_ST_HANDLER,AT91F_ST_ASM_HANDLER

以上红色部分即为利用定义的宏来处理中断。其中AT91F_ST_ASM_HANDLER是一个全局标号,可在其它文件中引用。AT91F_ST_ASM_HANDLER是前面定义的C函数。中断发生时道先找到标号AT91F_ST_ASM_HANDLER并执行其展开的汇编代码,保存PC及模式之后跳到C函数void AT91F_ST_HANDLER(void)。在返回该函数时有恢复PC和模式。这样就完成了一次中断的调用过程。

注:读者可能会注意到宏IRQHandle前面并没有标号,这也是允许的,该标号是可选的。

更多关于RealView MDK的技术文章,请点击此处!

附:

MDK中还允许直接使用中断函数,而无须使用汇编代码来处理中断。只须在中断服务子程序加上一些关键字来标识它是一个中断服务子程序,这样在编译器编译的时候会自动在服务子程序的入口和出口加上一些与中断相关的现场保护与恢复汇编指令。

中断标识符与您所选的编译器有关。强大的RealView MDK支持三种主流编译器。它们是RealView编译器、Keil CARM编译器以及GNU编译器。在使用不同的编译器时,中断标识符有所不同。现通过举例来说明不同编译器下中断标识符的用法:

RealView编译器:

__irq void IRQ_Handler (void) {

   /* the interrupt code */

}

Keil CARM编译器:

void IRQ_Handler (void) __irq  {

  /* the interrupt code */}

GNU编译器:

void IRQ_Handler (void) __attribute__ ((interrupt)); // Generate Interrupt

 

void IRQ_Handler (void) {

   /* the interrupt code */

}更多关于RealView MDK的技术文章,请点击此处!

 

 




关键词: RealView     中宏     使用方法     中断     函数     AS    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]