esp32 c3蓝牙开发乐鑫科技华南代理商汇编程序示例,[例1] 计算 A=1+2+3+...+99+100。
分析:实现 1~100 的循环加法,并将结果保存到内存中。
在esp32 c3蓝牙开发乐鑫科技华南代理商汇编语言程序中,声明循环次数和变量 A 的存储地址两个常数。使用 0和t1 寄存器分别保存循环次数和变量 A 的临时值。
在 gas 汇编语言中,用符号“NAME”代替特定值 VALUE 的声明方式如下:
.equ NAME,VALUE//NAME = VALUE
示例5.3: 实现累加和的汇编程序。
/*1+2+...+99+100 */
1 .section .text,"ax" //声明.text 段及其属性
2 .global _start //声明全局标签_start,指定程序人口
3 .equ NUMBER,100 //设定循环次数
4 .equ MEMADD,0x400000 //设定存储变量A的地址
5 _start:
6 li t0,NUMBER //计数寄存器t0循环初始值100
7 li t1,0 //累加加过寄存器t1清0
8 addloop: //行标签
9 add t1 ,t1,t0 //t1=t1+10,累加计算
10 addi t0,t0,-1 //循环计数器-1
11 bltu x0,t0,addloop //if t0>0,循环计算
12 li t5,MEMADD //装载存储地址到 t5
13 sw t1,(t5) //保存数据到内存
14 nop //空操作
15 .end
在示例 5.3 中:
第 1、2 行,分别声明段属性和全局标签;
第 3、4 行,常数声明;
第 6、7 行,装载立即数,用伪指令 li 装任意 32 位数;
第 9、10 行,循环主体部分,第 9 行累加计算,第 10 行循环变量减 1,esp32 c3蓝牙开发乐鑫科技华南代理商使用变量递减方式进行循环;
第 13 行,保存数据,将累加结果从 t1 寄存器写人内存 MEMADD 地址处。
0x11 0x120x13 0x14
[例2] 矩阵A= 0x21 0x22 0x23 0x24 ,计算A[3][0]= A[2][0]+A[1][0]。
0x31 0x32 0x33 0x34
esp32 c3蓝牙开发乐鑫科技华南代理商分析: 从保存矩阵数据 内存中的两个不同地址读取数据,并将这两个数据的和写入矩阵数据内存中其他地址。
程序的主要关注点:
1 如何在程序中声明数据段?
2 如何在内存中分配空间并初始化数据?
3 如何获取所分配数据空间的地址?
示例 5.4:矩阵计算程序
/ Array */
1 . section . text,"ax' /声明.text 段及其属性
2 .global_start /声明全局标签 _start,指定程序入口
3 _start;
4 la a0, array //装载矩阵数组起始地址
5 Iw al,4*4(a0) //读取 A[1][0]
6 lw a4,8*4(a0) //读取 A[2][0]
7 add al ,al ,a4 //相加
8 sw al,12 * 4(a0) //写人A[3][0]
9 nop //空操作
10 . section .data_run,"w' //声明可读写数据段
11 .global array //声明全局标签
12 array: //矩阵标签
13 .word 0x11,0x12,0x13,0x14 //分配内存,并初始化数组
14 .word 0x21,0x22,0x23,0x2414 //分配内存,并初始化数组
15 .word 0x31,0x32,0x33,0x34 //分配内存,并初始化数组
16 .end //结束符
在示例 5.4中:
第 4行,使用伪指令 la 装载数组在内存中的基地址 array;
第 5、6 行,从内存中读取 4 字节数据;
第 8 行,把数据写入内存中;
第 10 行,声明运行时数据段及其属性,可写、可分配并初始化:第 11 行,声明数据段地址标签 array 为全局标签;
第 13、14、15 行分配内存空间并设置初始数据。
[例3] 定义宏,实现任意两个内存块之间,任意长度的数据移动。esp32 c3蓝牙开发乐鑫科技华南代理商使用所定义的宏,实现内存中长度 1K 数据的复制。
分析: 定义宏的名称和输入参数。输入参数包括源地址、目标地址和数据长度将宏名称定义为 MEMCPY,声明 3 个参数分别是源地址存器“src”目标存器“dst”和数据长度寄存器“length”。
在 gas 汇编语言中,宏定义的命令格式如下:
.macro name arg.[,arg.] //声明名称是 name 的指令宏块,arg 为形式参数。
在 gas 汇编语言中,“\”是宏块中的输入参数符。
程序的主要关注点:
1声明宏的方式;
2宏定义中参数的表示形式;
3引用宏的方式。
示例5.5:宏定义声明。
/* .macro definition */
1 .macro MEMCPY src,dst,length //宏名和参数定义
2 mv to,\length //复制长度寄存器
3 my t1,src //复制源地址寄存器
4 mv t2,\dst //复制目标地址寄存器
5 1: //局部标签
6 Ib t3,(t1) //读1字节
7 sb t3,(t2) //写1字节
8 addi tl ,t1,1 //源地址+1
9 addi t2,t2,1 //目标地址 +1
10 addi t0,t0,- //长度计数器 -1
11 bltu x0,t0,1b //跳转 1
12 .endm //宏结束
示例5.5中:
第 1、12 行,名字为 MEMCPY 宏的声明和结束命令;
第 2~4 行,把参数寄存器的值复制到临时寄存器;
第 6~10 行,循环主体,从源地址读取(lb)一字节数据,写入(sb)到目标地址。总循环次数是需要移动的数据长度。
第5行,局部标签(local label)“1”,第 11行是跳转到局部标签的语句,“1b”中的“b”表示“back”往回跳(地址减小的方向)。如果跳向地址增加的方向(“forward”)则将“b”换成“f”。esp32 c3蓝牙开发乐鑫科技华南代理商在同一个程序中可能多次引用宏,如果在宏中使用普通标签,则可能出现程序中不同地址使用同一标签的情形。因此,在宏块中,使用局部标签。
示例 5.6:主程序中引用宏。
/* .macro reference in program * /
1 .equ DSADD,0x20008000 //日标地址
2 .equ NUMBER,32 //数据长度
3 .section .text,"ax" //声明.text 域和属性
4 .global_start //声明全局标签 _start,指定程序入口
5 _start:
6 la a ,memdata //装载源地址
7 li al,DSADD //装载目标地址
8 li a3,NUMBER //装载数据长度
9 MEMCPY a0,a1,a3 //引用宏
10 nop //空操作
11 .section .data_run,"wa", % progbits //数据区定义
12 .global memdata //数据标签
13 memdata: //数据标签
14 .word 0x11223344,0x22334455,0x33445566,0x44556677 //数据
15 .word 0x55667788,0x66778899,0x77889900,0x88990011 //数据
16 .word 0x99001122,0x88990011,0x99112233,0x88990011 //数据
17 .end
在示例5.6中。使用 MRMCPY将数据从初始数新区 memdatn 复制到目标地址0x20008000。
第 1、2 行,声明目标地址和数据长度;
第 6~8 行,参数赋值;
第9行,引用宏 MEMCPY,引用方式与指令格式相似,宏名称后跟随实际参数。多引用时,esp32 c3蓝牙开发乐鑫科技华南代理商实际参数的类型和数量必须与宏定义中形式参数的类型和数量一致。