The near and far keywords(DSP & CCS)

// 摘自: TMS320C6000 Optimizing Compiler v7.4 User`s Guide.pdf

====================================================================================================

The C6000 C/C++ compiler extends the C/C++ language with the near and far keywords to specify how global and static variables are accessed and how functions are called. 

Syntactically, the near and far keywords are treated as storage class modifiers. They can appear before, after, or in between the storage class specifiers and types. With the exception of near and far, two storageclass modifiers cannot be used together in a single declaration. The following examples are legal combinations of near and far with other storage class modifiers:

far static int x;
static near int x;
static int far x;
far int foo();
static far int foo();

near and far Data Objects


Global and static data objects can be accessed in the following two ways: 

near keywordThe compiler assumes that the data item can be accessed relative to the data page pointer. For example:

LDW  *+dp(_address), a0
far keywordThe compiler cannot access the data item via the DP. This can be required if the total amount of  program data is larger than the offset allowed (32K) from the DP. For example:
MVKL  _address, a1
MVKH  _address, a1

LDW   *a1, a0

Once a variable has been defined to be far, all external references to this variable in other C files or headers must also contain the far keyword. This is also true of the near keyword. However, you will get compiler or linker errors when the far keyword is not used everywhere. Not using the near keyword everywhere only leads to slower data access times.


If you use the DATA_SECTION pragma, the object is indicated as a far variable, and this cannot be overridden. If you reference this object in another file, then you need to use extern far when declaring this object in the other source file. This ensures access to the variable, since the variable might not be in the .bss section. For details, seeSection 6.9.6.


NOTE: Defining Global Variables in Assembly Code

         If you also define a global variable in assembly code with the .usect directive (where the variable is not assigned in the .bss section) or you allocate a variable into separate section using a #pragma DATA_SECTION directive; and you want to reference that variable in C code, you must declare the variable as extern far. This ensures the compiler does not try to generate an illegal access of the variable by way of the data page pointer. 

When data objects do not have the near or far keyword specified, the compiler will use far accesses to aggregate data and near accesses to non-aggregate data. For more information on the data memory model and ways to control accesses to data, see Section 7.1.5.1.


Near and far Function Calls


Function calls can be invoked in one of two ways:
near keyword   The compiler assumes that destination of the call is within ± 1 M word of the caller. Here the compiler uses the PC-relative branch instruction.

B _func


far keyword    The compiler is told by you that the call is not within ± 1 M word.
MVKL _func, al
MVKH _func, al
B _func


By default, the compiler generates small-memory model code, which means that every function call is
handled as if it were declared near, unless it is actually declared far.
For more information on function calls, see Section 7.1.6.

-------------------------------------------------------------------------------------------------------------------------------


<think>好的,用户之前询问了英飞凌TC275的Tasking编译器支持的#pragma放置段种类,现在他们想了解nearfar的底层原理。我需要先回忆一下之前的回答,确保这次的内容能衔接上。 首先,用户可能已经对内存分段有了基本了解,但需要更深入的底层原理。他们可能是嵌入式开发者,关注内存管理和性能优化。需要解释nearfar在内存地址访问上的区别,以及硬件层面的原因,比如地址总线的限制。 接下来,我得考虑如何结构化回答。用户可能希望知道原理、硬件支持、编译器处理方式以及实际应用中的权衡。需要分点说明,保持清晰。 需要提到16位或8位微控制器的背景,因为nearfar在这些架构中更常见。TC275虽然是32位的,但可能兼容这些概念。需要解释指针大小不同,near是短指针,访问速度快,far是长指针,可以访问更广的内存,但速度慢。 还要涉及内存分区的bank切换机制,比如数据放在不同的bank,需要特殊指令访问,这会影响代码生成和性能。编译器如何处理nearfar变量,比如生成不同的指令,可能影响代码大小和执行效率。 实际应用中的考量,比如将频繁访问的数据放在near区域,提升性能,而大块数据用far。同时,需要注意编译器是否自动优化,或者需要手动指定。 可能用户在使用中遇到了性能问题,或者想知道如何优化内存布局,所以需要给出实际例子和建议。例如,在Tasking编译器中如何声明nearfar变量,以及链接脚本的配置。 最后,确保内容准确,参考Tasking的手册,特别是关于内存分配的部分,但用户可能没有手册,所以需要以易懂的方式解释。避免使用过多术语,但必要时需准确,比如地址总线宽度、指针大小、banks等。 总结,回答需要涵盖原理、硬件支持、编译器处理、实际应用,以及示例,帮助用户理解如何有效使用nearfar优化他们的嵌入式系统。</think>在嵌入式系统中,`near` 和 `far` 是用于控制内存访问范围的关键概念,其底层原理与**微控制器的地址总线宽度**和**内存分段机制**密切相关。以下从硬件架构到编译器实现的分层解析: --- ### 一、硬件基础原理 1. **地址总线限制** - 在 16 位或 8 位微控制器(如某些传统 8051/C166 架构)中,CPU 的**自然指针宽度**有限 例如:16 位地址总线最大直接寻址范围仅为 $2^{16} = 64KB$ - 为了扩展寻址能力,硬件通过**分段(Banking)机制**将内存划分为多个逻辑区域(Banks) 2. **内存分段机制** - **near 空间**(默认段):CPU 可直接通过短指针访问的快速内存区域 - 特点:地址范围小(如 16 位对应 64KB),无需额外操作 - **far 空间**:需要**段寄存器(Bank Register)**配合访问的扩展内存区域 - 特点:地址范围大(如 24 位对应 16MB),但需要额外的指令加载段地址 --- ### 二、编译器实现原理 1. **指针类型区分** ```c int near *ptr1; // 短指针(2字节,访问默认段) int far *ptr2; // 长指针(4字节,包含段地址和偏移) ``` - **near 指针**:仅存储偏移地址,依赖当前段寄存器隐含的基地址 - **far 指针**:显式包含段选择符(Segment Selector)和偏移地址 2. **代码生成差异** - **near 访问**(高效): 编译器生成简单寻址指令,例如: ```asm MOV R0, #my_var ; 直接使用偏移地址 ``` - **far 访问**(低效): 需要先加载段寄存器,再计算物理地址: ```asm MOV DPP, #HIGH(my_far_var) ; 设置数据页指针(Data Page Pointer) MOV R0, #LOW(my_far_var) ; 加载偏移地址 ``` --- ### 三、Tasking 编译器中的优化策略 1. **内存模型选择** - **Small 模式**:默认所有变量为 `near`,适用于小型项目 - **Large 模式**:允许混合使用 `near`/`far`,需手动标注扩展内存 2. **性能与空间权衡** | 类型 | 访问速度 | 内存占用 | 典型应用场景 | |-------|-------------------|-------------|-----------------------| | near | 1 个 CPU 周期 | 指针较小 | 高频访问变量、堆栈 | | far | 3-5 个 CPU 周期 | 指针较大 | 大数组、外设寄存器 | 3. **实际代码示例(TC275)** ```c #pragma section near_data "NEAR_RAM" // 定义near段(默认映射到DSPR) uint32_t fast_counter @ "NEAR_RAM"; // 高频计数器使用near空间 #pragma section far_data "FAR_ROM" // 定义far段(映射到PFLASH) const far uint8_t large_table[10000]; // 大常量表使用far空间 ``` --- ### 四、扩展应用原理 1. **链接器脚本(.lsl)配合** - 在内存分配时明确指定 `near` 和 `far` 的物理地址范围 ```lsl memory near_ram { size = 64K; type = RAM; map (addr=0xD0000000) } memory far_rom { size = 2M; type = ROM; map (addr=0x80000000) } ``` 2. **混合模式优化技巧** - 对结构体成员使用 `#pragma ordering` 控制内存布局,将高频字段放在 `near` 区域 --- ### 五、现代架构的演变 在 32 位架构(如 TC275 的 TriCore)中: - **地址总线扩展**:32 位寻址可覆盖 $4GB$ 空间,`near`/`far` 的区分不再严格必要 - **遗留支持**:Tasking 编译器仍保留相关关键字,主要服务于: - 兼容旧代码 - 优化特定内存分区(如 LMU 快速 RAM 与普通 Flash 的访问速度差异) 建议通过反汇编验证实际生成的指令差异,这对性能关键型代码的优化至关重要。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值