基于Keil a51汇编 —— MPL 宏定义

2023-10-09 19:04
文章标签 定义 keil 汇编 mpl a51

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

MPL 宏

Ax51汇编程序支持的宏处理语言(MPL)是一种字符串替换工具,使您能够编写可修复的代码块(宏)并将其插入源文本中的一个或多个位置。

宏处理器查看源文件的方式与汇编程序不同。

  • 对于汇编程序来说,源文件是一系列指令、语句和MCU指令。
  • 对于宏处理器,源文件是一长串经过处理的字符。宏处理器扫描源文件以搜索对已定义宏的调用。宏调用将替换为内置或用户定义的宏。

MPL 的一个有价值的功能是条件组装。在宏中使用条件汇编会导致紧凑的配置相关代码,这对于良好的程序设计至关重要。此外,它还生成尽可能紧凑的代码。

注意:

  • 宏处理在组装代码之前进行。它独立于程序集。宏时间不同于装配时间。因此,汇编程序知道的东西(如汇编语言符号、语言标签、使用 SET 和
    EQU 语句定义的符号以及位置计数器)对于宏处理器来说是未知的。

MPL 宏概述

在汇编程序中使用 MPL 宏相对容易。

  1. 使用MPL用于启用 MPL 宏处理器的汇编程序指令。更重要的是,使某些MPL宏扩展不会被禁用诺宏命令。
  2. 定义要使用的宏。您可以创建一个包含文件,其中包含要在源文件之间共享的宏定义。
  3. 调用或调用程序源中定义的宏函数。宏处理器扩展汇编程序组装的宏函数(在宏处理时)。

所有 MPL 预定义和用户定义的函数都必须以元字符开头。默认情况下,元字符是百分比 (‘%’) 字符。但是,元字符可能会被元炭MPL 函数。

MPL 元字符

所有 MPL 预定义和用户定义的函数都必须以元字符开头。默认情况下,元字符是百分号 (‘%’)。但是,元字符可能会被元炭MPL 函数。

定义 MPL 宏

定义 MPL 函数创建一个宏。定义函数的语法为:

%DEFINE (macro-name <[>parameter-list<]>) (macro-body)%*DEFINE (macro-name <[>parameter-list<]>) (macro-body)
%是元字符用于指示宏函数
*指定在文本模式下展开宏。
macro-name是宏的名称。宏名称最多可以包含 31 个字符,并且必须以 A-Z、a-z、_ 或 ?。后续字符可以是 A-Z、A-Z、_、?,或 0-9。
parameter-list是括在分隔符内并用分隔符分隔的参数列表。
macro-body是展开以替换宏名称和参数列表的文本。它可能包含对其他宏的调用。如果是这样,这些宏也会展开。定义宏时,在调用宏之前,宏主体中包含的那些宏调用不会展开。

注意:

  • 创建宏后,可以通过后续的 DEFINE 函数重新定义它。
  • 宏可以定义,也可以不带正式参数列表。
  • 参数列表是一个相当自由格式的列表。指定时要小心。

不带参数的宏

没有参数(或参数)的宏定义如下:

%*DEFINE (macro-name) (macro-body)

该定义需要宏名称和在调用宏时展开的宏主体。例如,以下宏定义:

%*DEFINE (my_asdf) (asdf)

当调用时:

%my_asdf

扩展到:

asdf

带参数的宏

具有参数(或参数)的宏定义如下:

%*DEFINE (macro-name <[>parameter-list<]>) (macro-body)

参数列表列出了传递给宏的形式参数。参数列表中的参数在宏主体中用于在调用宏时填充值。这允许您设计为许多操作生成代码的泛型宏。

参数列表中的参数由唯一标识符(您选择的)指定,这些标识符由宏分隔符(通常是括号和逗号)分隔。参数列表括在括号内,各个参数用逗号分隔。这只是一个约定,而不是一个要求。

参数列表规范的唯一要求是宏参数的传递方式和定义宏时使用的分隔符相同。例如,以下宏定义中的参数列表:

%*DEFINE (BMOVE (src, dst, cnt)) (...)

是(src,dst,cnt)。若要调用此宏,必须使用相同的分隔符指定参数。例如:

%BMOVE (1, 2, 3)

但是,没有理由必须将参数括在括号内或必须用逗号分隔。例如:

%*DEFINE (BMOVE src dst cnt) (...)

若要调用此宏,必须按如下方式指定参数:

%BMOVE 1 2 3

宏主体中的参数用参数名称表示,前面是元字符(在上面的示例中为 %src、%dst 和 %cnt)。以下宏定义显示了一个更完整的示例

%*DEFINE (BMOVE (src, dst, cnt)) LOCAL lab (MOV     R2,#%cntMOV     R1,#%srcMOV     R0,#%dst
%lab:   MOV     A,@R1MOV     @R0,AINC     R0INC     R1DJNZ    R2,lab
)

参数可以在宏主体中以任意次数和任意顺序使用。如果参数与宏同名并在宏正文中使用,则会展开该参数(而不是调用宏)。

如果宏与其中一个参数同名,则无法在宏主体中调用该宏,因为这会导致无限递归。

调用 MPL 宏

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

%*DEFINE (BMOVE (src, dst, cnt)) LOCAL lab (MOV     R2,#%cntMOV     R1,#%srcMOV     R0,#%dst
%lab:   MOV     A,@R1MOV     @R0,AINC     R0INC     R1DJNZ    R2,lab
)

若要调用此宏,请指定元字符后跟宏名称和参数列表(如果有)。实际参数必须具有平衡的文本,并且可以包含对其他宏的调用。例如,可以按如下方式调用上述宏:

%BMOVE (array1,array2,10)

宏扩展为:

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

注意:

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

局部符号

MPL 宏可能包括作为分支目标的本地标签。固定的标签名称会导致错误,如果多次调用宏。发生这种情况是因为同一标签名称在源文件中只能使用一次。此问题可以通过使用局部符号来解决。本地宏符号附加一个唯一的序列号,每次调用宏时,该数字都会递增。

必须在宏定义行中声明本地符号:

%*DEFINE (macro-name <[>parameter-list<]>) <[>LOCAL local-list<]> (macro-body)

其中,本地列表是宏的本地符号的列表(用逗号或空格分隔)。

局部符号在宏宏体中使用时必须以元字符为前缀。例如:

%*DEFINE (BMOVE (src, dst, cnt)) LOCAL lab (MOV     R2,#%cntMOV     R1,#%srcMOV     R0,#%dst
%lab:   MOV     A,@R1MOV     @R0,AINC     R0INC     R1DJNZ    R2,lab
)

表达式

MPL 宏处理器将平衡文本字符串解释为数值表达式,当它们用于以下 MPL 函数的参数时:

  • EVAL
  • IF
  • REPEAT
  • SUBSTR
  • WHILE

数值表达式的处理方式如下:

  • 表达式的文本以计算宏函数参数的普通方式展开。
  • 生成的字符串被计算为一个数值,该数值被转换为表达式值(表达式的最终值)的字符表示形式。数值表达式中可以使用以下运算符:
  • Parentheses()
  • HIGH,LOW
  • *, /, MOD, SHL, SHR
  • EQ, LT, LE, GT, GE, NE
  • NOT
  • AND,OR,XOR

MPL 数值表达式的算术是使用有符号 16 位整数执行的。关系运算符的结果为 0 (FALSE) 或 1 (TRUE)。

数值常量

可以使用下表中指定的后缀和字符以十六进制(以 16 为基数)、十进制(以 10 为基数)、八进制(以 8 为基数)和二进制(以 2 为基数)指定数字:

字符常量

MPL 宏处理器支持 ASCII 字符串,这些字符串可能包含一个或两个用单引号 (“'”) 括起来的字符。例如:
注意:
宏处理器无法访问汇编程序的符号表。因此,在宏处理过程中,标签以及 SET 和 EQU 符号的值是未知的。但是,您可以使用设置宏函数来定义宏符号。

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



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

相关文章

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

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

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

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

笔记整理—内核!启动!—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. 静态二维数组 定义: 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/)    - **简介**: 这是一个专注于嵌入式系统设计的专业网

java类中定义接口的有哪些好处

第一步:首先是是定义一个类,同时里面定义接口 public class Util { public interface Worker { void work(int a); } } 第二步:定义一个类去实现第一步类中定义的接口 public class Demo implements Worker { @Override public void work(int a) { System

vue3 为组件的 emits 标注类型,defineEmits基于类型的定义的简单理解

1)在 <script setup> 中,emit 函数的类型标注也可以通过运行时声明或是类型声明进行。 2)基于类型的: const emit = defineEmits<{ (e: 'change', id: number): void (e: 'update', value: string): void }>() 说明:e: 指定了方法名,id:数字型的参数,这个就是限定了方法名及

python 字符串的定义和操作方法

str='  why is money  ' # 获取字符串对应索引的值 print(f"{str[0]}") print(f"{str[-1]}") #获取对应字符元素的数量 num=str.count('y') print(f"字符y的数量:{num}") #对应元素所在的索引 index=str.index("is") print(f"{index}")