在CodeWarrior中用MemoryBanker优化代码

标签: 嵌入式  单片机  分页存储  优化

由于在暑假匆忙接收的嵌入式项目中需要使用特别大的数组,非分页RAM的内存不够用了,没办法,硬着头皮尝试使用分页RAM,但是完全没有单片机的基础,导致极其的困难。之前写程序都是按照纯软件的思维,主要考虑架构,不会考虑到每个变量具体存在哪个物理地址这么底层的问题,结果被飞思卡尔这分页地址、prm文件什么的搞得一头雾水,而网上的资料又少,讲的又大同小异的笼统,最后写出来的程序因为这分页地址的原因存在各种问题(还以为把变量放到分页RAM了,结果现在稍微懂了点回去看,发现其实很多根本还是分配在非分页区。晕倒~。但是居然还能相对正常运行也是很神奇)。这些天各种找相关的资料,结果发现在CodeWarrior的官方文档资料里其实把我想知道的都讲的很清楚了(还是官方文档给力,以后学什么东西直接找官方文档,不去到处找网上一堆零零散散的资源来学了)。本着学习的态度,将逐步把官方文档翻译一遍,供大家一起交流学习进步。

翻译的资料是公开的,我想应该不会有什么版权问题,如涉及版权问题,请联系我删除文章,原文档在这里(https://www.nxp.com/pages/codewarrior-development-studio-for-hcs12x-microcontrollers-classic-ide-v5.2:CW-HCS12X?&tab=Documentation_Tab&linkline=Users-Guides),另感谢NXP提供的学习资料。


在S12(X)项目中使用MemoryBanker

译者注:译者博客(http://blog.csdn.net/lin_strong),转载请保留这条。此为官方文档TN262,仅供学习交流使用,请勿用于商业用途。

CodeWarriorTM HC12 编译器和链接器支持对代码、数据和常量section进行自动存储分配(在这篇文档中也称为MemoryBanker)。当**这个优化时,链接器会尝试使用最优化的方式来在不同的内存区域间分配对象。对于函数来说,链接器会分析应用调用树(application call tree)以确定跨不同存储区(bank)的最优分配。
比如,假设这是你的应用调用树:
应用调用树
所有的函数都是用远调用约定来调用(CALL指令)。
在分析了应用调用树后,链接器会按下图中那样分配函数,因为这样更有效率。
应用调用树
所有红色的函数都是使用近调用约定(JSR)调用的。这会节省代码大小以及执行时间。

对于变量和常量,链接器会根据对象大小和在应用中被引用的次数来决定最优分配。

MemoryBanker是怎么工作的

需要两次的 编译-链接 来完成优化。

  • 阶段一. 在第一阶段,编译器会进行初步编译,然后链接器会将优化分配信息写到新的头文件中。
  • 阶段二. 在第二阶段,编译器使用新的include文件来再编译源码。链接器创建优化分配后的应用。然后最终的应用被链接器创建出来。
    二次编译
注意:
阶段一会输出另外(除了头文件外)两类文件:可选的包含阶段二中编译器使用的编译器选项的文件,以及包含要用在阶段二的库的名字的文本文件。高级用户可以使用这些选项,因为这些选项只用于命令行(见 从命令行**)

使用MemoryBanker的时机

通常来说MemoryBanker优化只会在项目的对象(数据或代码)无法装进16位地址空间时才可用。MemoryBanker无法优化基于small地址模型的项目。

Large地址模型十分低效

Large地址模型项目默认使用远调用约定和远数据访问,这会涉及分页切换。这样常常会导致低效率的代码。比如,甚至位于同个分页的函数也会使用远调用约定(CALL)来跳转,而不是使用更轻巧快捷的JSR指令。

地址模型间的关系(small、banked、large)

使用MemoryBanker效果最理想的是那些使用分页内存来存储数据/代码/常量的项目-典型地基于custom地址模型。
MemoryBanker代码优化还可以用于数据(常量或非常量)没有被分页存储,但是代码被分进许多代码内存页的应用 - banked地址模型。因此,MemoryBanker只可以用于在项目向导中选择”Custom memory model”或者”Banked memory model”的项目。

设备MemoryBanker支持

目前,MemoryBanker用于S12X系列,它们含有MMC模块,这个模块通过分页的方式提供了对全局8MB地址空间的访问。可使用MemoryBanker的S12X/S12XE家族成员有:

  • S12XA
  • S12XB
  • S12XD
  • S12XE
  • S12XF
  • S12XHZ
  • S12XS

哪种应用最受益于MemoryBanker

MemoryBanker的优化效果依赖于许多因素,比如:对象数、对象间的关系、对象被调用/数据访问的次数。在下表中,我们列出了常见的应用例子,以及他们可以从MemoryBanker受益多少。

+ -
通常使用large地址模型的应用 不适用分页内存的应用 - samll地址模型
经常访问或调用放在不同分页中的数据对象(变量/常量)或代码对象(函数)的应用 偶尔访问分页区数据对象或函数很少相互调用的应用
有许多分散在多个内存页的较小函数的复杂应用 包含较大的尺寸接近于分页大小的函数的应用

过程 — 怎么在我的应用中**MemoryBanker

这篇文档描述了怎么在创建新项目时或在现有的项目中使用MemoryBanker。要注意,应用的搭建时间会翻倍,因为会经过两次 编译+链接 过程。

文档描述了两种**MemoryBander的方式:从IDE和从命令行。

从项目向导(IDE)**

项目向导可以直接创建一个启用了MemoryBanker功能的“即时可用”的项目,其MemoryBanker的特性取决于选择的选项。下面会向你展示怎么创建一个带有MemoryBanker的新项目。创建的项目可以作为一个模版来使用。下图展示了项目的搭建过程中,由项目向导添加进项目的搭建工具选项产生的影响。

编译过程

步骤 1 — 使用项目向导创建一个新项目

根据项目需求以及MemoryBanker的限制,选择设备系列以及项目的其他参数。

步骤 2 — 选择支持分页内存的地址模型

Custom地址模型提供了相对于Large地址模型能产生更有效率代码的额外选项。Banked地址模型默认所有数据都使用non-banked内存。当使用banked地址模型时,MemoryBanker优化只对代码有效,对数据无效。
选择地址模型

步骤 3 — 使能MemoryBanker优化

项目向导能使MemoryBanker用于优化代码或数据或者二者。有两个勾选框用于控制MemoryBanker优化。“Data”选项能不能用取决于选择的地址模式和地址映射。
启用MemoryBanker

步骤 3a — 调整Custom地址模型

还有一些内存相关的选项可以被用来在特殊情形下加强优化效果。(见 当所有的常量或者所有非常量数据能装进本地内存时的额外优化)

步骤 4 — 项目可以使用了

生成的项目包含特殊的结构,与不使用MemoryBanker的项目有差异。target结构是最大的差异。项目包含两个target,分别叫“Standard”和“Pass 1”。“Pass 1”是“Standard”的子项,它总是先于“Standard”搭建并代表着两步搭建概念的第一阶段,而“Standard”则对应着第二阶段(见 从项目向导(IDE)**)。为了产生可执行文件,必须要选择“Standard”这个target。
两个target

注意:
项目向导不包含所有的MemoryBander选项。为了满足 项目向导地址模型对话框 中可选选项外的需求(比如,只对常量使用MemoryBanker),你需要为两个target手动调整编译器/连接器的选项。

从命令行**

后面会手把手指导你怎么让一个现存的命令行项目使用MemoryBanker。
这个指导也可以用于IDE项目,但可能创建新的IDE项目然后把文件移到新项目会更方便点。

步骤 1 — 标识将被分配的对象
你必须定义将分配到分页集合上的一个代码section名、一个数据section名和一个常量section名。假设,你想要分配一个叫DISTRIBUTE的代码section、叫CONST_DISTRIBUTE的常量section和叫DATA_DISTRIBUTE的数据section。

步骤 1.1 — 标识想要分配的函数
在你想要使用MemoryBanker分配的每个函数前加上这一行:

#pragma CODE_SEG DISTRIBUTE

想要**整个应用的存储分配只需要简单地在一个头文件中放入这一句,然后将它包含在应用中的每个源文件中。你可以使用选项 -AddIncl 来添加一个头文件到一列包含文件中。CodeWarriorTM 已经准备好了一个叫做“distribution_support.h”的头文件,它在路径 {Install}\lib\hc12c\include\distribution_support.h下,其中的{Install}指的是你的CodeWarrior安装路径。这个文件很常用于代码/数据/常量 分配。为了**“distribution_support.h”内的代码分配,需要定义宏 _DISTRIBUTE_CODE。(比如,可以添加编译器选项 -D_DISTRIBUTE_CODE)。

这样的话,重要的就是标识出应用中的那些不能被分配在分页内存上的函数。
任何必须要分配到non-banked地址的函数都不应该放在DISTRIBUTE section中。像那些CPU向量表,运行时支持函数…..之类的函数就是这种情况。如果你的应用中有这种必须确保放在 NON_BANKED 地址的函数,然后你又想在后面切换回DISTRIBUTE section的话。

你可以这样做:

#pragma push
#pragma CODE_SEG __NEAR_SEG NON_BANKED
void myInterupt(void) {
   /* 这里是中断代码 */
}
#pragma pop

同样的,会从一个汇编源文件或从一个库模块中调用的函数也不应该放在DISTRIBUTE块中。

步骤 1.2 — 标识想要分配的变量
在你想要使用MemoryBanker分配的每个变量前加上这一行:

#pragma DATA_SEG DATA_DISTRIBUTE

想要**整个应用的存储分配只需要简单地在一个头文件中放入这一句,然后将它包含在应用中的每个源文件中。你可以使用选项 -AddIncl 来添加一个头文件到一列包含文件中。CodeWarriorTM 已经准备好了一个叫做“distribution_support.h”的头文件,它在路径 {Install}\lib\hc12c\include\distribution_support.h下,其中的{Install}指的是你的CodeWarrior安装路径。这个文件很常用于代码/数据/常量 分配。为了**“distribution_support.h”内的代码分配,需要定义宏 _DISTRIBUTE_DATA。(比如,可以添加编译器选项 -D_DISTRIBUTE_DATA)。

这样的话,重要的就是标识出应用中的那些不能被分配在分页内存上的变量。
任何必须要分配到non-banked地址的变量都不应该放在DATA_DISTRIBUTE section中。
如果你的应用中有这种必须确保放在其他section的变量,然后你又想在后面切换回DATA_DISTRIBUTE section的话。

你可以这样做:

#pragma push
#pragma DATA_SEG MY_DATA
int criticalData;
#pragma pop

任何 定义在C源文件并被汇编源文件访问 或者 在库模块内的变量都不能被放在DATA_DISTRIBUTE section。

步骤 1.3 — 标识想要分配的常量
在你想要使用MemoryBanker分配的每个常量前加上这一行:

#pragma CONST_SEG CONST_DISTRIBUTE

想要**整个应用的存储分配只需要简单地在一个头文件中放入这一句,然后将它包含在应用中的每个源文件中。你可以使用选项 -AddIncl 来添加一个头文件到一列包含文件中。CodeWarriorTM 已经准备好了一个叫做“distribution_support.h”的头文件,它在路径 {Install}\lib\hc12c\include\distribution_support.h下,其中的{Install}指的是你的CodeWarrior安装路径。这个文件很常用于代码/数据/常量 分配。为了**“distribution_support.h”内的代码分配,需要定义宏 _CONST_DISTRIBUTE。(比如,可以添加编译器选项 -D_CONST_DISTRIBUTE)。

这样的话,重要的就是标识出应用中的那些不能被分配在分页内存上的常量。
任何必须要分配到non-banked地址的常量都不应该放在CONST_DISTRIBUTE section中。
如果你的应用中有这种必须确保放在其他section的常量,然后你又想在后面切换回CONST_DISTRIBUTE section的话。

你可以这样做:

#pragma push
#pragma CONST_SEG MY_CONST
Const int criticalData = 0x2355;
#pragma pop

任何 定义在C源文件并被汇编源文件访问 或者 在库模块内的常量都不能被放在CONST_DISTRIBUTE section。

步骤 2 — 修改你的PRM文件以使能存储分配
需要修改链接器PRM文件以使能存储分配
所有应该包含代码的内存区域(通常是Flash和EEPROM内存)必须赋值属性IBCC_FAR或IBCC_NEAR。

属性 描述
IBCC_FAR 英特尔存储调用约定far. 应用于分页内存的segment
IBCC_NEAR 英特尔存储调用约定near. 应用于非分页内存的segment

所有的应该包含数据或者常量(通常是RAM、Flash和EEPROM内存)的内存区域必须赋值属性DATA_FAR或DATA_NEAR。

属性 描述
DATA_FAR 通过全局寻址模式来访问符号. 应用于分页内存的segment
DATA_NEAR 通过扩展寻址来访问符号. 应用于非分页内存的segment

下面是一个PRM文件的SEGMENTS块,它使能了存储分配。在(CodeWarrior_Examples)/HCS12X/HSC12X_MemoryBanker_cmdline\prm\example.prm下有一个使能了MemoryBanker的.prm文件的例子:

SEGMENTS
   RAM = READ_WRITE DATA_NEAR 0x2000 TO 0x3FFF;
   NEAR_DATA_ROM = READ_ONLY DATA_NEAR IBCC_NEAR 0x4000 TO 0x4100;
   NEAR_CODE_ROM = READ_ONLY DATA_NEAR IBCC_NEAR 0x4101 TO 0x7FFF;
   ROM_C000 = READ_ONLY DATA_NEAR IBCC_NEAR 0xC000 TO 0xFEFF;
   RAM_F0 = READ_WRITE DATA_FAR 0xF01000 TO 0xF01FFF;
   PAGE_C0 = READ_ONLY DATA_FAR IBCC_FAR 0xC08000 TO 0xC0BFFF;
   PAGE_C1 = READ_ONLY DATA_FAR IBCC_FAR 0xC18000 TO 0xC1BFFF;
END

在你添加了以上的near和far属性后,你需要在PLACEMENT块中声明你想在哪里放置DISTRIBUTE、CONST_DISTRIBUTE、DATA_DISTRIBUTE sections。在PLACEMENT块中,你需要在需要分配的section使用关键词DISTRIBUTE_INTO。
placement块看起来是这样的:

PLACEMENT
   _PRESTART,
   STARTUP,
   ROM_VAR,
   STRINGS,
   VIRTUAL_TABLE_SEGMENT,
   NON_BANKED,
   COPY             INTO ROM_C000;
   DEFAULT_ROM      INTO PAGE_C0, PAGE_C1;
   SSTACK,
   DEFAULT_RAM      INTO RAM;
   DISTRIBUTE       DISTRIBUTE_INTO NEAR_CODE_ROM, PAGE_C0, PAGE_C1;
   CONST_DISTRIBUTE DISTRIBUTE_INTO NEAR_DATA_ROM, PAGE_C0, PAGE_C1;
   DATA_DISTRIBUTE  DISTRIBUTE_INTO RAM, RAM_F0;
END

每个需要分配的placement(DISTRIBUTE/ CONST_DISTRIBUTE/DATA_DISTRIBUTE)中至少要有一个segment是NEAR的,否则MemoryBanker优化不会工作,而且链接器会提交一个错误。

步骤 3 — 让链接器评估优化分配
为了让链接器生成与优化存储分配有关的信息,你需要给你的第一阶段的链接器添加如下选项:

选项 描述
-Dist 使能函数的存储分配
-DistSeg 声明我们想要使能分配的代码section的名字
-DistFile 声明代码的优化文件的名字。这是在第二阶段时,编译器将会使用的文件
-DistInfo 可选的。声明代码的分配信息文件的名字。如果声明了,链接器就会产生一个文本文件,里头写着存储分配后节省的代码大小
-ConstDist 使能常量的存储分配
-ConstDistSeg 声明我们想要使能分配的常量section的名字
-DataDist 使能变量的存储分配
-DataDistSeg 声明我们想要使能分配的数据section的名字
-DataDistFile 声明数据和常量的优化文件的名字。这是在第二阶段时,编译器将会使用的文件
-DataDistInfo 可选的。声明数据和常量的分配信息文件的名字。如果声明了,链接器就会产生一个文本文件,里头写着存储分配后节省的代码大小

除了上面的选项外,还有一些选项可以控制是否生成在第二阶段中使用包含额外的用于阶段二的编译器选项的文件以及包含要使用在阶段二中的库的名字的文件。

选项 描述
-Options 使能为阶段二生成编译器选项
-OptionFile 可选的。声明选项文件的名字
-LibOptions 使能为阶段二生成包含库名字的文件
-LibFile 可选的。声明阶段二使用的包含库名字的文件的名字。

对于我们的例子,必须添加以下选项到链接器命令行

-DataDist –DataDistInfodata.txt -DataDistSegDATA_DISTRIBUTE –DataDistFiledata.h -ConstDist -ConstDistSegCONST_DISTRIBUTE -Dist -DistInfocode.txt -DistSegDISTRIBUTE -DistFilecode.h

这将会:

  • 使能数据分配
  • 分配位于section DATA_DISTRIBUTE内的变量
  • 生成一个叫data.h的文件,其中包含用于第二阶段搭建的输入数据
  • 生成一个叫data.txt的文件,其中包含关于优化了多少代码大小的信息
  • 使能常量分配
  • 分配位于section CONST_DISTRIBUTE内的常量
  • 使能代码分配
  • 分配位于section DISTRIBUTE内的函数
  • 生成一个叫code.h的文件,其中包含用于第二阶段搭建的输入数据
  • 生成一个叫code.txt的文件,其中包含关于优化了多少代码大小的信息

步骤 4 — 使用步骤3的结果再编译应用
现在你需要再编译你的应用了,包括步骤3中产生的新头文件。为了这个目的,你仅仅需要在应用的每个源文件中包含进优化文件。
可以通过添加 -AddIncl选项到命令行中来实现。
在我们的例子中,我们需要添加到编译器命令行中的选项是:

-AddInclcode.h –AddIncldata.h

所有其他的那些在编译阶段一中使用的代码/数据/常量分配相关选项都不会用于阶段二。

由于MemoryBanker有可能把那些相邻实现的函数放置在不同的分页中,你还需要禁止把JSR操作码换为BSR的优化。所以我们推荐你再添加选项 -Onb=b到编译器命令行中。
由可选选项–Options和–OptionsFile生成的编译器选项文件会在步骤4中被使用。

步骤 5 — 获得最终的可执行文件
最终,你需要去掉选项-Dist并重链接你的应用以生成最终的可执行文件。

由可选的选项–LibOptions 和 –LibFile生成的包含库清单的文件应该通过使用选项–ReadLibFile 和-P2LibFile添加进去。

你可以在路径{Install}(CodeWarrior_Examples)\HCS12X\HSC12X_MemoryBanker_cmdline下找到使用MemoryBanker的例子工程。

当所有的常量或者所有非常量数据能装进本地内存时的额外优化

CodeWarrior引入了在特定条件下(比如,如果不需要的话不使用非常量数据分页,如果可能的话用BSR替代JSR)的新的内存选项,它可能能进一步优化地址访问。这些选项可以在创建应用时根据代码、常量和非常量(变量、栈……)的预计大小来选择。

注意:
MemoryBanker只在Memory Map被设置为FLASH时才可以使用。(见 步骤 3 — 让链接器评估优化分配 中的截图)

S12X本地地址

选项对内存分布的影响

如果所有的常量(或者非常量数据)都能装进本地内存中,MemoryBanker就可以把所有对常量的访问都当做访问near数据。这个特性没有整合进IDE中。所以它只可以从命令行中使用。链接器可以自动地在阶段一中为阶段二生成一些编译器选项:-ConstQualiNear、 -NonConstQualiNear 或 -Mb。(见 步骤 3 — 让链接器评估优化分配)选项应该被加到阶段二的编译器选项中去。这些选项只在所有的常量和/或非常量数据都能装进本地地址映射时才会生成。

注意:
在阶段一中如果自动生成了任意编译器选项,那么库也不得不改变。链接器能够自动地完成它。(见 从命令行** 中的步骤3-步骤5)

如果其中一个选项生成了,那么甚至通过指针的访问都会被优化,除了当他们作为函数参数使用的情况。这是因为经常会出现程序员把指向常量的指针赋值给指向非常量的指针(以及反过来用)。唯一使传递的参数获得优化的方法是总是添加一个__near声明符,这意味着用户完全负责实际传递给函数的东西。

让现有的IDE项目使用MemoryBanker

首先想清楚你现有的应用是否能受益于MemoryBanker。
基本来说,有两种方法在现有的项目上启用MemoryBanker:

  1. 修改现有的项目以创建个特殊的项目结构(IDE或makefile)并手动配置MemoryBanker。
  2. 使用CodeWarrior项目向导创建一个新的项目,然后把所有原项目的文件都转移过去(仅限于IDE项目)。
    .

由于MemoryBanker需要在.prm文件以及两个target(阶段一和阶段二)的编译器/链接器设置中修改一堆东西。我们更推荐直接新建一个启用了MemoryBanker优化的项目,而不是试图修改原来那个。
这种方法的优点是,转移先前项目的文件可以非常简单。

修改MemoryBanker项目的地址模型

在项目的开发中,你可能会遇到之前选择的地址模型和选项不再适用的情况。比如,常量和变量装不进非分页地址了。链接器在这种情况下会报错。

最简单的修改基于IDE的项目的地址模型的方法是:

  1. 使用项目向导创建一个全新的项目,根据最新的对象大小估计,配置地址模型和内存设置。
  2. 从原项目中转移所有自己的源文件和自定的搭建工具设置到新项目中。
    .

在命令行项目中改变地址模型(见 从命令行**)或直接修改现有IDE项目的地址模型十分复杂,因为需要手动修改所有编译阶段的设置。以下是如果你要手动修改地址模型 和/或 内存设置时需要的主要步骤清单:

  • pass 1 target(默认叫做“Pass 1”)的编译器设置 — 根据新地址模型和地址模型设置来修改编译器选项。
  • pass 2 target(默认叫做“Standard”)的编译器设置 — 根据新地址模型和地址模型设置来修改编译器选项。
  • ANSI库 — 有许多不同的预编译ANSI库。需要使用对应于新地址模型的那一个替换掉项目中原来的那一个(见 {Install} lib\hc12c\readme.txt 了解更多可用的库)。
  • 如果项目中包含了任何其他的库(比如. 第三方库),它们需要用应用使用的地址模型选项(-Ml或-Mb)重编译。MemoryBanker优化不能用于没有源码的库。
注意:
为了让这个过程简单一些,你可以使用项目向导创建一个新的临时项目。通过向导对话框选择新的地址模型选项。最后,替换或添加临时项目的编译器/链接器选项到你原来那个项目,替换掉原来的设置。你也可以看看向导添加进来的ANSI库,在你的项目中使用同一个。

从一个项目中移除MemoryBanker

用以下几步来禁用MemoryBanker特性:
1. 在IDE项目中移除“Pass 1”子target,或者在makefile中移除Pass 1 编译器/链接器 的行以禁用多步编译。
2. 在“Standard”target中移除所有与MemoryBanker相关的编译器/链接器选项(见 从项目向导(IDE)** 中的选项)。

局限性

  • 只有你有应用的源码时才能使用MemoryBanker。如果你只有第三方库的一个.lib文件的话是没法优化的。
  • 地址插入到CPU向量表中的函数必须分配在non-banked地址
  • 放入到DISTRIBUTE segment中的函数不能使用额外的调用约定信息。比如,下面这个是非法的:
 #pragma CODE_SEG DISTRIBUTE
 void near MyNearFunction(void) { …
  • 当你在应用中混用C和汇编时,有些要注意的。 定义在C源文件中并被汇编源文件访问的符号(变量、常量、函数)不应该放置在DISTRIBUTE section中。
  • MemoryBanker对于包含ProcessorExpert源文件的项目不起作用
  • MemoryBanker对于OSEKturbo项目不起作用
  • 目前,MemoryBanker不工作于多核XGATE项目。这是V5.0的限制。
  • MemoryBanker只应用于S12X系列,它们有MMC单元因此有分页特性以支持全局8MB寻址空间。当前只有S12X系列设备可以利用MemoryBanker(S12XA、S12XB、S12XD、S12XE、S12XF、S12XHZ、S12XS)

检查对象分配和节省的内存量

当你在使用MemoryBanker时,链接器会产生许多文本文件以帮助你检查:

  • 链接器是怎么在可用分页间分配对象的
  • 由于这个优化而节省的代码

检查对象分配

选项–DistFile 和 –DataDistFile指定的文件会包含 链接器是怎么在可用的内存分页中分配代码和数据 的信息。

这里是一个描述了代码分配的分配文件的例子:

#pragma REALLOC_OBJ "DISTRIBUTE0" main __INTERSEG_CC__
#pragma REALLOC_OBJ "DISTRIBUTE0" ("calc_banked.o") IsUnaerOp __NON_INTERSEG_CC__
#pragma REALLOC_OBJ "DISTRIBUTE0" ("calc_banked.o") Illegal __NON_INTERSEG_CC__
#pragma REALLOC_OBJ "DISTRIBUTE0" ("calc_banked.o") ReadInt __NON_INTERSEG_CC__

在上面的片段中,
- INTERSEG_CC 标识一个函数是使用CALL指令调用的(远调用约定)。
- NON_INTERSEG_CC 标识一个函数是使用JSR指令调用的(近调用约定)。

这里是一个数据和常量分配文件的例子:

#pragma REALLOC_OBJ "DATA_DISTRIBUTE0" gint __NON_FAR_DAC__
#pragma REALLOC_OBJ "DATA_DISTRIBUTE0" hint __NON_FAR_DAC__
#pragma REALLOC_OBJ "DATA_DISTRIBUTE0" fint __NON_FAR_DAC__
#pragma REALLOC_OBJ "DATA_DISTRIBUTE0" iint __NON_FAR_DAC__
#pragma REALLOC_OBJ "DATA_DISTRIBUTE0" d1 __NON_FAR_DAC__
#pragma REALLOC_OBJ "DATA_DISTRIBUTE0" c1 __NON_FAR_DAC__
#pragma REALLOC_OBJ "DATA_DISTRIBUTE0" e1 __NON_FAR_DAC__
#pragma REALLOC_OBJ "DATA_DISTRIBUTE1" a1 __FAR_DAC__

在上面的片段中,

  • FAR_DAC 标识一个变量或常量分配在banked内存区(使用全局寻址模式访问)。
  • NON_FAR_DAC 标识一个变量或常量分配在non-banked内存区(使用扩展寻址模式访问)。

检查优化节省的内存量

选项–DistInfo 和 –DataDistInfo指定的文件会包含 通过MemoryBanker节省了多少代码大小 的信息。

这里是一个描述 当优化代码分配时节省的代码 的信息文件的例子:

main old size: 97 optimized size: 92 calling convention: far
[calc.o] IsUnaerOp old size: 16 optimized size: 16 calling convention: near
[calc.o] Illegal old size: 8 optimized size: 8 calling convention: near
[calc.o] ReadInt old size: 146 optimized size: 146 calling convention: near
EVAL_Eval old size: 262 optimized size: 252 calling convention: near

在上面的代码片段中,old size - optimized size 提供了你 由于MemoryBanker优化而节省了多少内存的信息。

版权声明:本文为lin_strong原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/lin_strong/article/details/78141063

智能推荐

spring cloud netflix (07) 服务的消费者(feign)

前言 完整知识点:spring cloud netflix 系列技术栈 Feign (同步通信 HTTP通信) feign是基于接口完成服务与服务之间的通信的 搭建Feign服务 项目结构 项目搭建 pom.xml application类 application.yml 使用feign完成服务与服务之间的通信 feign是基于接口完成服务与服务之间的通信的...

AtCoder Beginner Contest 174 E.Logs

AtCoder Beginner Contest 174 E.Logs 题目链接 到最后才发现是二分,菜菜的我/(ㄒoㄒ)/~~ 我们直接二分 [1,max{a[i]}][1,max\lbrace a[i]\rbrace][1,max{a[i]}] 即可,对每一个 midmidmid,每个数 a[i]a[i]a[i] 只需要切 a[i]−1mid\frac{a[i]-1}{mid}mi...

小程序基础与实战案例

小程序开发工具与基础 小程序开发准备: 申请小程序账号( appid ) 下载并安装微信开发者工具 具体步骤如下: 先进入 微信公众平台 ,下拉页面,把鼠标悬浮在小程序图标上 然后点击 小程序开发文档 照着里面给的步骤,就可以申请到小程序账号了。 然后就可以下载 开发者工具 了 下载完打开后的界面就是这个样子 下面让我们来新建一个小程序开发项目: 在AppID输入自己刚刚注册的AppID就可以,或...

VMware centOS7 下通过minikube部署Kubernetes

1、环境准备: VMware CentOS-7-x86_64 CPU:2*2core 内存:8G 宿主机和虚拟机需网络互通,虚拟机外网访问正常 Centos发行版版本查看:cat /etc/centos-release root用户操作 2、禁用swap分区 Kubernetes 1.8开始要求关闭系统的Swap,可暂时关闭或永久禁用, 使用 $ free -m 确认swap是否为开启状态 $ s...

逻辑回归与scikit-learn

欢迎关注本人的微信公众号AI_Engine LogisticRegression 算法原理 一句话概括:逻辑回归假设数据服从伯努利分布,通过极大化似然函数(损失函数)的方法,运用梯度下降或其他优化算法来求解参数,来达到将数据二分类的目的。 定义:逻辑回归(Logistic Regression)是一种用于解决二分类(0 or 1)问题的机器学习方法,用于估计某种事物的可能性(不是概率)。比如某用户...

猜你喜欢

指针OR数组?用他们来表达字符串又有何不同?

cocowy的编程之旅 在学习C语言的过程中我们经常可以看到或者听到这样一句话:数组其实等价于指针,例如: 在这里可以轻松的看出输出后他们的值相等,其实在计算机内存里面,p为本地变量,有着他自己的作用域。而指针变量q保存着这个数组的首地址,通过*号指向这个地址保存的变量值。 然而我们再看一个例子: 这个时候计算机报错,这是为什么呢? 其实原因很简单,指针说指向的这个字符串的地址是位于计算机代码段地...

广度搜索

广度搜索的基本使用方法 广度搜索不同于深度搜索,是一种一步一步进行的过程,每一个点只记录一遍。需要用到队列记录每一步可以走到的位置,找到目标位置输出步数即可。 用到的知识:结构体、队列 如图 首先我们需要定义一个结构体来存储每个遍历到的点和步数 广搜不会用到递归,所以可以直接在主函数里写,这里需要定义一个结构体队列 初始化队列并将起始点入列 遍历 完整代码...

NIO Socket 编程实现tcp通信入门(二)

1、NIO简介 NIO面向通道和缓冲区进行工作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。可以双向传输数据,是同步非阻塞式IO。NIO还引入了选择器机制,从而实现了一个选择器监听多个底层通道,减少了线程并发数。用NIO实现socket的Tcp通信需要掌握下面三个知识点: Buffer 缓冲区 Channel 通道 Selector 选择器   2、java.nio.Buff...

[字节码系列]ObjectWeb ASM构建Method Monitor

      在前面的篇章中,我们看到Java Instrutment的强大能力,本篇,我们将介绍如何使用ObjectWeb ASM的字节码增强能力构建Method Monitor       1.什么是ObjectWeb ASM      ObjectWeb ...

Core Location 电子围栏:入门

原文:Geofencing with Core Location: Getting Started 作者:Andy Pereira 译者:kmyhy 更新说明:Andy Pereira 将本教程升级至 Xcode 9.3 和 Swift 4.1。 Geofencing 会在设备进入/离开指定的电子围栏时通知应用程序。它可以让你写出一些很酷的应用程序,当你从家里出来时触发通知,或者在附近出现最爱的商...