2

FPGAおよびASIC用の汎用画像処理コアを開発しています。アイデアは、標準のプロセッサをそれに接続することです。私が抱えている問題の1つは、それを「プログラム」する方法です。説明させてください:コアには、私の「カスタム」拡張機能用の命令デコーダーがあります。例えば:

vector_addition $vector[0], $vector[1], $vector[2]    // (i.e. v2 = v0+v1) 

そしてもっとそのようなものがたくさんあります。この操作は、次のようなプロセッサforループ、非ベクトル操作などを使用して、プロセッサによってバスを介してコアに送信されます。

for (i=0; i<15;i++)           // to be executed in the processor
     vector_add(v0, v1, v2)   // to be executed in my custom core

プログラムはC/C++で書かれています。コアは、マシンコードでの命令自体のみを必要とします

  1. オペコード=vector_add= 0x12h
  2. register_src_1 = v0 = 0x00h
  3. register_src_2 = v1 = 0x01h
  4. register_dst = v2 = 0x02h

    マシンコード=opcore| v0 | v1 | v2 = 0x7606E600h

(または何でも、バイナリで命令を構築するためのさまざまなフィールドの単なる組み合わせ)

バスを介してコアに送信すると、コアは専用バスを使用してメモリからすべてのデータを要求し、プロセッサを使用せずにすべてを処理できます。大きな手がかりは、前の命令を16進表現に変換するにはどうすればよいかということです。(バスを介して送信しても問題ありません)。頭に浮かぶいくつかのオプションは

  • インタプリタされたコードを実行する(プロセッサで実行時にマシンコードに変換する)->ある種のインラインマクロを使用しても、非常に遅い
  • カスタムセクションを外部カスタムコンパイラでコンパイルし、外部メモリからバイナリをロードして、独自の命令でコアに移動します->ソースコードの読み取り/理解が難しい、SDK統合が不十分、コードが非常にセグメント化されている場合はセクションが多すぎる
  • JITコンパイル->これだけで複雑になりますか?
  • コンパイラの拡張->悪夢!
  • ループ、ポインタ、メモリ割り当て、変数など、すべてを処理するためにカスタムコアに接続されたカスタムプロセッサ...->作業が多すぎる

問題はソフトウェア/コンパイラに関するものですが、このトピックに関する深い知識を持っている人にとっては、これはFPGAのSoCであり、メインプロセッサはMicroBlazeであり、IPコアはAXI4バスを採用しています。

正しく説明できたらいいのに…よろしくお願いします!

4

3 に答える 3

1

完全に理解できるかどうかはわかりませんが、以前に似たようなことに直面したことがあると思います。rodrigoの応答に対するコメントに基づくと、コード全体に小さな命令が散在しているように思われます。また、外部コンパイラが可能であるとおっしゃっていますが、それは苦痛です。外部コンパイラをCマクロと組み合わせると、まともなものを得ることができます。

このコードを考えてみましょう:

for (i=0; i<15;i++)
     CORE_EXEC(vector_add(v0, v1, v2), ref1)

CORE_EXECマクロは、次の2つの目的を果たします。

  1. 外部ツールを使用して、ソースファイルでこれらのエントリをスキャンし、コアコードをコンパイルできます。このコードは、変数として「ref1」名を使用してCにリンクされます(バイナリビットを含むCファイルを生成するだけです)。
  2. Cでは、CORE_EXECマクロを定義して、処理のために「ref1」文字列をコアに渡します。

したがって、ステージ1は、コンパイルされたバイナリコア命令のファイルを生成します。たとえば、上記の文字列は次のようになります。

const char * const cx_ref1[] = { 0x12, 0x00, 0x01, 0x02 };

そして、次のようにCORE_EXECを定義できます。

#define CORE_EXEC( code, name ) send_core_exec( cx_##name )

もちろん、プレフィックスは好きなように選択できますが、C ++では、代わりに名前空間を使用することもできます。

ツールチェーンに関しては、すべてのビットに対して1つのファイルを作成することも、C ++ファイルごとに1つのファイルを作成することもできます。これにより、ダーティ検出が容易になる場合があります。次に、生成されたファイルをソースコードに含めるだけです。

于 2012-01-13T14:05:51.773 に答える
0

プログラムの開始時にすべてのコード セクションをマシン コードに変換し (1 回だけ)、メモリ ブロックにバイナリ形式で保存し、必要に応じてそれらのバイナリを使用できませんでしたか。

これが基本的に OpenGL シェーダーの仕組みであり、管理が非常に簡単だと思います。

主な欠点は、同じスクリプトのテキスト表現とバイナリ表現の両方がメモリ内にあるため、メモリの消費です。これがあなたにとって問題かどうかはわかりません。そうである場合は、コンパイル後にソース テキストをアンロードするなど、部分的な解決策があります。

于 2012-01-13T13:38:32.727 に答える
0

いくつかのカスタム命令を追加するためにアーム コアを変更しようとしていて、実行したい操作がコンパイル時にわかっていたとします (すぐに実行に移されます)。

たとえば、アセンブリを使用します。

.globl vecabc
vecabc:
   .word 0x7606E600 ;@ special instruction
   bx lr

または、コンパイラのインライン構文が何であれインライン化します。たとえば、cコンパイラがインラインアセンブリ言語のレジスタに入力し、アセンブラがそれらの命令をアセンブルする場合など、プロセッサレジスタを使用する必要がある場合は難しくなります。実際の asm を記述し、上記のように命令ストリームに単語を挿入するだけで、コンパイラのみが一部のバイトをデータとして、一部のバイトを命令として区別し、コアはそれらを書き込まれた順序で認識します。

リアルタイムで処理する必要がある場合は、自己変更コードを使用できます。ここでも asm をトランポリンに使用するのが好きです。RAM のどこかで実行する命令をビルドします。たとえば、アドレス 0x20000000 で実行し、トランポリンで呼び出します。

.globl tramp
tramp:
    bx r0 ;@ assuming you encoded a return in your instructions

で呼び出す

tramp(0x20000000);

上記に関連する別のパスは、アセンブラを変更して新しい命令を追加し、それらの命令の構文を作成することです。次に、ストレートアセンブリ言語またはインラインアセンブリ言語を自由に使用できます。コンパイラを変更せずにコンパイラにそれらを使用させることはできません。これは、アセンブラが変更された後の別のパスです。

于 2012-01-13T15:48:08.380 に答える