MPLAB® C30
C 编译器
用户指南
2006 Microchip Technology Inc. DS51284E_CN
请注意以下有关 Microchip 器件代码保护功能的要点:
• Microchip 的产品均达到 Microchip 数据手册中所述的技术指标。
• Microchip 确信:在正常使用的情况下, Microchip 系列产品是当今市场上同类产品中最安全的产品之一。
• 目前,仍存在着恶意、甚至是非法破坏代码保护功能的行为。就我们所知,所有这些行为都不是以 Microchip 数据手册中规定的
操作规范来使用 Microchip 产品的。这样做的人极可能侵犯了知识产权。
• Microchip 愿与那些注重代码完整性的客户合作。
• Microchip 或任何其他半导体厂商均无法保证其代码的安全性。代码保护并不意味着我们保证产品是 “牢不可破”的。
代码保护功能处于持续发展中。 Microchip 承诺将不断改进产品的代码保护功能。任何试图破坏 Microchip 代码保护功能的行为均可视
为违反了 《数字器件千年版权法案 (Digital Millennium Copyright Act )》。如果这种行为导致他人在未经授权的情况下,能访问您的
软件或其他受版权保护的成果,您有权依据该法案提起诉讼,从而制止这种行为。
提供本文档的中文版本仅为了便于理解。请勿忽视文档中包含
的英文部分,因为其中提供了有关 Microchip 产品性能和使用
情况的有用信息。Microchip Technology Inc. 及其分公司和相
关公司、各级主管与员工及事务代理机构对译文中可能存在的
任何差错不承担任何责任。建议参考 Microchip Technology
Inc. 的英文原版文档。
本出版物中所述的器件应用信息及其他类似内容仅为您提供便
利,它们可能由更新之信息所替代。确保应用符合技术规范,
是您自身应负的责任。Microchip 对这些信息不作任何明示或
暗示、书面或口头、法定或其他形式的声明或担保,包括但不
限于针对其使用情况、质量、性能、适销性或特定用途的适用
性的声明或担保。 Microchip 对因这些信息及使用这些信息而
引起的后果不承担任何责任。如果将 Microchip 器件用于生命
维持和 / 或生命安全应用,一切风险由买方自负。买方同意在
由此引发任何一切伤害、索赔、诉讼或费用时,会维护和保障
Microchip 免于承担法律责任,并加以赔偿。在 Microchip 知识
产权保护下,不得暗中或以其他方式转让任何许可证。
商标
Microchip 的名称和徽标组合、 Microchip 徽标、 Accuron、
dsPIC、 K
EEL OQ、 microID 、 MPLAB、 PIC、 PICmicro、
PICSTART、 PRO MATE、 PowerSmart、 rfPIC 和
SmartShunt 均为 Microchip Technology Inc. 在美国和其他国
家或地区的注册商标。
AmpLab、 FilterLab、 Migratable Memory、 MXDEV、
MXLAB、 SEEVAL、 SmartSensor 和 The Embedded Control
Solutions Company 均为 Microchip Technology Inc.在美国的
注册商标。
Analog-for-the-Digital Age、 Application Maestro、
dsPICDEM、 dsPICDEM.net、 dsPICworks、 ECAN、
ECONOMONITOR、 FanSense、 FlexROM、 fuzzyLAB、
In-Circuit Serial Programming、 ICSP、 ICEPIC、 Linear
Active Thermistor、 Mindi、 MiWi、 MPASM、 MPLIB、
MPLINK、 PICkit、 PICDEM、 PICDEM.net、 PICLAB、
PICtail、 PowerCal、 PowerInfo、 PowerMate、 PowerTool、
REAL ICE、rfLAB、rfPICDEM、Select Mode、Smart Serial、
SmartTel、 Total Endurance、 UNI/O、 WiperLock 和 ZENA
均为 Microchip Technology Inc . 在美国和其他国家或地区的商
标。
SQTP 是 Microchip Technology Inc . 在美国的服务标记。
在此提及的所有其他商标均为各持有公司所有。
© 2006, Microchip Technology Inc .版权所有。
Microchip
Gresham
晶圆生产厂均通过了
单片机、
存储器和模拟产品方面的质量体系流程均符合
外,
ISO 9001:2000
位于美国亚利桑那州
及位于加利福尼亚州
®
KEE LOQ
Microchip
在开发系统的设计和生产方面的质量体系也已通过了
认证。
Chandler和Tem p e
ISO/TS-16949:2002
跳码器件、串行
Mountain View
认证。公司在
EEPROM
、位于俄勒冈州
的全球总部、设计中心和
、单片机外设、非易失性
ISO/TS-16949:2002
PICmicro
®
。此
8
DS51284E_CN 第ii 页 2006 Microchip Technology Inc.
位
MPLAB® C30
用户指南
目录
前言 ................................................................................................................................. 1
第 1 章 编译器概述
1.1 简介 ................................................................................................................ 7
1.2 主要内容 ......................................................................................................... 7
1.3 MPLAB C30 介绍 ............................................................................................ 7
1.4 MPLAB C30 及其他开发工具 .......................................................................... 7
1.5 MPLAB C30 的功能 ........................................................................................ 9
第 2 章 MPLAB C30 与 ANSI C 的差别
2.1 简介 .............................................................................................................. 11
2.2 主要内容 ....................................................................................................... 11
2.3 关键字差别 ................................................................................................... 11
2.4 语句差别 ....................................................................................................... 27
2.5 表达式差别 ................................................................................................... 28
第 3 章 使用 MPLAB C30 C 编译器
3.1 简介 .............................................................................................................. 29
3.2 主要内容 ....................................................................................................... 29
3.3 概述 .............................................................................................................. 29
3.4 文件命名约定 ................................................................................................ 30
3.5 选项 .............................................................................................................. 30
3.6 环境变量 ....................................................................................................... 55
3.7 预定义常量 ................................................................................................... 56
3.8 通过命令行编译单个文件 .............................................................................. 57
3.9 通过命令行编译多个文件 .............................................................................. 58
第 4 章 MPLAB C30 C 编译器运行时环境
4.1 简介 .............................................................................................................. 59
4.2 主要内容 ....................................................................................................... 59
4.3 地址空间 ....................................................................................................... 59
4.4 代码段和数据段 ............................................................................................ 61
4.5 启动和初始化 ................................................................................................ 63
4.6 存储空间 ....................................................................................................... 64
4.7 存储模型 ....................................................................................................... 65
4.8 定位代码和数据 ............................................................................................ 67
4.9 软件堆栈 ....................................................................................................... 68
4.10 C 堆栈使用 ................................................................................................. 69
4.11 C 堆使用 ..................................................................................................... 71
2006 Microchip Technology Inc. DS51284E_CN 第 iii 页
MPLAB® C30 用户指南
4.12 函数调用约定 .............................................................................................. 72
4.13 寄存器约定 ................................................................................................. 74
4.14 位反转寻址和模寻址 ................................................................................... 75
4.15 程序空间可视性 ( PSV)的使用 ................................................................ 75
第 5 章 数据类型
5.1 简介 .............................................................................................................. 77
5.2 主要内容 ....................................................................................................... 77
5.3 数据表示 ....................................................................................................... 77
5.4 整型 .............................................................................................................. 77
5.5 浮点型 .......................................................................................................... 78
5.6 指针 .............................................................................................................. 78
第 6 章 器件支持文件
6.1 简介 .............................................................................................................. 79
6.2 主要内容 ....................................................................................................... 79
6.3 处理器头文件 ................................................................................................ 79
6.4 寄存器定义文件 ............................................................................................ 80
6.5 使用特殊功能寄存器 ..................................................................................... 81
6.6 使用宏 .......................................................................................................... 83
6.7 从 C 代码访问 EEDATA——仅适用于 dsPIC30F DSC ................................. 84
第 7 章 中断
7.1 简介 .............................................................................................................. 87
7.2 主要内容 ....................................................................................................... 87
7.3 编写中断服务程序 ........................................................................................ 88
7.4 写中断向量 ................................................................................................... 90
7.5 中断服务程序现场保护 ............................................................................... 100
7.6 中断响应时间 .............................................................................................. 100
7.7 中断嵌套 ..................................................................................................... 100
7.8 允许 / 禁止中断 ........................................................................................... 101
7.9 中断服务程序和一般代码共用存储空间 ...................................................... 102
第 8 章 汇编语言和 C 模块混合编程
8.1 简介 ............................................................................................................ 107
8.2 主要内容 ..................................................................................................... 107
8.3 在汇编语言中使用 C 变量和 C 函数 ............................................................ 107
8.4 使用行内汇编 .............................................................................................. 109
附录 A 实现定义的操作
A.1 简介 ............................................................................................................ 115
A.2 翻译 ............................................................................................................ 116
A.3 环境 ............................................................................................................ 116
A.4 标识符 ........................................................................................................ 117
A.5 字符 ............................................................................................................ 117
A.6 整型 ............................................................................................................ 118
A.7 浮点型 ........................................................................................................ 118
DS51284E_CN 第 iv 页 2006 Microchip Technology Inc.
目录
A.8 数组和指针 ................................................................................................. 119
A.9 寄存器 ........................................................................................................ 119
A.10 结构、联合、枚举和位域 ......................................................................... 120
A.11 限定符 ...................................................................................................... 120
A.12 声明符 ...................................................................................................... 120
A.13 语句 .......................................................................................................... 120
A.14 预处理伪指令 ........................................................................................... 121
A.15 库函数 ...................................................................................................... 122
A.16 信号 .......................................................................................................... 123
A.17 流和文件 ................................................................................................... 123
A.18 tmpfile ...................................................................................................... 124
A.19 errno ......................................................................................................... 124
A.20 存储器 ...................................................................................................... 124
A.21 abort ......................................................................................................... 124
A.22 exit ........................................................................................................... 124
A.23 getenv ...................................................................................................... 125
A.24 系统 .......................................................................................................... 125
A.25 strerror ..................................................................................................... 125
附录 B MPLAB C30 C 编译器诊断
B.1 简介 ............................................................................................................ 127
B.2 错误 ............................................................................................................ 127
B.3 警告 ............................................................................................................ 146
附录 C MPLAB C18 与 MPLAB C30 C 编译器
C.1 简介 ............................................................................................................ 167
C.2 数据格式 .................................................................................................... 168
C.3 指针 ............................................................................................................ 168
C.4 存储类别 .................................................................................................... 168
C.5 堆栈使用 .................................................................................................... 168
C.6 存储限定符 ................................................................................................. 169
C.7 预定义宏名 ................................................................................................. 169
C.8 整型的提升 ................................................................................................. 169
C.9 字符串常量 ................................................................................................. 169
C.10 匿名结构 .................................................................................................. 170
C.11 快速存取存储区 ........................................................................................ 170
C.12 行内汇编 .................................................................................................. 170
C.13 Pragma 伪指令 ......................................................................................... 170
C.14 存储模型 .................................................................................................. 171
C.15 调用约定 .................................................................................................. 171
C.16 启动代码 .................................................................................................. 172
C.17 编译器管理的资源 .................................................................................... 172
C.18 优化 .......................................................................................................... 172
C.19 目标模块格式 ........................................................................................... 172
C.20 实现定义的操作 ........................................................................................ 172
C.21 位域 .......................................................................................................... 173
2006 Microchip Technology Inc. DS51284E_CN 第 v 页
MPLAB® C30 用户指南
附录 D 不赞成使用的特性
D.1 简介 ........................................................................................................... 175
D.2 主要内容 .................................................................................................... 175
D.3 预定义常量 ................................................................................................ 175
附录 E ASCII 字符集
附录 F GNU 自由文档许可证
术语表 ..........................................................................................................................185
索引 .............................................................................................................................193
全球销售及服务网点 ....................................................................................................202
DS51284E_CN 第 vi 页 2006 Microchip Technology Inc.
MPLAB® C30
用户指南
前言
客户须知
所有文档均会过时,本文档也不例外。 Microchip 的工具和文档将不断演变以满足客户的需求,因此
实际使用中有些对话框和 / 或工具说明可能与本文档所述之内容有所不同。请访问我们的网站
(www.microchip.com )获取最新文档。
文档均标记有 “DS ”编号。该编号出现在每页底部的页码之前。 DS 编号的命名约定为
“DSXXXXXA ”,其中 “XXXXX ”为文档编号,“A ”为文档版本。
欲了解开发工具的最新信息,请参考 MPLAB
(主题),打开现有在线帮助文件列表。
简介
本文档的目的是帮助大家使用 Microchip 针对 dsPIC ®数字信号控制器 (Digital Signal
Controllers, DSC)的 MPLAB C30 C 编译器开发应用程序。 MPLAB C30 是一款基于
GNU 编译器集 (GNU Compiler Collection, GCC)的语言工具,以来自 Free
Software Foundation (FSF)的源代码为基础。关于 FSF 的信息可登陆网站
WWW.FSF.ORG。
您还可从 Microchip 获得其他 GNU 语言工具:
• MPLAB ASM30 汇编器
• MPLAB LINK30 链接器
• MPLAB LIB30 库管理器 / 归档程序
本章涉及以下内容:
• 关于本指南
• 推荐读物
• 疑难解答
• Microchip 网站
• 开发系统变更通知客户服务
• 客户支持
®
IDE 在线帮助。从 Help (帮助)菜单选择 Topics
2006 Microchip Technology Inc. DS51284E_CN 第 1 页
MPLAB® C30 用户指南
关于本指南
文档编排
本文档介绍如何使用 MPLAB C30 来开发固件。内容安排如下:
• 第 1 章: 编译器概述 — 介绍 MPLAB C30、开发工具和功能。
• 第 2 章: MPLAB C30 与 ANSI C 的区别 — 描述 MPLAB C30 语法支持的 C 语言和
标准 ANSI-89 C 之间的区别。
• 第 3 章: 使用 MPLAB C30 — 介绍怎样通过命令行使用 MPLAB C30。
• 第 4 章: MPLAB C30 运行时环境 — 介绍 MPLAB C30 运行时模型,包括段信息、
初始化、存储器模式和软件堆栈等。
• 第 5 章: 数据类型 — 介绍 MPLAB C30 整型、浮点型和指针型数据类型。
• 第 6 章: 器件支持文件 — 介绍 MPLAB C30 的头文件和寄存器定义文件,以及怎样
使用特殊功能寄存器。
• 第 7 章: 中断 — 介绍怎样使用中断。
• 第 8 章: C 语言与汇编语言的混合编程 — 为使用 MPLAB C30 与 MPLAB ASM30
汇编语言模块提供指导。
• 附录 A :实现定义的操作 — 详细描述 ANSI 标准中描述为实现定义的、特定于
MPLAB C30 的参数。
• 附录 B: MPLAB C30 诊断信息 — 列出由 MPLAB C30 产生的错误和警告消息。
• 附录 C: MPLAB C18 和 MPLAB C30 的区别 — 介绍 PIC18XXXXX 编译器
(MPLAB C18 )和 dsPIC DSC 编译器 (MPLAB C30 )的主要区别。
• 附录 D:不赞成使用的特性 — 详述视为过时的特性。
• 附录 E: ASCII 字符集 — 介绍 ASCII 字符集。
• 附录 F: GNU 自由文档许可证 — Free Software Foundation 的使用许可证。
DS51284E_CN 第 2 页 2006 Microchip Technology Inc.
前言
本文档中使用的约定
本手册使用如下文档约定:
文档约定
说明 涵义 示例
Arial 字体:
斜体字 参考书目
需强调的文字 ...
首字母大写 窗口 Output 窗口
对话框 Settings 对话框
菜单选项 选择 Enable Programmer
引号 窗口或对话框中的字段名 “Save project before build”
带右尖括号且有下划线的斜体文字菜单路径
粗体字 对话框按钮 单击 OK
选项卡 单击 Power 选项卡
‘bnnnn
尖括号 < > 括起的文字 键盘上的按键 按 <Enter>, <F1>
Courier 字体:
常规 Courier New 源代码示例
斜体 Courier New 可变参数 file.o , 其中 file 可以是任
0xnnnn
方括号 [ ] 可选参数
花括号和竖线: { | } 选择互斥参数; “或”选择
省略号 ... 代替重复文字
图标
二进制数, n 是一个数字
文件名
文件路径
关键字
命令行选项
位值
常数 0xFF, ‘A’
十六进制数, n 是一个十六进
制数字
仅完全版软件支持的功能。
MPLAB® IDE User's Guide
仅有
的编译器 ...
File>Save
‘b00100, ‘b10
#define START
autoexec.bat
c:\mcc18\h
_asm, _endasm, static
-Opa+, -Opa-
0, 1
一有效文件名
0xFFFF , 0x007A
mcc18 [options] file
[options]
errorlevel {0|1}
var_name [,
var_name...]
并非所有的器件都支持此功
能。所支持器件将在标题或正
文中列出。
2006 Microchip Technology Inc. DS51284E_CN 第 3 页
MPLAB® C30 用户指南
推荐读物
本文档介绍如何使用 MPLAB C30 编译器。下面列出了其他有用的文档。 Microchip 提
供了如下文档,推荐将这些文档作为补充参考资料。
README 文件
关于 Microchip 工具的最新信息,请阅读软件附带的相关 README 文件 (ASCII 文本
文件)。
®
dsPIC
指导安装和使用 Microchip dsPIC 数字信号控制器 ( DSC)的语言工具 ( MPLAB
ASM30、 MPLAB LINK30 和 MPLAB C30)。还提供了使用 dsPIC DSC 软件模拟器
MPLAB SIM30 的示例。
MPLAB
指导使用 dsPIC DSC 汇编器、MPLAB ASM30 、dsPIC DSC 链接器、MPLAB LINK30
和各种 dsPIC DSC 实用程序,包括 MPLAB LIB30 归档程序 / 库管理器。
dsPIC30F Data Sheet General Purpose and Sensor Families (DS70083 )
这是 dsPIC30F 数字信号控制器 (DSC )的数据手册。总体介绍了器件及其架构。详
细介绍了存储器的构成、 DSP 操作和外设功能。还包括器件的电气参数。
dsPIC30F 系列参考手册 (DS70046D_CN )
该系列的参考指南,介绍了 dsPIC30F 系列 DSC 的架构和外设。
dsPIC30F/33F 程序员参考手册 (DS70157B_CN )
dsPIC30F/33F 器件的编程人员指南。包括编程模型和指令集。
C 标准信息
American National Standard for Information Systems – Programming Language – C .
DSC 语言工具入门 ( DS70094C_CN)
®
ASM30、 MPLAB LINK30 和实用程序用户指南 ( DS51317D_CN)
American National Standards Institute (ANSI), 11 West 42nd. Street, New York,
New York, 10036.
此标准规定了用 C 语言编写程序的格式,并对 C 程序进行了解释。其目的是提高
C 程序在多种计算机系统上的可移植性、可靠性、可维护性及执行效率。
C 参考书籍
Harbison, Samuel P., and Steele, Guy L., C A Reference Manual,第四版,
Prentice-Hall, Englewood Cliffs, N.J. 07632.
Kernighan, Brian W., and Ritchie, Dennis M., The C Programming Language,第二
版。 Prentice Hall, Englewood Cliffs, N.J. 07632.
Kochan, Steven G., Programming In ANSI C,修订版。 Hayden Books, Indianapolis,
Indiana 46268.
Plauger, P.J., The Standard C Library, Prentice-Hall, Englewood Cliffs, N.J. 07632.
Van Sickle, Ted., Programming Microcontrollers in C,第一版。 LLH Technology
Publishing, Eagle Rock, Virginia 24085.
DS51284E_CN 第 4 页 2006 Microchip Technology Inc.
疑难解答
在本文中找不到的常见问题信息可以查阅 README 文件。
MICROCHIP 网站
Microchip 网站 (www.microchip.com )为客户提供在线支持。客户可通过该网站方便
地获取文件和信息。只要使用常用的因特网浏览器即可访问。网站提供以下信息:
• 产品支持——数据手册和勘误表、应用笔记和样本程序、设计资源、用户指南以及
硬件支持文档、最新的软件版本以及存档软件
• 一般技术支持——常见问题 (FAQ )、技术支持请求、在线讨论组以及 Microchip
顾问计划成员名单
• Microchip 业务 ——产品选型和订购指南、最新 Microchip 新闻稿、研讨会和活动安
排表、 Microchip 销售办事处、代理商以及工厂代表列表
开发系统变更通知客户服务
Microchip 的客户通知服务有助于客户了解 Microchip 产品的最新信息。注册客户可在
他们感兴趣的某个产品系列或开发工具发生变更、更新、发布新版本或勘误表时,收
到电子邮件通知。
欲注册,请登录 Microchip 网站 www.microchip.com,点击 “变更通知客户
(Customer Change Notification )”服务并按照注册说明完成注册。
开发系统产品的分类如下:
• 编译器—— Microchip C 编译器及其他语言工具的最新信息,包括 MPLAB C18 和
MPLAB C30 C 编译器、 MPASM
MPLAB LINK30 目标链接器,以及 MPLIB
• 仿真器—— Microchip 在线仿真器的最新信息,包括 MPLAB ICE 2000 和 MPLAB
ICE 4000。
• 在线调试器—— Microchip 在线调试器 MPLAB ICD 2 的最新信息。
• MPLAB
MPLAB IDE 的最新信息,主要针对 MPLAB IDE、 MPLAB SIM 模拟器、 MPLAB
IDE 项目管理器以及一般编辑和调试功能。
• 编程器—— Microchip 编程器的最新信息,包括 MPLAB PM3 和 PRO MATE
编程器以及 PICSTART
®
前言
TM
和 MPLAB ASM30 汇编器、 MPLINKTM和
TM
和 MPLAB LIB30 目标库管理器。
IDE ——关于支持开发系统工具的 Windows ®集成开发环境 Microchip
®
®
Plus 和 PICkit ® 1 开发编程器。
II 器件
2006 Microchip Technology Inc. DS51284E_CN 第 5 页
MPLAB® C30 用户指南
客户支持
Microchip 产品的用户可通过以下渠道获得帮助:
• 代理商或代表
• 当地销售办事处
• 应用工程师 ( FAE)
• 技术支持
客户应联系其代理商、代表或应用工程师 (FAE )寻求支持。当地销售办事处也可为
客户提供帮助。本文档后附有销售办事处的联系方式。
也可通过 http://support.microchip.com 获得网上技术支持。
DS51284E_CN 第 6 页 2006 Microchip Technology Inc.
1.1 简介
1.2 主要内容
MPLAB® C30
用户指南
第 1 章 编译器概述
dsPIC®数字信号控制器 (DSC)系列将 DSP 应用所需的高性能和嵌入式应用所需的
标准单片机功能融合在一起。也可以将不带 DSP 功能的其他高性能单片机 (MCU )
用于其他应用。
所有这些器件得到了一套完整的软件开发工具的充分支持,包括一个优化的 C 编译
器、一个汇编器、一个链接器和一个归档程序 / 库管理器。
本章总体介绍了这些工具以及优化的 C 编译器的功能,包括 C 编译器如何与 MPLAB
ASM30 汇编器和 MPLAB LINK30 链接器配合工作。汇编器和链接器在
ASM30
本章将介绍如下内容:
• MPLAB C30 介绍
• MPLAB C30 及其他开发工具
• MPLAB C30 的功能
、
MPLAB LINK30
和实用程序用户指南》
(DS51317D_CN )中有详细介绍。
《
MPLAB®
1.3 MPLAB C30 介绍
MPLAB C30 是一个遵循 ANSI x3.159-1989 标准的优化 C 编译器,它包括针对 dsPIC
DSC 嵌入式控制应用的语言扩展。这个编译器是基于 Windows
序,它为开发 C 代码提供了一个平台。它是来自 Free Software Foundation 的 GCC
编译器。
1.4 MPLAB C30 及其他开发工具
MPLAB C30 对 C 源文件进行编译,生成汇编语言文件。由编译器生成的文件与其他
目标文件和库文件进行汇编和链接以产生最终的应用程序,应用程序格式为 COFF 或
ELF 文件格式。 COFF 或 ELF 文件可以载入 MPLAB IDE 中进行测试和调试,或使用
转换实用程序将 COFF 或 ELF 文件转换为 Intel
器件编程器。图 1-1 概括了软件开发的数据流图。
®
操作系统的应用程
®
hex 格式,以便载入命令行模拟器或
2006 Microchip Technology Inc. DS51284E_CN 第 7 页
MPLAB® C30 用户指南
图 1-1 : 软件开发工具数据流图
C 源文件
(*.c )
C 编译器
源文件(*.s )
编译器
驱动程序
汇编源文件
(*.s )
归档程序(库管理器)
目标文件库
(*.a )
汇编器
COFF/ELF 目标文件
(*.o )
链接器
可执行文件
(*.exe )
MPLAB IDE
调试工具
命令行
模拟器
DS51284E_CN 第 8 页 2006 Microchip Technology Inc.
1.5 MPLAB C30 的功能
MPLAB C30 C 编译器是一个全功能的优化编译器,可将标准的 ANSI C 程序翻译为
dsPIC DSC 汇编语言源代码。同时它还支持许多命令行选项和语言扩展,可以对
dsPIC DSC 器件的硬件功能进行完全访问,以便更好地控制代码的生成。这一节介绍
了编译器的主要功能。
1.5.1 ANSI C 标准
MPLAB C30 编译器是一个完全经过验证的编译器,符合 ANSI C 标准,该标准由
ANSI 规范定义并在 Kernighan 和 Ritchie 的 C Programming Language (第二版)中
有详细说明。 ANSI 标准包括对原始 C 定义的扩展,这些扩展现在成为 C 语言的标准
功能。这些扩展增强了 C 语言的可移植性,同时增强了功能。
1.5.2 优化
编译器使用一套采用多种先进技术的高级优化,将 C 源代码编译为高效而紧凑的代
码。优化包括适用于所有 C 代码的高级优化,以及利用 dsPIC DSC 架构特征专门针对
dsPIC DSC 器件的优化。
1.5.3 ANSI 标准函数库支持
MPLAB C30 带有一个完整的 ANSI 标准函数库。所有这些库函数都经过验证并遵循
ANSI C 库标准。这个函数库包括字符串处理、动态存储器分配、数据转换、计时和数
学函数 (三角、指数和双曲线函数)。还包括用于文件处理的标准 I/O 函数,支持通
过命令行模拟器对主机文件系统进行完全的访问。同时还提供低级文件 I/O 函数的完
整功能性源代码,这可以作为需要这些功能的应用的一个起点。
编译器概述
1.5.4 灵活的存储器模型
编译器可同时支持大小两种代码和数据模型。小代码模型利用调用和分支指令的更有
效形式,而小数据模型支持使用压缩指令对 SFR 空间的数据进行访问。
编译器支持两种模型来访问常量。“constants in data ”模型使用数据存储器,由运行
时库初始化。“constants in code ”模型使用程序存储器,通过程序空间可视性
(Program Space Visibility , PSV )窗口访问。
1.5.5 编译器驱动程序
MPLAB C30 包括一个强大的命令行驱动程序。通过这个驱动程序,应用程序的编译、
汇编和链接可以一步完成 (参见图 1-1 )。
2006 Microchip Technology Inc. DS51284E_CN 第 9 页
MPLAB® C30 用户指南
注:
DS51284E_CN 第 10 页 2006 Microchip Technology Inc.
第 2 章 MPLAB C30 与 ANSI C 的差别
2.1 简介
2.2 主要内容
2.3 关键字差别
MPLAB® C30
用户指南
本章讨论 MPLAB C30 语法支持的 C 语言和 1989 年标准 ANSI C 之间的差别。
本章包括以下主要内容:
• 关键字差别
• 语句差别
• 表达式差别
本节说明 ANSI C 和 MPLAB C30 所接受 C 在关键字方面的差别。新关键字是基本
GCC 实现的一部分,本节的讨论基于标准的 GCC 文档,选择 GCC MPLAB C30 部分
的特定语法和语义来讲述。
• 指定变量的属性
• 指定函数的属性
• 内联函数
• 指定寄存器中的变量
• 复数
• 双字整型
• 用 typeof 引用类型
2006 Microchip Technology Inc. DS51284E_CN 第 11 页
MPLAB® C30 用户指南
2.3.1 指定变量的属性
MPLAB C30 的关键字 _ _attribute__ 用来指定变量或结构位域的特殊属性。关键
字后的双括弧中的内容是属性说明。下面是目前支持的变量属性:
• address (addr)
• aligned (alignment)
• deprecated
• far
• mode (mode)
• near
• noload
• packed
• persistent
• reverse (alignment)
• section ("section-name")
• sfr (address)
• space (space)
• transparent_union
• unordered
• unused
• weak
也可以通过在关键字前后使用 __ (双下划线)来指定属性 (例如,用
__aligned__ 代替 aligned)。这样将使你在头文件中使用它们时不必考虑会出现与
宏同名的情况。
要指定多个属性,可在双括弧内用逗号将属性分隔开,例如:
__attribute__ ((aligned (16), packed))。
注: 一个项目中对变量属性的使用要一致,这很重要。例如,如果在文件 A 中
用 far 属性定义了一个变量,在文件 B 中将其声明为 extern 而不带
far ,就可能导致链接错误。
address (addr )
address 属性为变量指定绝对地址。这个属性不能与 section 属性同时使用;
address 属性优先。带 address 属性的变量不能存放到 auto_psv 空间 (参见
space() 属性或 -mconst-in-code 选项);这样做会产生警告,且编译器将此变量
存放到 PSV 空间。
如果要将变量存放到 PSV 段,地址应为程序存储器地址。
int var __attribute__ ((address(0x800)));
DS51284E_CN 第 12 页 2006 Microchip Technology Inc.
MPLAB C30 与 ANSI C 的差别
aligned (alignment )
该属性为变量指定最小的对齐方式,用字节表示。对齐方式必须是 2 的次幂。例如,
下面的声明:
int x __attribute__ ((aligned (16))) = 0;
使编译器按照 16 字节分配全局变量 x 。对于 dsPIC DSC 器件,这可以与访问需要对
齐的 操作数的 DSP 指令和寻址模式的 asm 语句配合使用。
在前面的例子中,我们可以显式地指定我们希望编译器对给定变量使用的对齐方式
(用字节表示)。或者,我们可以省略对齐方式,而要求编译器为变量使用 dsPIC DSC
器件的最大有用对齐。例如,我们可以这样写:
short array[3] __attribute__ ((aligned));
当省略了对齐属性说明中的对齐方式时,编译器会自动将已声明变量的对齐方式设置
为目标单片机任何数据类型所使用的最大对齐方式。在 dsPIC DSC 器件中,为双字节
(1 个字)。
aligned 属性只能增大对齐;但可以通过指定 packed 属性来减小对齐 (见下文)。
aligned 属性与 reverse 属性冲突,同时指定两者会产生错误。
deprecated
deprecated 属性使得包含这一属性的声明能被编译器特别识别到。当使用
deprecated 函数或变量时,编译器会发出警告。
deprecated 定义仍将被编译器执行,并被反映到目标文件中。例如,编译以下程序:
int __ attribute__(( __deprecated__)) i;
int main() {
return i;
}
将产生警告:
deprecated.c:4: warning: `i' is deprecated (declared
at deprecated.c:1)
在生成的目标文件中,仍以通常的方式定义了 i。
far
far 属性告知编译器不必将变量分配到 near (前 8 KB )数据空间中(即变量可以分配
到数据存储器中的任何地址)。
2006 Microchip Technology Inc. DS51284E_CN 第 13 页
MPLAB® C30 用户指南
mode (mode )
在变量声明中使用该属性来指定与模式 mode 对应的数据类型。实际上就是允许根据
变量的宽度指定整数或浮点数类型。 mode 的有效值见下表:
模式 宽度 MPLAB
QI 8 位 char
HI 16 位 int
SI 32 位 long
DI 64 位 long long
SF 32 位 float
DF 64 位 long double
这一属性对于编写可在所有 MPLAB C30 支持的目标单片机之间移植的代码很有用。
例如,如下函数将两个 32 位有符号整数相加,并返回一个 32 位有符号整数结果:
typedef int __attribute__((__ mode__(SI))) int32;
int32
add32(int32 a, int32 b)
{
return(a+b);
}
可以指定 byte 或 _ _byte_ _ 模式指明模式对应于单字节整数, word 或 __word__
模式对应于单字整数, pointer 或 __pointer__ 模式用于表示指针。
®
C30 类型
near
near 属性告知编译器变量将变量分配到 near 数据空间(数据存储器的前 8 KB )。对这
种变量的访问有时比访问未分配 (或不知已分配)到 near 数据空间的变量效率高。
int num __attribute__ ((near));
noload
noload 属性指明应该为变量分配空间,但不应为变量装入初值。这一属性对于设计在
运行时将变量装入存储器 (如从串行 EEPROM )的应用程序可能有用。
int table1[50] __ attribute__ ((noload)) = { 0 };
DS51284E_CN 第 14 页 2006 Microchip Technology Inc.
MPLAB C30 与 ANSI C 的差别
packed
packed 属性指定变量或结构位域采用最小的可能对齐方式 —— 变量占一个字节,位
域占一位,除非用 aligned 属性指定了一个更大的值。
下面的结构中位域 x 被压缩,所以它紧接在 a 之后:
struct foo
{
char a;
int x[2]
};
注: dsPIC 器件要求字按偶数字节对齐,因此在使用 packed 属性时要特别
persistent
persistent 属性指定在启动时变量不应被初始化或清零。具有 persistent 属性的
变量可用于存储器件复位后仍保持有效的状态信息。
int last_mode __attribute__ ((persistent));
reverse (alignment )
reverse 属性为变量的结束地址加 1 指定最小对齐。对齐以字节指定,必须是 2 的次
幂。反向对齐的变量可用于递减 dsPIC DSC 汇编语言中的模缓冲区。如果应用程序需
要在 C 中定义的变量可从汇编语言访问,这一属性可能有用。
int buf1[128] __attribute__ ((reverse(256)));
reverse属性与 aligned和 section属性冲突。试图为反向对齐的变量指定一个段将
被忽略,并发出警告。为同一个变量同时指定 reverse 和 aligned 会产生错误。带
有 reverse 属性的变量不能存放到 auto_psv 空间 (参见 space 属性或
-mconst-in-code 选项);试图这样做将导致警告,且编译器会将变量存放到 PSV
空间。
__ attribute__ ((packed));
小心,避免运行时寻址错误。
section ("section-name" )
默认情况下,编译器将其生成的目标代码存放在 .data 和 .bss 段中。 section 属
性允许指定变量 (或函数)存放到特定的段中。
struct array {int i[32];}
struct array buf
section 属性与 address 和 reverse 属性冲突。在这两种冲突情形下,段名将被忽
略,并发出警告。这一属性还可能与 space 属性冲突。更多信息,参见关于 space
属性的说明。
__attribute__ ((section("userdata"))) = {0};
2006 Microchip Technology Inc. DS51284E_CN 第 15 页
MPLAB® C30 用户指南
sfr (address )
sfr 属性告知编译器变量是一个特殊功能寄存器 (SFR ),同时使用 address 参数指
定变量的运行时地址。
extern volatile int __attribute__ ((sfr(0x200)))u1mod;
为避免产生错误,需要使用 extern 说明符。
注: 按照约定,仅在处理器头文件中使用 sfr 属性。为将一个普通变量定义到
指定的地址,要使用 address 属性,且用 near 或 far 来指定正确的寻
址模式。
space (space )
一般来说,编译器在一般数据空间内分配变量。可使用 space 属性来指示编译器将变
量分配到特定存储空间。关于存储空间的更多论述参见第 4.6 节 “存储空间”。
space 属性接受如下参数:
data
将变量分配到一般数据空间。可使用一般的 C 语句访问一般数据空间中的变量。
这是默认的分配。
xmemory ——仅适用于 dsPIC30F/33F DSC
将变量分配到 X 数据空间。 可使用一般的 C 语句访问 X 数据空间中的变量。
xmemory 空间分配举例如下:
int x[32] __attribute__ ((space(xmemory)));
ymemory ——仅适用于 dsPIC30F/33F DSC
将变量分配到 Y 数据空间。 可使用一般的 C 语句访问 Y 数据空间中的变量。
ymemory 空间分配举例如下:
int y[32] __attribute__ ((space(ymemory)));
prog
将变量分配到程序空间中为可执行代码指定的段。程序空间中的变量不能使用一
般的 C 语句访问,这些变量必须由编程人员显式访问,通常通过表访问行内汇
编指令,或使用程序空间可视性窗口访问。
auto_psv
将变量分配到程序空间中为自动程序空间可视性窗口访问指定的编译器管理段。
auto_psv 空间中的变量可使用一般的 C 语句来读 (但不能写),且变量的分配
空间最大为 32K 。当指定 space(auto_psv) 时,不能使用 section 属性指
定段名;任何段名将被忽略并产生警告。 auto_psv 空间中的变量不能存放到
特定地址或反对齐。
注: 在启动时分配到 auto_psv 段中的变量不装入数据存储器。这一属性
对于减少 RAM 使用可能有用。
DS51284E_CN 第 16 页 2006 Microchip Technology Inc.
MPLAB C30 与 ANSI C 的差别
dma ——仅适用于 PIC24H MCU 和 dsPIC33F DSC
将变量分配到 DMA 存储区。可以通过一般的 C 语句和 DMA 外设访问 DMA 存
储区中的变量。可使用 __
库》
(DS51456B_CN ))来得到用于配置 DMA 外设的正确偏移量。
psv
将变量分配到程序空间中为程序空间可视性窗口访问指定的段。链接器将定位
段,因此可以通过 PSVPAG 寄存器的设置来访问整个变量。 PSV 空间中的变量
不是由编译器管理的,不能使用一般的 C 语句访问。这些变量必须由编程人员
显式访问,通常使用表访问行内汇编指令,或使用程序空间可视性窗口访问。
eedata ——仅适用于 dsPIC30F DSC
将变量分配到 EEData 空间。 EEData 空间中的变量不能使用一般的 C 语句访
问。这些变量必须由编程人员显式访问,通常使用表访问行内汇编指令,或使用
程序空间可视性窗口访问。
transparent_union
这是属于 union 型函数参数的属性,即相应的参数可以是任何联合成员的类型,但以
第一个联合成员的类型传递参数。使用 transparent 联合的第一个成员的调用约定将参
数传递给函数,而不是使用联合本身的调用约定。联合的所有成员必须具有相同的机
器码表示,这对于保证参数传递正常进行是必需的。
builtin_dmaoffset() (参见
《
dsPIC
®
语言工具
unordered
unordered 属性表明变量存放的地址可以相对于所在 C 源文件中其他变量的位置而改
变。
const int __attribute__ ((unordered)) i;
unused
这一变量属性表明变量可能不被使用。 MPLAB C30 不会为这种变量产生未使用变量
警告。
weak
weak 属性声明 weak 符号。weak 符号可能被全局定义取代。当对外部符号的引用使用
weak 时,则链接时不需要该符号。例如:
extern int __attribute__((__ weak__)) s;
int foo() {
if (&s) return s;
return 0; /* possibly some other value */
}
在上面的程序中,如果 s 没有被其他模块定义,程序仍会链接,但不会给 s 分配地
址。若条件验证 s 已被定义,就返回它的值 (如果它有值的话)。否则将返回 “0 ”
值。这个特征很有用,主要用于提供与任意库链接的通用代码。
2006 Microchip Technology Inc. DS51284E_CN 第 17 页
MPLAB® C30 用户指南
weak 属性可以应用于函数和变量:
extern int __attribute__((__ weak__)) compress_data(void *buf);
int process(void *buf) {
if (compress_data) {
if (compress_data(buf) == -1) /* error */
}
/* process buf */
}
在上述代码中,函数 compress_data 只有在与其他模块链接时才使用。是否使用该
特性是由链接时决定的,而不是由编译时决定的。
weak 属性对定义的影响更为复杂,需要多个文件加以说明:
/* weak1.c */
int
void foo() {
i = 1;
}
/* weak2.c */
int i;
extern void foo(void);
void bar() {
i = 2;
}
__attribute__((__weak__)) i;
main() {
foo();
bar();
}
在 weak2.c 中对 i 的定义使符号成为强定义。链接时不会出现错误,两个 i 指向同
一个存储位置。为 weak1.c 中的 i 分配存储空间,但这个空间不可访问。
不能保证两个程序里的 i 具有相同的类型,如果将 weak2.c 中的 i 改为 float 型,
仍然允许链接,但是函数 foo 的操作将无法预料。 foo 将向 32 位浮点值的最低有效
部分写入一个值。相反,在 weak1.c 中把 i 的 weak 定义改为 float 型,将导致灾
难性结果。这样会把一个 32 位的浮点值写到 16 位的整型地址中,覆盖掉紧接 i 之后
存储的任何变量。
在只存在 weak 定义的情况下,链接器才选择为第一个这种定义分配存储空间。其他
定义是不可访问的。
无论符号属于什么类型,操作是相同的;函数和变量具有相同的操作。
DS51284E_CN 第 18 页 2006 Microchip Technology Inc.
MPLAB C30 与 ANSI C 的差别
2.3.2 指定函数的属性
在 MPLAB C30 中,可以对程序中调用的函数进行某些声明,帮助编译器优化函数调
用,且更准确地检查代码。
关键字 _attribute_ 允许在声明时指定特殊的属性。关键字后面紧跟双括弧中的属
性说明。目前支持函数的下列属性:
• address (addr)
• alias ("target")
• const
• deprecated
• far
• format (archetype, string-index, first-to-check)
• format_arg (string-index)
• interrupt [ ( [ save(list) ] [, irq(irqid) ] [, altirq(altirqid)] [, preprologue(asm) ] ) ]
• near
• no_instrument_function
• noload
• noreturn
• section ("section-name")
• shadow
• unused
• weak
我们也可以通过在关键字前后使用 __ (双下划线)来指定属性 (例如,用
__shadow __ 代替 shadow)。这样使得在头文件中使用它们时不必考虑会出现与宏
同名的情况。
我们要想在声明中指定多个属性,可以在双括弧内使用逗号将属性分隔开,或者在一
个属性声明后紧跟另一个属性声明。
address (addr )
address 属性为函数指定绝对地址。这个属性不能与 section 属性同时使用;
address 属性优先。
void foo() __attribute__ ((address(0x100))) {
...
}
alias ("target" )
alias 属性为另一个符号声明一个别名,必须指定这个符号。
使用这一属性会产生对对象的外部引用,必须在链接时解析该引用。
2006 Microchip Technology Inc. DS51284E_CN 第 19 页
MPLAB® C30 用户指南
const
许多函数除了检查自身的参数外不会检查任何其他值,只会影响其返回值。可像算术
运算符一样,对这种函数进行公共子表达式删除和循环优化。这些函数应该用属性
const 来声明。例如:
int square (int) __attribute__ ((const int));
也就是说,上述假设的 square 函数的实际被调用次数即使比程序指定的次数少一些
也是安全的。
应该注意,如果函数有指针参数,且检查指针指向的数据,那么这种函数一定不能用
const 声明。同样,调用非 const 函数的函数通常也不能声明为 const 。具 有 void 返
回值类型的 const 函数没有什么意义。
deprecated
关于 deprecated 属性的信息,请参阅第 2.3.1 节 “指定变量的属性” 。
far
far 属性告知编译器不应该用更有效的调用指令形式来调用该函数。
format (archetype , string-index , first-to-check )
format 属性指定一个函数具有 printf 、scanf 或 strftime 类型参数,要割据格式
字符串检查这些参数的类型。例如,考虑以下声明:
extern int
my_printf (void *my_object, const char *my_format, ...)
__attribute__ ((format (printf, 2, 3)));
以上语句使编译器检查对 my_printf 调用中的参数,确定是否与 printf 类型的格
式字符串参数 my_format 一致。
参数 archetype 确定如何解释格式字符串,应该为 printf 、 scanf 或 strftime
之一。参数 string-index 指定哪个参数是格式字符串参数 (参数从左至右编号,
从 1 开始), first-to-check 指定根据格式字符串检查的第一个参数的编号。对于
不能检查参数的函数 (如 vprintf ),指定第三个参数为 0 。这种情况下,编译器仅
检查格式字符串的一致性。
在上面的例子中,格式字符串 (my_format )是函数 my_print 的第二个参数,从
第三个参数开始检查,所以 format 属性的正确参数是 2 和 3 。
format 属性允许识别以格式字符串作为参数的用户自定义函数,所以 MPLAB C30 可
以检查对这些函数的调用有无错误。每当要求这种警告 (使用 -Wformat )时,编译
器总会检查 ANSI 库函数 printf 、 fprintf 、 sprintf 、 scanf 、 fscanf 、
sscanf 、 strftime 、 vprintf 、 vfprintf 和 vsprintf 的格式,所以不必修改
头文件 stdio.h 。
DS51284E_CN 第 20 页 2006 Microchip Technology Inc.
MPLAB C30 与 ANSI C 的差别
format_arg (string-index )
format_arg 属性指定一个函数具有 printf 或者 scanf 类型的参数,修改这个函
数 (如将它翻译为另外一种语言),并把函数的结果传递给 printf 或 scanf 类型的
函数。例如,考虑以下声明:
extern char *
my_dgettext (char *my_domain, const char *my_format)
上述语句使编译器检查对函数 my_dgettext 的调用中的参数,该函数的结果传递给
printf、 scanf 或 strftime 类型函数,确定是否与 printf 类型的格式字符串参
数 my_format 一致。
参数 string-index 指定哪个参数是格式字符串参数 (从 1 开始)。
format-arg 属性允许识别修改格式字符串的用户定义函数,所以 MPLAB C30 可以
检查对 printf 、 scanf 或 strftime 函数的调用,这些函数的操作数是对用户定义
函数的调用。
interrupt [ ( [ save(list ) ] [, irq(irqid ) ]
[, altirq(altirqid )] [, preprologue(asm ) ] ) ]
使用这个选项来指明指定的函数是中断服务程序。当指定这个属性时,编译器将生成适
用于中断服务程序的函数 prologue 和 epilogue 序列。可选的参数 save 指定函数
prologue 和epilogue 中分别保存和恢复的变量列表。可选参数 irq和altirq 指定要使用
的中断向量表 ID 。可选参数 preprologue 指定要在编译器生成的 prologue 代码前生
成的汇编代码。完整的说明和示例,请参阅第 7 章“中断”。
__attribute__ ((format_arg (2)));
near
near 属性告知编译器可以使用 call 指令的更有效形式调用函数。
no_instrument_function
如果指定命令行选项 -finstrument-functions ,那么几乎所有用户函数的入口和
出口处在编译时都会被插入 profiling 函数。而函数被指定此选项时将不执行上述操作。
noload
noload 属性指明应该为函数分配空间,但不应把实际代码装入存储器。如果应用程序
设计为在运行时将函数装入存储器 (如从 EEPROM ),这一属性很有用。
void bar() __attribute__ ((noload)) {
...
}
2006 Microchip Technology Inc. DS51284E_CN 第 21 页
MPLAB® C30 用户指南
noreturn
一些标准库函数是不能返回的,例如 abort 和 exit 。 MPLAB C30 自动清楚这种情
况。有些程序自定义了不会返回的函数,我们可以将这些函数声明为 noreturn 来告
知编译器这种情况。
void fatal (int i) __attribute__ ((noreturn));
void
fatal (int i)
{
/* Print error message. */
exit (1);
}
noreturn 关键字告知编译器 fatal 不会返回。这可以优化代码,而不必考虑如果
fatal 返回会怎样。这可以在某种程度上优化代码。而且这样有助于避免未初始化变
量的假警告。
对于 noreturn 函数,非 void 的返回值类型并没有什么意义。
section ("section-name" )
通常,编译器将生成的代码存放在 .text 段中。但有时可能需要其他的段,或者需要
将某些函数存放在特殊的段中。 Section 属性指定将一个函数存放在特定的段中。例
如下面的声明:
extern void foobar (void) __attribute__ ((section (".libtext")));
上述语句将函数 foobar 存放在 .libtext 段中。
section 属性与 address 属性有冲突。忽略段名会导致警告。
shadow
shadow 属性使编译器使用影子寄存器而不是软件堆栈来保存寄存器。该属性通常与
interrupt 属性同时使用。
void __attribute__ ((interrupt, shadow)) _T1Interrupt (void)
unused
这个函数属性,表明函数可能不会被使用。 MPLAB C30 不会为这种函数发出未使用函
数的警告。
weak
关于 weak 属性,参见第 2.3.1 节 “指定变量的属性”。
DS51284E_CN 第 22 页 2006 Microchip Technology Inc.
MPLAB C30 与 ANSI C 的差别
2.3.3 内联函数
通过声明一个函数为 inline ,可以指示 MPLAB C30 将这个函数的代码集成到调用函
数的代码中。通常这样可避免函数调用的开销,使代码执行速度更快。另外,若任何
实际的参数值为常数,它们的已知值可允许在编译时进行简化,这样不用包含所有的
内联函数代码。对代码量的影响是不容易预估的。使用内联函数,机器代码量视具体
情况可能更大也有可能更小。
注: 仅当函数定义可见 (不只是有函数原型)时,才能使用函数内联。为将一
个函数内联到多个源文件中,可将函数定义放在每个源文件包含的头文件
中。
为将函数声明为内联,在其声明中使用 inline 关键字,例如:
inline int
inc (int *a)
{
(*a)++;
}
(如果使用 -traditional 选项或 -ansi 选项,用 _inline_ 代替 inline 。)还
可以通过使用命令行选项 -finline-functions 将所有 “足够简单”的函数内联。
编译器可以根据对函数大小的估计,直观地决定哪些函数足够简单,可以这样集成。
注: 仅当使能 -finline 或优化时才识别 inline 关键字。
函数定义中的某些用法可能使函数不适合于内联替代。这些用法包括:varargs 的使
用、 alloca 的使用,长度可变数据的使用,以及相对 goto 和非局部 goto 的使用。
如果使用了命令行选项 -winline ,当标识为 inline 的函数不能被替代时,会发出
警告,并给出失败原因。
在 MPLAB C30 语法中,关键字 inline 不会影响函数的链接。
当一个函数同时为 inline 和 static 时,如果对该函数的所有调用都集成到调用函
数中,且从不使用该函数的地址,那么该函数自身的汇编程序代码从不会被引用。在
这种情况下, MPLAB C30 实际上并不输出该函数的汇编代码,除非指定命令行选项
-fkeep-inline-functions 。有些调用由于各种原因不能被集成 (特别是在函数
定义之前的调用不能被集成,定义内的递归调用也不能被集成)。如果存在非集成的调
用,那么会以通常方式将函数编译成汇编代码。如果程序引用函数的地址,也必须以
通常的方式编译函数,因为它不能被内联。仅在内联函数被声明为 static ,且函数
定义在函数使用之前的情况下,编译器才会删除内联函数。
当 inline 函数不是 static 时,编译器必须假定其他源文件可能调用这个函数。因
为全局符号只能在所有程序中定义一次,不能在其他源文件中定义该函数,所以其他
源文件中的调用不能被集成。因此,非 static 的内联函数总是以通常的方式编译。
2006 Microchip Technology Inc. DS51284E_CN 第 23 页
MPLAB® C30 用户指南
如果我们在函数定义中同时指定 inline 和 extern ,这样定义的函数就只能用来内
联。不能以通常的方式编译函数,即使显式地引用其地址。这种地址变成了一个外部
引用,如同我们只是声明了函数却没有定义它。
同时使用 inline 和 extern 对于宏有类似的影响。使用这些关键字将一个函数的定
义放在头文件中,并且将定义的另外一份拷贝 (不带 inline 和 extern )放在库文
件中。头文件中的定义使得对于该函数的大多数调用被内联。如果还有任何使用该函
数的地方,将引用库文件中的拷贝。
2.3.4 指定寄存器中的变量
MPLAB C30 允许把几个全局变量存放到指定的硬件寄存器中。
注: 使用太多的寄存器,尤其是寄存器 W0 ,可能影响 MPLAB C30 的编译能
力。
我们也可以指定在其中存放普通寄存器变量的寄存器。
• 全局寄存器变量在整个程序执行过程中保留寄存器的值。这在程序中可能很有用,
如编程语言解释程序,带有几个经常被访问的全局变量。
• 特定寄存器中的局部寄存器变量并不保留寄存器的值。编译器的数据流分析可以确
定何时指定寄存器包含有效的值,何时可将指定寄存器用于其他用途。局部寄存器
变量不使用时其中存储的值可被删除。对局部寄存器变量的引用可以被删除、移动
或简化。
如果要将汇编指令的一个输出直接写到某个特定的寄存器,这些局部变量有时便于扩
展行内汇编使用 (参见第 8 章 “汇编语言和 C 模块混合编程”)。(只要指定的寄存
器符合为行内汇编语句中的操作数指定的约束就可以。)
2.3.4.1 定义全局寄存器变量
在 MPLAB C30 中,可通过以下语句来定义一个全局寄存器变量:
register int *foo asm ("w8");
其中, w8 是要使用的寄存器名。选择一个可被函数调用正常保存和恢复的寄存器
(W8-W13 ),这样库函数就不会破坏它的值。
将一个全局寄存器变量定义到某个寄存器中,可完全保留该寄存器的值,至少在当前
的编译中。在当前的编译中,寄存器不会被分配给函数中的任何其他用途。寄存器不
会被这些函数保存和恢复。即使该寄存器的内容不被使用,也不会被删除,但是对该
寄存器的引用可被删除、移动或简化。
从信号处理程序或者从多个控制线程访问全局寄存器变量是不安全的,因为系统库函
数可能临时使用寄存器做别的工作 (除非你特别为待处理任务重新编译它们)。
同样不安全的是,使用一个全局寄存器变量的函数,通过函数 lose 来调用另外一个
这样的函数 foo ,而编译函数 lose 时未知该全局变量 (即在未声明该变量的源文件
中)。这是因为 lose 可能会将其他某个值保存到该寄存器中。例如,不能在比较函数
中使用传递给 qsort 的全局寄存器变量,因为 qsort 可能已经把其他值存放到该寄
存器中了。用相同的全局寄存器变量定义来重新编译 qsort ,可以避免此问题。
DS51284E_CN 第 24 页 2006 Microchip Technology Inc.
MPLAB C30 与 ANSI C 的差别
如果想重新编译实际上没有使用该全局寄存器变量的 qsort 或其他源文件,因此这些
源文件不会将该寄存器用于其他用途,那么指定编译器命令行选项 -ffixed-reg 就
足够了。这种情况下实际上不需要在其源代码中加一个全局寄存器声明。
一个函数若可能改变一个全局寄存器变量的值,它就不能安全地被不保存和恢复该变
量编译的函数调用,因为这可能破坏调用函数返回时期望找到的值。因此,若一个程
序片段使用了全局寄存器变量,作为该程序片段入口的函数必须显式地保存和恢复属
于其调用函数的值。
库函数 longjmp 将恢复每个全局寄存器变量在 setjmp 时的值。
所有全局寄存器变量的声明必须在所有函数定义之前。如果这种声明在函数定义之后,
寄存器可能被声明之前的函数用于其他用途。
全局寄存器变量不能有初值,因为可执行文件不能为一个寄存器提供初值。
2.3.4.2 为局部变量指定寄存器
可以通过以下语句用一个指定的寄存器定义局部寄存器变量:
register int *foo asm ("w8");
其中, w8 是使用的寄存器名。应该注意这与定义全局寄存器变量的语法相同,但是对
于局部变量,这种定义应该出现在一个函数中。
定义这种寄存器不保留寄存器的值,流控制确定变量的值无效时,其他用途仍可使用
这种寄存器。使用这一功能,可能使编译某些函数时可用寄存器太少。
该选项并不能保证 MPLAB C30 生成的代码始终将这一变量存放在指定的寄存器中。
不可以在 asm 语句中,编写对该寄存器的显式引用,并假定它总是引用这个变量。
局部寄存器变量不使用时其分配可被删除。对局部寄存器变量的引用可以被删除、移
动或简化。
2.3.5 复数
MPLAB C30 支持复数数据类型。我们可以用关键字 __complex__ 来声明整型复数
和浮点型复数。
例如, __complex__ float x; 定义 x 为实部和虚部都是浮点型的变量。
__complex__ short int y; 定义 y 的实部和虚部都是 short int 型的。
要写一个复数数据类型的常量,使用后缀 “i ”或 “j ”(两者之一,两者是等同
的)。例如, 2.5fi 是 _ _complex_ _ float 型的, 3i 是 _ _complex_ _ int 型
的。这种常量只有虚部值,但是我们可以通过将其与实常数相加来形成任何复数值。
2006 Microchip Technology Inc. DS51284E_CN 第 25 页
MPLAB® C30 用户指南
要提取复数值符号 exp 的实部,写 __real__ exp 。类似地,用 _ _imag_ _ 来提取
虚部。例如:
__complex__ float z;
float r;
float i;
r =
i =
当对复数型值使用算子 “ ~”时,执行复数的共扼。
MPLAB C30 可以采用非邻近的方式分配复数自动变量,甚至可以将实部分配到寄存器
中,而将虚部分配到堆栈中,反之亦然。调试信息格式无法表示这种非邻近的分配,
所以 MPLAB C30 把非邻近的复数变量描述为两个独立的非复数类型变量。如果实际
变量名是 foo ,那么两个假设变量命名为 foo$real 和 foo$imag 。
__real__ z;
__imag__ z;
2.3.6 双字整型
MPLAB C30 支持长度为 long int 两倍的整型数据类型。对于有符号整型,写 long
long int,而对于无符号整型,使用 unsigned long long int。可以通过在整型
上添加后缀 LL 得到 long long int 类型的整型常量,在整数上添加后缀 ULL 得到
unsigned long long int 类型的整型常量。
可以在算术运算中像使用其他整型一样使用这些类型。这些数据类型的加、减和位逻
辑布尔运算是开放源代码的,但是,这些数据类型的除法与移位不是开放源代码的。
这些不开放源代码的运算要使用 MPLAB C30 自带的特殊库函数。
2.3.7 用 typeof 引用类型
引用表达式类型的另一种方法是使用 typeof 关键字。使用这个关键字的语法与
sizeof 相似,但是其结构在语义上类似于用 typedef 定义的类型名。
有两种方法写 typeof 的参数:使用表达式或者使用类型。以下为使用表达式的例
子:
typeof (x[0](1))
这里假设 x 是函数数组,描述的类型就是函数值的类型。
以下为使用类型名作为参数的例子:
typeof (int *)
这里,描述的类型是指向 int 的指针。
如果写一个包含在 ANSI C 程序中时必须有效的头文件,要使用 __typeof__ ,而不
要使用 typeof 。
DS51284E_CN 第 26 页 2006 Microchip Technology Inc.
2.4 语句差别
MPLAB C30 与 ANSI C 的差别
typeof 结构可用于可使用 typedef 名的任何地方。例如,可以在声明和强制类型转
换中,或者 sizeof 或 typeof 的内部使用它。
• 用 x 指向的类型声明 y:
typeof (*x) y;
• 将 y 声明为这种值的数组:
typeof (*x) y[4];
• 将 y 声明为指向字符的指针数组:
typeof (typeof (char *)[4]) y;
它等同于如下的传统 C 声明:
char *y[4];
为了弄清楚 typeof 声明的含义,以及为什么是有用的方法,我们用以下宏改写它:
#define pointer(T) typeof(T *)
#define array(T, N) typeof(T [N])
现在声明可以这样改写:
array (pointer (char), 4) y;
这样, array (pointer (char), 4) 是指向 char 的四个指针的数组类型。
本节讲述普通 ANSI C 与 MPLAB C30 所接受 C 之间的语句差别。语句差别是基本
GCC 实现的一部分,本节讨论的内容基于标准 GCC 文档,选择了 GCC 中 MPLAB
C30 部分的特定语法和语义来讲述。
• 将标号作为值
• 省略操作数的条件表达式
•case范围
2.4.1 将标号作为值
可以用单目运算符 “&& ”获得在当前函数 (或包含函数)中定义的标号的地址。值的
类型为 void * 。这个值为常量,并可在这种类型的常量有效的任何地方使用这个值。
例如:
void *ptr;
...
ptr = &&foo;
为使用这些值,需要能跳转到值。这通过计算 goto 语句 goto *exp; 来实现。例如:
goto *ptr;
可使用 void * 类型的任何表达式。
这些常量的一个用途是用于初始化用作跳转表的静态数组:
static void *array[] = { &&foo, &&bar, &&hack };
然后就可以通过索引来这样选择标号:
goto *array[i];
注: 这并不检查下标是否超出范围 (C 中的数组索引从不这样做)。
2006 Microchip Technology Inc. DS51284E_CN 第 27 页
MPLAB® C30 用户指南
这种标号值数组的用途与 switch 语句很类似。 switch 语句更整齐,比数组更好。
标号值的另外一个用途是在线程代码的解释程序中。解释程序函数中的标号可存储在
线程代码中用于快速调度。
这种机制可能被错误使用,而跳转到其他函数的代码中。编译器不能阻止这种现象的
发生,因此必须小心,确保目标地址对于当前函数有效。
2.4.2 省略操作数的条件表达式
条件表达式的中间操作数可以被省略。如果第一个操作数非零,它的值就是条件表达
式的值。
因此,对于表达式:
x ? : y
如果 x 的值非零,表达式的值就是 x 的值;否则,就是 y 的值。
这个例子完全等价于:
x ? x : y
在这个简单的例子中,省略中间操作数并不是特别有用。当第一个操作数存在或者可
能存在 (如果它是一个宏参数)副作用时,省略中间操作数就变得特别有用。那么重
复中间操作数将产生副作用两次。省略中间操作数使用了已经计算过的值,而不会因
为重新计算而产生不希望的影响。
2.5 表达式差别
“ll ”或 “LL ”表示双字整型的二进制常量。
2.4.3 case 范围
可以如下在单个 case 标号中指定一个连续值的范围:
case low ... high :
这与各个 case 标号的适当数字有相同的作用, 每个数字对应从 low 到 high 中的每
个整数值。
这一功能对于 ASCII 字符码范围特别有用:
case 'A' ... 'Z':
注意:在 ... 两边要写空格,否则它和整数一起使用时可能出现解析错误。例如要这样
写:
case 1 ... 5:
而不要这样写:
case 1...5:
本节讨论普通 ANSI C 和 MPLAB C30 所接受的 C 之间的表达式差别。
2.5.1 二进制常量
前面有 0b 或 0B 的一串二进制数字 (数字 “0 ”后跟字母 “b ”或 “B ”)视为二进
制整型。二进制数字由数字 “0 ”和 “1 ”组成。例如,十进制数字 255 可用二进制表
示为 0b11111111 。
像其他整型常量一样,二进制常量可以以字母 “u ”或 “U ”为后缀来指定为无符号
型。二进制常量也可以以字母 “l ”或 “L ”为后缀,指定为长整型。类似地,后缀
DS51284E_CN 第 28 页 2006 Microchip Technology Inc.
3.1 简介
3.2 主要内容
MPLAB® C30
用户指南
第 3 章 使用 MPLAB C30 C 编译器
本章讨论通过命令行使用 MPLAB ® C30 C 编译器。关于在 MPLAB IDE 中使用
MPLAB C30 的信息,请参阅
本章介绍以下内容:
• 概述
• 文件命名约定
• 选项
• 环境变量
• 预定义常量
• 通过命令行编译单个文件
• 通过命令行编译多个文件
《
dsPIC® DSC
语言工具入门》
(DS70094C_CN )。
3.3 概述
编译驱动程序 (pic30-gcc )对 C 和汇编语言模块及库文件进行编译、汇编和链接。
大多数编译器命令行选项对于 GCC 工具集的所有实现都是通用的。只有少数是专门针
对 MPLAB C30 编译器的。
编译器命令行的基本形式如下:
pic30-gcc [options ] files
注: 命令行选项和文件扩展名要区分大小写。
在第 3.5 节“选项”中对可用的选项进行了描述。
例如,下面的命令行编译、汇编和链接 C 源文件 hello.c ,生成可执行文件
hello.exe。
pic30-gcc -o hello.exe hello.c
2006 Microchip Technology Inc. DS51284E_CN 第 29 页
MPLAB® C30 用户指南
3.4 文件命名约定
编译驱动程序识别如下文件扩展名,文件扩展名要区分大小写。
表 3-1 : 文件名
扩展名 定义
file.c 必须预处理的 C 源文件。
file.h 头文件 (不对其进行编译或链接)。
file.i
file.o
file.p
file.s
file.S
其他 要传递给链接器的文件。
3.5 选项
MPLAB C30 提供了许多控制编译的选项,它们都是区分大小写的。
• 针对 dsPIC DSC 器件的选项
• 控制输出类型的选项
• 控制 C 语言的选项
• 警告与错误控制选项
• 调试选项
• 控制优化的选项
• 控 制预处理器的选项
• 汇编选项
• 链接选项
• 目录搜索选项
• 代码生成约定选项
不应预处理的源文件。
目标文件。
预过程抽象汇编语言文件。
汇编代码。
必须预处理的汇编代码。
DS51284E_CN 第 30 页 2006 Microchip Technology Inc.
使用 MPLAB C30 C 编译器
3.5.1 针对 dsPIC DSC 器件的选项
关于存储模型的更多信息,请参阅第 4.7 节 “存储模型”。
®
表 3-2 :针 对dsPIC
选项 定义
-mconst-in-code 将常量存放在 auto_psv 空间中。编译器将使用 PSV 窗口访问这些变
量。(这是默认设置。)
-mconst-in-data 将常量存放到数据存储空间中。
-merrata=
id[,id] *
-mlarge-code
-mlarge-data
-mcpu=
<it>target
(1)
-mpa
此选项使能特定的勘误变通解决方案 (errata workaround), 由 id 标
识。 id 的有效值时常改变,对于某个特定的器件可能不需要。 list
的 id 将列出目前支持的勘误表标识符以及对勘误表的简单描述。 all
的 id 将使能所有目前支持的勘误变通解决方案。
使用大代码模型编译。对于被调用函数是局部函数还是全局函数不做假
设。
选择这个选项时,大于 32k 的单个函数是不支持的,这样的函数可能导
致汇编时错误,因为函数内部的所有分支都是短跳转形式 .
使用大代码模型编译。不假定静态变量和外部变量的位置。
此选项选择具体的目标器件 (且如果要进行这一处理的话,将目标器件
选择信息传递给汇编器和链接器)。这个选项会对某些预定义常量的设
置产生影响,更多信息参见第 3.7 节 “预定义常量” 。可在本编译器
发布版本附带的 README.TXT 中找到所接受目标器件的完整列表。
使能过程抽象优化。对嵌套深度没有限制。
DSC 器件的选项
-mpa=n
-mno-pa
注 1: 过程抽象的操作与内联函数相反。这一过程设计为通过翻译单元从多处抽取相同的
(1)
(1)
代码序列,并存放到一个公共代码区。尽管这个选项一般并不会提高所生成代码的
运行时性能,却可以显著减小代码长度。采用 -mpa 编译的程序可能难以调试;在
使用 COFF 目标格式调试时,不推荐使用这个选项。
过程抽象是生成汇编文件后,一个独立的编译阶段。这个阶段不跨翻译单元优化。
当使能过程优化阶段时,行内汇编代码仅限于有效的机器指令。不能使用无效的机
器指令或指令序列,或汇编伪指令 (段伪指令、宏和包含文件等),否则过程抽象
阶段会失败,影响输出文件的生成。
允许过程抽象优化达到 n 级。如果 n 为 0 ,那么禁止优化。如果 n 为
1 ,允许一级抽象;也就是说,源代码中的指令序列可以抽象为子程序。
如果 n 为 2 ,允许二级抽象;也就是说,在一级抽象中包含在子程序中
的指令可以抽象为更深一级的子程序。对于更大的 n 值,继续依此类
推。
实际上是为了将子程序调用嵌套的深度限制为最大值 n 。
不允许过程抽象优化。
(这是默认设置。)
2006 Microchip Technology Inc. DS51284E_CN 第 31 页
MPLAB® C30 用户指南
表 3-2 :针 对dsPIC
选项 定义
-mno-isr-warn 默认情况下,如果在识别到的中断向量名后没有加 __interrupt__,
-momf=omf
-msmall-code
-msmall-data
-msmall-scalar
-mtext=name
-msmart-io
[=0|1|2]
注 1 : 过程抽象的操作与内联函数相反。这一过程设计为通过翻译单元从多处抽取相同的
代码序列,并存放到一个公共代码区。尽管这个选项一般并不会提高所生成代码的
运行时性能,却可以显著减小代码长度。采用 -mpa 编译的程序可能难以调试;在
使用 COFF 目标格式调试时,不推荐使用这个选项。
过程抽象是生成汇编文件后,一个独立的编译阶段。这个阶段不跨翻译单元优化。
当使能过程优化阶段时,行内汇编代码仅限于有效的机器指令。不能使用无效的机
器指令或指令序列,或汇编伪指令 (段伪指令、宏和包含文件等),否则过程抽象
阶段会失败,影响输出文件的生成。
®
DSC 器件的选项 (续)
编译器将产生警告。此选项将禁止这个功能。
选择编译器使用的 OMF (目标模块格式)。 omf 说明符可以为下列之
一:
coff 生成 COFF 目标文件。(这是默认设置。)
elf 生成 ELF 目标文件。
ELF 目标文件使用的调试格式为 DWARF 2.0 。
使用小代码模型编译。假定被调用函数在调用函数的 32K 字内。(这是
默认设置。)
使用小数据模型编译。假定所有静态变量和外部变量位于数据存储空间
的低 8KB 地址。(这是默认设置。)
与 -msmall-data 类似,不同的是仅假定静态标量和外部标量位于数
据存储空间的低 8KB 地址。(这是默认设置。)
指定 -mtext=name 将文本 (程序代码)放入名为 name 的段中,而不
是默认的 .text 段中。等号两边不能有空格。
该选项试图对传递给 printf 和 scanf 函数,以及这两个函数 “f”
和“v”形式的格式字符串进行静态分析。非浮点型参数的使用将转换
成使用仅支持整型的库函数形式。 -msmart-io=0 将禁止这个选项,
而 -msmart-io=2 将使编译器转换带有变量或未知格式参数的函数调
用。默认情况下 -msmart-io=1 ,将仅转换它能验证的立即数值。
DS51284E_CN 第 32 页 2006 Microchip Technology Inc.
3.5.2 控制输出类型的选项
表 3-3 : 输出类型控制选项
选项 定义
-c
-E
-o file
-S
-v
-x
编译或汇编源文件,但不链接。默认的文件扩展名为 .o 。
在预处理过程之后,即正常运行编译器之前停止。默认输出文件为
stdout 。
将输出放在 file 中。
在正常编译之后,即调用汇编器之前停止。默认输出文件扩展名为
.s 。
在编译的每个阶段打印执行的命令。
可用 -x 选项显式地指定输入语言:
-x
language
为后面的输入文件显式地指定语言 (而不是让编译器根据文件名后缀
选择默认的语言)。这个选项适用于其后直到下一个 -x 选项之前的所
有输入文件。 MPLAB C30 支持下面的值:
c c-header cpp-output
assembler assembler-with-cpp
-x none
关闭所有语言指定,随后的文件按其文件名后缀处理。如果已使用另一
个 -x 选项,这是默认但必需的。例如:
pic30-gcc -x assembler foo.asm bar.asm -x none
main.c mabonga.s
使用 MPLAB C30 C 编译器
--help
没有 -x none 时,编译器将假定所有输入文件都为汇编语言。
打印命令行选项的描述。
2006 Microchip Technology Inc. DS51284E_CN 第 33 页
MPLAB® C30 用户指南
3.5.3 控制 C 语言的选项
表 3-4 : C 语言控制选项
选项 定义
-ansi
-aux-info filename
-ffreestanding
-fno-asm
-fno-builtin
-fno-builtin-function
-fsigned-char
-fsigned-bitfields
-funsigned-bitfields
-fno-signed-bitfields
-fno-unsigned-bitfields
-funsigned-char
-fwritable-strings
支持 (且仅支持)所有 ANSI 标准的 C 程序。
对于在翻译单元中声明和 / 或定义的函数,包括头文件中的
函数,输出到给定文件名的原型声明中。除了 C ,这个选项
在其他语言中通常被忽略。除了声明以外,文件在注释中指
出了每个声明的来源 (源文件和行),不论声明是隐含的,
原型的,还是非原型的 (在行号和冒号后面的第一个字符
中,I 、N 代表新的,O 代表旧的),也不论它来自声明还是
定义 (在随后的字符中,分别用 C 和 F 代表)。如果是函
数定义,在函数声明之后的注释中,还提供 K&R 型参数列
表,后跟这些参数的声明。
指明编译在独立环境中进行。这意指 -fno-builtin 选
项。独立的环境就是其中可能不存在标准库,程序也不必在
主函数中启动的环境。最显而易见的例子就是 OS 内核。这
与 -fno-hosted 等价。
不识别 asm 、 inline 或 typeof 关键字,因此代码可以
将这些单词用作标识符。可以使用关键字 __asm __、
__ inline__ 和 __ typeof __。-ansi 意指 -fno-asm 。
不识别不以 __builtin_ 作为前缀开始的内建函数。
使 char 型变量为有符号,就像 signed char 。(这是默
认设置。)
如果声明时未使用 signed 或 unsigned ,这些选项用来
控制位域是有符号还是无符号的。默认情况下,这样的位域
都是有符号的,除非使用 -traditional ,它使位域总是
无符号的。
使 char 型变量无符号,就像 usigned char 。
将字符串存储到可写的数据段中,但不要使字符串成为唯一
的。
DS51284E_CN 第 34 页 2006 Microchip Technology Inc.
使用 MPLAB C30 C 编译器
3.5.4 警告与错误控制选项
警告是诊断消息,它报告非本质错误、但有危险的语法结构,或暗示可能存在错误。
可以使用以 -W 开头的选项请求许多特定的警告,例如,使用 -Wimplicit 请求关于
隐式声明的警告。每条这些特定的警告选项也可以用以 -Wno- 开头的相反形式来关闭
警告,如 -Wno-implicit 。本手册只列出了这两种形式中的一种,这两种形式都不
是默认的。
下面的选项控制 MPLAB C30 C 编译器产生的警告的数量和种类。
表 3-5 : -WALL 隐含的警告 / 错误选项
选项 定义
-fsyntax-only
-pedantic
-pedantic-errors
-w
-Wall
-Wchar-subscripts
-Wcomment
-Wcomments
-Wdiv-by-zero
-Werror-implicit-
function-declaration
-Wformat
-Wimplicit
-Wimplicit-function-
declaration
-Wimplicit-int
-Wmain
-Wmissing-braces
检查代码的语法,除此之外不做任何事情。
发出 严格 ANSI C 要求的所有警告;拒绝所有使用禁止扩展
名的程序。
类似于 -pedantic ,只是发出错误而不是警告。
禁止所有警告消息。
使能本表中列出的所有 -W 选项。这将使能关于某些用户认为
有问题的,及容易避免的 (或修改来禁止警告的)语法结构
的所有警告,即使是与宏一起。
如果数组下标具有 char 类型则警告。
当注释开始符号 /* 出现在 /* 注释中,或反斜杠换行出现在
// 注释中发出警告。
编译时发现整数除以 0 则警告。禁止这个消息可使用
-Wno-div-by-zero 。浮点数除以 0 不会警告,因为它可以
是获得无穷大和 NaN 的一种合法方法。(这是默认情况。)
函数在声明前被使用将给出错误。
检查对 printf 和 scanf 等函数的调用,确保所提供参数的
类型与指定的格式字符串相符合。
等价于同时指定 -Wimplicit-int 和
-Wimplicit-function-declaration 。
函数在声明前被使用将给出警告。
如果声明没有指定类型则警告。
如果 main 的类型有问题则警告。 main 应该是一个具有外部
链接的函数,它返回 int ,并带有正确类型的 0 、 2 或 3 个参
数。
如果一个聚集或联合的初始化中括号不全则警告。在下面的
例子中, a 的初始化中括号不全,而对 b 的初始化是正确的。
int a[2][2] = { 0, 1, 2, 3 };
int b[2][2] = { { 0, 1 }, { 2, 3 } };
2006 Microchip Technology Inc. DS51284E_CN 第 35 页
MPLAB® C30 用户指南
表 3-5 : -WALL 隐含的警告 / 错误选项 (续)
选项 定义
-Wmultichar
-Wno-multichar
-Wparentheses
-Wreturn-type
-Wsequence-point
使用多字符的 character 常量时警告。通常出现这样的常量
是由于输入错误。由于这种常量具有实现定义的值,不应将
它们用在可移植代码中。下面举例说明了多字符 character
常量的使用:
char
xx(void)
{
return('xx');
}
在某些上下文中省略圆括号时警告,如在需要真值的上下文
中有一个赋值,或者运算符嵌套的运算优先级容易混淆时。
当函数定义为其返回值类型默认为 int 时发出警告。如果函
数的返回值类型不是 void ,那么不带返回值的任何 return
语句都会导致产生警告。
由于违背 C 标准中的顺序点规则而导致代码中有未定义的语
义时发出警告。
C 标准定义了 C 程序中根据顺序点对表达式求值的顺序,顺
序点代表程序各部分执行的局部顺序:在顺序点之前执行的
部分和顺序点之后执行的部分。这些在一个完整表达式 (不
是一个更大的表达式的一部分)的求值之后,在对第一个运
算符 (&& 、 || 、 ? : 或 , (逗号)运算符)求值之后,在调用
函数前 (但在对其参数和表示被调用函数的表达式求值后),
以及某些其他地方发生。除了顺序点规则指定的顺序外,未
指定表达式的子表达式的求值顺序。所有这些规则仅规定了
局部的顺序,而没有规定全局的顺序,因为,如在一个表达
式中调用了两个函数,而它们之间没有顺序点,就没有指定
函数调用的顺序。但是,标准委员会规定函数调用不能重叠。
没有指定在顺序点之间,对对象的值的修改何时生效。操作
依赖于这一点的程序有不确定的操作; C 标准规定,“在上
一个顺序点和下一个顺序点之间,对象所储存的值最多只能
被表达式求值修改一次。而且,前一个值是只读的以便确定
将被储存的值。”如果程序违反这些规则,任何特定实现的结
果都是完全不可预估的。
具有未定义操作的代码示例有:a = a++; ,
a[n] = b[n++]; 及 a[i++] = i; 。这个选项不能诊断某
些更复杂的情况,并可能给出偶然错误的结果,但通常在检
测程序中的这类问题时,这个选项还是很有效的。
DS51284E_CN 第 36 页 2006 Microchip Technology Inc.
使用 MPLAB C30 C 编译器
表 3-5 : -WALL 隐含的警告 / 错误选项 (续)
选项 定义
-Wswitch
-Wsystem-headers
-Wtrigraphs
-Wuninitialized
-Wunknown-pragmas
-Wunused
-Wunused-function
-Wunused-label
每当 switch 语句中有一个枚举类型的索引,并且这个枚举
的一个或多个指定码缺少 case 时发出警告。(默认标号的存
在禁止这个警告。)当使用这个选项时,枚举范围之外的
case 标号也会引起警告。
打印关于系统头文件中语法结构的警告消息。系统头文件的
警告通常是被禁止的,因为通常认为它们不会有真正的问题,
只会使编译器的输出可读性更差。使用这个命令行选项告知
MPLAB C30 发出关于系统头文件的警告,就像在用户代码中
一样。但是,注意将 -Wall 与该选项一起使用时不会对系统
头文件中的未知 pragma 伪指令发出警告,这时,必须同时使
用 -Wunknown-pragmas 。
遇到三字母组合时发出警告 (假定使能了三字母组合)。
使用自动变量而没有先对其初始化时发出警告。
这些警告只有在允许优化时才出现,因为它们需要只有优化
时才计算的数据流信息。
仅当将变量分配给寄存器时才产生这些警告。因此,对于声
明为 volatile 的变量,或是变量地址被占用,或者大小不
是 1 , 2 , 4 和 8 字节的变量不会产生这些警告。同样对于结
构、联合或数组,即使它们在寄存器中,也不会产生这些警
告。
注意,当一个变量只是用于计算一个值而变量本身不会被使
用时,也不会产生警告,因为在警告被打印前,这样的计算
就会被数据流分析删除。
当遇到一个 MPLAB C30 无法理解的 #pragma 伪指令时发出
警告。如果使用这个选项,甚至对系统头文件中的未知
pragma 伪指令也会发出警告。如果警告只能通过命令行选项
-Wall 来使能,情况就不是这样了。
每当变量除了其声明外未被使用过时,每当函数声明为 static
但从未定义时,每当声明了标号但未使用时,每当一条语句
的计算结果未被显式使用时,发出警告。要获得未使用的函
数参数的警告,必须同时指定 -W 和 -Wunused 。
强制转换表达式类型可以避免禁止对表达式的这种警告。同
样地, unused 属性可以禁止对未使用的变量、参数和标号的
警告。
每当声明了 static 函数但没有定义函数时,或一个非内联
static 函数未使用时,发出警告。
声明了一个标号但未使用时发出警告。要禁止这种警告,可
以使用 unused 属性 (参见第 2.3.1 节 “指定变量的属
性”)。
2006 Microchip Technology Inc. DS51284E_CN 第 37 页
MPLAB® C30 用户指南
表 3-5 : -WALL 隐含的警告 / 错误选项 (续)
选项 定义
-Wunused-parameter
-Wunused-variable
-Wunused-value
下面是不被 -Wall 隐含的 -W 选项。其中有些是关于用户通常认为不会有问题,但有
时会希望检查一下的语法结构的警告。其他是在某些情况下必须或很难避免的语法结
构的警告,没有简单的方法来修改代码以禁止这些警告。
表 3-6 : -WALL 不隐含的警告 / 错误选项
选项 定义
-W
当对函数参数进行了声明但从未使用时,发出警告。要禁止
这种警告,使用 unused 属性 (参见第 2.3.1 节 “指定变量
的属性”)。
当对局部变量或非常量的 static 变量进行了声明但从未使用
时,发出警告。要禁止这种警告,使用 unused 属性 (参见
第 2.3.1 节 “指定变量的属性”)。
语句的计算结果未显式使用时发出警告。要禁止这种警告,
可以将表达式类型转换为 void 。
为以下事件输出额外警告消息:
• 非易变的自动变量可能会被对 longjmp 的调用改变。这些
警告仅在优化编译时才会出现。编译器仅识别对 setjmp 的
调用,而不会知道将在何处调用 longjmp ,信号处理程序
可以在代码中的任何地方调用 longjmp 。因此,即使当实
际没有问题时也可能会产生警告,因为实际上不能在会产生
问题的地方调用 longjmp 。
• 函数可以通过 return value; 和 return; 退出。函数体结
束时不传递任何返回值的语句视为 return; 。
• 表达式语句或者逗号表达式的左侧没有副作用。为了禁止这
种警告,将未使用表达式的类型强制转换为 void 。例如,
表达式 x[i,j] 会产生警告,而表达式 x[(void)i,j] 不
会产生警告。
• 用 < 或 <= 将无符号值与 0 比较。
• 出现了像 x<=y<=z 这样的不等式;这等价于
(x<=y ? 1 : 0) <= z ,这只是普通数学表示的不同解释
罢了。
• 存储类型修饰符如 static 在声明中没有放在最前面,根据
标准,这种用法已经过时了。
• 如果还指定了 -Wall 或 -Wunused ,会出现关于未使用变
量的警告。
• 当将有符号值转换为无符号值时,比较有符号值和无符号值
会产生不正确的结果。(但是如果还指定了
-Wno-sign-compare 的话,就不会产生警告。)
DS51284E_CN 第 38 页 2006 Microchip Technology Inc.
使用 MPLAB C30 C 编译器
表 3-6 : -WALL 不隐含的警告 / 错误选项 (续)
选项 定义
-W
-Waggregate-return
-Wbad-function-cast
-Wcast-align
-Wcast-qual
-Wconversion
-Werror
-Winline
-Wlarger-than-len
-Wlong-long
-Wno-long-long
-Wmissing-declarations
-Wmissing format-attribute
• 聚集的初始化中括号不全。例如,下面的代码由于在初始化
x.h 时漏掉了括号会产生警告 :
struct s { int f, g; };
struct t { struct s h; int i; };
struct t x = { 1, 2, 3 };
• 聚集的初始化中没有初始化所有成员,例如,下面的代码由
于 x.h 会被隐式初始化为零而会产生警告:
struct s { int f, g, h; };
struct s x = { 3, 4 };
定义或调用了返回结构或联合的任何函数时产生警告。
当将函数调用强制转换为不匹配类型时产生警告。例如,如果
int foof() 被强制转换为任何 * 指针类型。
当强制转换指针类型,使目标所需分配的存储空间增加时产生警
告。例如,如果将 char * 强制转换为 int * 会产生警告。
当对指针进行强制类型转换,从目标类型中去掉类型限定符时,
会产生警告。例如,将 const char * 强制转换为普通的
char * 就会产生警告。
如果一个原型导致一个参数的类型转换与没有原型时不同,则发
出警告。这包括定点型转换为浮点型或反之,及改变定点参数符
号或宽度的转换,与默认的提升相同时除外。
当负的整型常量表达式隐式转换为无符号类型时也发出警告。例
如,如果 x 为无符号类型,赋值 x = -1 将产生警告。但是,显
式的强制类型转换,如 (unsigned) -1 ,不会产生警告。
使所有警告变为错误。
一个函数已声明为内联,或指定了 -finline-functions 选
项时,如果函数不能被内联,将产生警告。
当定义了大于 len 字节的对象时产生警告。
使用 long long 类型时发出警告。这是默认设置。为禁止警告
消息,使用 -Wno-long-long 。仅当使用 -pedantic 标志
时,才考虑标志 -Wlong-long 和 -Wno-long-long 。
如果在定义一个全局函数之前没有先对其进行声明将产生警告。
即使定义本身提供了原型,也要在定义全局函数之前先声明它。
如果使能了 -Wformat ,可指定 format 属性的函数也会产生
警告。注意这些函数仅是可指定 format 属性的函数,不是已指
定 format 属性的函数。如果不使能 -Wformat ,这一选项不
起作用。
2006 Microchip Technology Inc. DS51284E_CN 第 39 页
MPLAB® C30 用户指南
表 3-6 : -WALL 不隐含的警告 / 错误选项 (续)
选项 定义
-Wmissing-noreturn
-Wmissing-prototypes
-Wnested-externs
-Wno-deprecated declarations
-Wpadded
-Wpointer-arith
-Wredundant-decls
-Wshadow
-Wsign-compare
-Wno-sign-compare
-Wstrict-prototypes
-Wtraditional
-Wundef
-Wunreachable-code
对可指定 noreturn 属性的函数产生警告。这些函数仅是可指
定这一属性的函数,并不是已指定了这一属性的函数。手工检验
这些函数时要小心。实际上,在添加 noreturn 属性之前也不
要返回;否则可能会引入微小的代码生成错误。
如果全局函数在定义之前没有先声明原型会产生警告。即使定义
本身提供了原型也会发出这个警告。(这个选项可用于检测不在
头文件中声明的全局函数。)
如果在函数内部遇到了 extern 声明,发出警告。
不要对使用通过 deprecated 属性指定为 deprecated 的函数、
变量和类型发出警告。
如果一个结构中包含了填充,不管是为了对齐结构的一个元素,
还是为了对齐整个结构,都发出警告。
对于与函数类型或 void 的长度有关的任何类型发出警告。为方
便用 void * 指针和指向函数的指针计算, MPLAB C30 将这些
类型的长度分配为 1 。
如果在同一个作用域内多次声明了任何符号则发出警告,即使多
个声明都有效且没有改变任何符号。
当一个局部变量屏蔽另一个局部变量时发出警告。
当比较有符号值和无符号值时,将有符号值转换为无符号值,比
较产生不正确结果时发出警告。这个警告也可通过 -W 来使能;
要获得 -W 的其他警告,而不获得这个警告,使用
-W -Wno-sign-compare 。
如果对一个函数的定义或声明没有指定参数类型则发出警告。
(如果函数定义或声明前有指定函数参数类型的声明,则允许旧
式函数定义而不发出警告。)
如果某些语法结构在传统 C 和 ANSI C 中操作不同,产生警告。
• 宏参数出现在宏体中的字符串常量中。在传统 C 中,这些宏
参数将替代参数,但在 ANSI C 中是常量的一部分。
• 在一个块中声明为 external 的函数,在块结束后被使用。
•switch语句有 long 类型的操作数。
• 非静态函数声明后跟一个静态函数声明。某些传统 C 编译器
不接受这种语法结构。
如果在 #if 伪指令中对一个未定义的标识符求值会产生警告。
如果编译器检测到代码将永远不会被执行到则发出警告。即使在
有些情况下,受影响的代码行的一部分能被执行到,这个选项也
可能产生警告,因此在删除明显执行不到的代码时要小心。例
如,函数被内联时,警告可能表明仅在函数的一个内联拷贝中,
该行执行不到。
DS51284E_CN 第 40 页 2006 Microchip Technology Inc.
使用 MPLAB C30 C 编译器
表 3-6 : -WALL 不隐含的警告 / 错误选项 (续)
选项 定义
-Wwrite-strings
3.5.5 调试选项
表 3-7 :调 试 选 项
选项 定义
-g
-Q
-save-temps
字符串常量类型为 const char[length] 时,将一个字符串
常量的地址复制到一个非常量 char * 指针会产生警告。 这些警
告有助于在编译时查找试图写字符串常量的代码,但仅是在声明
和原型中使用 const 时非常小心的前提下。否则,这是不安全
的,这也是 -Wall 为什么不要求这些警告的原因。
产生调试信息。
®
MPLAB
码。调试优化代码的缺点是有时可能产生异常结果:
- 某些声明的变量可能根本不存在;
- 控制流程可能短暂异常转移;
- 某些语句可能由于计算常量结果或已经获得其值而不执行;
- 某些语句可能由于被移出循环在不同的地方执行。
尽管如此,证明还是可以调试优化输出的。这使优化可能有错误
的程序变得合理。
使编译器打印它在编译的每个函数名,并在结束时打印关于每遍
编译的一些统计信息。
不要删除中间文件。将中间文件放在当前目录中,并根据源文件
命名它们。因此,用 “-c -save-temps ”编译 “foo.c ”将生
成下面的文件:
‘foo.i ’ (预处理文件)
‘foo.p ’ (预过程抽象汇编语言文件)
‘foo.s ’ (汇编语言文件)
‘foo.o ’ (目标文件)
C30 支持同时使用 -g 和 -O ,因此可以调试优化的代
2006 Microchip Technology Inc. DS51284E_CN 第 41 页
MPLAB® C30 用户指南
3.5.6 控制优化的选项
表 3-8 : 一般优化选项
选项 定义
-O0
-O
-O1
-O2
-O3
-Os
不要优化 (这是默认设置)。
不指定 -O 选项,编译器的目标是降低编译成本,使调试产生
期望的结果。语句是独立的:如果在语句中插入断点暂停程
序,然后可以给任何一个变量赋一个新的值或将程序计数器更
改到指向函数中的任何其他语句,得到希望从源代码得到的结
果。
编译器仅将声明为 register 的变量分配到寄存器中。
优化。优化编译需要花费更多的时间,且对于较大的函数,需
要占用更多的存储空间。
指定 -O 选项时,编译器试图减小代码尺寸并缩短执行时间。
指定 -O 选项时,编译器开启 -fthread-jumps 和
-fdefer-pop ,并开启 -fomit-frame-pointer 。
®
执行更多优化。 MPLAB
不进行空间和速度的权衡。 -O2 选项使能除循环展开
(-funroll-loops )、函数内联
(-finline-functions )及严格别名优化
(-fstrict-aliasing )之外的所有可选优化。这个选项还
使能强制复制存储器操作数 (-fforce-mem )及帧指针删除
(-fomit-frame-pointer )。与 -O 相比,这个选项增加了
编译时间,但提高了生成代码的性能。
执行最多的优化。 -O3 开启所有 -O2 指定的优化并开启内联函
数选项。
优化代码尺寸。 -Os 使能一般不增加代码尺寸的所有 -O2 优
化。同时执行用于减小代码尺寸的其他优化。
C30 几乎执行所有支持的优化,而
DS51284E_CN 第 42 页 2006 Microchip Technology Inc.
使用 MPLAB C30 C 编译器
下面的选项控制特定的优化。 -O2 选项启用这些优化中除 -funroll-loops 、
-funroll-all-loops 和 -fstrict-aliasing 外的所有优化选项。
在少数情况下,当需要进行 “微调”优化时,可以使用下面的选项。
表 3-9 : 特定的优化选项
选项 定义
-falign-functions
-falign-functions=n
-falign-labels
-falign-labels=n
-falign-loops
-falign-loops=n
-fcaller-saves
-fcse-follow-jumps
-fcse-skip-blocks
-fexpensive optimizations
-ffunction-sections
-fdata-sections
将函数的开头对齐到下一个大于 n 的 2 的次幂,最多跳过 n 字
节。
例如,
-falign-functions=32 将函数对齐到下一个
32 字节边界,但是 -falign-functions=24 仅在可以通过
跳过等于或小于 23 字节能对齐到下一个 32 字节边界的情况
下,才将函数对齐到下一个 32 字节边界。
-fno-align-functions 和 -falign-functions=1 是等
价的,表明函数不会被对齐。
汇编器仅当 n 为 2 的次幂时,才支持这个标志;因此 n 是向上
舍入的。如果不指定 n ,则使用由机器决定的默认设置。
将所有分支的目标地址对齐到 2 的次幂边界,像
-falign-functions 一样,最多跳过 n 字节。这个选项可能
容易使代码速度变慢,因为当以代码的通常流程到达分支的目
标地址时,它必须插入空操作。
如果 -falign-loops 或 -falign-jumps 可用,并且大于
这个值,则使用它们的值。
如果不指定 n ,则使用由机器决定的默认设置,很可能是 1 ,
表明不对齐。
将循环对齐到 2 的次幂边界,像 -falign-functions 一
样,最多跳过 n 字节。希望循环能执行许多次,从而补偿执行
的任何空操作。
如果不指定 n ,则使用由机器决定的默认设置。
通过在函数调用前后发出其他指令来保护和恢复寄存器,使能
将值分配到会被函数调用破坏的寄存器中。仅当这种分配能生
成更好的代码时才进行这种分配。
在公共子表达式消除中,当任何其他路径都不到达跳转的目标
地址时,浏览跳转指令。例如,当 CSE 遇到一条带有 else
子句的 if 语句时,当条件检测为假时, CSE 将跟随跳转。
这与 -fcse-follow-jumps 类似,但使 CSE 跟随根据条件
跳过块的跳转。 当 CSE 遇到一个没有 else 子句的简单 if 语
句时, -fcse-skip-blocks 使 CSE 跟随 if 前后的跳转。
执行许多成本较高的次要优化。
将每个函数或数据项存放到输出文件中其自己的段。函数名或
数据项名决定输出文件中的段名。
仅当使用这些选项有明显的好处时,才使用这些选项。当指定
这些选项时,汇编器和链接器可能生成较大的目标文件和可执
行文件,且速度较慢。
2006 Microchip Technology Inc. DS51284E_CN 第 43 页
MPLAB® C30 用户指南
表 3-9 : 特定的优化选项 (续)
选项 定义
-fgcse
-fgcse-lm
-fgcse-sm
-fmove-all-movables
-fno-defer-pop
-fno-peephole
-fno-peephole2
-foptimize register-move
-fregmove
-freduce-all-givs
-frename-registers
-frerun-cse-after loop
-frerun-loop-opt
-fschedule-insns
-fschedule-insns2
-fstrength-reduce
执行全局公共子表达式消除。这会同时执行全局常量和复制传
播。
使能 -fgcse-lm 时,全局公共子表达式消除将试图移动仅能
被向其中存储破坏的装载。这允许将包含装载 / 存储序列的循
环改变为循环外的装载,以及循环内的复制 / 装载。
当使能 -fgcse-sm 时,将在公共子表达式消除后运行存储移
动。这试图将存储移出循环。当将这个选项与 -fgcse-lm 一
起使用时,包含装载 / 存储序列的循环可改变为循环前的装载
和循环后的存储。
强制将循环内所有不可变的计算移出循环。
每次函数调用时,总是在函数一返回时就弹出函数的参数。编
译器通常允许几个函数调用的参数累积在堆栈中,并将所有参
数一次弹出堆栈。
禁止特定于机器的窥孔 (peephole)优化。窥孔优化发生在
编译过程中的不同点。 -fno-peephole 禁止对机器指令进行
窥孔优化,而 -fno-peephole2 禁止高级窥孔优化。要完全
禁止窥孔优化, 要同时使用这两个选项。
试图重新分配 move 指令中的寄存器编号,并作为其他简单指
令的操作数来增加关联的寄存器数量。
-fregmove 和 -foptimize-register-moves 是相同的优
化。
强制循环中的所有一般归纳变量降低强度。
这些选项可能生成更好或更差的代码;其结果在很大程度上取
决于源代码中循环的结构。
试图通过使用寄存器分配后余下的寄存器来避免经过调度的代
码中的假相关性。这种优化对于有许多寄存器的处理器比较有
用。但它可能使调试无法进行,因为变量将不会存储在固定的
寄存器中。
在执行循环优化后,重新运行公共子表达式消除。
运行循环优化两次。
®
试图对指令重新排序,以消除 dsPIC
(Read-After-Write )停顿 (详情请参阅 《dsPIC30F
考手册
》( DS70046D_CN ))。 一般可提高性能,而不会影
响代码长度。
类似于 -fschedule-insns ,但要求在进行寄存器分配后再
执行一次指令调度。
执行降低循环强度和删除迭代变量优化。
DSC 写 - 后 - 读
系列参
DS51284E_CN 第 44 页 2006 Microchip Technology Inc.
使用 MPLAB C30 C 编译器
表 3-9 : 特定的优化选项 (续)
选项 定义
-fstrict-aliasing
-fthread-jumps
-funroll-loops
-funroll-all-loops
允许编译器采用适用于被编译语言的最严格别名规则。对于
C ,这根据表达式的类型进行优化。尤其是,假定一种类型的
对象不会和另一种类型的对象存放在同一地址,除非类型几乎
相同。例如, unsigned int 可引用 int ,但不能引用
void* 或 double 。字符类型可引用任何其他类型。
特别要注意下面的代码:
union a_union {
int i;
double d;
};
int f() {
union a_union t;
t.d = 3.0;
return t.i;
}
不读最后写入的联合成员,而读其他联合成员 (称为
“type-punning ”)比较常见。即使对于
-fstrict-aliasing ,如果通过联合类型访问存储器,
type-punning 也是允许的。因此上面的代码可得到期望的结
果。但下面的代码可能得不到期望的结果:
int f() {
a_union t;
int* ip;
t.d = 3.0;
ip = &t.i;
return *ip;
}
是一种优化,检测一个转移的目标语句是否包含另一个条件判
断。如果是这样,第一个转移改变为指向第二个转移的目标语
句,或紧随其后的语句,这取决于条件是真还是假。
执行循环展开优化。仅对在编译时或运行时其迭代次数可以确
定的循环进行这种优化。 -funroll-loops 隐含了
-fstrength-reduce 和 -frerun-cse-after-loop 。
执行循环展开优化。对于所有的循环执行这种优化,通常这种
优化会使程序运行较慢。
-funroll-all-loops 隐含了 -fstrength-reduce 和
-frerun-cse-after-loop。
2006 Microchip Technology Inc. DS51284E_CN 第 45 页
MPLAB® C30 用户指南
-fflag 形式的选项指定依赖于机器的标志。大多数标志有正的形式和负的形式;
-ffoo 的负的形式为 -fno-foo。在下表中,仅列出了一种形式 (非默认的形式)。
表 3-10 : 独立于机器的优化选项
选项 定义
-fforce-mem
-finline-functions
-finline-limit=n
-fkeep-inline-functions
-fkeep-static-consts
-fno-function-cse
在对存储器操作数进行算术运算之前,强制将存储器操作
数复制到寄存器中。这样通过使所有存储器引用可能的公
共子表达式,可生成更好的代码。当它们不是公共子表达
式时,指令组合应该删除单独的寄存器装载。 -O2 开启这
个选项。
将所有简单的函数合并到其调用函数中。编译器直观地决
定哪些函数足够简单值得这样合并。如果合并了对某个给
定函数的所有调用,且函数声明为 static ,则通常该函
数本身不作为汇编代码输出。
默认情况下, MPLAB C30 限制可内联的函数的大小。这
个选项允许控制显式声明为 inline 的函数 (即用 inline
关键字标记的函数)的这一限制。 n 是可内联的函数的大
小,以虚拟指令的条数为单位 (参数处理不包括在内)。
n 的默认值为 10000。增加这个值可能导致被内联的代码
更多,并可能增加编译时间和存储器开销。
减小这个值通常使编译更快,更少的代码被内联 (可能程
序执行速度变慢)。这一选项对于使用内联的程序尤其有
用。
注:在这里,虚拟指令代表函数大小的抽象测量。它不代
表汇编指令条数,同样对于不同版本的编译器,它的确切
含义可能会有所不同。
即使合并了对一个给定函数的所有调用,且函数声明为
static ,输出函数的一个独立的运行时可调用形式。这
个选项不影响 extern 内联函数。
当没有开启优化时,发出声明为 static const 的变量,即
使变量没有被引用。
MPLAB C30 默认使能这个选项。如果需要强制编译器检
查是否引用了这个变量,而不管是否开启了优化,使用
-fno-keep-static-consts 选项。
不要将函数的地址存放在寄存器中;使调用 constant 函数
的每条指令显式包含函数的地址。
这个选项导致生成的代码效率不高,但对于某些企图修改
程序的人来说,会对不使用这个选项而生成的优化程序感
到束手无策。
DS51284E_CN 第 46 页 2006 Microchip Technology Inc.
使用 MPLAB C30 C 编译器
表 3-10 : 独立于机器的优化选项 (续)
选项 定义
-fno-inline
-fomit-frame-pointer
-foptimize-sibling-calls
3.5.7 控制预处理器的选项
表 3-11 : 预处理器选项
选项 定义
-Aquestion (answer )
-A -predicate =answer
-A predicate =answer
-C
-dD
-Dmacro
-Dmacro =defn
-dM
-dN
-fno-show-column
-H
不要理会 inline 关键字。这个选项通常用于使编译器不
要展开任何内联函数。 如果不使能优化,不会展开任何内
联函数。
对于不需要帧指针的函数,不要将帧指针存放在寄存器
中。这可以避免指令保护、设置和恢复帧指针;它还使一
个额外的寄存器可用于许多函数。
优化同属和尾递归调用。
断言问题 question 的答案 answer ,以防用预处理条件,如
#if #question (answer ) 来测试问题。 -A- 禁止通常描述目
标机器的标准断言。
例如, main 的函数原型可声明如下:
#if #environ(freestanding)
int main(void);
#else
int main(int argc, char *argv[]);
#endif
-A 命令行选项可用于在两个原型之间进行选择。例如,为选择
二者中的第一个,可使用下面的命令行选项:
-Aenviron(freestanding)
取消带谓词 predicate 和答案 answer 的断言。
进行带谓词 predicate 和答案 nswer 的断言。这个形式比仍
然支持的老形式 -A predicate(answer) 好,因为这个形式
不使用 shell 特殊字符。
告知预处理器不要舍弃注释。与 -E 选项一起使用。
告知预处理器不要按照正确的顺序将宏定义移动到输出中。
将字符串 1 作为宏定义来定义宏 macro 。
将宏 macro 定义为 defn 。在任何 -U 选项之前处理命令行中的
所有 -D 选项。
告知预处理器仅输出实际上处于预处理结尾的一系列宏定义。
与 -E 选项一起使用。
与 -dD 类似,不同之处在于宏参数和内容被忽略。输出中仅包
括 #define name 。
不要在诊断中打印列号。如果诊断被不理解列号的程序 (如
dejagnu )浏览,这可能是必要的。
打印使用的每个头文件的名字以及其他正常活动。
2006 Microchip Technology Inc. DS51284E_CN 第 47 页
MPLAB® C30 用户指南
表 3-11 : 预处理器选项 (续)
选项 定义
-I-
-Idir
-idirafter dir
-imacros file
-include file
-iprefix prefix
-isystem dir
-iwithprefix dir
-iwithprefixbefore
dir
仅对于 #include "file " ,才搜索在 -I- 选项之前 -I 选项
指定的任何目录;对于 #include <file > ,则不搜索这些目
录。
如果在 -I- 之后用 -I 选项指定了另外的目录,则对于所有
#include 伪指令,都搜索这些目录。(一般情况下以这种方式
使用所有 -I 目录。)
另外, -I- 选项禁止将当前目录 (即当前输入文件所在的目
录) 作为 #include "file " 的第一个搜索目录。无法覆盖
-I- 的这个作用。通过 -I ,可以指定搜索调用编译器时为当前
目录的目录。这与预处理器在默认情况下的操作不完全相同,
但一般情况下都可以这样做。
-I- 并不禁止使用头文件的标准系统目录。 因此, -I- 和
-nostdinc 是独立的。
将目录 dir 添加到要在其中搜索头文件的目录列表的开头。这
可用于覆盖系统头文件,替代为您自己的版本,因为在搜索系
统头文件目录之前搜索这些目录。如果使用多个 -I 选项,则以
自左向右的顺序浏览目录,最后搜索标准系统目录。
将目录 dir 添加到辅助包含路径中。当一个头文件在主包含路
径( -I 添加的路径)的任何目录中都找不到时,搜索辅助包
含路径的目录。
在处理常规输入文件之前,将文件处理为输入,舍弃生成的输
出。由于舍弃了由文件生成的输出, -imacros file 的唯一
作用是使文件中定义的宏可用在主输入中。
命令行中的任何 -D 和 -U 选项始终在 -imacros file 之前处
理,而与写这些选项的顺序无关。所有 -include 和
-imacros 选项以写这些选项时的顺序处理。
在处理常规输入文件之前,将文件处理为输入。 实际上,首先
编译文件的内容。命令行中的任何 -D 和 -U 选项始终在
-include file 之前处理,而与写这些选项的顺序无关。所有
-include 和 -imacros 选项以写这些选项时的顺序处理。
指定 prefix 作为后面 -iwithprefix 选项的前缀。
将一个目录添加到辅助包含路径的开头,将其标记为系统目录,
因此可像处理标准系统目录一样处理这个目录。
将一个目录添加到辅助包含路径。目录名由前缀和 dir 组成,
其中前缀由前面的 -iprefix 指定。如果没有指定前缀,将使
用包含编译器安装路径的目录作为默认目录。
将一个目录添加到主包含路径。目录名由前缀和 dir 组成,这
与 -iwithprefix 相同。
DS51284E_CN 第 48 页 2006 Microchip Technology Inc.
表 3-11 : 预处理器选项 (续)
选项 定义
-M
-MD
-MF file
-MG
-MM
-MMD
-MP
-MQ
-MT target
告知预处理器输出适合于描述每个目标文件的相关性的 make
的规则。对于每个源文件,预处理器输出目标为该源文件目标
文件名且其相关性为它使用的所有 #include 头文件的 make
规则。这个规则可以为单行的或者太长时可用 \ 换行符来继续。
规则列表打印在标准输出中,而不是打印在预处理的 C 程序
中。
-M 隐含 -E (参见第 3.5.2 节 “控制输出类型的选项”)。
与 -M 类似,但将相关性信息写到一个文件,编译继续进行。包
含相关性信息的文件的名字与带 .d 扩展名的源文件名字相同。
当与 -M 或 -MM 一起使用时,指定在其中写入相关性信息的文
件。如果不给定 -MF 开关,预处理器将发送规则到微处理器输
出发送到的地方。
当与驱动程序选项 -MD 或 -MMD 一起使用时, -MF 覆盖默认的
相关性输出文件。
将缺少的头文件视为生成的文件,并假定它们位于源文件所在
的目录中。如果指定了 -MG ,那么必须也指定 -M 或 -MM 。
-MD 或 -MMD 不支持 -MG。
类似于 -M,但输出仅涉及到用 #include “file " 包含的用户
头文件。用 #include <file > 包含的系统头文件被忽略。
类似于 -MD ,但仅涉及到用户头文件,不涉及到系统头文件。
这个选项指示 CPP 除主文件外,还要为每个相关性添加假目
标,使每个不依赖于任何其他。如果删除头文件时不更新
Make-file 来匹配,这些假规则将避开 make 发出的错误。
下面是典型的输出:
test.o: test.c test.h
test.h:
与 -MT 相同,但它将特定于 Make 的任何字符用引号括起来。
-MQ '$(objpfx)foo.o' 给出 $$(objpfx)foo.o:
foo.c
默认的目标自动被引号括起来,就像指定了 -MQ 一样。
改变相关性生成发出的规则的目标。默认情况下, CPP 采用主
输入文件的名字,包含任何路径,删除任何文件后缀 (如
.c),并添加平台的通常目标后缀。结果就是目标。
-MT 选项将目标设置为你指定的字符串。如果需要多个目标,可
件它们指定为 -MT 的一个参数,或使用多个 -MT 选项。
例如:
-MT '$(objpfx)foo.o' 可能得到 $(objpfx)foo.o:
foo.c
使用 MPLAB C30 C 编译器
2006 Microchip Technology Inc. DS51284E_CN 第 49 页
MPLAB® C30 用户指南
表 3-11 : 预处理器选项 (续)
选项 定义
-nostdinc
-P
-trigraphs
-Umacro
-undef
3.5.8 汇编选项
表 3-12 : 汇编选项
选项 定义
-Wa,option
不要在标准系统目录中搜索头文件。仅搜索用 -I 选项指定的目
录 (及当前目录,如果需要的话)。(关于 -I 选项的信息,请
参阅第 3.5.10 节 “目录搜索选项”。)
通过同时使用 -nostdinc 和 -I- ,可将头文件搜索路径限制
为仅包括显式指定的目录。
告知预处理器不要产生 #line 伪指令。与 -E 选项一起使用
(参阅第 3.5.2 节 “控制输出类型的选项”)。
支持 ANSI C 三字母组合。 -ansi 选项也有这个作用。
取消宏 macro 定义。 -U 选项在所有 -D 选项之后,但在任何
-include 和 -imacros 选项之前起作用。
不要预定义任何非标准宏。
(包括结构标志。)
把 option 作为一个选项传递给汇编器。如果 option 中包含逗
号,说明有多个选项通过逗号分隔开。
DS51284E_CN 第 50 页 2006 Microchip Technology Inc.
使用 MPLAB C30 C 编译器
3.5.9 链接选项
如果使用了 -c 、 -S 或 -E 选项中的任何一个,则链接器不会运行,且不应将目标文件名用作
参数。
表 3-13 :链 接 选 项
选项 定义
-Ldir
-llibrary
-nodefaultlibs
-nostdlib
-s
-u symbol
-Wl,option
-Xlinker option
将目录 dir 添加到命令行选项 -l 指定的在其中搜索库的目录列表中。
链接时搜索名为 library 的库。
链接器在标准目录列表中搜索库,实际上是一个名为 liblibrary .a
的文件。链接器随后对这个文件的使用,就好像已经通过文件名精确指
定了这个文件一样。
在命令中的何处写这个选项是有所不同的,链接器按照指定库文件和目
标文件的顺序来处理这些文件。因此, foo.o -lz bar.o 先搜索
foo.o ,再搜索库 z ,最后搜索 bar.o 。如果 bar.o 引用 libz.a 中的函
数,则可能不装载这些函数。
搜索的目录包括几个标准系统目录和使用 -L 指定的任何目录。
通常采用这种方法找到的文件是库文件 (其成员为目标文件的归档文
件)。链接器通过浏览归档文件查找定义目前引用过但未定义的符号的
成员来处理归档文件。但如果找到的文件是一个普通的目标文件,则以
通常的方式链接这个文件。使用 -l 选项 (如 -lmylib )和指定文件名
(如 libmylib.a )的唯一不同之处在于, -l 按照指定搜索几个目录。
默认情况下,链接器被指示在 <install-path>\lib 中搜索 -l 选项
指定的库。对于安装到默认路径的编译器,这个目录为:
c:\Program Files\Microchip\MPLAB C30\lib 。
可使用在第 3.6 节 “环境变量”中定义的环境变量覆盖这个操作。
链接时不要使用标准系统库文件。仅指定的库文件会被传递给链接器。
编译器可能产生对 memcmp 、 memset 和 memcpy 的调用。 这些入口通
常由标准编译器库中的入口解析。当指定这个选项时,应通过其他某个
机制来提供这些入口点。
链接时不要使用标准系统启动文件或库文件。没有启动文件,仅指定的
库文件会被传递给链接器。编译器可能产生对 memcmp 、 memset
和 memcpy 的调用。这些入口通常由标准编译器库中的入口解析。当指
定这个选项时,应通过其他某个机制来提供这些入口点。
从可执行文件删除所有符号表和重定位信息。
假定 symbol 未定义,强制链接库模块来定义这个符号。可对不同的符
号多次使用 -u 来强制装载其他库模块,这样做是合法的。
将 option 作为一个选项传递给链接器。如果 option 包含逗号,它包
含逗号分隔开的多个选项。
将 option 作为一个选项传递给链接器。可使用这个选项提供 MPLAB
C30 不知如何识别的特定系统链接器选项。
2006 Microchip Technology Inc. DS51284E_CN 第 51 页
MPLAB® C30 用户指南
3.5.10 目录搜索选项
表 3-14 : 目录搜索选项
选项 定义
-Bprefix
-specs=file
这个选项指定在哪里查找可执行文件、库文件、头文件和编译器本
身的数据文件。
编译器驱动程序运行子程序 pic30-cpp 、 pic30-cc1 、
pic30-as 和 pic30 中的一个或多个子程序。它将其运行的每个程
序加上 prefix 作为前缀。
对于要运行的每个子程序,编译器驱动程序首先使用 -B 前缀 (如
果存在的话)。如果找不到子程序,或未指定 -B ,驱动程序将使
用 PIC30_EXEC_PREFIX 环境变量 (如果设置了的话)中保存的
值。更多信息,请参阅第 3.6 节 “环境变量”。最后,驱动程序将
在当前的 PATH 环境变量中搜索子程序。
有效指定目录名的 -B 前缀也适用于链接器中的库,因为编译器将
这些选项翻译为链接器的 -L 选项。它们也适用于预处理器中的头
文件,因为编译器将这些选项转化为预处理器的 -isystem 选项。
在这种情况下,编译器在前缀上附加 include 。指定很像 -B 这
样的前缀的另外一种方法是使用环境变量
PIC30_EXEC_PREFIX 。
为覆盖当确定哪些开关传递给 pic30-cc1 、 pic30-as 和
pic30-ld 等时, pic30-gcc 驱动程序使用的默认设置,在编译
器读入标准 specs 文件后处理文件。可在命令行中指定多个
-specs= file,以自左向右的顺序处理这些文件。
DS51284E_CN 第 52 页 2006 Microchip Technology Inc.
使用 MPLAB C30 C 编译器
3.5.11 代码生成约定选项
-fflag 形式的选项指定独立于机器的标志。大多数标志都有正的形式和负的形式;
-ffoo 负的形式为 -fno-foo。在下表中,仅列出了一种形式 (非默认形式)。
表 3-15 : 代码生成约定选项
选项 定义
-fargument-alias
-fargument-noalias
-fargument noalias-global
-fcall-saved-reg
-fcall-used-reg
-ffixed-reg
-finstrument functions
指定参数之间以及参数和全局数据之间的可能关系。
-fargument-alias 指定实参 (形参)可互相引用,并可引用全
局存储。
-fargument-noalias 指定实参不能互相引用,但可引用全局存
储。
-fargument-noalias-global 指定实参不能互相引用,也不能
引用全局存储。
每种语言都自动使用语言标准所要求的选项。不需要自己使用这些
选项。
将名为 reg 的寄存器视为函数保存的可分配寄存器。甚至可在其中
分配临时变量或跨调用有效的变量。如果函数使用了寄存器 reg ,
那么采用这种方式编译的函数将保护和恢复这个寄存器。
对帧指针和堆栈指针使用这个标志是错误的。将这个标志用于在机
器执行模型中有固定重要作用的其他寄存器,将产生灾难性结果。
将这个标志用于保存函数返回值的寄存器将产生另一种灾难性结
果。
所有模块中对这个标志的使用应该一致。
将名为 reg 的寄存器视为被函数调用破坏的可分配寄存器。可将这
个寄存器分配给临时变量或跨调用无效的变量。采用这个选项编译
的函数不会保护和恢复寄存器 reg 。
对帧指针或堆栈指针使用这个选项是错误的。将这个标志用于在机
器执行模型中有固定重要作用的其他寄存器,将产生灾难性结果。
所有模块中对这个标志的使用应该一致。
将名为 reg 的寄存器视为固定寄存器;生成的代码绝对不能引用它
(除非作为堆栈指针、帧指针或某个其他固定的功能)。
reg 必须为寄存器的名字,如 -ffixed-w3。
编译时在函数的入口和出口生成 instrumentation 调用。在函数入口
之后和函数出口之前,将通过当前函数的地址及其调用地址来调用
下面的 profiling 函数。
__cyg_profile_func_enter
void
(void *this_fn, void *call_site);
void __ cyg_profile_func_exit
(void *this_fn, void *call_site);
第一个参数是当前函数的起始地址,可在符号表中查找到。
profiling 函数应由用户提供。
函数 instrumentation 要求使用帧指针。 某些优化级别禁止使用帧指
针。 使用 -fno-omit-frame-pointer 将禁止这一点。
2006 Microchip Technology Inc. DS51284E_CN 第 53 页
MPLAB® C30 用户指南
表 3-15 : 代码生成约定选项 (续)
选项 定义
-fno-ident
-fpack-struct
-fpcc-struct return
-fno-short-double
-fshort-enums
-fverbose-asm
-fno-verbose-asm
-fvolatile
-fvolatile-global
-fvolatile-static
instrumentation 也可用于在其他函数中扩展内联的函数。 profiling
调用表明从概念上来讲在哪里进入和退出内联函数。这意味着这种
函数必须具有可寻址形式。如果对一个函数的所有使用都扩展内
联,这会增加额外增加代码长度。如果要在 C 代码中使用 extern
inline ,必须提供这种函数的可寻址形式。
可对函数指定属性 no_instrument_function ,在这种情况下
不会进行 instrumentation 。
忽略 #ident 伪指令。
将所有结构成员无缝隙地压缩在一起。通常不希望使用这个选项,
因为它使代码不是最优化的,且结构成员的偏移量与系统库不相
符。
®
dsPIC
属性时要小心,避免运行时寻址错误。
像长值一样,将短 struct 和 union 值返回到存储器中,而不是
返回到寄存器中。这样做效率不高,但其优点是可以使 MPLAB ®
C30 编译的文件与其他编译器编译的文件兼容。
短结构和联合指长度和对齐都与整型匹配的结构和联合。
默认情况下,编译器使用与 float 等价的 double 型。这个选项
使得 double 与 long double 等价。如果模块通过参数传递直接
或通过共享缓冲空间间接共用 double 数据,跨模块混合使用这个
选项可能会产生异常结果。无论使用哪个开关设置,随产品提供的
库都可正常工作。
按照 enum 类型声明的可能值范围的需要,为其分配字节。具体来
说, enum 类型等价于有足够空间的最小整型。
在输出的汇编代码中加入额外的注释信息以增强可读性。
默认设置为 -fno-verbose-asm ,将给出额外的信息,当比较两
个汇编文件时有用。
将通过指针进行的所有存储器引用视为 volatile 。
将对外部和全局数据项的所有存储器引用视为 volatile 。使用这个
开关对于 static 数据没有影响。
将对 static 数据的所有存储器引用视为 volatile 。
DSC 器件要求字按偶数字节边界对齐,因此当使用 packed
DS51284E_CN 第 54 页 2006 Microchip Technology Inc.
3.6 环境变量
使用 MPLAB C30 C 编译器
本节中提到的变量是可选的,但是如果定义了这些变量,将由编译器使用。如果没有
设置下面某些环境变量的值,编译器驱动程序或其他子程序,可能选择为这些变量确
定适当的值。驱动程序或其他子程序,利用有关 MPLAB C30 安装的内部知识。只要
安装结构是完整的,所有子目录和可执行文件在相同的相对路径中,驱动程序或子程
序就能确定可使用的值。
表 3-16 : 与编译器有关的环境变量
选项 定义
PIC30_C_INCLUDE_
PATH
PIC30_COMPILER_
PATH
PIC30_EXEC_
PREFIX
PIC30_LIBRARY_
PATH
PIC30_OMF
TMPDIR
此变量的值是一个分号分隔开的目录列表,很像 PATH 。当 MPLAB
C30 搜索头文件时,它在搜索标准头文件目录之前,搜索 -I 指定的目
录之后,搜索此变量中列出的目录。
如果未定义该环境变量,预处理器根据标准安装选择适当的值。默认
情况下,在下面的目录中搜索头文件:
<install-path>\include 和
<install-path>\support\h。
PIC30_COMPILER_PATH 的值是一个分号分隔的目录列表,很像
PATH。搜索子程序时,如果 MPLAB C30 使用 PIC30_EXEC_PREFIX
找不到子程序,它在这个变量指定的目录中搜索。
如果设置了 PIC30_EXEC_PREFIX ,它指定要在编译器执行的子程序
的名字中使用的前缀。当这个前缀和子程序名一起使用时,不添加目
录分隔符,但如果需要的话,可以指定一个以斜杠符结束的前缀。 如
果 MPLAB C30 使用指定的前缀找不到子程序,它将在 PATH 环境变量
中查找。
如果 PIC30_EXEC_PREFIX 环境变量未设置或设置为空值,则编译器
驱动程序根据标准安装选择适当的值。如果安装没有被修改,那么驱
动程序将能找到所需要的子程序。
使用 -B 命令行选项指定的其他前缀优先于 PIC30_EXEC_PREFIX 的
用户定义值或驱动程序定义 值。
通常情况下,最好将此值保持为未定义,让驱动程序查找子程序。
这个变量的值是分号分隔的目录列表,很像 PATH 。这个变量指定要传
递给链接器的目录列表。驱动程序对这个变量的默认求值为:
<install-path>\lib; <install-path>\support\gld.
指定 MPLAB C30 要使用的 目标模块格式 ( Object Module Format,
OMF)。默认情况下,工具生成 COFF 目标文件。如果环境变量
PIC30_OMF 的值为 elf ,工具将生成 ELF 目标文件。
如果设置了 TMPDIR ,它指定临时文件使用的目录。 MPLAB C30 使用
临时文件来保存编译的一个阶段的输出,这个输出将用作编译的下一
个阶段的输入:例如,预处理器的输出是编译器的输入。
®
2006 Microchip Technology Inc. DS51284E_CN 第 55 页
MPLAB® C30 用户指南
3.7 预定义常量
可使用几个常量来定制编译器输出。
3.7.1 常量
下表中的预处理符号由所使用的编译器定义。
编译器 符号 是否通过 -ansi 命令行选项定义?
®
MPLAB
ELF 版本 C30ELF 否
COFF 版本 C30COFF 否
下表中的符号定义目标器件系列。
__dsPIC30F__ 是
__dsPIC33F__ 是
__PIC24F__ 是
__PIC24H__ 是
此外,编译器还根据用 -mcpu= 设置的目标器件定义符号。例如, -mcpu=30F6014
定义了符号 __dsPIC30F6014__ 。
编译器将定义常量 _ _C30_VERSION__ ,给版本标识符赋一个数值。这可用于利用编
译器新版本中与老版本向后兼容的特性。
这个值基于当前版本的主版本号和次版本号。例如,版本 2.00 将 __C30_VERSION__
定义为 200 。可以将这个宏与标准预处理比较语句一起使用,以便根据条件包含 / 排除
各种代码结构。
可通过向命令行添加 --version 或查看版本附带的 README.TXT 文件,来确定
__C30_VERSION__ 的当前定义。
C30 C30 否
__C30 是
__C30__ 是
__C30ELF 是
__C30ELF__ 是
__C30COFF 是
__C30COFF__ 是
符号 是否通过 -ansi 命令行选项定义?
3.7.2 不赞成使用的常量
可在附录 D “不赞成使用的特性”中查到视为不赞成使用的常量。
DS51284E_CN 第 56 页 2006 Microchip Technology Inc.
3.8 通过命令行编译单个文件
本节说明如何编译和链接单个文件。为便于讨论,假定编译器安装在 c: 驱动器的
pic30-tools 目录中。因此就有下面的目录:
表 3-17 : 与编译器有关的目录
目录
c:\Program Files\
Microchip\MPLAB C30\
include
c:\Program Files\
Microchip\MPLAB C30\
support\h
c:Program Files\
Microchip\MPLAB C30\
lib
c:Program Files\
Microchip\MPLAB C30\
support\gld
c:Program Files\
Microchip\MPLAB C30\
bin
使用 MPLAB C30 C 编译器
内容
包含 ANSI C 头文件的目录。编译器在该目录中存放标准 C 函
数库的系统头文件。PIC30_C_INCLUDE_PATH 环境变量指向
这个目录。(在 DOS 命令提示符下键入 set 来检查这一点。)
包含针对 dsPIC
中存放针对 dsPIC DSC 器件的头文件。
PIC30_C_INCLUDE_PATH 环境变量指向这个目录。(在
DOS 命令提示符下键入 set 来检查这一点。)
库文件目录:该目录中存放库文件和预编译目标文件。
链接描述文件目录:在这个目录中存放不同型号器件的链接描
述文件。
可执行文件目录:存放编译程序。 PATH 环境变量包含这个目
录。
®
DSC 器件的头文件的目录。编译器在该目录
下面是一个两数相加的简单 C 程序。
使用任何文本编辑器创建下面的程序并保存为 ex1.c 。
#include <p30f2010.h>
int main(void);
unsigned int Add(unsigned int a, unsigned int b);
unsigned int x, y, z;
int
main(void)
{
x = 2;
y = 5;
z = Add(x,y);
return 0;
}
unsigned int
Add(unsigned int a, unsigned int b)
{
return(a+b);
}
程序的第一行包含了头文件 p30f2010.h ,这个头文件提供了该器件的所有特殊功能
寄存器的定义。关于头文件的详细信息,参见第 6 章 “器件支持文件”。
在 DOS 提示符下输入如下命令行来编译该程序:
C:\> pic30-gcc -o ex1.o ex1.c
命令行选项 -o ex1.cof 命名输出 COFF 可执行文件 (若未指定 -o 选项,则输出文
件名为 a.exe )。 COFF 可执行文件可装载到 MPLAB IDE 中。
2006 Microchip Technology Inc. DS51284E_CN 第 57 页
MPLAB® C30 用户指南
如果需要 hex 文件,如要装入器件编程器中,可以使用下面的命令:
C:\> pic30-bin2hex ex1.o
这样就生成了一个名为 ex1.hex 的 Intel hex 文件。
3.9 通过命令行编译多个文件
将 Add() 函数移到名为 add.c 的文件中来说明在一个应用程序中多个文件的使用。
即:
文件 1
/* ex1.c */
#include <p30f2010.h>
int main(void);
unsigned int Add(unsigned int a, unsigned int b);
unsigned int x, y, z;
int main(void)
{
x = 2;
y = 5;
z = Add(x,y);
return 0;
}
文件 2
/* add.c */
#include <p30f2010.h>
unsigned int
Add(unsigned int a, unsigned int b)
{
return(a+b);
}
在 DOS 提示符下输入如下命令行来编译这两个文件:
C:\> pic30-gcc -o ex1.o ex1.c add.c
这个命令编译模块 ex1.c 和 add.c 。编译的模块和编译器库文件链接,并生成可执行
文件 ex1.o 。
DS51284E_CN 第 58 页 2006 Microchip Technology Inc.
第 4 章 MPLAB C30 C 编译器运行时环境
4.1 简介
4.2 主要内容
MPLAB® C30
用户指南
本章讲述 MPLAB C30 C 编译器的运行时环境。
本章讨论的内容包括:
• 地址空间
• 代码段和数据段
• 启动和初始化
• 存储空间
• 存储模型
• 定位代码和数据
• 软件堆栈
•C堆栈使用
•C堆使用
• 函数调用约定
• 寄存器约定
• 位反转寻址和模寻址
• 程序空间可视性 ( PSV)的使用
4.3 地址空间
dsPIC 数字信号控制器 (DSC )器件融合了传统 PICmicro 单片机 (MCU )的特征
(外设、哈佛架构和 RISC )以及新的 DSP 功能。 dsPIC DSC 器件具有两个独立的存
储器:
• 程序存储器 (图 4-1) 包含可执行代码和常量数据。
• 数据存储器 (图 4-2)包含外部变量、静态变量、系统堆栈和数据寄存器。数据存
储器由 near 数据和 far 数据组成,其中, near 数据指数据存储空间的前 8KB , far
数据指数据存储空间的上面 56KB 。
尽管程序存储区和数据存储区是完全独立的,但编译器可通过程序空间可视性
(PSV )窗口访问程序存储器中的常量数据。
2006 Microchip Technology Inc. DS51284E_CN 第 59 页
MPLAB® C30 用户指南
图 4-1 : 程序存储空间映射
7FFFFF
.const
.dinit
008000
NEAR 一般程序存储空间
0
图 4-2 : 数据存储空间映射
FFFF
8000
.text
.handle
.const
程序存储器中的常量
数据存储器的初始化程序
一般程序存储
far 代码句柄
复位向量和异常向量
程序空间可视性
数据窗口(PSV )
堆栈(向上生长)
堆(可选)
NEAR 一般数据存储空间
2000
.ybss, .ydata
.nbss, .ndata
.xbss, .xdata
0
Y 数据存储空间
.bss, .data
一般数据存储空间
X 数据存储空间
存储器映射 SFR
DS51284E_CN 第 60 页 2006 Microchip Technology Inc.
4.4 代码段和数据段
段是指占用 dsPIC DSC 器件存储器中连续地址的可定位代码或数据块。在任何给定的
目标文件中,通常都有几个段。例如,一个文件中可能包含一个程序代码段、一个未
初始化数据段及其他段。
除非通过段属性 (关于段属性的信息,参见第 2.3 节 “关键字差别”)指定,否则,
MPLAB C30 编译器将代码和数据存放在默认的段中。所有由编译器生成的可执行代码
都被分配到名为 .text 的段中,而数据则根据数据类型分配在不同的段中,见
表 4-1 。
表 4-1 : 编译器生成的数据段
near .ndata .const .ndconst .nbss
far .data .const .dconst .bss
下面列出了每个默认的段,并描述了存储到段中的信息的类型。
.text
可执行代码分配到 .text 段中。
变量
MPLAB C30 C 编译器运行时环境
已初始化 未初始化
ROM 中的常量 RAM 中的常量
变量
.data
具有 far 属性的已初始化变量分配到 .data 段中。当选择大数据存储模型时 (即使
用 -mlarge-data 命令行选项时),这是已初始化变量的默认位置。
.ndata
具有 near 属性的已初始化变量分配到 .ndata 段中。当选择小数据存储模型时 (即
使用默认的 -msmall-data 命令行选项时),这是已初始化变量的默认段。
.const
当使用默认的 -mconst-in-code 命令行选项时,常量值,如字符串常量和 const
限定的变量,分配到 .const 段中。这种段位于程序存储器中并通过 PSV 窗口访问。
还可以通过段属性,不需要在命令行中使用 -mconst-in-code 选项,将变量存放到
.const 段中:
int i __attribute__((space(auto_psv)));
2006 Microchip Technology Inc. DS51284E_CN 第 61 页
MPLAB® C30 用户指南
.dconst
当使用 -mlarge-data 命令行选项时,不需使用 -mconst-in-code 选项,即可将
常量值,如字符串常量和 const 限定的变量分配到 .dconst 段中。 MPLAB C30 启
动代码将通过从 .dinit 段复制数据来初始化这种段,除非指定了链接器选项
--no-data-init 。 .dinit 段由链接器生成,分配到程序存储器中。
.ndconst
当使用默认的 -msmall-data 命令行选项时,不需使用 -mconst-in-code 命令行
选项,即可将常量值,如字符串常量和 const 限定的变量分配到 .ndconst 段中。
MPLABC30 启动代码将通过从 .dinit 段中复制数据来初始化这种段。 .dinit 段由
链接器生成,位于程序存储器中。
.bss
具有 far 属性的未初始化变量分配到 .bss 段中。当选择了大数据存储模型时 (即当
使用 -mlarge-data 命令行选项时),这是未初始化变量的默认位置。
.nbss
具有 near 属性的未初始化变量分配到 .nbss 段中。当选择小数据存储模型时 (即使
用默认的 -msmall-data 命令行选项时),这是未初始化变量的默认位置。
.pbss ——持久数据
如果应用需要将数据存储在 RAM 中而不受器件复位的影响,可以使用段 .pbss 。段
.pbss 分配到 near 数据存储区中,不会被 libpic30.a 中的默认启动模块修改。
可使用段属性将未初始化变量存放在 .pbss 段中:
int i __attribute__((persistent));
为了利用持久数据存储, main() 函数的开头要检测所发生复位的类型。在 RCON 复
位控制寄存器中的各位可用于检测复位源。详细信息请参阅
册》
(DS70046D_CN )的第 8 章。
《
dsPIC30F
系列参考手
DS51284E_CN 第 62 页 2006 Microchip Technology Inc.
4.5 启动和初始化
libpic30.a 归档 / 库中包含两个 C 运行时启动模块。这两个启动模块的入口点都是
__reset。链接描述文件在程序存储器的地址 0 存放了一条 GOTO __reset 指令,在
器件复位时转移控制。
默认情况下链接主启动模块并进行以下操作:
1. 使用链接器或用户定义链接描述文件提供的值对堆栈指针 ( W15)和堆栈指针
2. 如果定义了.const 段,那么将通过初始化PSVPAG和 CORCON寄存器将其映射
3. 读取 .dinit 段中的数据初始化模板,会导致所有未初始化的段被清零,同时所
4. 调用 main 函数时不带参数。
5. 如果从 main 函数返回,处理器将复位。
当指定 -Wl 、 --no-data-init 选项时,将链接备用启动模块 (crtl.o )。它执行
和上面相同的操作,除了第 3 步,这一步省略掉。备用启动模块比主启动模块小,所
以当不需要初始化数据时,可选择该模块来节省程序存储空间。
这两个模块的源代码 (采用 dsPIC DSC 汇编语言)存放在 c:\Program
Files\Microchip\MPLAB C30\src 目录中。如果需要,可以对启动模块进行修
改。例如,如果应用需要在调用 main 函数时带参数,可通过改变条件汇编伪指令来
提供这一支持。
MPLAB C30 C 编译器运行时环境
限制寄存器 (SPLIM )进行初始化。详细信息参见第 4.9 节 “软件堆栈”。
到程序空间可视性窗口。注意,当在 MPLAB IDE 中选择了 “Constants in code
space ”选项或在 MPLAB C30 命令行中指定了默认的 -mconst-in-code 选项
时,将定义一个 .const 段。
有已初始化段被初始化为从程序存储器中读取的值。数据初始化模板由链接器创
建,并支持第 4.4 节 “代码段和数据段”中列出的标准段和用户定义段。
注: 持久数据段 .pbss 不会被清零或初始化。
2006 Microchip Technology Inc. DS51284E_CN 第 63 页
MPLAB® C30 用户指南
4.6 存储空间
静态和外部变量通常分配到一般数据存储区中。如果选择了 constants-in-data 存储模
型, const 限定的变量将被分配到一般数据存储区中;如果选择了 constants-in-code
存储模型, const 限定的变量将被分配到程序存储器中。
为配合 dsPIC DSC 的架构特点, MPLAB C30 定义了几个专用存储空间。可通过使用
space 属性 (参见第 2.3.1 节 “指定变量的属性”),将静态和外部变量分配到专用
存储空间中:
data
一般数据空间。可使用普通 C 语句访问一般数据空间中的变量。这是默认的分配。
xmemory ——仅适用于 dsPIC30F/33F DSC
X 数据地址空间。 可使用普通 C 语句访问 X 数据空间中的变量。 X 数据地址空间尤其
适用于针对 DSP 的函数库和 / 或汇编语言指令。
ymemory ——仅适用于 dsPIC30F/33F 器件
Y 数据地址空间。可使用普通 C 语句访问 Y 数据空间中的变量。Y 数据地址空间尤其适
用于针对 DSP 的函数库和 / 或汇编语言指令。
prog
一般程序空间,通常保留给可执行代码。不能使用普通 C 语句访问程序空间中的变
量。这些变量必须由编程人员显式访问,通常通过表访问行内汇编指令,或使用程序
空间可视性窗口访问。
const
程序空间中编译器管理的区域,用于程序空间可视性窗口访问。 const 空间中的变量可
通过普通 C 语句读取,总分配空间最大为 32K 。
psv
程序空间,用于程序空间可视性窗口访问。 PSV 空间中的变量不由编译器管理,不能
通过普通 C 语句访问。这些变量必须由编程人员显式访问,通常通过表访问行内汇编
指令,或使用程序空间可视性窗口访问。可通过使用 PSVPAG 寄存器的设置,访问
PSV 空间中的变量。
eedata——仅适用于 dsPIC30F/33F 器件
数据 EEPROM 空间,位于程序存储器高地址的 16 位宽非易失性存储区。 eedata 空间
中的变量不能使用普通 C 语句访问。这些变量必须由编程人员显式访问,通常使用表
访问行内汇编指令,或使用程序空间可视性窗口访问。
dma ——仅适用于 PIC24H MCU 和 dsPIC30F/33F DSC
DMA 存储器。可使用一般 C 语句或通过 DMA 外设访问 DMA 存储器中的变量。
DS51284E_CN 第 64 页 2006 Microchip Technology Inc.
4.7 存储模型
MPLAB C30 C 编译器运行时环境
编译器支持几种存储模型。提供了命令行选项来根据所使用的特定 dsPIC DSC 器件和
存储器类型,选择最佳的存储模型。
表 4-2 : 存储模型命令行选项
选项 存储区定义 描述
-msmall-data
-msmall-scalar
-mlarge-data
-msmall-code
-mlarge-code
-mconst-in-data
-mconst-in-code
命令行选项适用于所有被编译的模块。各个变量和函数可以声明为 near 或 far ,以
便更好的控制代码的生成。关于设置变量和函数属性的信息,请参阅第 2.3.1 节“指
定变量的属性” 和第 2.3.2 节 “指定函数的属性”。
8 KB 数据存储区。
这是默认设置。
8 KB 的数据存储区。
这是默认设置。
大于 8 KB 的数据存储区。 使用数据引用伪指令。
32 K 字的程序存储区。
这是默认设置。
大于 32 K 字的程序存储区。 函数指针使用跳转表。 函数调用使用
位于数据存储器中的常量。 由启动代码从程序存储器中复制的值。
位于程序存储器中的常量。
这是默认设置。
允许使用类 PIC18 指令访问数据存储
器。
允许使用类 PIC18 指令访问数据存储
器中的标量。
函数指针不使用跳转表。函数调用使
用 RCALL 指令。
CALL 指令。
通过程序空间可视性 (PSV )数据窗
口访问这些值。
4.7.1 Near 数据和 Far 数据
如果变量分配到 near 数据段中,通常编译器能生成更好 (更紧凑)的代码。如果一个
应用的所有变量能存放在 8KB 的 near 数据存储区中,那么编译器在编译每个模块时
就会被要求使用默认的 -msmall-data 命令行选项来将这些变量存放在 near 数据存
储区中。如果标量类型 (非数组或结构类型)所占用的数据总量小于 8KB 的话,可使
用默认的 -msmall-scalar 选项。这要求编译器仅将应用中的标量存放在 near 数据
段中。
如果这些全局选项都不适合,那么就使用下面的可选方案:
2006 Microchip Technology Inc. DS51284E_CN 第 65 页
MPLAB® C30 用户指南
1. 可以使用 -mlarge-data 或 -mlarge-scalar 命令行选项编译应用的某些模
块。在这种情况下,仅这些模块使用的变量被分配到 far 数据段中。如果使用这
个可选方案,在使用外部定义的变量时一定要小心。如果使用这两个命令行选项
之一编译的模块使用了一个外部定义的变量,则定义这个变量的模块也要使用相
同的选项编译,或者在变量声明和定义时指定 far 属性。
2. 如果使用了 -mlarge-data 或 -mlarge-scalar 命令行选项,那么可通过指定
near 属性将变量排除在 far 数据空间外 (即存放在 near 数据空间)。
3. 命令行选项的作用域仅限于模块内部,也可以不使用命令行选项,而通过指定
far 属性将变量存放在 far 数据段中。
如果应用的 near 变量在 8K 的 near 数据空间中存放不下,链接器将产生错误消息。
4.7.2 Near 代码和 Far 代码
具有 near 属性的函数 (函数在彼此的 32K 字范围内)互相调用时比非 near 属性的函
数效率高。如果已知应用程序中的所有函数都是 near 的,那么在编译每个模块时就可
以使用默认的 -msmall-code 命令行选项来指示编译器采用更高效的函数调用形式。
如果这个默认的选项不适合,可以使用下面的可选方案:
1. 可以使用 -msmall-code 命令行选项来编译应用程序的某些模块。在这种情况
下,只有这些模块中的函数调用可以采用更高效的函数调用形式。
2. 如果已使用-msmall-code 命令行选项,那么编译器可能被指示对具有 far 属性
的函数使用长函数调用形式。
3. 命令行选项的作用域限于模块内部,可以不使用命令行选项,而通过在函数的定
义和声明中指定 near 属性,指示编译器使用更高效的函数调用形式调用这些函
数。
-msmall-code 命令行选项与 -msmall-data 命令行选项的区别在于,采用前者
时,为确保函数彼此 “靠近”分配,编译器不需进行特别的操作;而采用后者时,编
译器要将变量分配到特殊的段中。
如果函数声明为 near ,而其调用函数无法采用函数调用的更高效形式调用它时,链接
器将产生错误信息。
DS51284E_CN 第 66 页 2006 Microchip Technology Inc.
4.8 定位代码和数据
正如第 4.4 节 “代码段和数据段”中所述,编译器将代码存放在 .text 段中,而根据
所使用的存储模型和数据是否已初始化将数据存放在指定的段中。链接模块时,链接
器根据各个段的属性来确定段的起始地址。
某些情况下必须将特定函数或变量存放在某个特定地址或某个地址范围。为实现这一
点,最简单的方法是使用 address 属性,如第 2.3 节 “关键字差别”所述。例如,
将函数存放到程序存储器的地址 0x8000 中:
int __ attribute__ ((address(0x8000))) PrintString (const char *s);
同样,将变量 Mabonga 存放到数据存储器的地址 0x1000 中:
int __ attribute__ ((address(0x1000))) Mabonga = 1;
定位代码和数据的另一种方法是将函数或变量存放到用户定义的段中,并在自定义的
链接描述文件中指定该段的起始地址。具体如下:
1. 在 C 源程序中修改代码或数据的声明来指定用户定义的段。
2. 将这个用户定义段加入到一个自定义的链接描述文件中来指定段的起始地址。
例如,要将函数 PrintString 存放到程序存储器的 0x8000 地址中,首先要在 C 源
程序中对函数进行如下声明:
int __
PrintString(const char *s);
MPLAB C30 C 编译器运行时环境
attribute__((__section__(".myTextSection")))
段属性指定将函数存放到名为 .myTextSection 的段中,而不是默认的 .text 段
中。它没有指定用户定义的段存存放在哪里。这必须在一个自定义的链接描述文件中
指定,如下所示。以针对器件的链接描述文件为基础,加入如下段定义:
.myTextSection 0x8000 :
{
*(.myTextSection);
} >program
这指定了输出文件应包括一个名为 .myTextSection 的段,这个段位于地址
0x8000 ,包含所有名为 .myTextSection 的输入段。由于在本例中,在该段中只有
一个函数 PrintString ,那么这个函数将位于程序存储器的地址 0x8000 处。
类似地,要将变量 Mabonga 存放到数据存储器的地址 0x1000 中,首先要在 C 源程序
中声明该变量如下:
int __attribute__((__section_ _(".myDataSection"))) Mabonga =
1;
2006 Microchip Technology Inc. DS51284E_CN 第 67 页
MPLAB® C30 用户指南
段属性指定将变量存放到名为 .myDataSection 的段中,而不是默认的 .data 段
中。它没有指定用户定义的段存放在哪里。同样地,这必须在一个自定义的链接描述
文件中指定,如下所示。以特定器件的链接描述文件为基础,加入如下段定义:
.myDataSection 0x1000 :
{
*(.myDataSection);
} >data
这指定了输出文件应包含一个名为 .myDataSection 的段,这个段位于地址
0x1000 ,包含所有名为 .myDataSection 的输入段。在这个例子中,由于该段中仅
包含一个变量 Mabonga ,那么该变量将被存放到数据存储器的地址 0x1000 中。
4.9 软件堆栈
dsPIC DSC 器件的寄存器 W15 专门用作软件堆栈指针。所有处理器堆栈操作,包括
函数调用、中断和异常都使用软件堆栈。堆栈是向上生长的,向高存储地址生长。
dsPIC DSC 器件也支持堆栈溢出检测。如果堆栈指针限制寄存器 SPLIM 已被初始化,
器件将对所有堆栈操作的溢出进行检测。如果发生溢出,处理器将启动一个堆栈错误
异常处理。默认情况下,这将引起处理器复位。应用还可通过定义一个名为
_StackError 的中断函数来安装一个堆栈错误异常处理程序。详细信息请参阅第 7
章“中断”。
C 运行时启动模块在启动和初始化过程中对堆栈指针 (W15 )和堆栈指针限制寄存器
(SPLIM )进行初始化。初值通常由链接器提供,链接器尽可能在未使用的数据存储器
中分配最大的堆栈。链接映射输出文件中给出堆栈的地址。通过 -stack 链接器命令
行选项,应用可确保至少可获得一个最小的堆栈。详细信息请参阅
ASM30
另外,可以通过自定义链接描述文件中的用户定义段来分配指定大小的堆栈。在下面
的示例中, 0x100 字节的数据存储区保留给了堆栈。声明了用于 C 运行时启动模块的
两个符号, __SP_init 和 __SPLIM_init 。
.stack :
{
__SP_init = .;
. += 0x100
__SPLIM_init = .;
. += 8
} >data
、
MPLAB LINK30
和实用程序用户指南》
《
(DS51317D_CN )。
MPLAB®
__SP_init 定义了堆栈指针 (W15 )的初值,而 __SPLIM_init 定义了堆栈指针限
制寄存器 (SPLIM )的初值。 _ _SPLIM_init 的值应比物理堆栈限制小至少 8 个字
节,以便允许堆栈错误异常处理。如果安装了堆栈错误中断处理程序,由于要考虑到
中断处理程序本身的堆栈使用, __SPLIM_init 的值应该更小。默认的中断处理程序
不需要额外使用堆栈。
DS51284E_CN 第 68 页 2006 Microchip Technology Inc.
4.10 C 堆栈使用
C 编译器使用软件堆栈来进行如下操作:
• 分配自动变量
• 传递函数参数
• 在中断函数中保存处理器状态
• 保存函数返回地址
• 存储临时变量
• 函数调用时保护寄存器
运行时堆栈是向上生长的,从低地址向高地址生长。编译器使用两个工作寄存器来管
理堆栈:
•W15——这是堆栈指针。它指向栈顶,栈顶定义为堆栈的第一个未使用单元。
•W14——这是帧指针 (frame pointer, FP)。它指向当前函数的帧。如果需要,
图 4-3: 堆栈指针和帧指针
MPLAB C30 C 编译器运行时环境
每个函数都会在栈顶创建一个新的帧来分配自动变量和临时变量。可使用编译器选
项 -fomit-frame-pointer 来限制帧指针的使用。
堆栈
向高
地址
生长
C 运行时启动模块 (libpic30.a 中的 crt0.o 和 crt1.o )初始化堆栈指针 W15
使其指向栈底,初始化堆栈指针限制寄存器使其指向栈顶。堆栈向上生长,如果堆栈
超出堆栈指针限制寄存器中的值,将转入堆栈错误陷阱。用户可以通过初始化堆栈指
针限制寄存器来进一步限制堆栈的生长。
下图说明了调用一个函数的步骤。执行 CALL 或 RCALL 指令将返回地址压入软件堆
栈。参见图 4-4 。
函数帧
SP(W15)
FP(W14)
2006 Microchip Technology Inc. DS51284E_CN 第 69 页
MPLAB® C30 用户指南
图 4-4 : CALL 或 RCALL
SP (W15 )
返回地址 [23:16]
返回地址 [15:0]
堆栈
向高
地址
生长
现在被调用函数可以为其局部现场分配空间了 (图 4-5 )。
图 4-5 : 被调用函数的空间分配
堆栈
向高
地址
生长
参数 1
:
参数 n-1
参数 n
调用函数的帧
局部变量
和临时变量
前一个 FP
返回地址 [23:16]
返回地址 [15:0]
参数 1
:
FP(W14)
SP (W15)
FP (W14)
参数 n-1
参数 n
调用函数的帧
DS51284E_CN 第 70 页 2006 Microchip Technology Inc.
MPLAB C30 C 编译器运行时环境
最后,函数中用到的所有被调用函数保存寄存器被压入堆栈 (图 4-6 )。
图 4-6 : 将被调用函数保存的寄存器压入堆栈
SP (W15 )
被调用函数
保存的寄存器
[W14+n] 访问
局部现场
4.11 C 堆使用
局部变量
和临时变量
前一个 FP
堆栈
向高
地址
生长
C 运行时堆是数据存储器中的未初始化区域,用于使用标准 C 函数库中的动态存储器
管理函数 calloc 、 malloc 和 realloc 进行动态存储器分配。如果不使用这些函
数,就不需要分配堆。默认情况下不创建堆。
如果确实需要通过调用一个存储器分配函数直接使用动态存储器分配,或通过使用标
准 C 函数库的输入 / 输出函数来间接使用动态存储器分配的话,就必须创建一个堆。
通过使用链接器命令行选项 --heap 在链接器命令行中指定堆的大小即可创建一个
堆。例如,使用命令行来分配一个 512K 字节的堆:
pic30-gcc foo.c -Wl,--heap=512
返回地址 [23:16]
返回地址 [15:0]
参数 1
:
参数 n-1
参数 n
调用函数的帧
FP (W14)
[W14-n] 访问
基于堆栈的
函数参数
链接器会在堆栈下面分配一个堆 (图 4-2 )。
如果使用标准 C 函数库的输入 / 输出函数,就必须分配一个堆。如果 stdout 是使用
的唯一文件,那么堆的大小为 0 ,即使用命令行选项:
-Wl,--heap=0
如果打开几个文件,那么对于同时打开的每个文件,堆的大小必须包含 40 个字节。如
果堆存储区的空间不足, open 函数将返回错误指示。对于每个应被缓存的文件,都需
要 514 字节的堆空间。如果没有足够的堆存储区空间用于缓存,文件将以非缓存模式
打开。
2006 Microchip Technology Inc. DS51284E_CN 第 71 页
MPLAB® C30 用户指南
4.12 函数调用约定
调用函数时:
• 寄存器 W0-W7 由调用函数保存。为保存寄存器的值,调用函数必须将这些值压入
堆栈。
• 寄存器 W8-W14 由被调用函数保存。被调用函数必须保存它会修改的任何这些寄存
器。
• 寄存器 W0-W4 用于存放函数返回值。
表 4-3 : 需要的寄存器
数据类型 需要的寄存器数
char 1
int 1
short 1
pointer 1
long
float
double*
long double
structure
* 如果使用 -fno-short-double , double 等价于 long double 。
2 (邻近的 – 对齐到偶数编号的寄存器)
2 (邻近的 – 对齐到偶数编号的寄存器)
2 (邻近的 – 对齐到偶数编号的寄存器)
2 (邻近的 – 对齐到以 4 的倍数编号的寄存器)
结构中 2 个字节使用 1 个寄存器
参数存放到可用的第一批 (个)对齐的邻近寄存器中。如果需要的话,调用函数必须
保存参数。结构没有任何对齐限制;如果有足够的寄存器来保存整个结构,结构参数
将占用寄存器。函数结果存储在从 W0 开始的连续寄存器中。
4.12.1 函数参数
前八个工作寄存器 (W0-W7 )用于存储函数参数。参数以自左向右的顺序分配到寄存
器中,且参数被分配到对齐适当的第一个可用寄存器中。
下面的示例中,所有参数都通过寄存器传递,尽管这些参数不是以在声明中出现的顺
序存放在寄存器中。这种格式允许 MPLAB C30 编译器最高效地使用可用的参数寄存
器。
例 4-1 : 函数调用模型
void
params0(short p0, long p1, int p2, char p3, float p4, void *p5)
{
/*
** W0 p0
** W1 p2
** W3:W2 p1
** W4 p3
** W5 p5
** W7:W6 p4
*/
...
}
DS51284E_CN 第 72 页 2006 Microchip Technology Inc.
MPLAB C30 C 编译器运行时环境
下面这个示例说明如何传递结构给函数。如果整个结构都可以存放在可用的寄存器中,
那么通过寄存器来传递结构;否则结构参数将存放在堆栈中。
例 4-2 : 函数调用模型,传递结构
typedef struct bar {
int i;
double d;
} bar;
void
params1(int i, bar b) {
/*
** W0 i
** W1 b.i
** W5:W2 b.d
*/
}
与长度可变参数列表中的省略号 (...)对应的参数不分配到寄存器中。任何不分配到
寄存器的参数都以自右向左的顺序压入堆栈。
下面的示例中,由于结构参数太大而不能存放到寄存器中。但是,这并不会禁止使用
寄存器来存放下一个参数。
例 4-3 : 函数调用模型,基于堆栈的参数
typedef struct bar {
double d,e;
} bar;
void
params2(int i, bar b, int j) {
/*
** W0 i
** stack b
** W1 j
*/
}
对存放到堆栈的参数的访问与是否创建了帧指针有关。编译器一般情况下都创建帧指
针 (除非已另外指示编译器不要这样做),将通过帧指针寄存器 (W14 )访问基于堆
栈的参数。在上面的示例中,通过 W14-22 访问 b 。已通过减去上一个 FP 的 2 个字
节,返回地址的 4 个字节,和 b 的 16 个字节,计算出相对于帧指针的偏移量为 -22
(参见图 4-6 )。
不使用帧指针时,汇编编程人员必须知晓自过程的入口开始使用了多少堆栈空间。如
果没有额外使用堆栈空间,计算与上面类似。将通过 W15-20 访问 b :4 个字节用于返
回地址, 16 个字节用于访问 b 的首地址。
2006 Microchip Technology Inc. DS51284E_CN 第 73 页
MPLAB® C30 用户指南
4.12.2 返回值
8 位或 16 位标量的函数返回值返回到 W0 中, 32 位标量的函数返回值返回到 W1:W0
中,而 64 位标量的函数返回值返回到 W3:W2:W1:W0 中。聚集通过 W0 间接返回,
W0 由调用函数设置为包含聚集值的地址。
4.12.3 调用函数时保存寄存器
对于一般的函数调用,编译器指定函数调用时保护寄存器 W8-W15 。寄存器 W0-W7
可用作暂存寄存器。对于中断函数,编译器指定保护所有必需的寄存器,即 W0-W15
和 RCOUNT 。
4.13 寄存器约定
特定寄存器在 C 运行时环境中起着特殊的作用。寄存器变量使用一个或多个工作寄存
器,参见表 4-4 。
表 4-4 : 寄存器约定
变量 工作寄存器
char, signed char, unsigned char
short, signed short, unsigned
short
int, signed int,unsigned int
void * (or any pointer)
long, signed long, unsigned long
long long, signed long long,
unsigned long long
float
double*
long double
* 如果使用了 -fno-short-double , double 等价于 long double 。
W0-W13 和 W14 (如果没有用作帧指针的话)。
W0-W13 和 W14 (如果没有用作帧指针的话)。
W0-W13 和 W14 (如果没有用作帧指针的话)。
W0-W13 和 W14 (如果没有用作帧指针的话)。
一对邻近的寄存器,第一个寄存器是 {W0, W2,
W4, W6, W8, W10, W12} 之一。低编号的寄存器
包含值的最低 16 位。
四个邻近的寄存器,第一个寄存器是 {W0, W4,
W8} 之一。低编号的寄存器包含值的最低 16
位。接着的较高编号寄存器包含接着的较高位。
一对邻近的寄存器,第一个寄存器是 {W0, W2,
W4, W6, W8, W10, W12} 之一。低编号的寄存器
包含值的最低 16 位。
四个邻近的寄存器,第一个寄存器是 {W0, W2,
W4, W6, W8, W10, W12} 之一。低编号的寄存器
包含值的最低 16 位。
四个邻近的寄存器,第一个寄存器是 {W0, W4,
W8} 之一。低编号的寄存器包含值的最低 16
位。
DS51284E_CN 第 74 页 2006 Microchip Technology Inc.
4.14 位反转寻址和模寻址
编译器并不直接支持位反转寻址和模寻址的使用。如果对一个寄存器使能了这两种寻
址模式之一,那么编程人员要确保编译器不将该寄存器用作指针。当使能这两种寻址
模式之一时,在产生中断时要特别小心。
可以在 C 中定义将在存储器中对齐适当的数组用于通过汇编语言函数进行模寻址。
aligned 属性可用于定义用作递增模缓冲区的数组。 reverse 属性可用于定义用作
递减模缓冲区的数组。 关于这些属性的详细信息,请参阅第 2.3 节 “关键字差别”。
关于模寻址的更多信息,请参阅
3 章。
4.15 程序空间可视性 (PSV )的使用
默认情况下,编译器自动将字符串和 const 限定的未初始化变量分配到映射到 PSV
窗口的 .const 段。然后 PSV 管理由编译器进行管理,编译器不会移动 PSV ,将可
访问程序存储区的大小限制为 PSV 窗口本身的大小。
或者,应用程序可控制 PSV 窗口来完成自己的功能。在应用程序直接控制 PSV 使用
的优点是,这比将一个 .const 段永久映射到 PSV 窗口更为灵活。缺点是,应用程序
必须管理 PSV 控制寄存器和位。指定 -mconst-in-data 选项来指示编译器不要使
用 PSV 窗口。
space 属性可用来定义在 PSV 窗口中使用的变量 。为指定某些变量分配到编译器管理
的段 .const 中,使用属性 space(auto_psv) 。为将用于 PSV 访问的变量分配到
不由编译器管理的段中,使用属性 space(psv) 。关于这些属性的更多信息,请参阅
第 2.3 节 “关键字差别”。
关于 PSV 使用的更多信息,请参阅
用户指南》
(DS51317D_CN )。
MPLAB C30 C 编译器运行时环境
《
dsPIC30F
《
MPLAB® ASM30、MPLAB LINK30
系列参考手册》
(DS70046D_CN )的第
和实用程序
2006 Microchip Technology Inc. DS51284E_CN 第 75 页
MPLAB® C30 用户指南
注:
DS51284E_CN 第 76 页 2006 Microchip Technology Inc.
5.1 简介
5.2 主要内容
5.3 数据表示
MPLAB® C30
用户指南
第 5 章 数据类型
本章讲述 MPLAB C30 的数据类型。
本章讲述的内容包括:
• 数据表示
• 整型
• 浮点型
• 指针
多字节量以 “ little endian”格式存储,即:
• 低字节存储在低地址中
• 低位存储在编号低的位地址中
例如, 0x12345678 在地址 0x100 中存储如下:
5.4 整型
0x100 0x78 0x56 0x101
0x102 0x34 0x12 0x103
而 0x12345678 在寄存器 W4 和 W5 中存储如下:
W4 W5
0x5678 0x1234
表 5-1 列出了 MPLAB C30 所支持的整型数据类型。
表 5-1 : 整型数据类型
类型 位 最小值 最大值
char, signed char 8- 1 2 81 2 7
unsigned char 802 5 5
short, signed short 16 -32768 32767
unsigned short 16 0 65535
int, signed int 16 -32768 32767
unsigned int 16 0 65535
long, signed long 32 -2
unsigned long 32 0 2
long long**, signed long long** 64 -2
unsigned long long** 64 0 2
** ANSI-89 扩展
31
63
231 - 1
32
- 1
263 - 1
64
- 1
关于实现定义的整型的信息,请参阅第 A.6 节“整型”。
2006 Microchip Technology Inc. DS51284E_CN 第 77 页
MPLAB® C30 用户指南
5.5 浮点型
MPLAB C30 使用 IEEE-754 格式。表 5-2 列出了所支持的浮点型数据类型。
表 5-2 : 浮点型数据类型
类型 位
float 32 -126 127 2
double* 32 -126 127 2
long double 64 -1022 1023 2
E = 指数
N = 归一化的 (近似值)
* 如果使用 -fno-short-double , double 等价于 long double 。
关于实现定义的浮点型数的更多信息,请参阅第 A.7 节 “浮点型”。
5.6 指针
所有 MPLAB C30 指针都是 16 位宽的。这对于整个数据空间 (64 KB )的访问和小代
码模型 (32 K 字的代码)足够了。在大代码模型 (大于 32 K 字的代码)中,指针可
解析为 “句柄”;即,指针是位于程序空间前 32 K 字的 GOTO 指令的地址。
E 最小值 E 最大值 N 最小值 N 最大值
-126
-126
-1022
2
2
2
128
128
1024
DS51284E_CN 第 78 页 2006 Microchip Technology Inc.
6.1 简介
本章讲述为支持 MPLAB C30 编译使用的器件支持文件。
6.2 主要内容
本章讨论的内容包括:
• 处理器头文件
• 寄存器定义文件
• 使用特殊功能寄存器
• 使用宏
• 从 C 代码访问 EEDATA——仅适用于 dsPIC30F DSC
6.3 处理器头文件
处理器头文件随语言工具提供。这些头文件定义了每个 dsPIC DSC 器件中可用的特殊
功能寄存器 (SFR )。要在 C 中使用头文件,使用:
#include <p30fxxxx.h>
其中 xxxx 对应器件的型号。 C 头文件包含在 support\h 目录中。
为使用特殊功能寄存器名 (如 CORCONbits ),必须包含头文件。
MPLAB® C30
用户指南
第 6 章 器件支持文件
例如下面的模块,是为 PIC30F2010 器件编写的,包括两个函数:一个函数用于使能
PSV 窗口,另一个函数用于禁止 PSV 窗口。
#include <p30f2010.h>
void
EnablePSV(void)
{
CORCONbits.PSV = 1;
}
void
DisablePSV(void)
{
CORCONbits.PSV = 0;
}
2006 Microchip Technology Inc. DS51284E_CN 第 79 页
MPLAB® C30 用户指南
处理器头文件的约定是,使用器件数据手册中的寄存器名对每一个 SFR 命名。例如,
CORCON 指内核控制寄存器。如果 SFR 中有一些重要的位,因此头文件中还有为该
SFR 定义的结构,结构名与 SFR 的名字相同,只是在后面附加了 “ bits”。例如,
CORCONbits 是内核控制寄存器的结构。使用数据手册中位的名字命名结构中的各位
(或位域),如 PSV 表示 CORCON 寄存器中的 PSV 位。下面是对 CORCON 的完整定
义 (将来可能会有所变化):
/* CORCON: CPU Mode control Register */
extern volatile unsigned int CORCON
typedef struct tagCORCONBITS {
unsigned IF :1; /* Integer/Fractional mode */
unsigned RND :1; /* Rounding mode */
unsigned PSV :1; /* Program Space Visibility enable */
unsigned IPL3 :1;
unsigned ACCSAT :1; /* Acc saturation mode */
unsigned SATDW :1; /* Data space write saturation enable */
unsigned SATB :1; /* Acc B saturation enable */
unsigned SATA :1; /* Acc A saturation enable */
unsigned DL :3; /* DO loop nesting level status */
unsigned :4;
} CORCONBITS;
extern volatile CORCONBITS CORCONbits
注: 符号 CORCON 和 CORCONbits 指同一个寄存器,在链接时将解析为同一
地址。
__attribute__(( __near__));
__attribute__((__ near__));
6.4 寄存器定义文件
第 6.3 节 “处理器头文件” 中描述的处理器头文件指定了每个器件的所有 SFR,但并
未定义 SFR 的地址。 support\gld 目录中有每个器件的链接描述文件。链接描述文
件定义了 SFR 的地址。要使用链接描述文件,指定链接器命令行选项:
-T p30fxxxx.gld
其中 xxxx 指器件的型号。
例如,假定有一个名为 app2010.c 的文件,它包含 PIC30F2010 器件的一个应用程
序,则可使用下面的命令行编译和链接这个文件:
pic30-gcc -o app2010.o -T p30f2010.gld app2010.c
-o 命令行选项命名输出 COFF 可执行文件, -T 选项给出 PIC30F2010 器件的名称。
如果在当前的目录中找不到 p30f2010.gld ,链接器将在已知的库路径中搜索。对于
默认的安装,链接描述文件包含在 PIC30_LIBRARAY_PATH 中。更多信息参见第 3.6
节 “环境变量”。
DS51284E_CN 第 80 页 2006 Microchip Technology Inc.
6.5 使用特殊功能寄存器
在应用程序中使用特殊功能寄存器时要遵循以下三个步骤:
1. 包含所使用器件的 处理器头文件。这样能提供该型号器件特殊功能寄存器的源
代码。例如,下面的语句包含了 PIC30F6014 器件的头文件:
#include <p30f6014.h>
2. 像访问任何其他 C 变量一样访问特殊功能寄存器。源代码可对特殊功能寄存器进
行读和写。
例如,下面的语句将 Timer1 特殊功能寄存器中的所有位清零。
TMR1 = 0;
下面一条语句中的 T1CONbits.TON 表示 T1CON 寄存器中的第 15 位,即 “定时
器开启”位。这条语句将名为 TON 的位置 1 来启动定时器。
T1CONbits.TON = 1;
3. 链接相应器件的寄存器定义文件或链接描述文件。链接器提供特殊功能寄存器的
地址 (请记住在链接时位结构具有和 SFR 相同的地址)。 例 6.1 将使用:
p30f6014.gld
关于使用链接描述文件的更多信息,请参阅
实用程序用户指南》
下面的例子是实时时钟的示例代码。它使用了几个特殊功能寄存器。这些特殊功能寄
存器的描述参见 p30f6014.h 文件。该文件将和特定于器件的链接描述文件
p30f6014.gld 相链接。
(DS51317D_CN )。
器件支持文件
《
MPLAB® ASM30、MPLAB LINK30
和
2006 Microchip Technology Inc. DS51284E_CN 第 81 页
MPLAB® C30 用户指南
例 6-1 : 实时时钟示例代码
/*
** Sample Real Time Clock for dsPIC
**
** Uses Timer1, TCY clock timer mode
** and interrupt on period match
*/
#include <p30f6014.h>
/* Timer1 period for 1 ms with FOSC = 20 MHz */
#define TMR1_PERIOD 0x1388
struct clockType
{
unsigned int timer; /* countdown timer, milliseconds */
unsigned int ticks; /* absolute time, milliseconds */
unsigned int seconds; /* absolute time, seconds */
} volatile RTclock;
void reset_clock(void)
{
RTclock.timer = 0; /* clear software registers */
RTclock.ticks = 0;
RTclock.seconds = 0;
TMR1 = 0; /* clear timer1 register */
PR1 = TMR1_PERIOD; /* set period1 register */
T1CONbits.TCS = 0; /* set internal clock source */
IPC0bits.T1IP = 4; /* set priority level */
IFS0bits.T1IF = 0; /* clear interrupt flag */
IEC0bits.T1IE = 1; /* enable interrupts */
SRbits.IPL = 3; /* enable CPU priority levels 4-7*/
T1CONbits.TON = 1; /* start the timer*/
}
__attribute__((__ interrupt__)) _T1Interrupt(void)
void
{ static int sticks=0;
if (RTclock.timer > 0) /* if countdown timer is active */
RTclock.timer -= 1; /* decrement it */
RTclock.ticks++; /* increment ticks counter */
if (sticks++ > 1000)
{ /* if time to rollover */
sticks = 0; /* clear seconds ticks */
RTclock.seconds++; /* and increment seconds */
}
IFS0bits.T1IF = 0; /* clear interrupt flag */
return;
}
DS51284E_CN 第 82 页 2006 Microchip Technology Inc.
6.6 使用宏
器件支持文件
处理器头文件除定义了特殊功能寄存器外,还为 dsPIC30F 系列数字信号控制器定义
了有用的宏。
6.6.1 配置位设置宏
提供了可用来设置配置位的宏。例如,为使用宏设置 FOSC 位,可在 C 源代码开头前
插入下面的代码:
_FOSC(CSW_FSCM_ON & EC_PLL16);
这将使能外部时钟, PLL 设置为 16x 。同时使能时钟切换和时钟故障保护监测。
同样,设置 FBORPOR 位:
_FBORPOR(PBOR_ON & BORV_27 & PWRT_ON_64 & MCLR_DIS);
这将使能 2.7 V 的欠压复位,将上电延时定时器初始化为 64 ms ,并将 MCLR 引脚配
置为普通 I/O 口。
每个配置位的设置列表,参见处理器头文件。
6.6.2 行内汇编使用的宏
下面列出了用于在 C 中定义汇编代码的宏:
#define Nop() {__asm__ volatile ("nop");}
#define ClrWdt() {
#define Sleep() {
#define Idle() {
__asm__ volatile ("clrwdt");}
__asm__ volatile ("pwrsav #0");}
__asm__ volatile ("pwrsav #1");}
6.6.3 数据存储器分配宏
本节讲述可用于分配数据存储空间的宏。有两种类型:需要参数的宏和不需要参数的
宏。
下面的宏需要一个参数 N 来指定对齐。 N 必须是 2 的次幂,最小值为 2 。
#define _XBSS(N) __attribute__((space(xmemory), aligned(N)))
#define _XDATA(N)
#define _YBSS(N)
#define _YDATA(N)
#define _EEDATA(N)
例如,声明一个未初始化数组位于 X 存储区中,对齐到 32 字节地址:
int _XBSS(32) xbuf[16];
声明一个未初始化数组位于数据 EEPROM 中,没有特殊对齐方式:
int _EEDATA(2) table1[] = {0, 1, 1, 2, 3, 5, 8, 13, 21};
下面的宏不需要参数。这些宏可用于将变量分配到持久数据存储区或 near 数据存储区
中。
#define _PERSISTENT __attribute__((persistent))
#define _NEAR
例如,声明器件复位后能保留其值的两个变量:
int _PERSISTENT var1,var2;
__attribute__((space(xmemory), aligned(N)))
__attribute__((space(ymemory), aligned(N)))
__attribute__((space(ymemory), aligned(N)))
__attribute__((space(eedata), aligned(N)))
__attribute__((near))
2006 Microchip Technology Inc. DS51284E_CN 第 83 页
MPLAB® C30 用户指南
6.6.4 中断服务程序声明宏
下面的宏可用于声明中断服务程序 (ISR ):
#define _ISR __attribute__((interrupt))
#define _ISRFAST
例如,声明 timer0 中断的中断服务程序:
void _ISR _INT0Interrupt(void);
声明 SPI1 中断的快速现场保护中断服务程序:
void _ISRFAST _SPI1Interrupt(void);
注: 如果中断服务程序使用了第 7.4 节 “写中断向量”中给出的保留名,中断
服务程序的地址将自动填充到中断向量表中。
6.7 从 C 代码访问 EEDATA ——仅适用于 dsPIC30F DSC
MPLAB C30 提供了一些方便的宏定义来允许将数据存放在器件的 EE 数据区中。这实现
起来很简单:
int _EEDATA(2) user_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
user_data 将被存放在 EE 数据空间中,为给定的初值保留 10 个字。
dsPIC DSC 器件为编程人员提供了两种方法来访问这种存储区。一种方法是通过程序
空间可视性窗口。另一种方法是使用特殊机器指令 (TBLRDx )。
__attribute__((interrupt, shadow))
6.7.1 通过 PSV 访问 EEDATA
编译器通常管理 PSV 窗口来访问存储在程序存储器中的常量。否则, PSV 窗口可用于
访问 EEDATA 存储器。
要使用 PSV 窗口:
•PSVPAG 寄存器必须设置为要访问的程序存储器的正确地址。对于 EE 数据,该地
址为 0xFF ,但最好使用 __builtin_psvpage() 函数。
• 还应通过置位 CORCON 寄存器中的 PSV 位来使能 PSV 窗口。如果该位没有置位,
使用 PSV 窗口将始终读为 0x0000 。
例 6-2 :通 过PSV 访问 EEDATA
#include <p30fxxxx.h>
int main(void) {
PSVPAG =
CORCONbits.PSV = 1;
/* ... */
if (user_data[2]) ;/* do something */
}
__builtin_psvpage(&user_data);
DS51284E_CN 第 84 页 2006 Microchip Technology Inc.
器件支持文件
这些步骤仅需要执行一次。除非改变了 PSVPAG,否则可通过像普通 C 变量一样引用
EE 数据空间中的变量来读这些变量,如本例。
注: 这一访问模式与编译器管理的 PSV (-mconst-in-code )模式不兼容。
要注意防止出现冲突。
6.7.2 使用 TBLRDx 指令访问 EEDATA
编译器不直接支持 TBLRDx 指令,但可以通过行内汇编使用这些指令。像 PSV 访问一
样,通过一个 SFR 值形成一个 23 位的地址,并将地址编码为指令的一部分。为访问
与前面示例中的存储器,可使用下面的代码:
要使用 TBLRDx 指令:
•TBLPAG 寄存器必须设置为要访问的程序存储器的正确地址。对于 EE 数据存储器,
这一地址为 0x7F ,但最好使用 __builtin_tblpage() 函数。
• TBLRDx 指令只能通过 _ _asm_ _ 语句访问。关于这一指令的信息,请参阅
《
dsPIC30F/33F
例 6-3 : 通过表读访问 EEDATA
#include <p30fxxxx.h>
#define eedata_read(src, dest) { \
register int eedata_addr; \
register int eedata_val; \
\
eedata_addr =
__asm__ ("tblrdl [%1], %0" : "=r"(eedata_val) : "r"(eedata_addr)); \
dest = eedata_val; \
}
程序员参考手册》
(DS70157B_CN )。
__builtin_tbloffset(&src); \
int main(void) {
int value;
TBLPAG =
eedata_read(user_data[2], value);
if (value) ; /* do something */
}
__builtin_tblpage(&user_data);
6.7.3 其他信息来源
《
dsPIC30F
存程序存储器和 EE 数据存储器的使用进行了很好的论述。本章也包含关于程序存储
器和 EE 数据存储器运行时编程的信息。
系列参考手册》
(DS70046D_CN )的第 5 章对 dsPIC DSC 器件提供的闪
2006 Microchip Technology Inc. DS51284E_CN 第 85 页
MPLAB® C30 用户指南
注:
DS51284E_CN 第 86 页 2006 Microchip Technology Inc.
7.1 简介
7.2 主要内容
MPLAB® C30
用户指南
第 7 章 中断
中断处理对于大多数单片机应用来说都是很重要的一个方面。中断用来使软件操作与
实时发生的事件同步。当发生中断时,软件的正常执行流程被打断,调用专门的函数
来处理事件。当中断处理结束时,恢复先前的现场信息并继续正常执行流程。
dsPIC30F 器件支持多个内部和外部中断源。另外,允许高优先级中断中断任何正在处
理的低优先级中断。
MPLAB C30 编译器完全支持在 C 或行内汇编代码中进行中断处理。本章将对中断处
理做一个概括介绍。
本章讨论的主题包括:
• 编写中断服务程序 — 可以将一个或多个 C 函数指定为中断服务程序(ISR ),在 发
生中断时调用。为了获得最好的性能,通常将长的计算或需要调用库函数的操作放
在主应用程序中。当中断事件发生很快时,这种方式可以优化性能并最大程度降低
信息丢失的可能性。
• 写中断向量 — 当发生中断时, dsPIC30F 器件使用中断向量来转移应用控制。中断
向量是程序存储器中的专用地址,指定 ISR 的地址。为使用中断,应用必须在这
些地址中包含有效的函数地址。
• 中断服务程序现场保护 — 为了保证从中断返回到代码后,条件状态与中断前相
同,必须保护特定寄存器的现场信息。
• 中断响应时间 — 从中断事件发生到执行 ISR 第一条指令之间的时间就是中断响应
时间。
• 中断嵌套 — MPLAB C30 支持中断嵌套。
• 允许 / 禁止中断 — 通过两种方式允许和禁止中断源:全局允许和单独允许。
• 中断服务程序和一般代码共用存储空间 — 采用这种方法时如何降低潜在的危险。
2006 Microchip Technology Inc. DS51284E_CN 第 87 页
MPLAB® C30 用户指南
7.3 编写中断服务程序
可以根据本节提供的要领,仅使用 C 语言语法结构编写所有应用代码,其中包括中断
服务程序。
7.3.1 编写中断服务程序的要领
编写 ISR 的要领为:
• 不带参数并以 void 返回值类型声明 ISR (强制)
• 不要通过一般程序调用 ISR (强制)
• 不要用 ISR 调用其他函数 (建议)
MPLAB C30 的 ISR 和任何其他 C 函数一样,可以有局部变量,可以访问全局变量。
但是, ISR 需要声明为没有参数,没有返回值。这是必须的,因为 ISR 作为对硬件中
断或陷阱的响应,对它的调用与一般 C 程序异步 (即 ISR 不是按通常的方式调用的,
因此不能有参数和返回值)。
ISR 只能通过硬件中断或陷阱调用,不能通过其他 C 函数调用。 ISR 使用中断返回
(RETFIE )指令退出函数,而不是使用一般的 RETURN 指令。不恢复现场使用
RETFIE 指令退出中断服务程序会破坏处理器资源,如 Status 寄存器的值。
最后,由于中断响应时间的原因,建议不要使用 ISR 调用其他函数。更多信息请参阅
第 7.6 节 “中断响应时间” 。
7.3.2 编写中断服务程序的语法
为将 C 函数声明为中断服务程序,指定函数的 interrupt 属性 (参见第 2.3 节中关于
__attribute__ 关键字的描述)。 interrupt 属性的语法如下:
attribute__((interrupt [(
__
[ save(symbol-list )]
[, irq(irqid )]
[, altirq(altirqid )]
[, preprologue(asm )]
)]
))
可以在 interrupt 属性名和参数名的前后加下划线字符。因此, interrupt 和
__interrupt__ 是等价的, save 和 __save__ 也是等价的。
可选的 save 参数指定进入和退出 ISR 时需要保护和恢复的一个或多个变量。变量名
列表包含在括号内,变量名中间用逗号分隔开。
如果不想导出全局变量的值,应该保护可能在 ISR 中修改的全局变量。被 ISR 修改的
全局变量应该用 volatile 限定。
可选的 irq 参数允许将一个中断向量对应于一个特定的中断,可选的 altirq 参数允
许将一个中断向量对应于一个指定的备用中断。每个参数都需要一个括号括起来的中
断 ID 号。(参阅第 7.4 节 “写中断向量”中的中断 ID 列表。)
可选的 preprologue 参数允许在生成的代码中,编译器生成的函数 prologue 前插入
汇编语句。
DS51284E_CN 第 88 页 2006 Microchip Technology Inc.
中断
7.3.3 为中断服务程序编写代码
下面的原型声明了函数 isr0 为中断服务程序:
void __ attribute__(( __interrupt__ )) isr0(void);
由原型可以看出,中断函数必须不带参数,没有返回值。如果需要的话,编译器将保
护所有工作寄存器,以及 Status 寄存器和重复计数寄存器。课通过将其他变量指定为
interrupt 属性的参数保护这些变量。例如,要使编译器自动保护和恢复变量 var1 和
var2,使用下面的原型:
void __ attribute__(( __interrupt__ (__save__(var1,var2))))
isr0(void);
为请求编译器使用快速现场保护 (使用 push.s 和 pop.s 指令),指定函数的
shadow 属性 (参阅第 2.3.2 节 “指定函数的属性”)。例如:
void __ attribute__(( __interrupt__ , __shadow__ )) isr0(void);
7.3.4 使用宏声明简单的中断服务程序
如果一个中断服务程序不需要 interrupt 属性的任何可选参数,则可使用简单的语法。
在针对器件的头文件中定义了下面的宏:
#define _ISR __attribute__((interrupt))
#define _ISRFAST
例如,声明 timer0 中断的中断服务程序:
#include <p30fxxxx.h>
void _ISR _INT0Interrupt(void);
用快速现场保护声明 SPI1 中断的中断服务程序:
#include <p30fxxxx.h>
void _ISRFAST _SPI1Interrupt(void);
__attribute__((interrupt, shadow))
2006 Microchip Technology Inc. DS51284E_CN 第 89 页
MPLAB® C30 用户指南
7.4 写中断向量
dsPIC30F/33F DSC 和PIC24F/H MCU 器件有两个中断向量表 — 主表和备用表 — 每个
表都包含若干异常向量。
异常源有主异常向量和备用异常向量与之相关联,每个向量占据一个程序字,如下面
这些表所示。当 INTCON2 寄存器中的 ALTIVT 位置位时,使用备用向量名。
注: 器件复位不通过中断向量表处理。而是在器件复位时,清零程序计数器。
这使处理器从地址 0 处开始执行。按照约定,链接描述文件在该地址处构
建 GOTO 指令来转移控制到 C 运行时启动模块。
• 表 7-1 中断向量—— dsPIC30F DSC (非 SMPS)
• 表 7-2 中断向量—— dsPIC30F DSC ( SMPS)
• 表 7-3 中断向量—— PIC24F MCU
• 表 7-4 中断向量—— dsPIC33F DSC/PIC24H MCU
表 7-1: 中断向量—— dsPIC30F DSC (非 SMPS)
IRQ# 主向量名 备用向量名 向量函数
N/A _ReservedTrap0 _AltReservedTrap0 保留
N/A _OscillatorFail _AltOscillatorFail 振荡器故障陷阱
N/A _AddressError _AltAddressError 地址错误陷阱
N/A _StackError _AltStackError 堆栈错误陷阱
N/A _MathError _AltMathError 数学错误陷阱
N/A _ReservedTrap5 _AltReservedTrap5 保留
N/A _ReservedTrap6 _AltReservedTrap6 保留
N/A _ReservedTrap7 _AltReservedTrap7 保留
0 _INT0Interrupt _AltINT0Interrupt INT0 外部中断 0
1 _IC1Interrupt _AltIC1Interrupt IC1 输入捕捉 1
2 _OC1Interrupt _AltOC1Interrupt OC1 输出比较 1
3 _T1Interrupt _AltT1Interrupt TMR1 Timer 1 超时
4 _IC2Interrupt _AltIC2Interrupt IC2 输入捕捉 2
5 _OC2Interrupt _AltOC2Interrupt OC2 输出比较 2
6 _T2Interrupt _AltT2Interrupt TMR2 Timer 2 超时
7 _T3Interrupt _AltT3Interrupt TMR3 Timer 3 超时
8 _SPI1Interrupt _AltSPI1Interrupt SPI1 串行外设接口 1
9 _U1RXInterrupt _AltU1RXInterrupt UART1RX Uart 1 接收器
10 _U1TXInterrupt _AltU1TXInterrupt UART1TX Uart 1 发送器
11 _ADCInterrupt _AltADCInterrupt ADC 转换完成
12 _NVMInterrupt _AltNVMInterrupt NMM NVM 写完成
13 _SI2CInterrupt _AltSI2CInterrupt 从 I
14 _MI2CInterrupt _AltMI2CInterrupt 主 I
15 _CNInterrupt _AltCNInterrupt CN 输入变化中断
16 _INT1Interrupt _AltINT1Interrupt INT1 外部中断 1
17 _IC7Interrupt _AltIC7Interrupt IC7 输入捕捉 7
18 _IC8Interrupt _AltIC8Interrupt IC8 输入捕捉 8
19 _OC3Interrupt _AltOC3Interrupt OC3 输出比较 3
2
C™ 中断
2
C™ 中断
DS51284E_CN 第 90 页 2006 Microchip Technology Inc.
表 7-1: 中断向量—— dsPIC30F DSC (非 SMPS)(续)
IRQ# 主向量名 备用向量名 向量函数
20 _OC4Interrupt _AltOC4Interrupt OC4 输出比较 4
21 _T4Interrupt _AltT4Interrupt TMR4 Timer 4 超时
22 _T5Interrupt _AltT5Interrupt TMR5 Timer 5 超时
23 _INT2Interrupt _AltINT2Interrupt INT2 外部中断 2
24 _U2RXInterrupt _AltU2RXInterrupt UART2RX Uart 2 接收器
25 _U2TXInterrupt _AltU2TXInterrupt UART2TX Uart 2 发送器
26 _SPI2Interrupt _AltSPI2Interrupt SPI2 串行外设接口 2
27 _C1Interrupt _AltC1Interrupt CAN1 组合 IRQ
28 _IC3Interrupt _AltIC3Interrupt IC3 输入捕捉 3
29 _IC4Interrupt _AltIC4Interrupt IC4 输入捕捉 4
30 _IC5Interrupt _AltIC5Interrupt IC5 输入捕捉 5
31 _IC6Interrupt _AltIC6Interrupt IC6 输入捕捉 6
32 _OC5Interrupt _AltOC5Interrupt OC5 输出比较 5
33 _OC6Interrupt _AltOC6Interrupt OC6 输出比较 6
34 _OC7Interrupt _AltOC7Interrupt OC7 输出比较 7
35 _OC8Interrupt _AltOC8Interrupt OC8 输出比较 8
36 _INT3Interrupt _AltINT3Interrupt INT3 外部中断 3
37 _INT4Interrupt _AltINT4Interrupt INT4 外部中断 4
38 _C2Interrupt _AltC2Interrupt CAN2 组合 IRQ
39 _PWMInterrupt _AltPWMInterrupt PWM 周期匹配
40 _QEIInterrupt _AltQEIInterrupt QEI 位置计数器比较
41 _DCIInterrupt _AltDCIInterrupt DCI CODEC 传输完成
42 _LVDInterrupt _AltLVDInterrupt PLVD 检测到低电压
43 _FLTAInterrupt _AltFLTAInterrupt FLTA MCPWM 故障 A
44 _FLTBInterrupt _AltFLTBInterrupt FLTB MCPWM 故障 B
45 _Interrupt45 _AltInterrupt45 保留
46 _Interrupt46 _AltInterrupt46 保留
47 _Interrupt47 _AltInterrupt47 保留
48 _Interrupt48 _AltInterrupt48 保留
49 _Interrupt49 _AltInterrupt49 保留
50 _Interrupt50 _AltInterrupt50 保留
51 _Interrupt51 _AltInterrupt51 保留
52 _Interrupt52 _AltInterrupt52 保留
53 _Interrupt53 _AltInterrupt53 保留
中断
表 7-2 : 中断向量——dsPIC30F DSC (SMPS )
IRQ# 主向量名 备用向量名 向量函数
N/A _ReservedTrap0 _AltReservedTrap0 保留
N/A _OscillatorFail _AltOscillatorFail 振荡器故障陷阱
N/A _AddressError _AltAddressError 地址错误陷阱
N/A _StackError _AltStackError 堆栈错误陷阱
N/A _MathError _AltMathError 数学错误陷阱
N/A _ReservedTrap5 _AltReservedTrap5 保留
N/A _ReservedTrap6 _AltReservedTrap6 保留
N/A _ReservedTrap7 _AltReservedTrap7 保留
2006 Microchip Technology Inc. DS51284E_CN 第 91 页
MPLAB® C30 用户指南
表 7-2 : 中断向量——dsPIC30F DSC (SMPS )(续)
IRQ# 主向量名 备用向量名 向量函数
0 _INT0Interrupt _AltINT0Interrupt INT0 外部中断 0
1 _IC1Interrupt _AltIC1Interrupt IC1 输入捕捉 1
2 _OC1Interrupt _AltOC1Interrupt OC1 输出比较 1
3 _T1Interrupt _AltT1Interrupt TMR1 Timer 1 超时
4 _Interrupt4 _AltInterrupt4 保留
5 _OC2Interrupt _AltOC2Interrupt OC2 输出比较 2
6 _T2Interrupt _AltT2Interrupt TMR2 Timer 2 超时
7 _T3Interrupt _AltT3Interrupt TMR3 Timer 3 超时
8 _SPI1Interrupt _AltSPI1Interrupt SPI1 串行外设接口 1
9 _U1RXInterrupt _AltU1RXInterrupt UART1RX Uart 1 接收器
10 _U1TXInterrupt _AltU1TXInterrupt UART1TX Uart 1 发送器
11 _ADCInterrupt _AltADCInterrupt ADC 转换完成
12 _NVMInterrupt _AltNVMInterrupt NMM NVM 写完成
13 _I2CInterrupt _AltI2CInterrupt I
14 _I2CErrInterrupt _AltI2CErrInterrupt I2C™ 错误中断
15 _Interrupt15 _AltInterrupt15 保留
16 _INT1Interrupt _AltINT1Interrupt INT1 外部中断 1
17 _INT2Interrupt _AltINT2Interrupt INT2 外部中断 2
18 _PWMSpEvent
MatchInterrupt
19 _PWM1Interrupt _AltPWM1Interrupt PWM 周期匹配 1
20 _PWM2Interrupt _AltPWM2Interrupt PWM 周期匹配 2
21 _PWM3Interrupt _AltPWM3Interrupt PWM 周期匹配 3
22 _PWM4Interrupt _AltPWM4Interrupt PWM 周期匹配 4
23 _Interrupt23 _AltInterrupt23 保留
24 _Interrupt24 _AltInterrupt24 保留
25 _Interrupt25 _AltInterrupt25 保留
26 _Interrupt26 _AltInterrupt26 保留
27 _Interrupt27 _AltInterrupt27 保留
28 _Interrupt28 _AltInterrupt28 保留
29 _CMP1Interrupt _AltCMP1Interrupt 模拟比较器中断 1
30 _CMP2Interrupt _AltCMP2Interrupt 模拟比较器中断 2
31 _CMP3Interrupt _AltCMP3Interrupt 模拟比较器中断 3
32 _CMP4Interrupt _AltCMP4Interrupt 模拟比较器中断 4
33 _Interrupt33 _AltInterrupt33 保留
34 _Interrupt34 _AltInterrupt34 保留
35 _Interrupt35 _AltInterrupt35 保留
36 _Interrupt36 _AltInterrupt36 保留
37 _Interrupt37 _AltInterrupt37 保留
38 _Interrupt38 _AltInterrupt38 保留
39 _Interrupt39 _AltInterrupt39 保留
40 _Interrupt40 _AltInterrupt40 保留
41 _Interrupt41 _AltInterrupt41 保留
42 _Interrupt42 _AltInterrupt42 保留
43 _Interrupt43 _AltInterrupt43 保留
_AltPWMSpEvent
MatchInterrupt
2
C™ 中断
PWM 特殊事件中断
DS51284E_CN 第 92 页 2006 Microchip Technology Inc.
表 7-2: 中断向量—— dsPIC30F DSC ( SMPS)(续)
IRQ# 主向量名 备用向量名 向量函数
44 _Interrupt44 _AltInterrupt44 保留
45 _Interrupt45 _AltInterrupt45 保留
46 _Interrupt46 _AltInterrupt46 保留
47 _Interrupt47 _AltInterrupt47 保留
48 _Interrupt48 _AltInterrupt48 保留
49 _Interrupt49 _AltInterrupt49 保留
50 _Interrupt50 _AltInterrupt50 保留
51 _Interrupt51 _AltInterrupt51 保留
52 _Interrupt52 _AltInterrupt52 保留
53 _Interrupt53 _AltInterrupt53 保留
表 7-3: 中断向量—— PIC24F MCU
IRQ# 主向量名 备用向量名 向量函数
N/A _ReservedTrap0 _AltReservedTrap0 保留
N/A _OscillatorFail _AltOscillatorFail 振荡器故障陷阱
N/A _AddressError _AltAddressError 地址错误陷阱
N/A _StackError _AltStackError 堆栈错误陷阱
N/A _MathError _AltMathError 数学错误陷阱
N/A _ReservedTrap5 _AltReservedTrap5 保留
N/A _ReservedTrap6 _AltReservedTrap6 保留
N/A _ReservedTrap7 _AltReservedTrap7 保留
0 _INT0Interrupt _AltINT0Interrupt INT0 外部中断 0
1 _IC1Interrupt _AltIC1Interrupt IC1 输入捕捉 1
2 _OC1Interrupt _AltOC1Interrupt OC1 输出比较 1
3 _T1Interrupt _AltT1Interrupt TMR1 Timer 1 超时
4 _Interrupt4 _AltInterrupt4 保留
5 _IC2Interrupt _AltIC2Interrupt IC2 输入捕捉 2
6 _OC2Interrupt _AltOC2Interrupt OC2 输出比较 2
7 _T2Interrupt _AltT2Interrupt TMR2 Timer 2 超时
8 _T3Interrupt _AltT3Interrupt TMR3 Timer 3 超时
9 _SPI1ErrInterrupt _AltSPI1ErrInterrupt SPI1 错误中断
10 _SPI1Interrupt _AltSPI1Interrupt SPI1 传输完成中断
11 _U1RXInterrupt _AltU1RXInterrupt UART1RX Uart 1 接收器
12 _U1TXInterrupt _AltU1TXInterrupt UART1TX Uart 1 发送器
13 _ADC1Interrupt _AltADC1Interrupt ADC 1 转换完成
14 _Interrupt14 _AltInterrupt14 保留
15 _Interrupt15 _AltInterrupt15 保留
2
16 _SI2C1Interrupt _AltSI2C1Interrupt 从 I
17 _MI2C1Interrupt _AltMI2C1Interrupt 主 I
18 _CompInterrupt _AltCompInterrupt 比较器中断
19 _CNInterrupt _AltCNInterrupt CN 输入变化中断
20 _INT1Interrupt _AltINT1Interrupt INT1 外部中断 1
21 _Interrupt21 _AltInterrupt21 保留
22 _Interrupt22 _AltInterrupt22 保留
23 _Interrupt23 _AltInterrupt23 保留
C™ 中断 1
2
C™ 中断 1
中断
2006 Microchip Technology Inc. DS51284E_CN 第 93 页
MPLAB® C30 用户指南
表 7-3 : 中断向量——PIC24F MCU (续)
IRQ# 主向量名 备用向量名 向量函数
24 _Interrupt24 _AltInterrupt24 保留
25 _OC3Interrupt _AltOC3Interrupt OC3 输出比较 3
26 _OC4Interrupt _AltOC4Interrupt OC4 输出比较 4
27 _T4Interrupt _AltT4Interrupt TMR4 Timer 4 超时
28 _T5Interrupt _AltT5Interrupt TMR5 Timer 5 超时
29 _INT2Interrupt _AltINT2Interrupt INT2 外部中断 2
30 _U2RXInterrupt _AltU2RXInterrupt UART2RX Uart 2 接收器
31 _U2TXInterrupt _AltU2TXInterrupt UART2TX Uart 2 发送器
32 _SPI2ErrInterrupt _AltSPI2ErrInterrupt SPI2 错误中断
33 _SPI2Interrupt _AltSPI2Interrupt SPI2 传输完成中断
34 _Interrupt34 _AltInterrupt34 保留
35 _Interrupt35 _AltInterrupt35 保留
36 _Interrupt36 _AltInterrupt36 保留
37 _IC3Interrupt _AltIC3Interrupt IC3 输入捕捉 3
38 _IC4Interrupt _AltIC4Interrupt IC4 输入捕捉 4
39 _IC5Interrupt _AltIC5Interrupt IC5 输入捕捉 5
40 _Interrupt40 _AltInterrupt40 保留
41 _OC5Interrupt _AltOC5Interrupt OC5 输出比较 5
42 _Interrupt42 _AltInterrupt42 保留
43 _Interrupt43 _AltInterrupt43 保留
44 _Interrupt44 _AltInterrupt44 保留
45 _PMPInterrupt _AltPMPInterrupt 并行主端口中断
46 _Interrupt46 _AltInterrupt46 保留
47 _Interrupt47 _AltInterrupt47 保留
48 _Interrupt48 _AltInterrupt48 保留
49 _SI2C2Interrupt _AltSI2C2Interrupt 从 I
50 _MI2C2Interrupt _AltMI2C2Interrupt 主 I2C™ 中断 2
51 _Interrupt51 _AltInterrupt51 保留
52 _Interrupt52 _AltInterrupt52 保留
53 _INT3Interrupt _AltINT3Interrupt INT3 外部中断 3
54 _INT4Interrupt _AltINT4Interrupt INT4 外部中断 4
55 _Interrupt55 _AltInterrupt55 保留
56 _Interrupt56 _AltInterrupt56 保留
57 _Interrupt57 _AltInterrupt57 保留
58 _Interrupt58 _AltInterrupt58 保留
59 _Interrupt59 _AltInterrupt59 保留
60 _Interrupt60 _AltInterrupt60 保留
61 _Interrupt61 _AltInterrupt61 保留
62 _RTCCInterrupt _AltRTCCInterrupt 实时时钟和日历
63 _Interrupt63 _AltInterrupt63 保留
64 _Interrupt64 _AltInterrupt64 保留
65 _U1EInterrupt _AltU1EInterrupt UART1 错误中断
66 _U2EInterrupt _AltU2EInterrupt UART2 错误中断
67 _CRCInterrupt _AltCRCInterrupt 循环冗余校验
68 _Interrupt68 _AltInterrupt68 保留
2
C™ 中断 2
DS51284E_CN 第 94 页 2006 Microchip Technology Inc.