Microchip XC16の関数の絶対アドレス


8

デバイス:dsPIC33FJ128GP802

次のようにいくつかの* .sファイルがあります

.global _D1
.section .speex, code
_D1:
.pword 0x66C821,  0x1B0090,  0xD96C36,  0x9B60B0,  0xDD4E36,  0xBF4E53
.pword 0xD1098B,  0x719BD9,  0x873989,  0x003B69,  0x279035,  0xED4244
.pword 0xE1403C,  0x54D439,  0x826550,  0xC59627,  0xDD0432,  0x88FA29

同じことを* .hで宣言しました

extern void D1(void);

今、私はD1をテーブル読み取り関数に渡します

nowPlaying.file1 = (unsigned long) D1;
function(nowPlaying.file1);

私の問題は、D1のアドレスが0X8000より大きい場合、ルーチンが正しくないことです。大小のコードモデルを試しましたが、結果は同じです。これはポインタの16ビット制限によるものだと思います。コードからD1の絶対アドレスに直接アクセスする方法はありますか。組み込み関数やマクロのようなものかもしれません。


私はdsPICシリーズを使用したことがありませんが、アセンブラの代わりにCのconst配列を使用できないのはなぜですか。特定のコードの場所に配置するオプションがあると思います(他の理由で必要な場合)。多分コンパイラの最適化を考えるだけで、より高いメモリ位置でデータを参照することを期待していないため、ポインタが短くなります。
PeterJ 2013

はい、コンパイラのマニュアルには、関数ポインタを含むすべてのポインタは16ビットであると記載されています。メモリアドレスにアクセスする他の方法を探しています。const配列を使用する場合、dsPICで3バイトワードの上位バイトを使用できません。もう1つの理由は、アセンブリファイルは、音声データを圧縮するためにマイクロチップが提供するコンピューターソフトウェアによって生成されることです。
Saneesh AT 2013

関連質問:electronics.stackexchange.com/questions/56058/…(これはPIC向けですが、dsPICはおそらく同じように動作します)

データD1は関数またはデータの配列を表すことになっていますか?
フォトン

2
@Saneeshだから私の質問に答えてください。このコードですか、それともデータですか?それがコードである場合、システムは16ビットアドレス空間を超えてそれをサポートしないので、どのように表現しようとも、実行しようとしていることは不可能です。データの場合は、そのように言って、としてアドレス指定してみてくださいconst short D1[]
user207421 2013

回答:


4

説明しているデータ(データを格納するためのプログラムメモリの完全な24ビット使用)は、Cで定義および初期化できず、Cを介して直接読み取ることもできません。これにアクセスする唯一の方法は、C呼び出し可能なアセンブリ関数または組み込み関数にカプセル化することです。

ここには本当に2つの質問があります。

  1. コンパイラー、アセンブラー、およびリンカーを適切に使用する方法。これにより、アセンブリーファイルで24ビットD1データを、固定アドレスの名前のないデータではなく、シンボル名で再配置可能なデータとして定義すると、コンパイラーはこの変数を認識できます。そのアドレスを決定する

  2. データにアクセスする方法

(どのようにデータにアクセスする)第2の質問はで33EP部分に対して応答されDS70613Cとに33FJ部品に答えなければならないDS70204C(しかしマニュアル33FJの例では、下位16ビットを使用します)。以下は、33EPパーツに対して機能する33EPリファレンスマニュアルからのコードスニペットの例です。

(注:コードはintを使用しますがuint16_t、and を使用する方が良いでしょう#include <stdint.h>

int prog_data[10] __attribute__((space(prog))) =
  {0x0000, 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888, 0x9999};

unsigned int lowWord[10], highWord[10];
unsigned int tableOffset, loopCount;

int main(void){
    TBLPAG = __builtin_tblpage (prog_data);
    tableOffset = __builtin_tbloffset (prog_data);
    /* Read all 10 constants into the lowWord and highWord arrays */
    for (loopCount = 0; loopCount < 10; loopCount ++)
    {
        lowWord[loopCount] = __builtin_tblrdl (tableOffset);
        highWord[loopCount] = __builtin_tblrdh (tableOffset);
        tableOffset +=2;
    }
    while(1)
        ;
}

組み込み関数__builtin_tblrdl()__builtin_tblrdh()は、プログラムメモリ位置からデータの下位16ビットワードと上位16ビットワードを読み取るため __builtin_tblpage() and __builtin_tbloffset()に使用され、ページとアドレスのオフセットを抽出するために使用できることに注意してください。この特定の例では、highWord配列は常に0であり、lowWord配列はCで定義および初期化されたprog_dataと一致します。

ここではポインタは使用されていません。でタグ付けされた通常の変数を使用constして、リンカーが読み取り専用プログラム空間に配置し、標準のCポインター技術を使用してメモリを読み取ることができるようにしますが、コンパイラーがページングレジスタを自動的に管理します。あなたのために、あなたは16ビットデータだけを保存することができます。24ビットのデータをすべて取得するには、TBLRDLおよびTBLRDH組み込み関数にアクセスする必要があります。

コンパイラー/リンカー/その他をうまく操作する方法については、コンパイラーをだまして、16ビットのデータしか見えないことを伝える必要があります。以下は、別の場所で宣言された変数D1を取得するために機能した例です。

#define D1_SIZE 18
extern uint16_t __attribute__((space(prog))) D1[D1_SIZE];

#define READ_DATA(dst, v, len) readData(dst, __builtin_tblpage(v), __builtin_tbloffset(v), len)
void readData(uint32_t *pdst, uint16_t page, uint16_t offset, uint16_t len)
{
    TBLPAG = page;
    while (len-- > 0)
    {
        uint16_t lo = __builtin_tblrdl (offset);
        uint16_t hi = __builtin_tblrdh (offset);
        *pdst++ = (((uint32_t)(hi)) << 16) | ((uint32_t)(lo));
        offset += 2;
    }
}

...

uint32_t d1copy[D1_SIZE];
READ_DATA(d1copy, D1, D1_SIZE);

これにより、24ビット値が正しく読み取られ、uint32_tの下位24ビットに格納されます。Cで宣言されたextern D1変数は、コンパイラー/アセンブラー/リンカーの連携方法を利用して開始アドレスに到達するためにのみ使用されるダミー変数です。組み込み関数が残りの作業を処理します。

それが定義されている+アセンブリで初期化されているため、データのサイズを自動的に取得する方法はわかりません。


1

unsigned longおよびbackに変換しないでください。トラブルを求めています。あなたは基本的にコンパイラーに嘘をついています。nowPlaying.file1の正しい宣言は次のとおりです。

struct
{
    // other stuff ...
    void (*D1)(void);
    // other stuff ...
} nowPlaying;

そして同様にfunction()の場合:

extern void function(void (*file)(void));

すべての型キャストを削除します。

または、@ PeterJが示唆する場合、それはデータであり、両方の場所でextern short D1 []として宣言する必要があります。アセンブラは実際には必要ありません。すべてCでconst short D1 [] = {...};として宣言できます。コンパイラはconstであるため、コードセグメントに挿入する必要があります。


D1が関数へのポインターではない何かを読み間違えている場合を除き、それはコードスペースに格納されているデータです。
PeterJ 2013

1
@PeterJ次に、外部void D1(void)として宣言してはならず、extern short D1 []として定義する必要があります。これはどれも、質問がSOに属していないことを納得させるものではありません。
user207421 2013

OPが話していることは、Cではまったく表現できません。C呼び出し可能なアセンブリ関数または組み込み関数によってカプセル化する必要があります。
Jason S

@JasonS問題にその証拠はなく、OPは明確化に失敗しました。
user207421

はい、あります。PIC33F/ PIC33Eアーキテクチャに精通している場合です。
Jason S

0

簡単な答えは、アセンブラでサブルーチンを書くことです。覚えていれば、C30は24ビットポインターを使用してデータとしてプログラムメモリにアクセスしません。せいぜい、PSVウィンドウを介してプログラムメモリにアクセスできますが、表示できるのは、各24ビットプログラムメモリワードの下位16ビットだけです。

24ビットのプログラムメモリアドレスを指定すると、24ビットのデータを返すC30から呼び出し可能なアセンブラルーチンを記述するのが非常に簡単になります。ただし、データは24ビット値のコレクションですか、それとも実際に1ワードあたり3つにパックされたバイトのリストですか?後者の場合は、さらに簡単です。プログラムメモリのバイトアドレスビューを提供するアセンブラルーチンを記述します。アドレスは引き続き24ビットである必要がありますが、データ値は8ビットになりました。

または、ルーチン全体をアセンブラで記述します。この種の低レベルのバイトバンギングとメモリパッキングを行う場合は、おそらく簡単です。アセンブラーでは、マシンがやりたいように、好きなことを実行できます。Cでは、コンパイラーがマシンコードを作成するようにコンパイラーにつぶやくべき呪文を理解する必要があります。自分で直接行う方が簡単な場合もあります。dsPICアーキテクチャは、特にPIC 16よりも簡単にアセンブリコードを記述できます。


TBLRDLとTBLRDHは、アセンブリを使用するか__builtin_tblrdX()関数を使用するかに関係なく、ここで重要です。私はあなたに同意します+「Cではコンパイラにつぶやくべき呪文を理解する必要があります」という言い回しから追い出されました ただし皮肉なことに、実際に最大のパフォーマンスを絞り込もうとしている場合は__builtin()、コンパイラーがコードを生成する方法を最適化できるため、関数が優れていることがあります。 。
Jason S
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.