カスタマーサポートセンター

FAQ~よくある質問~ | FAQマスタ詳細表示

FAQ詳細情報

ID 10810926
FAQカテゴリ(大) リンカ
最終更新日 2016-01-02

質問内容

TN80460: プログラムを RAM で実行するためのXLINKの設定

回答内容

EWのターゲット: 全て
EWのコンポーネント: リンカ
更新日: 2012年 1月 2日 

 

背景
このテキストは、ROMの内容を、RAMにコピーして実行する方法を説明します。IARのコンパイラのうちいくつかは、サポートしているキーワードで行うことができます。このテキストは、そのようなサポートがないことを前提としていて、より、一般的なアプローチをとります。最も共通したケースは、メモリの内容を ROM から 実際に使用する RAMにコピーすることですが、メカニズムはもっと一般的で、特定の場所にリンクされた内容を別の場所に配置することです。

 

基本
以下は、コードを RAM にコピーするための手順です。

 1. コードを自分のセグメントに配置します。
 2. -Q リンカオプションを使用し、イニシャライザーセグメントを作成します。
 3. 元のセグメントを RAM に配置します。
 4. イニシャライザーセグメントを ROM に配置します。
 5. イニシャライザーセグメントの内容を RAM にコピーします。
 6. アプリケーションをデバッグします。

 

1 セグメントの内容を配置する

ROMからRAMの自身のセグメントににコピーする全ての内容を配置します。これは、アセンブラとコンパイラでそれぞれ別の方法で行います。

・ アセンブラを使用した例

アセンブラのファイルでは、どのセグメントが RSEGディレクティブを通して構成されるのか明示的に設定する必要があります。

   RSEG RAMCODE:CODE:NOROOT(2)

do_stuff:

:

これは、入口 do_stuff を定義する、RAMCODE という名前のセグメントの中でCODE型のセグメントの一部を生成します。これは 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 location をたくさん使用することはやりたくないと思います。数百 (千) のこれらの文字列がコードをちらかして、格納場所を変更する必要がある時はトラブルになるでしょう。#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.raw の中身をIMAGE_SEG にインポートします。このセグメントは、シンボル image1_start を定義しアラインメントはありません。--image_input を使用してインポートしたコードは、リンク時に生成されたイメージと同じアドレスに配置されることに注意してください。これには、位置独立コードのようにいくつかの例外があります。他の方法で保障されない限り、インポートしたコードは最初にリンクされたアドレスでのみ実行できます。

 

2 初期化セグメントの生成

-Q リンカオブションを使用して、イニシャライザセグメントを生成します。-Q は、1つの場所 (この場合 RAM) でリンクした内容を (この場合 ROM) 別の場所に配置します。

-QRAMCODE=RAMCODE_ID

これは、RAMCODEからイニシャライザセグメント RAMCODE_ID を作成します。

RAMCODE はラベルとデバッグ情報を含みます。これは、コードが配置され実際走行する場所です。これは 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. イニシャライザーセグメントの内容を RAM にコピーします。

ツールは、実際に RAMCODE_ID から RAMCODE にコピーすることは行いません。プログラマがランタイムで行われるようにする必要があります。プログラムの実行が main に到達するまでに、自動的にコピーが行われるようにスタートアップコードを修正することは可能ですが RAMCODE の内容が使用される前に、コピーが終了している必要があります。コピーはいつ行っても問題ありません。

 

実際のコピーはかなり簡単です。memcpyを呼び出すだけで十分ですが、セグメントのアドレスを取り出すところが少しトリッキーです。これは、IAR 拡張 ( または、アセンブラで書かれた関数を呼び出す可能性もあります ) を使用します。 このコードは、1つのアドレス空間を持つプロセッサでテストされています。もしプロセッサに、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 拡張はセグメントの開始アドレスを返します。このセグメントは前のプログラマで宣言されている必要があります。セグメントのアドレスが0x500-0x52Fである場合 __sfb は 0x500 を返します。

__sfe、セグメントフレーム終端、__sfbの反対、セグメントの後の最初のバイトのアドレスセグメントのアドレスが 0x500-0x52Fである場合 __sfe は 0x530 を返します。

activate_RAMCODE を呼び出した後は、この関数を使用する準備は整いました。

 

6 デバッグ

このサンプルでは、初期化されたコードは完全にデバッグ可能です。

 

全ての製品の名前は、それぞれの所有者の商標または登録商標です。

参考資料URL