在RAM中运行代码(XLINK)

浏览:1395来源:本站时间:2021-01-29

介绍

本文描述如何将ROM内容复制到执行它的RAM中。一些IAR编译器可以通过关键字支持实现这一目的,但这里采用一种更普遍适用的方法。最常见的情况是将内容从ROM复制到RAM(RAM中使用内容),但是更普遍的机制是,它支持将内容链接到一个位置,然后存储到另外一个位置。

复制代码到RAM的基本步骤如下:

1、将代码放置这一个段中

2、使用“-Q”链接选项创建段的初始式

3、将原始的段放置在RAM

4、将段的初始式放置在ROM

5、将初始式段的内容复制到该段

6、调试应用程序


1、将代码放置到段中

将希望在RAM中运行的代码放在它自己的段中。这可以在汇编器、编译器和image中通过不同的方式实现。

Ÿ   使用汇编器:

RSEG RAMCODE:CODE:NOROOT(2)

do_stuff:

.

.

这创建了一个名为RAMCODE,类型为CODE的段,定义入口为do_stuff,非ROOT(指示不能丢弃该段)4字节对齐。

注意:CODE段类型和CODE段名是不同的,虽然一个名为CODE的段也是CODE类型。

Ÿ   使用编译器:

一些IAR编译器提供了提供类似功能的命令行选项(有关任何特定编译器的详细信息,请参阅手册)IAR编译器提供了一个只能控制下一条语句的段的pragma (#pragma location)

#pragma location="SPECIAL_CODE"

int do_strange_things(int a, int b)

{

.

.

.

}

这将函数do_strange_things放在SPECIAL_CODE段中,它对文件中上面或下面的声明没有影响。

在代码中使用大量的#pragma语句可能不是你所希望的,特别是如果还需要对其进行修改。#pragma和宏通常不能很好地混在一起,但是有一个IAR扩展关键字_Pragma可以很好应用在这种场景。

#define RAMCODE(x) _Pragma("location=\"RAMCODE\"") x

这个宏会将传入的参数放置在RAMCODE段中,示例:

RAMCODE(int do_strange_things(int a, int b))

{

.

.

.

}

当然,不局限于代码:

#define CONST(x) _Pragma("location=\"CONST_SEG\"") x

例如,将常量定义作为参数传入给宏,放置在CONST_SEG段:

CONST(const int a = 4711;)

CONST(const int arr[3] = { 45, 34, -2};)

Ÿ   使--image_input

链接器选项--image_input允许一个字节一个字节地导入任何类型的文件,并将其放在一个段中。、

--image_input=image1.raw,image1_start,IMAGE_SEG,0

这将导入image1文件的内容到段IMAGE_SEG中。该段定义了符号image1_start,并且没有对齐。注意:通过--image_input导入的代码应该放置在链接时相同的地址上,除了一些例外,例如位置无关的代码。除非采取特别的措施,否则导入的代码只能在它链接的地址执行。


2、创建初始式段

使用-Q链接器选项创建初始化段,-Q运行在一个地方(本例是RAM)链接,在另外一个地(本例是ROM)存储。

-QRAMCODE=RAMCODE_ID

这将为段RAMCODE创建一个初始式段RAMCODE_ID

RAMCODE包含标签和调试信息,这是代码实际运行的地方,对RAMCODE的引用都在这里进行。

RAMCODE_ID的大小和RAMCODE一样,仅包含RAMCODE的实际字节,没有标签或调试信息。这里的字节仅用于复制到RAMCODE。将字节用于任何其他目的,比如执行当前驻留的代码(在复制之前),或者将它们复制到另一个地址会导致不明确的行为。


3、将原始段放置在RAM

RAMCODE是一个复制初始化的段,因此应该使用-Z段放置命令来放置,以确保段顺序的准确。

-Z(DATA)RAMCODE=RAM_START-RAM_END

注意,段放置命令的处理顺序与.xcl文件中的顺序相同,而且每次放置都要考虑到以前的放置。可能需要移动位置,以确保某个段被放置在某个特定段之前(或之后)


4、放置初始式段到ROM

RAMCODE_ID是一个复制初始化器段,因此应该使用Z段放置命令来确保段顺序的准确。

-Z(CONST)RAMCODE_ID=ROM_START-ROM_END


5、将字节从初始化段复制到该段

链接器并没有实际尝试将字节从RAMCODE_ID复制到RAMCODE,程序员必须在运行时进行此操作。可以在执行到达main之前修改启动代码来自动完成此操作,但是只要字节在使用RAMCODE的内容之前完成复制,其他的就无关紧要了。

实际的复制相当简单。调用memcpy就足够了,稍微棘手的部分是获取段的地址,使用IAR扩展(或可能调用汇编写的函数)。下面这段代码已经在具有单个地址空间的处理器上进行了测试。如果处理器对从ROM复制字节到RAM有特殊的要求(不同的地址空间,特殊的指令,特殊的地址要求,等等),所有这些要求都必须通过复制机制来满足。

/* copy all bytes between s (inclusive) and e (exclusive) to d */

void activate(void * s, void * e, void * d)

{

size_t size = (size_t)e - (size_t)s;

memcpy(d,s,size);

}


/* copy the bytes from RAMCODE_ID to RAMCODE */

void activate_RAMCODE(void)

{

#pragma segment="RAMCODE"

#pragma segment="RAMCODE_ID"

activate(__sfb("RAMCODE_ID"), __sfe("RAMCODE_ID"), __sfb("RAMCODE"));

}

#pragma segment=""告诉编译器有一个同名的段,除了允许在该区段上使用剩余__sfb和剩余__sfe外没有其他影响。

__sfb是一个IAR扩展字,返回段的起始地址,该段必须在前面的#pragma中提到过。如果段占用0x500- 0x52f,那么__sfb将返回0x500

__sfe返回段之后的第一个空闲字节的地址, 如果段占用0x500-0x52F__sfe将返回0x530

在调用了activate_RAMCODE之后,全部都就绪了。


6、调试

在本例中,复制初始化的代码在字节被复制之后应该具有完全的可调试性。

京ICP备:京ICP备05011254号-1 版权归北京麦克泰软件技术有限公司所有
北京麦克泰软件技术有限公司