DSP原理与应用 第5章 TMS320C55x汇编语言编程 刘忠国:liuzhg@sdu.edu.cn 电话:18764171197 ; 微信: jnliuzg 山东大学生物医学工程
任课教师:刘忠国 网站: http://course.sdu.edu.cn/G2S/dsp.cc http://www.ti.com TMS320C55x Assembly Language Tools User’s Guide (SPRU280H, 2004年) (SPRU280G, 2003年: lnk55命令在H版本无介绍) TMS320C55x DSP Mnemonic Instruction Set Reference Guide (SPRU374G, 2002年)
第5章TMS320C55x汇编语言编程 5.1 TMS320C55x软件开发流程 5.2 TMS320C55x目标文件格式
第5章TMS320C55x汇编语言编程 5.1 TMS320C55x软件开发流程 5.1.1软件开发流程 5.1.2软件开发工具
5.1 TMS320C55x软件开发流程 5.1.1 软件开发流程 编程语言 汇编语言 编程过程复杂,但程序执行效率高 C/C++语言 编程容易,但程序执行效率不如汇编语言 软件开发环境 集成开发环境CCS(Code Composer Studio)(第3章) 非集成开发环境(本章介绍) (:\ti\ccsv5\tools\compiler\c5500_4.4.1\bin中可执行文件)
5.1.1 软件开发流程 非集成开发环境下,C55x的软件开发流程和所 用工具与CCS下是一样的。因此本章有关内容也 是学习CCS的基础。 两个环境的不同在于: CCS把有关开发工具集成在一个Window界 面下使用,使用更方便 CCS增加了一些新的开发工具,功能更强大
:\ti\ccsv5\tools\compiler\c5500_4.4.1\bin (还包括include和lib文件夹)中可执行文件 源程序 (.C或.CPP) 图5-1 非集成开发环境下C55x软件开发流程图 源程序(.asm) 目标文件(.obj) 库文件(.lib) 可执行输出文件(.out) 可脱机运行的执行程序(.hex) :\ti\ccsv5\tools\compiler\c5500_4.4.1\bin (还包括include和lib文件夹)中可执行文件
第5章TMS320C55x汇编语言编程 5.1 TMS320C55x软件开发流程 5.1.1软件开发流程 5.1.2软件开发工具
5.1.2 软件开发工具 代码生成工具 源代码编辑器 采用汇编语言或C/C++语言编写的源程序均为 文本文件,可以在任何一种文本编辑器中进行。如 WORD、EDIT、TC、Windows操作系统自带的 笔记本等 C/C++编译器 用来将C/C++语言源程序(.C或.CPP)自动编译 为C55x的汇编语言源程序(.asm)。
5.1.2 软件开发工具 汇编器 用来将汇编语言源文件(.asm)汇编成机器语言COFF 目标文件(.obj)。 链接器 将汇编生成的、可重新定位的COFF目标模块(.obj)组 合成一个可执行的COFF目标模块(.out)。 文档管理器 允许用户将一组文件(源文件或目标文件)集中为一个 文档文件库 。
5.1.2 软件开发工具 建库实用程序 用来建立用户自己使用的、并用C/C++语言编写的 支持运行的库函数。 十六进制转换程序 可以很方便地将COFF目标文件(.out)转换成TI、 Intel、Motorola等公司的目标文件格式(.hex) 。 绝对制表程序 将链接后的目标文件作为输入, 生成.abs输出文件。 交叉引用制表程序 利用目标文件生成一个交叉引用清单,列出链接 的源文件中的符号以及它们的定义和引用情况。
5.1.2 软件开发工具 代码调试工具 软件仿真器(Simulator) 是一种模拟DSP芯片各种功能并在非实时条 件下进行软件调试的调试工具,它不需目标硬件 支持,只需在计算机上运行 硬件仿真器( XDS100,XDS510, XDS560 ) 可用来进行系统级的集成调试,是进行DSP 芯片软硬件开发的最佳工具
第5章TMS320C55x汇编语言编程 5.1 TMS320C55x软件开发流程 5.2 TMS320C55x目标文件格式 (COFF)
5.2 TMS320C55x目标文件格式 5.2.1 COFF文件的基本单元——段 5.2.2 汇编器对段的处理 5.2.3 链接器对段的处理 5.2.4 链接器对程序的重新定位 5.2.5 COFF文件中的符号
5.2.1 COFF文件的基本单元—段 通用目标文件格式COFF: Common Object File Format 段(section)是COFF文件的基本单元。一个段是一个 占据存储器里连续地址的代码或者数据块, COFF目标 文件的每个段都是分开和不同的 COFF目标文件通常包括3个默认段,即 .text段,通常包含可执行代码 .data段,通常包含初始化数据 .bss段,通常为未初始化变量保留存储空间
一些汇编伪指令可将代码和数据的各个部分与相 应的段相联系 图5-2目标文件中的段与目标存储器的关系
5.2 TMS320C55x目标文件格式 5.2.1 COFF文件的基本单元——段 5.2.2 汇编器对段的处理 5.2.3 链接器对段的处理 5.2.4 链接器对程序的重新定位 5.2.5 COFF文件中的符号
5.2.2 汇编器对段的处理 汇编器通过段伪指令自动识别各个段,并将段名 相同的语句汇编在一起; 汇编器有5条伪指令可以识别汇编语言程序的各 个不同段: .text、.data、.sect创建初始化段 .bss和.usect创建未初始化段 .sect与.usect创建自定义段和子段 本节内容: 1. 未初始化段;2. 初始化段;3. 自定义段; 4. 子段;5. 段指针;例5-1 段伪指令的使用
1.未初始化段 未初始化段占用处理器存储空间, 常常分配到RAM; 未初始化段在目标文件里无实际内容, 仅用于保留存储 空间, 当程序在运行时用这些空间来创建和存储变量; 汇编命令.bss和.usect用来创建未初始化数据区域: .bss symbol, size [,[blocking flag][,alignment flag]] symbol .usect ”section name”,size [,[blocking flag] [,alignment flag]] symbol: 指向.bss或者.usect指令创建的段的第一个字, 对应该存储空间的变量名; 可被其他段引用,被声明为一个全局符号。 size: 为对应段开辟的存储空间大小, 单位为字。 section name:段名 blocking flag: 可选。若是非零值, 汇编器会连续分配size字空间, 这些区域块不会跨越一页边界(size<128), 除非该段大于一页(在这种情况下, 目标文件会在页边界开始) alignment flag: 可选. 若是非零值(取2n, n= 0~7), 该段会按给出的字边界值开始存放段。
1.未初始化段 每次使用.bss指令,汇编器就在对应的段开辟更 多的存储空间 每次使用.usect指令,汇编器就在指定的自定义 段开辟更多的存储空间 .bss和.usect指令不结束当前段(例.data段)的 汇编去开始一个新的段,它们仅仅让汇编器暂时 退出当前段(例.data段)的编辑 .bss和.usect指令可以出现在一个初始化段 (例 .data段)的任何地方而不会影响该段的内容
2.初始化段 初始化段包含可执行代码或者初始化数据; 当程序被 装载时, 它们就被放到处理器存储空间里; 每个初始化段独立分配空间, 可以引用在其他段定义 的标识(symbol), 链接器自动处理这些段间引用; 定义初始化段的指令: .text [value] .data [value] .sect ”section name”[,value] value表示段指针(SPC)的开始值, 只可以指定一次,必须在段第一次出现时指定。 默认SPC从0开始。 当汇编器遇到其中一个指令就停止当前段的汇编(就好像一个当前段结束命令), 而将后面的代码汇编到另外指定的段, 直到遇到另一个.text、.data或者.sect指令。
3.自定义段 .usect 创建像.bss段那样的段,这些段为变量在RAM 开辟存储空间。 .sect创建像.text和.data段那样包含代码和数据的段, 可以创建可重分配地址的自定义段。 用户可以创建多达32767个自定义段,段名可以多至 200个字符。 每次使用这两个指令可以用不同的section name来创 建不同的段,如果用一个已经使用的section name, 那么汇编器将代码和数据都汇编到同一个段。
4.子段 子段是更大的段中的较小的段, 链接器可以像段一样操作它; 子段让用户可以更好的控制存储器映射; 可用.sect或者.usect指令来创建子段,子段名的格式为: section name: subsection name 同一个段中的子段可以独自分配地址,也可以一起分配存储空间。 例,在段.text中创建一个_func子段如下: .sect “text:_func” 用户可以为其单独分配地址, 也可以和.text段的其他部分一起分配地址。
5.段指针(Section Program Counters) 汇编器为每个段分配一个程序指针, 这些程 序指针称为段指针(SPCs); 一个SPC指向一个段的当前地址: 初始时, 汇编器设置每个SPC为0(默认,初 始化段可定义非0值); 当汇编器在段中填充代码和数据时, SPC跟 着增加; 如果重新开始汇编一个段, 汇编器会记得 该段SPC的原来值, 并继续增加SPC。
例5-1 段伪指令的使用---源程序(单独列出) 例5-1 段伪指令的使用---源程序(单独列出) 汇编语言源程序: .data coeff .word 011h,022h,033h .bss buffer, 10 prt .word 0123h .text Add: MOV 0Fh, AC0 Aloop: SUB #1, AC0 BCC Aloop, AC0>=#0 ivals .word 0AAh, 0BBh, 0CCh ;初始化数据段 ;3组数据放入.data段 ;在.bss段保留10个单元 ;.bss后0123h仍然在.data段 ;初始化文本段 ;2字节(省略@,DP直接寻址) ;2字节指令 ;3字节指令 ;初始化数据段 ;3组数据放入.data段
例5-1 段伪指令的使用---源程序(单独列出) var2 .usect “newvars”, 1 inbuf .usect “newvars”, 7 .text mpy: MOV 0Ah, AC1 mloop: MOV T3, HI(AC2) MPYK #10, AC1, AC1 BCC mloop, !overflow(AC1) .sect “vectors” .word 011h, 033h ;建newvars命名段,保留1个单元 ;在newvars段保留7个单元 ;初始化文本段 ;1字指令(省略@,DP直接寻址) ;2字节指令 ;3字节指令 ;建立vectors命名段 ;2组数据放入vectors命名段
例5-1 段伪指令的使用--- 段总结 汇编语言源程序经过汇编后,共建立了5个段: .text段——文本段,段内有10个字可执行的程序代码 例5-1 段伪指令的使用--- 段总结 汇编语言源程序经过汇编后,共建立了5个段: .text段——文本段,段内有10个字可执行的程序代码 .data段——已初始化的数据段,段内有7个字的数据 vectors段——用.sect命令生成的命名段,段内有2个字 的初始化段数据 .bss段——未初始化的数据段,在存储器中为变量保留 10个存储单元 newvars段——用.usect命令建立的未初始化的命名段, 为变量保留8个存储单元
例5-1,段伪指令的使用。 教材中列出的是一个汇编语言程序经汇编 后生成的.lst文件,每行包含4个区域(列): Field 1: (源程序)源代码行号 Field 2: 段指针SPC(段程序计数器) Field 3: 目标代码(机器码) Field 4: 初始源代码(源程序)
例5-1, 段伪指令的使用。列表文件(.lst): 汇编设置: 源程序的行号 段程序 计数器 目标 代码 汇编语言源程序 SPC 1 (空行) 2 ********************************** 3 ** 汇编一个初始化表到.data段 ** 4 ********************************** 5 .data 6 coeff .word 011h,022h,033h 7 ********************************** 8 ** 在.bss段中为变量保留空间 ** 9 ********************************** 10 .bss buffer,10 11 ********************************** 12 ** .bss结束后仍然在.data 段中 ** 13 ********************************** 14 prt .word 0123h 000000 000000 0011 000001 0022 000002 0033 000000 000003 0123 Project→Properties→CCS Build→C5500 Compiler→ Advanced Options →Assembler Options→ Generate Assembly Listing Files(al)
源程序的行号 段程序 计数器 目标 代码 汇编语言 源程序 SPC 15 ********************************** 16 ** 汇编代码到.text段 ** 17 ********************************** 18 000000 .text 19 000000 A01E add: MOV 0Fh,AC0 ;DP直接寻址 20 000002 4210 aloop: SUB #1, AC0 21 000004 0450 BCC aloop,AC0>=#0 000006 FB 22 ********************************** 23 ** 汇编另一个初始化表到.data段 24 ********************************** 25 000004 .data 26 000004 00AA ivals .word 0AAh,0BBh,0CCh 000005 00BB 000006 00CC 27 ********************************** 28 ** 为更多的变量定义另一个段 ** 29 ********************************** 30 000000 var2 .usect “newvars”,1 31 000001 inbuf .usect “newvars”,7
例5-1, 段伪指令的使用。列表文件(.lst): 32 **************************************** 33 ** 汇编更多代码到.text段 ** 34 **************************************** 35 000007 .text 36 000007 A114 mpy: MOV 0Ah, AC1 37 000009 5272 mloop: MOV T3, HI(AC2) 38 00000b 1E0A MPYK #10, AC1, AC1 00000d 90 39 00000e 0471 BCC mloop,!overflow(AC1) 000010 F8 40 **************************************** 41 为中断向量.vectors定义一个自定义段 42 **************************************** 43 000000 .sect “vectors” 44 000000 0011 .word 011h,033h 45 000001 0033 源程序的行号 段程序 计数器 目标 代码 汇编语言 源程序
例5-1 经汇编后,共建立了5个段: SPC 行号 目标代码 段名 行号 目标代码 .text 6 0011 .data 6 0022 6 100f f010 0001 f842 110a f166 000a F868 0006 0011 0022 0033 0123 00aa 00bb 00cc 没有数据 保留8个字 行号 目标代码 SPC .text 2 ******************************* 3 ** 汇编一个初始化表到.data段 ** 4 ******************************* 5 0000 .data 6 0000 0011 coeff .word 011h,022h,033h 0001 0022 0002 0033 7 ******************************* 8 ** 在.bss段中为变量保留空间 ** 9 ******************************* 10 0000 .bss buffer,10 11 ******************************* 12 ** 仍然在.data 段中 ** 13 ******************************* 14 0003 0123 prt .word 0123h 5 0000 .data 6 0000 0011 coeff .word 011h,022h,033h 6 0001 0022 6 0002 0033 6 0011 .data 6 0022 6 0033 14 0123 10 0000 .bss buffer,10 vectors .bss 10 没有数据 保留10个字 14 0003 0123 prt .word 0123h newvars
例5-1 经汇编后,共建立了5个段: 源程序的行号 段程序 计数器 目标 代码 汇编语言源程序 .data .bss .text .data 15 ********************************** 16 ** 汇编代码到.text段 ** 17 ********************************** 18 000000 .text 19 000000 A01E add: MOV 0Fh,AC0 20 000002 4210 aloop:SUB #1, AC0 21 000004 0450 BCC aloop,AC0>=#0 000006 FB 22 ********************************** 23 ** 汇编另一个初始化表到.data段 24 ********************************** 25 000004 .data 26 000004 00AA ivals .word 0AAh,0BBh,0CCh 000005 00BB 000006 00CC 27 ********************************** 28 ** 为更多的变量定义另一个段** 29 ********************************** 30 000000 var2 .usect “newvars”,1 31 000001 inbuf .usect “newvars”,7 行号 目标代码 段名 100f f010 0001 f842 0001’ 110a f166 000a F868 0006‘ 6 14 0011 0022 0033 0123 00aa 00bb 00cc .data 10 没有数据 保留10个字 .bss 19 .text A01E 20 4210 21 0450 21 fB .data 26 00aa 26 00bb 26 00cc newvars 30 保留1个字 31 保留7个字
例5-1 经汇编后,共建立了5个段: .text .data vectors .bss newvars 32 *********************************** 33 ** 汇编更多代码到.text段 ** 34 *********************************** 35 000007 .text 36 000007 A114 mpy: MOV 0Ah, AC1 37 000009 5272 mloop: MOV T3, HI(AC2) 38 00000b 1E0A MPYK #10, AC1, AC1 00000d 90 39 00000e 0471 BCC mloop,!overflow(AC1) 000010 F8 40 ************************************* 41 为中断向量.vectors定义段 42 ************************************* 43 000000 .sect “vectors” 44 000000 0011 .word 011h, 033h 45 000001 0033 行号 目标代码 段名 19 20 21 A01E 4210 0450 fB 110a f166 000a F868 0006 .text 6 14 26 0011 0022 0033 0123 00aa 00bb 00cc .data 0044 0088 10 没有数据 保留10个字 .bss 30 31 保留8个字 newvars .text 36 A114 37 5272 38 1E0A 38 90 39 0471 39 F8 vectors 43 0011 43 0033
vectors段:.sect指令创建的自定 义段,包含2字初始化数据; 这个例子创建了5个段: .text段:包含17字节目标代码; .data段:包含7字的目标代码; vectors段:.sect指令创建的自定 义段,包含2字初始化数据; .bss段:在存储器占用10个字; newvars段:.usect指令创建的 自定义段,在存储器中占8个字。 图5-3 例5-1产生的目标代码
5.2 TMS320C55x目标文件格式 5.2.1 COFF文件的基本单元——段 5.2.2 汇编器对段的处理 5.2.3 链接器对段的处理 5.2.4 链接器对程序的重新定位 5.2.5 COFF文件中的符号
5.2.3 链接器对段的处理 链接器对段的处理: 将一个或多个COFF目标文件(.obj)中的各种段作为 链接器的输入段, 经链接后在一个可执行的COFF模 块(.out)中建立各个输出段; 为各个输出段选定存储器地址; 链接器有2条伪指令支持上述任务(通常放在链接器 命令文件(.cmd)中执行, 是命令文件的主要内容) : MEMORY SECTIONS 若链接时不使用MEMORY和SECTIONS指令, 则链接器使用目的处理器的默认分配算法; 有时用户不想使用默认设置, 要自己进行 存储器映射, 就要使用MEMORY和SECTIONS等 链接指令。
图5-4 两个文件的链接过程 File1.obj .text1(.text) .data1(.data) .bss1(.bss) table1(.table) (初始化的命名段) u_vars1 (未初始化的命名段) 程序存储器 数据存储器 .text1 没有配置 .text .text2 .data1 .data .data2 .bss1 .bss table1 .bss2 u_vars1 table table2 File2.obj .text2(.text) .data2(.data) .bss2(.bss) table2(.table) (初始化的命名段) u_vars2 (未初始化的命名段) FFT u_vars u_vars2 FFT FFT 没有使用 没有使用 没有配置
5.2 TMS320C55x目标文件格式 5.2.1 COFF文件的基本单元——段 5.2.2 汇编器对段的处理 5.2.3 链接器对段的处理 5.2.4 链接器对程序的重新定位 5.2.5 COFF文件中的符号
5.2.4 链接器对程序的重新定位 1. 地址重新定位 汇编器对每个段汇编时都是从0地址开始,所有需要重 新定位的符号(标号)在段内都是相对于0地址的; 事实上所有段都不可能从存储器中0地址单元开始,因 此链接器必须对各个段进行重新定位 ; 重新定位的方法: 将各段配置到存储器中, 使每段都有一合适起始地址; 调整符号变量值(例5-2的Z,Y)到使其反映新的段地址; 调整相对于重新定位后的符号间的距离偏离值(例5-2 的”B Z”),使其反映调整后的新符号值(例5-2的Z)。
例5-2,程序重新定位。 1 .ref X ; X在其它文件中已定义 2 .ref Z ; Z在其它文件中已定义 3 000000 .text 4 000000 4A048 B Y 5 000002 6A00 B Z ; 产生重新定位入口地址 000004 0000! 6 000006 7600 MOV #X,AC0; 产生重新定位入口地址 000008 0008! 7 00000a 9400 Y: RESET ;L7 编码成以字节为单位的符号偏移地址 ;B L7 操作码0100 101E 0LLL LLLL ;B L24 操作码0110 1010 PPPP PPPP PPPP PPPP PPPP PPPP MOV K16, dst操作码0111 0110 KKKK KKKK KKKK KKKK FDDD 10xx FDDD: 0000 Accumulator 0 (AC0) 符号Y与SPC关系固定不需要重新定位,符号Z与本段SPC相对关系不确定, 需要重新定位,因为它定义在另一个的文件里。 汇编代码时,X和Z的值为0(汇编器假设所有未定义的外部符号都为0)。汇编器为X和Z产生重新定位入口地址。对X和Z的引用都是外部引用(在列表中由!符号表示)。
2.运行时间重新定位 在实际运行中,有时需要将代码装入存储器的一 个地方,而在另一个地方运行。 如:一些关键的执行代码必须装在系统的ROM 中,但运行时希望在较快的RAM中进行。 利用SECTIONS伪指令选项可让链接器对其定 位2次,方法如下: 使用load关键字设置装入地址 使用run关键字设置它的运行地址
5.2 TMS320C55x目标文件格式 5.2.1 COFF文件的基本单元——段 5.2.2 汇编器对段的处理 5.2.3 链接器对段的处理 5.2.4 链接器对程序的重新定位 5.2.5 COFF文件中的符号
5.2.5 COFF文件中的符号 1. 外部符号 COFF文件中有一个符号表,主要用来存储程序中有 关符号的信息; 链接器在执行程序定位时, 要使用符号表提供的信息, 而调试工具也要使用该表来提供符号调试。 1. 外部符号 在一个模块中定义、而在另一个模块中引用的符号。 可用伪指令.def、.ref或.global来定义或引用: .def :定义符号; 用来定义在当前模块中定义、可在别 的模块中引用的符号; .ref :引用符号; 当前模块引用在其他模块中定义的符 号; .global:定义全局符号; 可以是上面的任何一种情况。
2. 符号表 例5-3,外部符号的使用。 .def x ;定义内部符号x .ref y ;引用外部符号, y在其它文件中已定义 x: ADD #86, AC0, AC1 ; 定义x B y ; 引用y 2. 符号表 每当遇到一个外部符号, 无论是定义的还是引用的, 汇 编器都将在符号表中产生一条记录。 每个段在COFF文件里都有一个可重新定位符号记录表, 段中每次引用重新定位符号, 就对应记录表中的一条记 录。链接器使用这些符号表进行引用符号重新定位 。
第5章TMS320C55x汇编语言编程 5.1 TMS320C55x软件开发流程 5.2 TMS320C55x目标文件格式
5.3 TMS320C55x 汇编器 5.3.1 汇编器概述 5.3.2 汇编程序的运行 5.3.3 C55x汇编器的特点 5.3.1 汇编器概述 5.3.2 汇编程序的运行 5.3.3 C55x汇编器的特点 参考文献: TMS320C55x Assembly Language Tools User’s Guide (SPRU280H, 2004年) (SPRU280G, 2003年: lnk55命令在H版本无介绍)
5.3.1 汇编器概述 TMS320C55x有2个汇编器,即: masm55: 助记符指令汇编器,接受C54x和 C55x助记符指令汇编源程序。 asm55: 代数指令汇编器,只接受C55x代数指 令汇编源程序。 本章只介绍介绍助记符指令汇编器masm55,关于 代数指令汇编器asm55可参考文献[SPRU375E, TMS320C55x DSP Algebraic Instruction Set Reference Guide]
汇编器具有如下功能: 处理文本格式的源文件,产生可重新定位的 C55x目标文件(.obj); 产生列表文件(可选),可对该列表进行控制; 允许把代码分段,对每一个目标代码段提供一个 段指针SPC; 定义和引用全局符号,并提供源文件交叉引用表 (可选); 汇编条件程序块 ; 支持宏功能,允许定义宏命令。
5.3 TMS320C55x 汇编器 5.3.1 汇编器概述 5.3.2 汇编程序的运行 5.3.3 C55x汇编器的特点
5.3.2 汇编程序的运行 命令格式: masm55 [input file [object file [listing file]]] [-options] 其中: input file: 汇编源文件名, 默认扩展名为.asm; listing file: 汇编器产生的列表文件名, 默认扩展名 为.lst ; -options: 汇编器的选项, 为汇编器的使用提供各种 选择。
表5-1 汇编器masm55的选项及其功能 选 项 功 能 -@ 功 能 -@ -@filemane(文件名)可以将文件名的内容附加到命令行上。 使用该选项可以避免命令行长度的限制。如果在一个命令文件、文件名或选项参数中包含了嵌入的空格或连字号,则必须使用引号括起来,例如:“this-file.asm”。 -a 建立一个绝对列表文件;当选用-a时,汇编器不产生目标文件。 -c 使汇编语言文件中大小写没有区别。 -d 为名字符号设置初值。格式为-d name[=value]时,与汇编文件被插入name .set [=value]是等效的。如果value被省略,则此名字符号被置为1。 -f 抑制汇编器给无.asm扩展名的文件添加扩展名的默认行为。 -g 允许汇编器在源代码中进行代码调试。汇编语言源文件中每行的信息输出到COFF文件中。注意:用户不能对已经包含.line伪指令的汇编代码使用-g 选项。例如由C/C++编译器运行-g选项产生的代码。 -h,-help,-? 这些选项的任一个将显示可供使用的汇编器选项的清单。 -hc 将选定的文件复制到汇编模块。格式为-hc filename所选定的文件包含到源文件语句的前面,复制的文件将出现在汇编列表文件中。
表5-1 汇编器masm55的选项及其功能 选 项 功 能 -hi 功 能 -hi 将选定的文件包含到汇编模块。格式为-hi filename所选定的文件包含到源文件语句的前面,所包含的文件不出现在汇编列表文件中。 -i 规定一个目录。汇编器可在这个目录下找到.copy,.include或.mlib命令所命名的文件。格式为-i pathname, 最多可规定10个目录, 每一条路径名的前面都必须加上-i选项。 -l (小写l)生成一个列表文件。 –ma (ARMS模式)程序执行期间使能ARMS位。缺省状态下, 禁止ARMS。 –mc (CPL模式)程序执行期间使能CPL位。缺省状态下, 禁止CPL。 –mh 使汇编器处理C54x源程序时,产生快速代码。缺省状态下,产生的是小规模代码。 –mk 使C55x 为大内存模式,设置_large_model symbol 为1,为链接器提供检测小模式和大模式目标模型非法组合的信息。 –ml (C54x兼容模式) 程序执行期间使能C54CM 位。缺省状态下,禁止C54CM。 –mn 使汇编器取消C54x延时分支/调用指令处的NOP指令。
表5-1 汇编器masm55的选项及其功能 选 项 功 能 –mt 使汇编器处理C54x源程序时禁止SST 位。缺省状态下,禁止SST 位为使能状态。 –mv 使汇编器在处理某些可变长度指令时使用最大(P24)格式。缺省状态下,汇编器总是试图把所有变长度指令分解成最小长度。 –purecirc 使汇编器处理C54x源程序文件时,使用C54x循环寻址方式(不使用C55x循环寻址方式) -q 抑制汇编的标题以及所有的进展信息。 -r, -r[num] 压缩汇编器由num标识的标志。该标志是报告给汇编器的消息,这种消息不如警告严重。若不对num指定值,则所有标志都将被压缩。 -s 把所有定义的符号放进目标文件的符号表中。 汇编程序通常只将全局符号放进符号表。当利用-s选项时, 所定义的标号以及汇编时定义的常数也都放进符号表内。 -u ,-u name 取消预先定义的常数名,从而不考虑由任何-d选项所指定的常数。 -x 产生一个交叉引用表,并将它附加到列表文件的最后,还在目标文件上加上交叉引用信息。即使没有要求生成列表文件,汇编程序总还是要建立列表文件的。
5.3 TMS320C55x 汇编器 5.3.1 汇编器概述 5.3.2 汇编程序的运行 5.3.3 C55x汇编器的特点
5.3.3 C55x汇编器的特点 1.字节/字寻址 对于代码采用字节寻址方法 对于数据则采用字寻址方法 对于.struct 或 .union中的偏移量总是 以字为单位计算,即汇编器总是 把.struct或.union 视为数据
例5-4,C55x数据的字寻址方法。 .def Struct1, Struct2 .bss Struct1, 8 ;为Struct1分配8个字 .bss Struct2, 6 ;为Struct2分配6个字 .text MOV *(#(Struct1+2)),T0 ; 加载Struct1的第3个字 MOV *(#1000h),T1 ; 0x1000是绝对字地址 例5-5,C55x代码的字节寻址方法。 .text .ref Func CALL #(Func+3) ; 跳转到(Func+3字节)处 CALL #0x1000 ; 0x1000是绝对字节地址
2.可变长度指令解码 缺省状态下,汇编器尽量把所有的可变长度指令解码 成最小长度。(例: B L7; B L16; B P24) 涉及可变长度指令解码问题的指令还有几组(例: BCC L4, cond; BCC L8, cond; BCC L16, cond; BCC P24, cond)。 在某些情况下,用户可能希望选择最大长度(P24)指 令, 因为某些指令的P24实现方式比长度更小的实现方 式执行速度更快。 例如, “B P24”占用4个字节和3个周期,而“B L7” 占用3个字节和4个周期,在编译器选项中使用–mv即可实现这一目的。
3.存储器模式(Memory Modes ) 汇编器支持3种存储器模式,即 C54x兼容模式 CPL模式 ARMS模式 分别对应于3个状态位C54CM、CPL和 ARMS的值。 C54CM=1 or 0 CPL=1 or 0 ARMS=1 or 0 memory model 参考“第6章: 6.2.7 存储器模式”----小存储模式(默认)和大存储器模式(__LARGE_MODEL=1) 或参考5.5.3 汇编源程序中的符号(预定义的符号常数)
(1)C54x兼容模式 .c54cm_on(C54CM=1)和.c54cm_off(C54CM=0) 指令用于与C54x代码兼容。 当汇编器命令行选项和指令发生冲突时, 指令具有较高 优先权。(所有位于.c54 cm_on和.c54cm_off指令之 间的汇编源代码将在C54x兼容模式下汇编) .c54cm_on和.c54cm_off指令的作用域是静态的, 不 受汇编程序流的影响。 在C54x兼容模式下, AR0 取代T0 (C55x变址寄存器) 。 汇编器的–ml命令行选项 C54CM=1 例如,*(AR5+T0)在C54x兼容模式下无效, 应该用*(AR5 + AR0。 The assembler cannot track the value of the status bits. You must use assembler directives and/or command line options to inform the assembler of the value of these bits. BSET C54CM;硬指令 .c54cm_on; 伪指令 An instruction that modifies the value of the C54CM, CPL, or ARMS status bit must be immediately followed by an appropriate assembler directive.
(2)CPL模式 CPL模式影响直接寻址方式 .cpl_on(CPL=1)和.cpl_off(CPL=0)指令的作用域 是静态的, 不受汇编程序流的影响; 在CPL模式(.cpl_on)下,存储器直接寻址与堆栈指 针(SP)相关, 语法为*SP(dma); 在默认模式(.cpl_off)下,存储器直接寻址与数据页 寄存器(DP)相关,语法为@dma。 等价于汇编器–mc命令行选项 在.cpl_on和.cpl_off指令之间的汇编代码将在CPL模式 (CPL=1)下汇编。
(3)ARMS模式 ARMS模式影响间接寻址方式 .arms_on(ARMS=1)和.arms_off(ARMS=0)指令 的作用域是静态的, 不受汇编程序流的影响; 在默认模式(.arms_off)下, 编译器选择DSP方式, 存 储器间接寻址方式的短偏移操作数无效; 在ARMS模式(.arms_on)下, 编译器选择控制器方式, 存储器间接寻址方式的短偏移操作数有效, 有助于优化 代码长度。 等价于汇编器–ma命令行选项 *ARn(short(#k3)) 在.arms_on和.arm s_off指令之间的汇编代码将在ARMS模式(ARMS=1)下汇编。
4.汇编器关于MMR寻址的警告 当存储器映像寄存器(MMR)用于单存储器操作数(Smem) 位置时, 汇编器提示”Using MMR address”警告, 意味 着汇编器将MMR认为是DP间直接寻址操作数; 为使指令正常执行, DP必须设为0。 例: ADD SP,T0; 产生”Using MMR address” 警告语句: ”file.asm”, WARNING! at line 1: [W9999] Using MMR address. 汇编器关于这条指令影响的警告为: ADD value at address(DP+MMR address of SP),T0 使用此指令最好的方式是:ADD mmap(SP),T0 当已知DP值为0时, 用@符号, 以避免警告: ADD @SP,T0
第5章TMS320C55x汇编语言编程 5.1 TMS320C55x软件开发流程 5.2 TMS320C55x目标文件格式
5.4 TMS320C55x汇编伪指令 5.4.1 汇编伪指令 5.4.2 宏指令 ☼ 伪指令用于处理汇编和连接过程,是汇编语言源程序的重要组成部分,但是最后产生的目标文件不包括它们。
5.4 TMS320C55x汇编伪指令 5.4.1汇编伪指令 5.4.2宏指令
5.4.1 汇编指令 汇编指令为程序提供数据和汇编过程的控制, 功能有: 把代码和数据汇编到指定的段(.text, .data, .sect) 在存储区为非初始化变量保留存储空间(.bss, .usect) 控制列表文件的内容(. list, .mlist等) 初始化存储器(.word , .char , .float, .long等) 汇编条件块(.if , .else , .loop, .endloop等) 声明全局变量(.def , .ref, .global等) 指定宏指令库, 这是所用到宏指令的宏定义文件(.macro等) 检查符号调试信息(.equ, .eval等) 汇编伪指令和其参数必须写在一行中,可带标号和注释.
表5-2 定义段的汇编伪指令 指令格式 说 明 .bss symbol,size[,blocking][,alignment] 定义.bss段, 段长度size的单位为字 .clink [“section name”] 当前段或者指定段使能有条件连接 .data 定义一个.data段 .sect “section name” 定义一个自定义段 .text 定义一个.text段 symbol .usect “section name”, size [,blocking] [,align ment] 定义一个自定义段, 段长度size的单位为字
表5-3 初始化常数(数据和存储器)伪指令(1) 表5-3 初始化常数(数据和存储器)伪指令(1) 指令格式 说 明 .byte value_l[,…,value_n] 当前段初始化一个或者多个连续的字节或字 .char value_l[,…,value_n] .double value_l[,…,value_n] 初始化一个或者多个64位,IEEE双精度浮点常数 .ldouble value_l[,…,value_n] .field value[,size] 初始化一个变量长度的域 .float value_l[,…,value_n] 初始化一个或者多个32位,IEEE单精度浮点常数 .half value_l[,…,value_n] 初始化一个或多个16位整数 .short value_l[,…,value_n] .int value_l[,…,value_n] .long value_l[,…,value_n] 初始化一个或多个32位整数 .pstring “string_1” [,…, “string_n”] 初始化一个或多个文本字符串(从左开始每两个字符打包成一个字, 若是奇数个, 最右字节是0)
表5-3 初始化常数(数据和存储器)伪指令(2) 表5-3 初始化常数(数据和存储器)伪指令(2) 指令格式 说 明 .space size 在当前段保留存储空间,size的单位为位 .string “string_1”[,…, “string_n”] 初始化一个或多个文本字符串, 每个字符占一个字 .ubyte value_l[,…,value_n] 初始化当前段的连续字节或字 .uchar value_l[,…,value_n] .uhalf value_l[,…,value_n] 初始化一个或多个无符号16位整数 .ushort value_l[,…,value_n] .uint value_l[,…,value_n] .ulong value_l[,…,value_n] 初始化一个或多个无符号32位整数 .uword value_l[,…,value_n] .word value_l[,…,value_n] 初始化一个或多个16位整数 .xfloat value_l[,…,value_n] 初始化一个或多个32位,IEEE单精度浮点常数, 但是在长字边界不对齐 .xlong value_l[,…,value_n] 初始化一个或多个32位整数,但是在长字边界不对齐
表5-4 对齐段程序计数器(SPC)指令 指令格式 说 明 .align [size] 将SPC对齐由参数size指定的一个边界,参数必须是2的指数。size的单位对于代码段为字节, 对于数据段为字, 默认为128字节(代码段)或者128字(数据段) .even 等于.align 2
表5-5 引用其他文件的指令 指令格式 说 明 .copy [“]filename[”] 从其他文件引用源代码 .def symbol_1[,…,symbol_n] 指定在当前模块定义并且可能在其他模块使用的一个或多个符号 .global symbol_1[,…,symbol_n] 指定一个或多个全局(外部)符号 .include [“]filename[”] .ref symbol_1[,…,symbol_n] 指定在当前模块使用并且可能在其他模块定义的一个或多个符号
5.4 TMS320C55x汇编伪指令 5.4.1汇编伪指令 5.4.2宏指令
5.4.2 宏指令 宏指令的作用主要是: 定义自己的宏指令和重新定义已存在的宏指令 简化长的或者复杂的汇编代码 访问指令库 在一个宏里定义有条件和可重复块 在一个宏里操作字符串 控制扩展列表
1.使用宏指令 程序里常常包含执行多次的程序段,可以定义一个 宏来代替它,而不必重复写代码,在需要该程序段 时只需引用宏; 如果需要多次引用一个宏,但是每次都有不同的数 据,可以在宏里使用参数,每次使用时赋予参数不 同值即可; 宏支持一种用于宏参数的特别符号, 称为替换符号; 使用宏的步骤: 定义宏 引用宏指令 扩展宏指令
2.定义宏 可以在程序的任何位置定义宏; 必须在使用前定义; 可以在源文件的开始,在.include/.copy文 件或者在一个宏指令库里定义一个宏; 宏定义可以嵌套。可以在定义里引用其他的 宏,但是这些宏都必须和当前定义的宏在同 一个文件里。
宏定义的格式 宏名 .macro [参数1][,…, 参数n] 指令或者汇编指令 ;即宏的内容 [.mexit] .endm 宏名必须放在声明的最开始处(即所谓的标签域label field), 如果超出32个字符, 那么仅仅前32个字符有效。汇编器把宏名放到内部的操作码表; .macro :宏定义伪指令, 必须放在操作符位置; [.mexit]:相当于一条goto .endm语句, 当出错检测证实宏扩展会出错时有用; .endm:结束宏定义伪指令。
例5-6,宏的定义和引用。 1 * add3 2 * ADDRP = P1+P2+P3 3 * 4 * macro definition * 5 add3 .macro P1,P2,P3,ADDRP 6 MOV P1,AC0 7 ADD P2,AC0,AC0 8 ADD P3,AC0, AC0 9 MOV AC0, ADDRP 10 .endm 11 12 .global abc,def, ghi, adr 13 14 * macro call * 15 add3 abc,def,ghi,adr 如“add3 abc,def,ghi, *(#adr)”中的最后一个参数 可采用绝对寻址方式,不易出错,否则abc,def,ghi这些标号将看着直接寻址,标号地址值将按直接寻址计算偏移量的算法生成直接寻址的偏移量。
3.宏参数/替换符号 若多次引用一个宏, 并且每次处理不同的数据, 则可以 在宏里使用参数, 称为替换符号; 合法的替换符号符合的条件: 可以多至32个字符; 须以字母开头, 其它为数字,下划线,美元符号; 作为宏参数的替换符号只在宏定义内有效, 是局部变量; 一个宏里可以定义多至32个局部替换符号. 3.宏参数/替换符号 若多次引用一个宏, 并且每次处理不同的数据, 则可以 在宏里使用参数, 称为替换符号; 合法的替换符号符合的条件: 扩展时, 每个参数分配对应引用命令相应位置的字符串: 如果没有给出值,则默认为空字符; 如果给出值数目超过了宏参数个数,则剩余的所有值 作为一个字符串分配给最后一个参数; 若想传送一列值(多个参数值)给一个参数, 或传送一 个逗号(或分号)给参数时, 必须都放在引号里面; 在汇编时,汇编器用对应的字符串替换掉替换符号,然 后将源代码翻译为目标代码。
(1)定义替换符号的伪指令 Assign a Substitution Symbol .asg指令分配一个字符串给替换符号 格式: 如果没有引号,汇编器读字符直到遇到 逗号,开 始的和结尾的空格都将被去掉 .eval指令对数字替换符号进行运算 .eval 表达式,替换符号 .eval计算表达式的值,然后把结果的字符串值赋 给替换符号。如果表达式的结果不对应字符串值, 那么则赋空(null)字符串值给替换符号。
例5-7,. asg伪指令的使用. asg AR0,FP. ; 帧指针. asg. AR1+,Ind. ; 间接地址 例5-7,.asg伪指令的使用 .asg AR0,FP ; 帧指针 .asg *AR1+,Ind ; 间接地址 .asg “a,b,c”,parms ; 参数 例5-8,.eval伪指令的使用 .asg 1, counter .loop 100 .word counter .eval counter+1, counter .endloop
(2)内建替换符号函数 内建替换符号函数会产生返回值, 可以在表达 式中使用, 其在条件汇编表达式中特别有用; 内建替换符号函数如表5-6所示,其中的 a和b是代表替换符号或者字符常数的参数; 符号ch代表一个字符常数。
表5-6内建替换符号函数及其返回值 内建替换符号函数 返回值 $symlen(a) 字符串a的长度 $ symcmp(a, b ) <0 if a <b ;0 if a=b; >0 if a> b $ firstch(a,ch) 在字符串a中字符ch开始出现的索引值 $ lastch(a,ch) 在字符串a中字符ch最后出现的索引值 $ isdefed(a) 1 如果字符串a在符号表中有定义 0 如果a在符号表中没有定义 $ iscons(a) 1 如果a是一个二进制常数 2 如果a是一个八进制常数 3 如果a是一个十六进制常数 4 如果a是一个字符常数 5 如果a是一个十进制常数 $ isname(a) 1 如果字符串a是一个合法的符号名 0 如果不是 $ isreg(a) 1:若字符串a是一合法符号寄存器名; 0:若不是 $ structsz(a) 结构标识为a的结构的大小 $ structace(a) 结构标识为a的结构的引用入口 $ ismember(a,b) 把列表b中的最前面的一个元素赋给a (见例5-9) 0:如果b是一个空字符串
例5-9,内建替换符号函数的使用。 .asg label, ADDR ;ADDR=label .if( $symcmp(ADDR,”label”))=0 ;计算为真 SUB ADDR, AC0, AC0 .endif .asg “x,y,z”, list ;list=x,y,z .if ( $ismember(ADDR, list)) ; ADDR= x, list=y,z SUB ADDR, AC0, AC0 ;sub x
(3)强制替换操作符 有时若替代符号不能被汇编器识别,例如变量名+序号符号,则序号符号用强制替换符。 强制替换符的语法: :symbol: ;在symbol和“:”号之间不能有空格 汇编器在扩展其它替换符号之前,首先对被两个“:” 号括在中间的替换符号进行扩展; 强制替换符只能在宏内部使用,且不能与其它强制替换符相互嵌套。
例5-10,强制替换符的使用。 force .macro x .loop 8 AUX:x: .set x .eval x+1,x .endloop .endm force 0 宏force将产生下列源代码: AUX0 .set 0 AUX1 .set 1 . AUX7 .set 7
4.其他宏指令 指令格式 说 明 .var 替换符号l, … ,[替换符号n] 定义局部宏符号 .if 表达式 条件汇编开始 说 明 .var 替换符号l, … ,[替换符号n] 定义局部宏符号 .if 表达式 条件汇编开始 .elseif 表达式 可选条件汇编块 .else .endif 结束条件汇编 .loop [表达式] 循环块的开始 .break [表达式] 当满足条件则跳出循环 .endloop 结束循环 .emsg 发送出错信息到标准输出 .wmsg 发送警告信息到标准输出 .fclist 允许出错条件代码块列表出来(缺省) .fcnolist 禁止出错条件代码列表出来 .mlist 允许宏指令列表出来(缺省) .mnolist 禁止宏指令列表出来 .sslist 允许扩展替换符号列表出来 .ssnolist 禁止扩展替换符号列表出来(缺省) false conditional
第5章TMS320C55x汇编语言编程 5.1 TMS320C55x软件开发流程 5.2 TMS320C55x目标文件格式
5.5 TMS320C55x汇编语言源文件的书写格式 TMS320C55x汇编语言源程序由源语句组成。这些语句可以包含汇编语言指令、汇编伪指令和注释。 程序的编写必须符合一定的格式,以便汇编器将源文件转换成机器语言的目标文件。 5.5.1 汇编语言源文件格式 5.5.2 汇编语言中的常数与字符串 5.5.3 汇编源程序中的符号 5.5.4 汇编源程序中的表达式 5.5.5 内建数学函数
5.5.1 汇编语言源文件格式 汇编语言程序以.asm为扩展名 一条语句占源程序的一行 总长度可以是源文件编辑器格式允许的长度 语句的执行部分必须限制在200个字符以内 源语句格式 标号 助记符 操作数 注释
5.5.1 汇编语言源文件格式 1. 源语句格式 助记符指令源语句的每一行通常包含4个部分: 标号区、 助记符区、操作数区和注释区 5.5.1 汇编语言源文件格式 1. 源语句格式 助记符指令源语句的每一行通常包含4个部分: 标号区、 助记符区、操作数区和注释区 助记符指令语法格式: [标号][:] 助记符 [操作数] [; 注释] 例5-11,助记符指令源语句 SYM1 .set 2 ;SYM1 = 2 Begin: MOV #SYM1, AR1 ;AR1=2 .data .byte 016h ; 初始化(016h)
语句的书写规则: 所有语句必须以标号、空格、星号或分号(*或;)开始. 标号是可选项, 若使用标号, 则标号必须从第一列开始. 所有包含有汇编伪指令的语句必须在一行完成指定. 各部分之间必须用空格分开, Tab字符与空格等效. 注释是可选项。若注释在第一列开始时, 必须用星号或 分号开头, 在其他列开始的注释前面必须以分号开头. 如果源程序很长, 需要书写若干行, 可以在前一行用反 斜杠字符(\)结束, 余下部分接着在下一行继续书写。 Begin: MOV #SYM1, AR1 ;AR1=2
2. 标号 所有汇编指令和大多数汇编伪指令都可以选用标号, 供 本程序或其它程序调用; 标号必须从语句的第1列写起, 其后的冒号 “:”可选; 标号为任选项, 若不使用标号, 则语句的第一列必须是 空格、星号或分号 ; 标号是由字母、数字以及下划线和美元符号等组成, 最 多可达32个字符; 标号分大小写, 且第一个字符不能是数字; 在用标号时, 标号的值是段程序计数器SPC的当前值。 SYM1 .set 2 ;SYM1 = 2 Begin: MOV #SYM1, AR1 ;AR1=2
3.助记符 助记符用来表示指令所完成的操作,可以是汇编 语言指令、汇编伪指令、宏指令。 助记符指令:一般用大写,不能从第一列开始 汇编伪指令:用来为程序提供数据和控制汇编进 程,以句号“.”开始,且用小写 宏指令:用来定义一段程序,以便宏调用来调用 这段程序,以句号“.”开始,且用小写 宏调用:用来调用由宏伪指令定义的程序段 SYM1 .set 2 ;SYM1 = 2 Begin: MOV #SYM1, AR1 ;AR1=2
4.操作数 操作数是指令中参与操作的数值或汇编伪指令定义的 内容, 紧跟在助记符后面, 由一个或多个空格分开; MOV #SYM1+2, *AR3 MOV #1000h, @4Fh 操作数是指令中参与操作的数值或汇编伪指令定义的 内容, 紧跟在助记符后面, 由一个或多个空格分开; 操作数之间必须用逗号“,”分隔; 操作数可以是常数、符号或表达式 ; 操作数中的常数、符号或表达式可用来作为地址、立 即数或间接地址; 作为操作数的前缀有三种情况: 用“#” 号为前缀的操作数作立即数处理; 用“*”为前缀的操作数是间接地址,即其内容作为地址; 用“@”为前缀的操作数作直接地址, 即操作数偏移地址. 间接地址如“*AR3” ,或绝对地址如“*(#1000h)”
5.注释 用来说明指令功能,便于用户阅读。 注释可位于句首或句尾, 位于句首时, 以 “*” 或“;” 开始, 位于句尾时, 以分号“;” 开始。 注释可单独一行或数行。 注释是任选项 。 ****例5-1**** SYM1 .set 2 ;SYM1 = 2 Begin: MOV #SYM1, AR1 ;AR1=2
5.5 TMS320C55x汇编语言源文件的书写格式 5.5.1 汇编语言源文件格式 5.5.2 汇编语言中的常数与字符串 5.5.1 汇编语言源文件格式 5.5.2 汇编语言中的常数与字符串 5.5.3 汇编源程序中的符号 5.5.4 汇编源程序中的表达式 5.5.5 内建数学函数
5.5.2 汇编语言中的常数与字符串 汇编器可支持7种类型的常数与字符串,见表5-8 字符串可用于下列伪指令中: 表5-8 汇编器支持的常数与字符串 数据类型 举 例 说 明 二进制 1110001b或1110001B 八进制 226q或572Q 十进制 1234或+1234或-11234 缺省型 十六进制 0A40h或0A40H或0xA40 浮点数 1.623e-23 仅用于C语言 字符 ‘D’ 字符串 “this is a string” 字符串可用于下列伪指令中: (.copy ”filename”): 作为复制伪指令中的文件名 (.sect ”section name”): 作为命名段伪指令中的段名 (例.byte ”charstr”): 作为数据初始化伪指令中的变量名 (例.string ”hello”) : 作为该伪指令的操作数 .copy ”test.asm” 字符值
5.5 TMS320C55x汇编语言源文件的书写格式 5.5.1 汇编语言源文件格式 5.5.2 汇编语言中的常数与字符串 5.5.1 汇编语言源文件格式 5.5.2 汇编语言中的常数与字符串 5.5.3 汇编源程序中的符号 5.5.4 汇编源程序中的表达式 5.5.5 内建数学函数
5.5.3 汇编源程序中的符号 汇编程序中的符号用于标号、常数和替代字符。 由字母、数字以及下划线和美元符号(A~Z, a~z, 0~9, _和$)等组成。 符号名最多可长达200个字符。 在符号中, 第1位不能是数字,且符号中不能含空格。 标号 符号常数(例5-1) 汇编器预定义的符号常数 局部标号(例5-14,例5-15 )
所以指令不能顶格写,必须有空格,否则变成标号 1.标号 作为标号的符号代表在程序中对应位置的符号地址。 通常标号是局部变量, 在一个文件中局部使用的标号必 须是唯一的。 助记符操作码和汇编伪指令名(无前缀 “.”)为有效标号。 缺省状态下标号分大小写。若在使用汇编器时选择-c选 项, 则不分大小写。 标号还可以作为.global,.ref,.def或.bss等汇编伪指令 的操作数。 所以指令不能顶格写,必须有空格,否则变成标号 例5-12,作为标号的符号。 .global label1 label2: nop ADD @label1, AC1, AC1; B label2 @label1寻址存储单元 的地址: XDP+ (label1 地址的低7位). (CPL=0)
2.符号常数 K .set 1024 ;常数定义 符号也可被设置成常数值。为了提高程序的可读性, 可以用有意义的名称来代表一些重要的常数值。 伪指令.set和.struct/.tag/.endstruct可以用来将 常数赋给符号名; 符号常数不能被重新定义; 汇编器的-d选项相当于用一个符号表示一个常数。该 符号可用以代替汇编源程序中的对应常数。 在汇编源程序中,可采用下列伪指令对符号进行检测: .if $isdefed(”name”) ;用内建函数检测存在name? .if $isdefed(”name”) = 0 ;不存在name? .if name = value ; name等于某数值 .if name != value ; name不等于某数值 使用-d选项的格式如下: masm55 –dname=[value] name为定义的符号名 value是赋予该符号的数值。如果忽落value,则该符号的数值将会被赋予1
例5-13,符号常数 K .set 1024 ;常数定义 maxbuf .set 2*K value .set 0 delta .set 1 item .struct ;item 结构定义 .int value ;常数value偏移量= 0 .int delta ;常数delta偏移量= 1 i_len .endstruct array .tag item ;数组声明 .bss array, i_len*K
3. 汇编器预定义的符号常数 汇编器有若干预定义符号, 包括: 美元符号$, 代表段程序指针SPC的当前值; _large_model表示正在使用的存储器模式: 缺省状态下, 该值为0(小模式); 采用–mk选项可使其值为1; 存储器映像寄存器符号, 如AC0~AC3, AR0~AR7, T0~T3等; 可用_large_model编写与存储器模型无关的程序代码: .if _large_model AMOV #addr, XAR2 ;装载23-bit 地址 .else AMOV #addr, AR2 ; 装载16-bit 地址 .endif 参考“第6章: 6.2.7 存储器模式”----小存储模式(默认)和大存储器模式(参考参数设置_LARGE_MODEL=1)
4. 局部标号 局部标号是一种特殊的标号, 使用的范围和影响是临时性的; 局部标号可被取消定义, 并可再次被定义或自动产生; 定义 方法: 取消局部变量的方法: 用$n来定义, n是0~9的十进制数 用NAME?定义, NAME是任何一个合法的符号名; 局部标号不能用伪指令来定义; 使用.newblock伪指令 ; 使用伪指令.sect,.text或.data改变段; 使用伪指令.include或.copy,进入include文件; 达到include文件的结尾, 离开include文件。
例5-14,$n局部标号的使用。 (a)正确使用方法: Label1:MOV ADDRA,AC0 ;把地址A赋予AC0 SUB ADDRB,AC0,AC0 ;减地址B BCC $1,AC0 < #0 ;如果AC0<0, 跳转至 $1 MOV ADDRB,AC0 ;否则加载地址B至 AC0 B $2 ;并且跳转至$2. $1 MOV ADDRA,AC0 ;$1:加载地址A至AC0 $2 ADD ADDRC,AC0,AC0 ;$2:加载地址C .newblock ;取消$1定义,使得该符号可再次被 使用. BCC $1,AC0 < #0 ;如果AC0<0, 跳转至 $1 MOV AC0,ADDRC ;存储AC0的低位置地 址C. $1 NOP
例5-14,$n局部标号的使用。 (b)错误使用方法: Label1: MOV ADDRA,AC0 SUB ADDRB,AC0,AC0 BCC $1, AC0<#0 MOV ADDRB,AC0 B $2 $1 MOV ADDRA,AC0 $2 ADD ADDRC,AC0,AC0 MOV AC0, ADDRC $1 NOP ; 错误: $1被多次定义. 无.newblock
例5-15,name?局部标号的使用。 宏不取消其前面的局部变量 nop mylab? nop ;局部标号‘mylab’的第1次定义 B mylab? .copy ”a.inc” ; include文件a中有‘mylab’第2次定义 mylab? Nop ;从包括文件中退出复位后,‘mylab’的 ;第3次定义 mymac .macro mylab? nop ;在宏中‘mylab’的第4个定义 .endm mymac ;宏调用 B mylab? ;引用‘mylab’的第3个定义.既不被宏调 ;用复位, 也不与定义在宏中的相同名冲突 宏不取消其前面的局部变量 在宏中定义的局部标号‘mylab’只作用于宏内
.sect ”Sector_One” ;改变段 nop ;允许‘mylab’的第5个定义 .data .int 0 .text mylab? nop nop B mylab? .newblock ; .newblock伪指令 .data ;允许‘mylab’的第6个定义 mylab? nop
5.5 TMS320C55x汇编语言源文件的书写格式 5.5.1 汇编语言源文件格式 5.5.2 汇编语言中的常数与字符串 5.5.1 汇编语言源文件格式 5.5.2 汇编语言中的常数与字符串 5.5.3 汇编源程序中的符号 5.5.4 汇编源程序中的表达式 5.5.5 内建数学函数
5.5.4 汇编源程序中的表达式 表达式可以是常数、符号,或者是由算术 运算符分开的一系列常数和符号。 有效表达式的范围为-32768~32767 要求表达式中的符号或汇编时间常数在 表达式之前已定义 有效定义的表达式的计算是绝对的
例5-16,有效定义的表达式。 .data label1 .word 0 ;将16位值0,1,2放入标号为 .word 1 ;label1的当前段连续字中 .word 2 label2 .word 3 ;将3放入标号为label2的字中 X .set 50h ;定义X的值 goodsym1 .set 100h+X ;有效定义的表达式 goodsym2 .set label1 goodsym3 .set label2-label1 ;有效定义的表达式
例5-17,无效定义的表达式。 .global Y ;定义Y为全局外部符号 badsym1 .set Y ;Y在当前文件中未定义 badsym2 .set 50h+Y ;无效的表达式 badsym3 .set 50h+Z ;无效的表达式, Z还未定义 Z .set 60h ;定义Z, 但应在表达式使用之前
表5-9 汇编源程序表达式中的运算符 序号 符 号 运算操作 求值顺序 1 + - ~ ! 取正、取负、按位求1补码、逻辑负(非) 从右至左 2 * / % 乘法、除法、求模 从左至右 3 + - 加法、减法 4 << >> 左移、右移 5 < <= 小于、小于等于 6 > >= 大于、大于等于 7 != = 不等于、等于 8 & 按位与运算 9 ∧ 按位异或运算 10 | 按位或运算
5.5 TMS320C55x汇编语言源文件的书写格式 5.5.1 汇编语言源文件格式 5.5.2 汇编语言中的常数与字符串 5.5.1 汇编语言源文件格式 5.5.2 汇编语言中的常数与字符串 5.5.3 汇编源程序中的符号 5.5.4 汇编源程序中的表达式 5.5.5 内建数学函数
5.5.5 内建数学函数 汇编器支持如表5-10所示的内建数学函数 函数中的表达式必须为常数。 $acos(expr) 表5-10 汇编器内建数学函数 $acos(expr) 返回浮点expr的反余弦函数值 $asin(expr) 返回浮点expr的反正弦函数值 $atan(expr) 返回浮点expr的反正切函数值 $atan2(expr) 返回浮点expr的反正切函数值(–pi to pi) $ceil(expr) 返回不小于expr的最小整数值 $cosh(expr) 返回浮点expr的双曲余弦函数值 $cos(expr) 返回浮点expr的余弦函数值 $cvf(expr) 把expr转变为浮点数 $cvi(expr) 把expr转变为整数 $exp(expr) 返回浮点expr的自然指数值 $fabs(expr) 返回浮点expr的绝对值 $floor(expr) 返回不大于expr的最大整数值 对比 5.4.2 宏指令: 内建替换符号函数
$fmod(expr1, expr2) 返回表达式expr1 除以expr2的余数 $int(expr) 如果expr为整数返回1 $ldexp(expr1, expr2) 返回expr1 与2的expr2次幂的乘积 $log10(expr) 返回expr的以10为底的对数 $log(expr) 返回expr的以e为底的对数 $max(expr1, expr2) 返回表达式expr1 和expr2的最大值 $min(expr1, expr2) 返回表达式expr1 和expr2的最小值 $pow(expr1, expr2) 返回表达式expr1的expr2次幂 $round(expr) 返回表达式expr 最近的整数 $sgn(expr) 返回表达式expr 的符号 $sin(expr) 返回浮点expr的正弦函数值 $sinh(expr) 返回浮点expr的双曲正弦函数值 $sqrt(expr) 返回浮点expr的平方根值 $tan(expr) 返回浮点expr的正切函数值 $tanh(expr) 返回浮点expr的双曲正切函数值 $trunc(expr) 返回截去小数部分后的expr的整数值
第5章TMS320C55x汇编语言编程 5.1 TMS320C55x软件开发流程 5.2 TMS320C55x目标文件格式
5.6TMS320C55x链接器 5.6.1 概述 5.6.2 链接器的运行 5.6.3 链接器命令文件的编写与使用 5.6.1 概述 5.6.2 链接器的运行 5.6.3 链接器命令文件的编写与使用 5.6.4 MEMORY指令 5.6.5 SECTIONS指令
5.6.1 概述 TMS320C55x链接器有两个功能强大的指令,即 MEMORY和SECTIONS。
5.6TMS320C55x链接器 5.6.1 概述 5.6.2 链接器的运行 5.6.3 链接器命令文件的编写与使用 5.6.1 概述 5.6.2 链接器的运行 5.6.3 链接器命令文件的编写与使用 5.6.4 MEMORY指令 5.6.5 SECTIONS指令
5.6.2 链接器的运行 1、C55x链接器的三种运行方法: 键入命令:lnk55 TMS320C55x Assembly Language Tools User’s Guide (SPRU280H, 2004年)无lnk55介绍 5.6.2 链接器的运行 (参考 SPRU280G, 2003年: lnk55命令在 H版本无介绍) 1、C55x链接器的三种运行方法: 键入命令:lnk55 键入命令:lnk55 a.obj b.obj -o link.out 键入命令:lnk55 linker.cmd 链接器会提示如下信息: Command files: (要求键入一个或多个命令文件) Object files [.obj]: (要求键入一个或多个需要链接的目标文件) Output Files [a.out]:(要求键入一个链接器所生成的输出文件名) Options: (要求附加一个链接选项) 在命令行中指定选项和文件名: 目标文件: a.obj、b.obj 命令选项: -o 输出文件: link.out linker.cmd: 链接命令文件。 在执行上述命令之前, 需将链接的目标文件、链接命令选项以及存储器配置要求等编写到链接命令文件linker.cmd中; MEMORY,SECTIONS指令
例5-18,链接器命令文件举例。 将两个目标文件a.obj和b.obj进行链接,生成一个映像 文件prog.map和一个可执行的输出文件prog.out。 -e start /*从全局标号start开始执行程序*/ a.obj /* 第一个输入文件 */ b.obj /*第二个输入文件*/ –o prog.out /* 产生.out文件选项 */ –m prog.map /*产生.map文件选项 */ 完整链接器命令文件还有MEMORY和SECTIONS命令(没有则默认设置) MEMORY { DARAM: org= 000100h, len = 8000h SARAM: org= 010000h, len = 8000h } SECTIONS { vars :> DARAM .table: > SARAM /* 初始化段前加点.*/ .text:> SARAM
2.链接命令选项 选 项 含 义 -a 生成一个绝对地址的、可执行的输出模块。如果既不用-a选项, 也不用-r选项, 链接器就像规定-a选项那样处理。 -ar 生成一个可重新定位、可执行的目标模块。这里采用了-a和-r两个选项(可以分开写成-a –r, 也可以连在一起 写作-ar), 与-a选项相比, -ar选项还在输出文件中保留有重新定位信息。 -c 用TMS320C55x C/C++编译器的ROM自动初始化模型所定义的链接约定(在运行时自动初始化变量) -cr 用TMS320C55x C/C++编译器的RAM自动初始化模型所定义的链接约定(装载时自动初始化变量) -e global_symbol 定义一全局符号, 该符号指定输出模块的入口地址(对C语言若用了−c或−cr, 则默认_c_int00为入口) -f fill_vale 对输出模块各段之间的空单元设置一个16位数值(fill_value),如果不用-f选项, 则这些空单元都置0。 -h 使所有全局符号均为静态的
选 项 含 义 -help 或? 显示链接器所有命令行选项列表 –heap size 设置存储器heap块的大小(用于C/C++程序中动态存储器分配),缺省值为2000字节 -i dir 更改搜索文档库算法,先到dir (目录)中搜索。此选项必须出现在-l选项之前。 -l filename 命名一个文档库文件作为链接器的输入文件; filename为文档库的某个文件名。此选项必须出现在-i选项之后。 -m filename 生成一个.map映像文件,filename是映像文件的文件名。.map文件中说明存储器配置、输入、输出段布局以及外部符号重定位之后的地址等。 -o filename 对可执行输出模块命名。如果默认, 则此文件名为a.out。 -r 生成一个可重新定位的输出模块。当利用-r选项且不用 -a选项时, 链接器生成一个不可执行的文件。 –stack size 设置主堆栈大小,缺省值为1000字节 –sysstack size 设置次级堆栈大小,缺省值为1000字节
2.链接命令选项 在链接时, 连接器通过链接命令选项控制链接 操作。 链接命令选项可以放在命令行或命令文件中, 所有选项前面必须加一短划线“-”。 除-l和-i选项外, 其他选项的先后顺序并不重要。 选项之间可以用空格分开。 最常用选项为-m和-o, 分别表示输出的地址分 配表映像文件名和输出可执行文件名。
5.6TMS320C55x链接器 5.6.1 概述 5.6.2 链接器的运行 5.6.3 链接器命令文件的编写与使用 5.6.1 概述 5.6.2 链接器的运行 5.6.3 链接器命令文件的编写与使用 5.6.4 MEMORY指令 5.6.5 SECTIONS指令
5.6.3 链接器命令文件的编写与使用 链接命令文件用来为链接器提供链接信息, 可 将链接操作所需的信息放在一个文件中, 这在 多次使用同样的链接信息时, 可方便地调用; 在链接命令文件中, 可使用MEMORY和 SECTIONS伪指令, 为实际应用指定存储器结 构和地址的映射; MEMORY: 用来指定目标存储器结构; SECTIONS: 用来控制段的构成与地址分配;
链接命令文件为ASCⅡ文件, 可包含以下内容: 输入文件名, 用来指定目标文件、存档库或其他命 令文件; 链接器选项, 它们在命令文件中的使用方法与在命 令行中相同; 链接伪指令MEMORY和SECTIONS, 用来指定目 标存储器结构和地址分配; 赋值说明, 用于给全局符号定义和赋值; a.obj /* 第一个输入文件 */ b.obj /*第二个输入文件*/ -e start /*从全局标号start开始执行程序*/ –o prog.out /* 产生.out文件选项 */ –m prog.map /*产生.map文件选项 */
5.6TMS320C55x链接器 5.6.1 概述 5.6.2 链接器的运行 5.6.3 链接器命令文件的编写与使用 5.6.1 概述 5.6.2 链接器的运行 5.6.3 链接器命令文件的编写与使用 5.6.4 MEMORY指令 5.6.5 SECTIONS指令
5.6.4 MEMORY指令 PAGE:用于识别一个存储空间, 可用多达255个页, 具体决定于配置情况。(若无PAGE, 则默认为PAGE0) 通常页0对应程序存储空间, 页1对应数据存储空间。 每个页面表现为一个完全独立的地址空间。 页0上的已配置空间和页1上的已配置空间可交叠。 MEMORY { [PAGE 0:] name_1[(attr)]:origin=constant,length=constant; [PAGE n:] name_n[(attr)]:origin=constant,length=constant; } Name:命名一个存储空间范围。 可以一到任意个字符, 合法字符含大小写26字母、$和_。 名字仅对链接器有用, 在输出文件或符号里不再保留。 在不同页的存储空间范围可以有相同的名字, 但在一页内不允许不同空间段有相同名字和交叠。
MEMORY、SECTIONS指令: PAGE的用法 不同页上的16位地址可重叠,因在不同页其24位的地址不会相同。 MEMORY { PAGE0: ONCHIP : origin = 0800h, length = 0240h PROG: origin=02C00h, length=0D200h PAGE1: OVR_MEM: origin=0A00h, length=02200h DATA : origin=02C00h, length=0D400h } SECTIONS .text: load = PROG PAGE 0 .data: load = PROG PAGE 0 .bss : load = DATA PAGE 1
5.6.4 MEMORY指令 MEMORY { [PAGE 0:] name_1[(attr)]:origin=constant,length=constant; [PAGE n:] name_n[(attr)]:origin=constant,length=constant; } Origin:指定存储段的开始地址。 值为24位二进制常数, 可以是十进制、八进制或十六进制, 单位为字节, 也可以写为org或者o Attr: 指定与命名的存储空间范围相联系的1~4个属性, 使用时必须放在小括号里。 属性限制输出段在存储空间的分配。若不使用任何属性, 可把输出段分配到任何存储空间范围; 合法的属性包括:R: 该存储空间可读; W: 该存储空间可写; X:该存储空间可以包含可执行代码; I: 该存储空间可以初始化。
5.6.4 MEMORY指令 MEMORY { [PAGE 0:] name_1[(attr)]:origin=constant,length=cons tant; [PAGE n:] name_n[(attr)]:o=constant,l=constant,f=0FF FFh } Length: 指定存储段的长度 值为24位二进制常数, 可以是十进制、八进制或者十六进制, 单位为字节, 也可以写len或者l Fill: 指定存储段的填充字符,为可选参数。 值为2字节整型数, 可以是十进制、八进制或十六进制。 填充值用来填充没有分配程序段的存储空间, 也可写为f。
MEMORY、SECTIONS指令: 默认的分配法 { ROM (RIX) : origin = 0100h, length = 0FEFFh VECTOR(RIX): origin=0FFFF00h, length=0100h RAM (RWIX) : origin=010100h, length=0FFFFh } SECTIONS { .text > ROM .switch > ROM .const > ROM .cinit > ROM .vectors > VECTOR .data > RAM .bss > RAM .sysmem > RAM .stack > RAM .sysstack > RAM .cio > RAM 没有PAGE页面定义, 则默认为PAGE0
5.6TMS320C55x链接器 5.6.1 概述 5.6.2 链接器的运行 5.6.3 链接器命令文件的编写与使用 5.6.1 概述 5.6.2 链接器的运行 5.6.3 链接器命令文件的编写与使用 5.6.4 MEMORY指令 5.6.5 SECTIONS指令
5.6.5 SECTIONS指令 SECTIONS { name_1: [property, property, property …] } 以name开始的一行定义了一个输出段。段名name后是属性列表,这些属性定义了段的内容和段如何分配到存储器。 SECTIONS { .text: load =ROM, run=800h .bss : RAM .vectors: >0FF80h .data: load =RAM, align = 16 }
Run allocation 定义在存储器中段运行的位置: run=allocation 或run > allocation 一个段可能的属性包括: Load allocation 定义在存储器中段被装载的位置: load=allocation 或 allocation 或 >allocation Run allocation 定义在存储器中段运行的位置: run=allocation 或run > allocation Input sections 定义组成输出段的输入段: 句法为 {input_sections} Section type定义特殊种类段的标志: 句法为 type=COPY 或 type=DSECT 或 type=NOLOAD Fill value定义用来填充未初始化空间的值: 句法为 fill=value 或 Name: …{…}=value (略) dummy section SECTIONS { .text : { abc.obj(xqt) *(.text) } .data : { *(.data) fil.obj(table) 输出段.text段的输入段组成: abc.obj的自定义段xqt,及所有目标文件的.text段
-o prog.out /* 用-o参数指定输出文件名 */ SECTIONS { .text: load =ROM, run=800h 例5-19,链接器的使用。 a.obj b.obj /*输入文件 */ -o prog.out /* 用-o参数指定输出文件名 */ SECTIONS { .text: load =ROM, run=800h .const: load=ROM .bss : load=RAM .vectors: load=0FF80h .data: >RAM, align = 16 } , run=RAM MEMORY (若省略,则SECTIONS分配的存储名是MEMORY默认设置如下) { ROM (RIX) : origin = 0100h, length = 0FEFFh VECTOR(RIX): origin=0FFFF00h, length=0100h RAM (RWIX) : origin=010100h, length=0FFFFh } MEMORY (按图5-5存储器映射图,教材略去的MEMORY可设置如下) { RAM (RIX) : origin = 0100h, length = 07EFFh ROM (RWIX) : origin=8000h, length=0FFFFh }
图5-5 段在存储器里的分配
第5章TMS320C55x汇编语言编程 5.1 TMS320C55x软件开发流程 5.2 TMS320C55x目标文件格式
5.7 一个完整的TMS320C55x汇编程序 (1)汇编源程序(test.asm) 例5-20, 这是一个完整的C55x 汇编程序, 其功能计算: y = x0 + x3 + x1 + x2。通过该例程可以加深对 C55x 汇编程序的了解, 熟悉C55x 的寻址方式和开发 调试方法。 (1)汇编源程序(test.asm) * Step 1: 定义有关代码段和数据段 .def x,y,init x .usect “vars”,4 ;为变量x留4个未初始化16位存储单元 y .usect “vars”, 1 ;为变量y留41个未初始化16位存储单元 .sect “.table” ;创建初始化段“.table”,存储x的初始化值 init .int 1,2,3,4 .text ; 创建代码段(.text) .global start ; 定义代码段的起始标号 start
(1)汇编源程序(test.asm) * Step 1: 定义有关代码段和数据段 .def x,y,init x .usect “vars”,4 ;为变量x留4个未初始化16位存储单元 y .usect “vars”, 1 ;为变量y留41个未初始化16位存储单元 .sect “.table” ;创建初始化段“table”,存储x的初始化值 init .int 1,2,3,4 .text ; 创建代码段(.text) .global start ; 定义代码段的起始标号 start (续上页) * Step 2: 处理器模式初始化 BCLR C54CM ; 设置处理器为55x模式 .C54CM_off ;(紧随)告知汇编器C54CM=0 BCLR AR0LC ;设置AR0为线性模式 BCLR AR6LC ;设置AR6为线性模式
DP直接寻址必须保证CPL=0, 否则CPL=1就成了SP直接寻址 *Step 3a: 采用间接寻址方法复制init的初始化值到x copy ;这里是标号 AMOV #x,XAR0 ; XAR0 指向变量x AMOV #init, XAR6 ; XAR6指向初始化表table MOV *AR6+,*AR0+ ; 复制开始 MOV *AR6+,*AR0+ MOV *AR6+, *AR0+ * Step 3b: 采用DP直接寻址方法将x开始的4个单元的值相加 add ;这里是标号 AMOV #x,XDP ; XDP 指向变量x(准备DP直接寻址须CPL=0) .dp x ;必须有,使.dp值指向变量x的16位地址(Doffset = (Daddr – .dp) & 7Fh) MOV @x,AC0 ADD @x+3,AC0 ADD @x+1,AC0 ADD @x+2,AC0 *Step 3c: 用绝对寻址法把结果写到变量y MOV AC0,*(#y) end ;这里是标号 nop B end #init的23位地址送XAR6 BCLR CPL ;清零CPL .CPL_off ;告知汇编器CPL=0 DP直接寻址必须保证CPL=0, 否则CPL=1就成了SP直接寻址 可采用绝对寻址方式: MOV *(#x), AC0 ADD *(#x+3), AC0 ADD *(#x+1), AC0 ADD *(#x+2), AC0
(2)链接器命令文件 (test.cmd) test.obj /* 输入文件 */ –o test.out /* 输出文件 */ –m test.map /* map文件*/ MEMORY { DARAM: org= 000100h, len = 8000h SARAM: org= 010000h, len = 8000h } SECTIONS { vars :> DARAM .table: > SARAM /* 初始化段’table’前加点.*/ .text:> SARAM 其他段名tabl,ttable则不需要。
第5章作业 5.11 (仿真调试)利用5-20所给的命令文件,在 CCS下建立关于例5-1、5-20的汇编语言工程, 并对工程进行构建、调试。通过仿真调试加 深对汇编语言中的典型伪指令和段的理解。 5.1~5.10 (参考问题看书) 。