链接:https://pan.baidu.com/s/1bG0tuVaACATvjLwD05j1FQ?pwd=1688
提取码:1688
上午:ARM编程模型
下午:常用ARM指令
教学内容:
1、ARM数据类型
字节(Byte):在ARM体系结构及常见的8位/16位处理器体系结构中,字节的长度均为8位
字(Word):在ARM体系结构中,字的长度为32位,而在8位/16位处理器体系结构中,字的长度一般为16位(注:字必须与4字节的边界对准)
半字(Half-Word):在ARM体系结构中,半字的长度为16位,与8位/16位处理器体系结构中字的长度一致。(注:半字必须与2字节的边界对准)
每一个地址存储都是8位,32处理器是指能运算32位运算,一般就有32位地址/数据线。
2、ARM体系结构的存储器格式
大端格式:字数据的高字节存储在低地址中,而字数据的低字节则存放在高地址中
小端格式:低地址中存放的是字数据的低字节,高地址存放的是字数据的高字节
arm的大小端可以自己设置,默认是小端,不论大端还是小端,每一个地址(8位)存储数据都从小大存,比如:
要存511=255+256,(地址从高到低)小端方式:1 FF 大端方式:FF 1
3、ARM微处理器的工作状态
两种工作状态:
ARM:处理器执行32位的字对齐的ARM指令(4字节对齐)
Thumb:处理器执行16位的半字对齐的Thumb指令(2字节对齐,更节省空间)
系统开始的时候只能是ARM,Thumb状态不能处理异常,发生异常时候,系统自动切换为ARM态,处理完自动切换成Thumb态。
对于ARM状态来说,所有的数据包括代码存储都是按4字节存储,而Thumb状态的计算还是按32位方式计算,仅仅只是把代码按2字节方式存储,所以Thumb状态的节省空间仅仅是节省程序空间。
ARM的存储方式和51不同,而与计算机形式相同。flash相当于硬盘,RAM相当于内存条。
4、中断和异常
ARM有7种中断方式:
1)、复位
处理器上一旦有复位输入,ARM处理器立刻停止执行当前指令。复位后,ARM处理器在禁止中断的管理模式下,从地址0x00000000开始执行代码
2)、未定义指令异常
当ARM处理器执行协处理器指令时,它必须等待任一外部协处理器应答后,才能真正执行这条指令。若协处理器没有响应,就会出现未定义指令异常
3)、软件中断异常
该异常由执行SWI指令产生,在操作系统中系统调用的实现就是借助于此异常(一般用于状态切
4)、预取中止(取指令存储器中止)
若处理器预取指令的地址不存在,或该地址不允许当前指令访问,存储器会向处理器发出中止信号,但当预取的指令被执行时,才会产生指令预取中止异常,常用作虚拟内存保护
5)、数据中止(访问数据存储器中止)
若处理器数据访问指令的地址不存在,或该地址不允许当前指令访问时,产生数据中止异常
6)、IRQ异常
当处理器的外部中断请求引脚有效,且CPSR中的I=0,产生IRQ异常系统的外设可通过该异常请求中断服务
7)、FIQ异常
当处理器的外部中断请求引脚有效,且CPSR中的F=0,产生FIQ异常FIQ支持数据传送和通道处理,并有足够的私有寄存器,从而在应用中可避免对寄存器保存的需求,减少了开销
5、ARM微处理器的工作模式
ARM 有7个基本工作模式
1)、用户模式(usr):
正常程序执行的模式,大部分任务执行在这种模式
2)、快速中断模式(fiq): 高速数据传输或通道处理
当一个高优先级(fast)中断产生时将会进入这种模式
3)、外部中断模式(irq):通常的中断处理
当一个低优先级(normal)中断产生时将会进入这种模式
4)、管理模式(svc):
当复位或软中断指令执行时将会进入这种模式
供操作系统使用的一种保护模式
5)、中止模式(abt):虚拟存储及存储保护
当存取异常时将会进入这种模式
6)、未定义模式(und):软件仿真硬件协处理器
当执行未定义指令时会进入这种模式
7)、系统模式(sys): 特权级的操作系统任务
供需要访问系统资源的操作系统任务使用
6、ARM体系结构的寄存器组织
ARM处理器总共有37个寄存器:
31个32位的通用寄存器;6个状态寄存器
R0-R7:8个 R8-R14:12个 PC:1个 CPSR:1个 SPSR:5个 R13-R14:10个
共有:
8+12+1+1+5+10=37,6个状态,31个通用寄存器;其中R13一般作为SP指针,R14作为PC寄存器
未分组寄存器R0~R7
在所有的运行模式下,未分组寄存器都指向同一个物理寄存器,他们未被系统用作特殊的用途
分组寄存器R8~R14
使用fiq模式时,访问寄存器R8_fiq~R12_fiq;
使用除fiq模式以外的其他模式时,访问寄存器R8_usr~R12_usr
在所有处理器模式下都可以访问当前程序状态寄存器CPSR (Current Program Status Register)。
每种异常模式都有一个保存程序状态寄存器SPSR (Saved Program Status Register)。当异常出现时,SPSR用于保留CPSR的状态
由于用户模式和系统模式不属于异常模式,他们没有SPSR,当在这两种模式下访问SPSR,结果是未知的
T为处理器工作状态选择位:T=1,程序运行于Thumb态
I和F为中断/快中断禁止位;I=1,禁止IRQ中断 F=1,禁止FIQ中断
M0-M4:设置工作模式
第三项的“C的值”是"V的值"
注意,对于减法来说C是反的,有借位C=0,没借位C=1。
7、ARM指令
ARM指令格式如下:
ARM寻址方式:
立即数寻址,寄存器寻址,寄存器间接寻址,基址变址寻址,多寄存器寻址,相对寻址,堆栈寻址
立即数寻址:ADD R0,R0,#1; R0+1->R0
寄存器寻址:ADD R0,R1,R2; R1+R2->R0
寄存器间接寻址:LDR R0,[R1]; [R1]->R0
基址变址寻址:LDR R0,[R1,#4]; [R1+4]->R0
LDR R0,[R1],#4; [R1]->R0,R1+4->R1
LDR R0,[R1,#4]!; [R1+4]->R0,R1+4->R1
多寄存器寻址:LDMIA R0,{R1,R2,R3,R4};
[R0]->R1,[R0+4]->R2,[R0+8]->R3,[R0+12]->R4
相对寻址: BL NEXT; 跳转到NEXT标号处
堆栈寻址:
满堆栈:指针指向最后存储地址的堆栈
空堆栈:指针指向要存的下一地址的堆栈(比如51)
递增堆栈:存储是从小到大地址存
递减堆栈:存储是从大到小地址存
ARM微处理器支持这四种类型的堆栈工作方式:
-满递增堆栈:堆栈指针指向最后压入的数据,且由低地址向高地址生成
-满递减堆栈:堆栈指针指向最后压入的数据,且由高地址向低地址生成
-空递增堆栈:堆栈指针指向下一个将要放入数据的空位置,且由低地址向高地址生成
-空递减堆栈:堆栈指针指向下一个将要放入数据的空位置,且由高地址向低地址生成
如果是满堆栈方式,是存前改变SP,取之后再改变SP;而如果空堆栈方式,是存后改变SP,取前改变SP
7、ARM指令
ARM指令可以添加执行条件,条件判断主要是看CPSR中的N,Z,C,V即有16条件判断:
数据传送指令:
— MOV 数据传送指令 — MVN 数据取反传送指令
— CMP 比较指令 — CMN 反值比较指令
— TST 位测试指令 — TEQ 相等测试指令
— ADD 加法指令 — ADC 带进位加法指令
— SUB 减法指令 — SBC 带借位减法指令
— RSB 逆向减法指令 — RSC 带借位的逆向减法指令
— AND 按位与指令 — ORR 按位或指令
— EOR按位异或指令 — BIC 位清除指令
红色指令不能加条件
注:不加S的运算不会影响状态寄存器
//-----------------------------------------------------------------
例如:
MOV R0,R1; R1->R0
MOVEQ R0,R1; 如果Z=1;执行R1->R0
MOVS R1,R0,LSL#3; S为指令会改变CPSR,LSL逻辑左移,即R0*8->R1
MVN R1,#0; 0的反码为 0XFFFFFFFF,以补码来看即-1,-1->R1
CMP R1,R0; 比较R1和R0,即R1-R0,结果影响CPSR
CMN R1,#100; R1+100,结果影响CPSR
TST R1,#%1; TST做微与计算,%为二进制,测试最低位是否为0,为真,则Z=1
TST R1,#0Xfe; 测试低1-7位是否为1,为真,则Z=1
TEQ R1,R0; R1和R0异或,如果R0和R1相等,则Z=1
ADD R0,R1,R2; R1+R2->R0
ADD R0,R1,R2,LSL#1; R2*2+R1->R0
ADC R0,R1,R2; R1+R2+C->R0
SUB R0,R1,R2,LSL#2 ; R1-R2*2->R0
SBCS R0,R1,R2; R1-R1-!C->R0
RSB R0,R1,R2; R2-R1->R0
RSC R0,R1,R2; R2-R1-!C->R0
AND R0,R1,#3; R1&3->R0
ORR R0,R1,#3; R1|3->R0
EOR R0,R1,#3; R1^3->R0
BIC R0,R0,#%1011; 清除R0的0,1,3位再赋值给R0
//--------------------------------------------------------------------------
乘法指令:
ARM的乘法指令有6条,可分为32位和64位计算的,指令中的所有操作数、目的寄存器必须为通用寄存器,不能对操作数使用立即数或被移位的寄存器,同时,目的寄存器和操作数1必须是不同的寄存器
— MUL 32位乘法指令
— MLA 32位乘加指令
— SMULL 64位有符号数乘法指令
— SMLAL 64位有符号数乘加指令
— UMULL 64位无符号数乘法指令
— UMLAL 64位无符号数乘加指令
例如:
//--------------------------------------------------------------------------
MUL R0,R1,R2; R1*R2->R0
MLA R0,R1,R2,R3; R1*R2+R3->R0
SMULL R0,R1,R2,R3; 低32位的R2*R3->R0,高32位的R2*R3->R1
SMALAL R0,R1,R2,R3; R0=(R2*R3)的低32位+R0 ,R1=(R2*R3)的高32位+R1
UMULL R0,R1,R2,R3; R0=(R2*R3)的低32位+R0 ,R1=(R2*R3)的高32位+R1
UMLAL R0,R1,R2,R3; R0=(R2*R3)的低32位+R0 ,R1=(R2*R3)的高32位+R1
//*******************************************************
8、CPSR的访问
MRS指令的格式为:
MRS{条件} 通用寄存器,程序状态寄存器(CPSR或SPSR)
MRS指令用于将程序状态寄存器的内容传送到通用寄存器中。该指令一般用在以下几种情况:当需要改变程序状态寄存器的内容时,可用MRS将程序状态寄存器的内容读入通用寄存器,修改后再写回程序状态寄存器当在异常处理或进程切换时,需要保存程序状态寄存器的值,可先用该指令读出程序状态寄存器的值,然后保存
MRS R0,CPSR ;传送CPSR的内容到R0
MRS R0,SPSR ;传送SPSR的内容到R0
MSR指令的格式为:
MSR{条件}程序状态寄存器(CPSR或SPSR)_<域>,操作数
MSR指令用于将操作数的内容传送到程序状态寄存器的特定域中
<域>用于设置程序状态寄存器中需要操作的位,32位的程序状态寄存器可分为4个域:位[31:24]为条件标志位域,用f表示;位[23:16]为状态位域,用s表示; 位[15:8]为扩展位域,用x表示;位[7:0]为控制位域,用c表示;
MSR CPSR,R0 ;传送R0的内容到CPSR
MSR SPSR,R0 ;传送R0的内容到SPSR
MSR CPSR_c,R0 ;传送R0的内容到SPSR,但仅仅修改CPSR中的控制位域
9、内存访问指令
常用的加载存储指令如下:
— LDR 字数据加载指令
— LDRB 字节数据加载指令
— LDRH 半字数据加载指令
— STR 字数据存储指令
— STRB 字节数据存储指令
— STRH 半字数据存储指令
1)、LDR指令
LDR指令的格式为:
LDR{条件} 目的寄存器,<存储器地址>
LDR指令用于从存储器中将一个32位的字数据传送到目的寄存器中。
当程序计数器PC作为目的寄存器时,指令从存储器中读取的字数据被当作目的地址,从而可以实现程序流程的跳转
2)、LDRB指令
LDRB指令的格式为: LDR{条件}B 目的寄存器,<存储器地址>
LDRB R0,[R1] ;将存储器地址为R1的字节数据读入 寄存器R0,并将R0的高24位清零
LDRB R0,[R1,#8] ;将存储器地址为R1+8的字节数据读入寄存器R0,并将R0的高24位清零
3)、LDRH指令
LDRH指令的格式为:
LDR{条件}H 目的寄存器,<存储器地址>
LDRH R0,[R1] ;将存储器地址为R1的半字数据读入寄存器R0,并将R0的高16位清零
LDRH R0,[R1,#8] ;将存储器地址为R1+8的半字数据读入寄存器R0,并将R0的高16位清零
LDRH R0,[R1,R2] ;将存储器地址为R1+R2的半字数据读入寄存器R0,并将R0的高16位清零
4)、STR指令
STR指令的格式为:
STR{条件} 源寄存器,<存储器地址>
STR指令用于从源寄存器中将一个32位的字数据传送到存储器中。该指令在程序设计中比较常用,且寻址方式灵活多样,使用方式可参考指令LDR
STR R0,[R1],#8 ;将R0中的字数据写入以R1为地址的存储器中,并将新地址R1+8写入R1
STR R0,[R1,#8] ;将R0中的字数据写入以R1+8为地址的存储器中
5)、STRB指令
STRB指令的格式为:
STR{条件}B 源寄存器,<存储器地址>
STRB指令用于从源寄存器中将一个8位的字节数据传送到存储器中
STRB R0,[R1] ;将寄存器R0中的字节数据写入以R1为地址的存储器中
STRB R0,[R1,#8] ;将寄存器R0中的字节数据写入以R1+8为地址的存储器中
6)、STRH指令
STRH指令的格式为:
STR{条件}H 源寄存器,<存储器地址>
STRH指令用于从源寄存器中将一个16位的半字数据传送到存储器中。该半字数据为源寄存器中的低16位
STRH R0,[R1] ;将寄存器R0中的半字数据写入以R1为地址的存储器中
STRH R0,[R1,#8] ;将寄存器R0中的半字数据写入以R1+8为地址的存储器中
9、批数据加载和存储
-IA 每次传送后地址加1;
-IB 每次传送前地址加1;
-A 每次传送后地址减1;
-DB 每次传送前地址减1;
-FD 满递减堆栈;
-ED 空递减堆栈;
-FA 满递增堆栈;
-EA 空递增堆栈;
LDM(或STM)指令的格式为:
LDM(或STM){条件}{类型} 基址寄存器{!},寄存器列表{∧}
ARM微处理器所支持批量数据加载/存储指令可以一次在一片连续的存储器单元和多个寄存器之间传送数据
批量加载指令(LDR)用于将一片连续的存储器中的数据传送到多个寄存器
批量数据存储指令(STR)则完成相反的操作
该指令的常见用途是将多个寄存器的内容入栈或出栈
STMFD R13!,{R0,R4-R12,LR};将寄存器列表中的寄存器(R0,R4到R12,LR)存入堆栈,最后r13存放的是最新的值
LDMFD R13!,{R0,R4-R12,PC};将堆栈内容恢复到寄存器(R0,R4到R12,LR)
10、移位指令
— LSL 逻辑左移
— ASL 算术左移
— LSR 逻辑右移
— ASR 算术右移
— ROR 循环右移
— RRX 带扩展的循环右移
1)算术移位 当乘数或除数是2n时,算术移位用来快速地完成对整数进行乘法或除法的运算。算数左移n位相当于乘上2n,执行方法是把原来的数中每一位都向左移动n个位置,左面移出的高位丢弃不要,右面低位空出的位置上全部补0。
2)逻辑移位 逻辑左移n位的执行方法,是把原来的数中每一位都向左移动n个位置,左面移出的高位丢弃不要,右面低位空出的位置上全部补"0"。 逻辑右移n位的执行方法是把原来数中的每一位都向右移动n个位置,右面移出的低位丢弃不要,左面高位空出的位置上全部补0。
逻辑移位:不考虑正负号 算术移位:考虑正负号。
在ARM里不设置循环左移是有道理的?
循环右移可以一次性实现1~31位的移位操作。因此,循环左移n位(0 10、跳转指令 — B 跳转指令 — BL 带返回的跳转指令 — BLX 带返回和状态切换的跳转指令 — BX 带状态切换的跳转指令(ARM-Thurb之间跳转) B Label ;程序无条件跳转到标号Label处执行 CMP R1,#0 BEQ Label ;当CPSR寄存器中的Z条件码置位时,程序跳转到标号Label处执行 11、伪指令 1)、AREA 语法格式:AREA 段名{,属性1}{,属性2}⋯⋯ AREA伪指令用于定义一个代码段或数据段 段名若以数字开头,则该段名需用“|”括起来,如|1_test| 一个汇编语言程序至少要包含一个段,当程序太长时,也可以将程序分为多个代码段和数据段 常用的属性如下所示 —CODE属性:用于定义代码段,默认为READONLY —DATA属性:用于定义数据段,默认为READWRITE —READONLY属性:指定本段为只读,代码段默认为READONLY —READWRITE属性:指定本段为可读可写,数据段的默认属性为READWRITE —NOINIT属性:指定该数据段仅仅保留了内存单元,而没有将初始值写入内存单元,或将内存单元初始化为零 —COMMON属性:该属性定义一个通用的段,不包含任何的用户代码和数据 例如: AREA Init ,CODE,READONLY 指令序列;该伪指令定义了一个代码段,段名为Init,属性为只读 2)、CODE16、CODE32 语法格式:CODE16(或CODE32) CODE16伪指令通知编译器,其后的指令序列为16位的Thumb指令 CODE32伪指令通知编译器,其后的指令序列为32位的ARM指令 CODE16和CODE32只是指示编译器其后指令的类型,并不能对处理器进行状态的切换 3)、ENTRY ENTRY伪指令用于指定汇编程序的入口点。 在一个完整的汇编程序中至少要有一个ENTRY(可以没有) 使用示例: AREA Init , CODE , READONLY ENTRY ;指定应用程序的入口点 …… 4)、END 语法格式:END END伪指令用于通知编译器已经到了源程序的结尾 AREA Init,CODE,READONLY .. END ;指定应用程序的结尾 5)、EQU 语法格式:名称 EQU 表达式{,类型} EQU伪指令用于为程序中的常量、标号等定义一个等效的字符名称,类似于C语言中的#define。 “名称”为伪指令定义的字符,名称EQU可用“*”代替 Test EQU 50 ;定义标号Test的值为50 6)、EXPORT(或GLOBAL) 语法格式: EXPORT 标号{[WEAK]} EXPORT伪指令用于在程序中声明一个全局的标号,该标号可在其他的文件中引用 AREA Init,CODE,READONLY EXPORT Stest ;声明一个可全局引用的标号Stest .. END 7)、IMPORT(或EXTERN) 语法格式: IMPORT 标号{[WEAK]} IMPORT伪指令用于通知编译器要使用的标号在其他的源文件中定义,但要在当前源文件中引用 AREA Init,CODE,READONLY IMPORT Main ;通知编译器当前文件要引用标号Main,但Main在其他源文件中定义.. END 8)、GET(或INCLUDE) 语法格式: GET 文件名 GET伪指令用于将一个源文件包含到当前的源文件中,并将被包含的源文件在当前位置进行汇编处理 GET伪指令只能用于包含源文件,包含目标文件需要使用INCBIN伪指令 AREA Init,CODE,READONLY GET a1.s ;通知编译器当前源文件包含源文件a1.s GET C:\a2.s;通知编译器当前源文件包含源文件 C:\a2.s .. END 9)、INCBIN 语法格式: INCBIN 文件名 INCBIN伪指令用于将一个目标文件或数据文件包含到当前的源文件中,被包含的文件不作任何变动的存放在当前文件中,编译器从其后开始继续处理 AREA Init,CODE,READONLY INCBIN a1.dat ;通知编译器当前源文件包含文件a1.dat INCBIN C:\a2.txt ;通知编译器当前源文件包含文件C:\a2.txt .. END 10)、RN 语法格式:名称 RN 表达式 RN伪指令用于给一个寄存器定义一个别名 采用这种方式可以方便程序员记忆该寄存器的功能;其中,名称为给寄存器定义的别名,表达式为寄存器的编码 Temp RN R0 ;将R0定义一个别名Temp 12、数据伪指令 常见的数据定义伪指令有如下几种: -DCB 用于分配一片连续的字节存储单元并用指定的数据初始化 -DCW(DCWU)用于分配一片连续的半字存储单元并用指定的数据初始化 -DCD(DCDU)用于分配一片连续的字存储单元并用指定的数据初始化 —DCFD(DCFDU)用于为双精度的浮点数分配一片连续的字存储单元并用指定的数据初始化 —DCFS (DCFSU )用于为单精度的浮点数分配一片连续的字存储单元并用指定的数据初始化 —DCQ (DCQU )用于分配一片以8字节为单位的连续的存储单元并用指定的数据初始 —SPACE用于分配一片连续的存储单元 —MAP用于定义一个结构化的内存表首地址 —FIELD用于定义一个结构化的内存表的数据域 例如: Str DCB 0x33,0x45,0x12;分配一片连续的字节存储单元并初始化。 DataTest DCW 1,2,3 ;分配一片连续的半字存储单元并初始化 DataTest DCD 4 , 5 , 6;分配一片连续的字存储单元并初始化 FDataTest DCFS 2E5,-5E7;分配一片连续的字存储单元并初始化为指定的单精度数 FDataTest DCFD 2E115 ,-5E7 ;分配一片连续的字存储单元并初始化为指定的双精度数 DataTest DCQ 100;分配一片8字节连续的存储单元并初始化为指定的值100 DataSpace SPACE 100;分配连续100 字节的存储单元并初始化为0 13、汇编控制指令 — IF、ELSE、ENDIF — WHILE、WEND — MACRO、MEND — MEXIT 1)、 IF、ELSE、ENDIF 语法格式: IF 逻辑表达式 指令序列1 { ELSE 指令序列2 } ENDIF IF、ELSE、ENDIF伪指令可以嵌套使用 GBLL Test ;声明一个全局的逻辑变量,变量名为Test .. IF Test = TRUE 指令序列1 ELSE 指令序列2 ENDIF 2)、WHILE、WEND 语法格式: WHILE 逻辑表达式 指令序列 WEND WHILE、WEND伪指令可以嵌套使用 GBLA Counter ;声明一个全局的数学变量,变量名为Counter Counter SETA 3 ;由变量Counter控制循环次数 .. WHILE Counter < 10 指令序列 WEND 3)、MACRO、MEND 语法格式: MACRO $标号 宏名 $参数1,$参数2,.. 宏定义体 MEND MACRO、MEND伪指令可以将一段代码定义为一个整体,称为宏指令,然后就可以在程序中通过宏指令多次调用该段代码 其中,在宏指令被展开时,$标号会被替换为用户定义的符号。包含在MACRO和MEND之间的指令序列称为宏定义体 宏指令可以使用一个或多个参数,当汇编器将宏指令被展开时,这些参数被相应的值替换 宏指令的使用方式和功能与子程序有些相似,子程序可提供模块化的程序设计、节省存储空间并提高运行速度,但在使用时需保护现场,增加了系统开销。因此,在代码较短且需要传递的参数较多时,可使用宏指令代替子程序 MACRO、MEND伪指令可以嵌套使用 14、其他伪指令 LDR指令 大范围的地址读取伪指令 NOP指令 NOP指令产生所需的ARM无操作代码 可以使用指令MOV R0,R0 NOP不能有条件使用。执行和不执行无操作指令是一样的,因而不需要有条件执行。ALU状态不受NOP影响 常见的符号定义伪指令有如下几种: -用于定义全局变量的GBLA (数字)、GBLL(逻辑) 和GBLS(字符) -用于定义局部变量的LCLA 、LCLL 和LCLS -用于对变量赋值的 SETA 、SETL 、SETS -为通用寄存器列表定义名称的RLIST 例: GBLA Test1 ;定义一个全局的数字变量,变量名为Test1 Test1 SETA 0xaa ;将该变量赋值为0xaa GBLL Test2 ;定义一个全局的逻辑变量,变量名为Test2 Test2 SETL {TRUE} ;将该变量赋值为真 GBLS Test3 ;定义一个全局的字符串变量,变量名为Test3 Test3 SETS “Testing” ;将该变量赋值为“Testing” LCLA Test4 ;声明一个局部的数字变量,变量名为Test4 Test4 SETA 0xaa ;将该变量赋值为0xaa LCLL Test5 ;声明一个局部的逻辑变量,变量名Test4 Test5 SETL {TRUE} ;将该变量赋值为真 LCLS Test6 ;定义一个局部的字符串变量,变量名为Test6 Test6 SETS “Testing ” ;将该变量赋值为“Testing”