基于Keil a51汇编 —— 标准宏定义

2023-10-10 13:45
文章标签 定义 keil 标准 汇编 a51

本文主要是介绍基于Keil a51汇编 —— 标准宏定义,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

定义标准宏

标准宏定义如下:

macro-name MACRO <[>parameter-list<]>
<[>LOCAL local-labels<]>
.
.
.
macro-body
.
.
.ENDM

macro-name 宏的名称
parameter-list 可以传递给宏的形式参数的可选列表

LOAD_R0 MACRO R0_ValMOV   R0, #R0_ValENDM

定义一个名为 LOAD_R0 的宏,该宏使用传递给宏的第一个参数的值加载寄存器 0。

注意:

  • 与 MPL 宏不同,一旦定义了标准宏,就可能无法重新定义它。
  • 宏可以定义,也可以不带正式参数列表。
  • 标准宏定义最多可嵌套 9 个级别。
  • 标准宏可以递归调用,深度可达 9 级。

宏参数
宏主体中的参数用参数名称(在上面的示例中为 src、dst 和 cnt)表示。它们可以在宏体内以任意次数和任何顺序使用。如果参数与宏同名并在宏主体中使用,则会展开该参数。不调用宏。

标准宏最多可以有 16 个参数。在宏定义和调用中,参数必须用逗号 (‘,’) 分隔。例如:

mymacro MACRO   P1,P2,P3,P4,P5,P6,P7,P8,P9,P10,P11,P12,P13,P14,P15,P16

您将按如下方式调用此宏:

mymacro A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P

您可以通过从宏调用中省略参数来传递参数的 NULL 值。分隔逗号仍然是必需的。例如:

mymacro A,,C,,E,,G,,I,,K,,M,,O,

空参数可以使用无宏运算符。

调用标准宏

下面定义了一个名为 BMOVE 的宏,该宏采用三个参数:源、目标和计数。宏生成的代码将任意数量的字节从内存的一部分复制到另一部分。

BMOVE   MACRO   src, dst, cnt
LOCAL   labMOV     R2,#cntMOV     R1,#srcMOV     R0,#dst
lab:    MOV     A,@R1MOV     @R0,AINC     R0INC     R1DJNZ    R2,labENDM

若要调用此宏,请指定宏名称和参数列表。例如,可以按如下方式调用上述宏:

BMOVE array1, array2, 10

宏扩展为:

		   MOV     R2,#10MOV     R1,#array1MOV     R0,#array2
??0000:    MOV     A,@R1MOV     @R0,AINC     R0INC     R1DJNZ    R2,??0000

注意:

  • 上面的示例会产生程序集错误,因为源文件不包含段定义。
  • 这根和玄美指令可用于在汇编程序列表文件中包括宏定义和宏调用。

局部符号(LOCAL)

标准宏可能包括作为分支目标的本地标签。

固定的标签名称会导致错误,如果多次调用宏。发生这种情况是因为同一标签名称在源文件中只能使用一次。此问题可以通过使用局部符号来解决。本地宏符号将替换为唯一的顺序编号标签,该标签在每次调用宏时递增。

下面的示例演示如何使用宏定义中的 LOCAL 语句创建本地标签实验室。

BMOVE   MACRO   src, dst, cnt
LOCAL   labMOV     R2,#cntMOV     R1,#srcMOV     R0,#dst
lab:    MOV     A,@R1MOV     @R0,AINC     R0INC     R1DJNZ    R2,labENDM

注意:

  • 必须在紧跟在宏定义后面的行中声明本地标签。
  • 一个宏中最多可以定义 16 个本地标签。

退出宏(EXITM)

EXITM 指令立即终止宏扩展。检测到此指令时,宏处理器将停止扩展当前宏,并在下一个 ENDM 指令之后恢复处理。EXITM 指令在条件语句中很有用。例如:

WAIT    MACRO X            ; macro definitionIF NUL X           ; make sure X has a valueEXITM            ; if not then exitENDIFREPT X             ; generate X NOP instructionsNOPENDM               ; end REPT
ENDM                       ; end MACRO

内置宏

标准宏处理器具有三个内置宏,可以单独使用,也可以在宏定义中使用。它们是:

  • 这REPT宏,将块重复指定次数的宏。
  • 这IRP宏,为每个指定的参数重复一个块一次。
  • 这IRPC宏,为字符串中的每个字符重复一个块一次。

这些内置宏中的每一个都必须以 ENDM 语句终止。

REPT
REPT 内置宏定义如下:

REPT count macro-body
ENDM
  • count 是宏观主体展开的次数
  • macro-body 是调用宏时展开的文本。

例如:

REPT 5NOP
ENDM

扩展为:

		NOPNOPNOPNOPNOP

IRP
IRP 内置宏定义如下:

IRP parm-name, <parm-list>macro-body
ENDM
  • parm-name 是宏主体中使用的参数名称。每次展开宏时,都会使用参数列表中的后续值来替换宏主体中的参数名称。
  • parm-list 是参数名称替换值的列表。

例如:

IRP regnum, <R0,R1,R2,R3,R4>PUSH    A&regnum
ENDM

扩展为:

        PUSH    AR0PUSH    AR1PUSH    AR2PUSH    AR3PUSH    AR4

IRPC
IRPC 内置宏定义如下:

IRPC parm-name, parm-stringmacro-body
ENDM

parm-name

  • List item 是宏主体中使用的参数名称。每次展开宏时,都会使用参数字符串中的后续字符来替换宏主体中的参数名称。
  • parm-string 是文本字符串,其字符用于替换宏正文中的参数名称。

例如:

IRPC sendchar, TESTMOV     R0, #'sendchar'CALL    outchar
ENDM

扩展为:

        MOV     R0, #'T'CALL    outcharMOV     R0, #'E'CALL    outcharMOV     R0, #'S'CALL    outcharMOV     R0, #'T'CALL    outchar

标准宏运算符

有几个运算符可用于标准宏。

符号描述
NULNUL 运算符用于确定宏参数是否为 NULL
&与号运算符用于连接文本和参数
<>尖括号运算符用于文字化逗号和空格等分隔符
%百分号运算符用于表示解释为表达式的宏参数
;;双分号运算符指示应忽略该行的后续文本
!感叹号运算符用于表示文字字符

NUL 运算符
当宏调用中省略形式参数时,将为其分配值 NULL。可以通过在宏的 IF 控制语句中使用 NUL 运算符来检查 NULL 参数。

NUL 运算符需要一个参数。如果未找到参数,NUL 将返回值 0。

EXAMPLE MACRO   XIF NUL XEXITMENDIFNOPENDMEXAMPLE            ; Invoke the macro with no parameters
;Nothing is output since the macro exits (because the x parameter is NULL)

注意:

  • 空白字符 (’ ') 的 ASCII 值为 20h,不等同于 NULL。

& 运算符
与号运算符 (‘&’) 可用于连接文本和宏参数,如以下示例所示:

MAK_NOP_LABEL MACRO XLABEL&X: NOPENDM

此宏为每个调用插入一个新标签和一个 NOP 指令。传递给宏的参数将追加到文本 LABEL 中,以便为每行创建标签。例如:

LOC     OBJ     LINE  SOURCE1     MAK_NOP_LABEL MACRO X2             LABEL&X: NOP3             ENDM456     MAK_NOP_LABEL 1
0000    00      7+1   LABEL1: NOP8     MAK_NOP_LABEL 2
0001    00      9+1   LABEL2: NOP10    MAK_NOP_LABEL 3
0002    00      11+1  LABEL3: NOP12    MAK_NOP_LABEL 4
0003    00      13+1  LABEL4: NOP1415    END

<> 运算符
尖括号字符(“<”、“>”)将应按字面传递到宏的文本括起来。某些字符(如逗号 (‘,’)必须括在尖括号中才能传递给宏。

下面的示例演示在尖括号内传递参数列表的宏声明和调用。

1 FLAG_CLR MACRO FLAGS
2 MOV A, #0
3 IRP F, <FLAGS>
4 MOV FLAG&F, A
5 ENDM
6 ENDM
7
8 DSEG
0000 9 FLAG1: DS 1
0001 10 FLAG2: DS 1
0002 11 FLAG3: DS 1
0003 12 FLAG4: DS 1
0004 13 FLAG5: DS 1
0005 14 FLAG6: DS 1
0006 15 FLAG7: DS 1
0007 16 FLAG8: DS 1
0008 17 FLAG9: DS 1
18
19 CSEG
20
21 FLAG_CLR <1>
0000 7400 22+1 MOV A, #0
23+1 IRP F, <1>
24+1 MOV FLAG&F, A
25+1 ENDM
0002 F500 26+2 MOV FLAG1, A
27 FLAG_CLR <1,2,3>
0004 7400 28+1 MOV A, #0
29+1 IRP F, <1,2,3>
30+1 MOV FLAG&F, A
31+1 ENDM
0006 F500 32+2 MOV FLAG1, A
0008 F501 33+2 MOV FLAG2, A
000A F502 34+2 MOV FLAG3, A
35 FLAG_CLR <1,3,5,7>
000C 7400 36+1 MOV A, #0
37+1 IRP F, <1,3,5,7>
38+1 MOV FLAG&F, A
39+1 ENDM
000E F500 40+2 MOV FLAG1, A
0010 F502 41+2 MOV FLAG3, A
0012 F504 42+2 MOV FLAG5, A
0014 F506 43+2 MOV FLAG7, A

在前面的示例中,声明了 FLAG_CLR 宏以清除多个标志变量中的任何一个。FLAGS 参数指定第 3 行中的 IRP 指令使用的参数列表。IRP 指令重复指令 MOV FLAG&F,A 表示 FLAGS 参数中的每个参数。

FLAG_CLR宏在第 21、27 和 35 行中调用。在第 21 行中,只传递一个参数。在第 27 行中传递三个参数,在第 35 行中传递四个参数。参数列表括在尖括号中,因此可以将其称为单个宏参数 FLAGS。宏生成的代码位于第 26、32-34 和 40-43 行。

& 运算符
百分比运算符 (‘%’) 用于将表达式的值传递给宏,而不是传递文本表达式本身。下面的示例演示一个宏定义,该定义需要一个数值以及使用百分比运算符将表达式的值传递给宏的宏调用。

OUTPORT MACRO   NMOV     R1, #NENDMRESET_SIG EQU 0FFh
CLEAR_SIG EQU 0OUTPORT %(RESET_SIG AND NOT 11110000b)
; Expands into MOV R1, #15OUTPORT %(CLEAR_SIG OR 11110000b)
; Expands into MOV R1, #240

无法将突出显示的行中计算的表达式传递给宏,因为宏需要数值。此类表达式必须在宏之前计算。百分比运算符强制汇编程序生成一个数值,然后将其传递给宏。

;; 运算符
双分号运算符 (‘;;’) 用于指示在展开宏时不应输出行上的其余文本。此运算符通常用于在宏扩展中不需要的注释之前。例如:

MOV_R_A MACRO   n                       ;; helper macroMOV     R&n,A                   ;; set R# to 0ENDMREGCLR  MACRO   CNTREGNUM  SET 0MOV     A, #0                   ;; load A with 0REPT    CNT             ;; rpt for CNT registersMOV_R_A %REGNUM         ;; set R# to 0REGNUM  SET REGNUM+1ENDMENDM

! 运算符
感叹号运算符 (‘!’) 用于指示要按字面方式将特殊字符传递给宏。使用此运算符,可以将逗号 (‘,’) 和尖括号字符(‘<’ 和 ‘>’)(通常被解释为分隔符)传递给宏。

这篇关于基于Keil a51汇编 —— 标准宏定义的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/180832

相关文章

MCU7.keil中build产生的hex文件解读

1.hex文件大致解读 闲来无事,查看了MCU6.用keil新建项目的hex文件 用FlexHex打开 给我的第一印象是:经过软件的解释之后,发现这些数据排列地十分整齐 :02000F0080FE71:03000000020003F8:0C000300787FE4F6D8FD75810702000F3D:00000001FF 把解释后的数据当作十六进制来观察 1.每一行数据

数据治理框架-ISO数据治理标准

引言 "数据治理"并不是一个新的概念,国内外有很多组织专注于数据治理理论和实践的研究。目前国际上,主要的数据治理框架有ISO数据治理标准、GDI数据治理框架、DAMA数据治理管理框架等。 ISO数据治理标准 改标准阐述了数据治理的标准、基本原则和数据治理模型,是一套完整的数据治理方法论。 ISO/IEC 38505标准的数据治理方法论的核心内容如下: 数据治理的目标:促进组织高效、合理地

Spring 源码解读:自定义实现Bean定义的注册与解析

引言 在Spring框架中,Bean的注册与解析是整个依赖注入流程的核心步骤。通过Bean定义,Spring容器知道如何创建、配置和管理每个Bean实例。本篇文章将通过实现一个简化版的Bean定义注册与解析机制,帮助你理解Spring框架背后的设计逻辑。我们还将对比Spring中的BeanDefinition和BeanDefinitionRegistry,以全面掌握Bean注册和解析的核心原理。

C 标准库 - `<float.h>`

C 标准库 - <float.h> 概述 <float.h> 是 C 标准库中的一个头文件,它定义了与浮点数类型相关的宏。这些宏提供了关于浮点数的属性信息,如精度、最小和最大值、以及舍入误差等。这个头文件对于需要精确控制浮点数行为的程序非常有用,尤其是在数值计算和科学计算领域。 主要宏 <float.h> 中定义了许多宏,下面列举了一些主要的宏: FLT_RADIX:定义了浮点数的基数。

笔记整理—内核!启动!—kernel部分(2)从汇编阶段到start_kernel

kernel起始与ENTRY(stext),和uboot一样,都是从汇编阶段开始的,因为对于kernel而言,还没进行栈的维护,所以无法使用c语言。_HEAD定义了后面代码属于段名为.head .text的段。         内核起始部分代码被解压代码调用,前面关于uboot的文章中有提到过(eg:zImage)。uboot启动是无条件的,只要代码的位置对,上电就工作,kern

浙大数据结构:树的定义与操作

四种遍历 #include<iostream>#include<queue>using namespace std;typedef struct treenode *BinTree;typedef BinTree position;typedef int ElementType;struct treenode{ElementType data;BinTree left;BinTre

类和对象的定义和调用演示(C++)

我习惯把类的定义放在头文件中 Student.h #define _CRT_SECURE_NO_WARNINGS#include <string>using namespace std;class student{public:char m_name[25];int m_age;int m_score;char* get_name(){return m_name;}int set_name

《C++标准库》读书笔记/第一天(C++新特性(1))

C++11新特性(1) 以auto完成类型自动推导 auto i=42; //以auto声明的变量,其类型会根据其初值被自动推倒出来,因此一定需要一个初始化操作; static auto a=0.19;//可以用额外限定符修饰 vector<string> v;  auto pos=v.begin();//如果类型很长或类型表达式复杂 auto很有用; auto l=[] (int

c++ 定义二位数组

在 C++ 中,定义二维数组有几种常见的方式。以下是几个示例: 1. 静态二维数组 定义: int array[3][4]; 这里,array 是一个 3 行 4 列的整数二维数组。 初始化: int array[3][4] = {{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12}}; 2. 动态二维数组 使用指针和动态内存分配: 定义:

汇编:嵌入式软件架构学习资源

成为嵌入式软件架构设计师需要掌握多方面的知识,包括嵌入式系统、实时操作系统、硬件接口、软件设计模式等。 以下是一些推荐的博客和网站,可以帮助你深入学习嵌入式软件架构设计: ### 1. **Embedded.com**    - **网址**: [Embedded.com](https://www.embedded.com/)    - **简介**: 这是一个专注于嵌入式系统设计的专业网