这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界» 论坛首页» 嵌入式开发» 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 跳转至

回复

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