はじめに
Xilinx 社の ZYNQ において、PL(Programmable Logic)から PS(Processing System)へメモリアクセスする際、ACP(Accelerator Coherency Port)を使うと、ハードウェアによって CPU キャッシュとメインメモリとのコヒーレンシが保証されます。しかし、この ACP を有効に使うには AxCACHE 信号と AxUSER 信号に適切な値を入力しなければなりません。この記事では ACP を使う際の AxCACHE 信号と AxUSER 信号に関して説明します。
結論から先に言うと、AxUSER[0]=1、AxCACHE[3:0]=1111 または 1110 を入力するのが良いでしょう。
ブロック図
次図にZynq-7000 の PS の ACP 周りのブロック図を示します。
Fig.1 Zynq-7000 PS Block Diagram
このブロック図のように、ACP は SCU(Snoop Control Unit)を通して、CPU の L1 Cache と L2 Cache に接続されています。そして L2 Cache の先に DDR Controller を介してメインメモリに繋がっています。
ACP インターフェース
『UG585 Zynq-7000 All Programmable SoC Technical Refernce Manual』には、ACP アクセスに対して次のように記述されています。
コヒーレントなACP読み出し要求
ARVALID とともに ARUSER[0]=1および ARCACHE[1] = 1 が送信された場合、ACP 読み出し要求はコヒーレントです。この場合、SCU はコヒーレンシを維持します。データがいずれかのCortex-A9 プロセッサにある場合、データはそのプロセッサから直接読み出されて ACP ポートに返されます。データがいずれの Cortex-A9 プロセッサにもない場合、すべての AXI パラメーター (ロック属性を除く) と共に読み出し要求がいずれか 1 つの SCU AXI マスターポー トに発行されます。
非コヒーレントなACP読み出し要求
ARVALID と共に ARUSER[0] = 0 ま たは ARCACHE[1] = 0 が送信された場合、ACP 読み出し要求は非コヒーレントです。この場合、SCU はコヒーレンシを維持せず、読み出し要求はいずれか 1 つの SCU AXI マスターポー ト L2 キャッシュコ ン トローラーまたは OCM へ直接転送されます。
コヒーレントなACP書き出し要求
AWVALID と共に AWUSER[0] = 1 および AWCACHE[1] = 1 が送信された場合、ACP 書き込み要求はコヒーレントです。この場合、SCU はコヒーレンシを維持します。データがいずれかのCortex-A9 プロセッサにある場合、最初にその CPU のデータをクリーニングして無効にします。データがいずれのCortex-A9 プロセッサにもない場合、または既にクリーニングと無効化が実行されている場合、対応するすべてのAXI パラメーター (ロック属性を除く) と共に書き込み要求がいずれか 1 つの SCU AXI マスターポー トに発行されます。
注記: 書き込みパラメーターの設定によっては、トランザクションを L2 キャッシュに割り当てることもできます。
非コヒーレントな ACP 書き込み要求
AWVALID と共に AWUSER[0] = 0 ま たは AWCACHE[1] = 0 が送信された場合、ACP 書き込み要求は非コヒーレントです。この場合、SCU はコヒーレンシを維持せず、書き込み要求はいずれか 1 つの SCU AXI マスターポートに直接転送されます。
L2 キャッシュインターフェース
前節の ACP の説明で、次の点が重要です。
- コヒーレントなACP読み出し要求において、データがいずれの Cortex-A9 プロセッサにもない場合、すべての AXI パラメーター (ロック属性を除く) と共に読み出し要求がいずれか 1つの SCU AXI マスターポー トに発行されます。
- コヒーレントなACP書き出し要求において、データがいずれのCortex-A9 プロセッサにもない場合、または既にクリーニングと無効化が実行されている場合、対応するすべてのAXI パラメーター (ロック属性を除く) と共に書き込み要求がいずれか 1 つの SCU AXI マスターポー トに発行されます。
つまり、CPUキャッシュにデータが無い場合は L2キャッシュに対してトランザクションが発生し、その時に ACP から入力された AxCACHE の値がそのまま L2 キャッシュコントローラーの AxCACHE に入力されるということです。
ここで『CoreLink Level 2 Cache Controller L2C-310 Technical Reference Manual』の 2.3.1 Cache attribute の項には次のようなテーブルがあります。
Table.1 AWCACHE and ARCACHE definitions
AxCACHE[3:0] | AXI meaning | ARMv6 and ARMv7 equivalent | |||
WA | RA | C | B | ||
0 | 0 | 0 | 0 | Non-cachable, non-bufferable | Strongly ordered |
0 | 0 | 0 | 1 | Bufferable only | Device |
0 | 0 | 1 | 0 | Cacheable but do not allocate | Outer non-cacheable |
0 | 0 | 1 | 1 | Cacheable and bufferable, do not allocate | Outer non-cacheable |
0 | 1 | 1 | 0 | Cacheable write-through, allocate on read | Outer write-through, no allocate on write |
0 | 1 | 1 | 1 | Cacheable write-back, allocate on read | Outer write-back, no allocate on write |
1 | 0 | 1 | 0 | Cacheable write-through, allocate on write | - |
1 | 0 | 1 | 1 | Cacheable write-back, allocate on write | - |
1 | 1 | 1 | 0 | Cacheable write-through, allocate on both read and write | - |
1 | 1 | 1 | 1 | Cacheable write-back, allocate on both read and write | Outer write-back, write allocate |
これらのオペレーションに関して、もう少し詳しく説明すると次のようになります。
Non-cacheable and non-bufferable
- キャッシュ不可、バッファ不可
- AxCACHE : 0000
- 読み出し : L2にはキャッシュされず、メモリへのアクセスが発生
- 書き込み : バッファーには格納されず、メモリへのアクセスが発生
Bufferable only
- バッファ可能のみ
- AxCACHE : 0001
- 読み出し : L2にはキャッシュされず、メモリへのアクセスが発生
- 書き込み : ストアバッファには格納されるが、結合されず直ちにメモリへドレイン
Cacheable but do not allocate
- キャッシュ可能、バッファ不可、割り当て無し
- AxCACHE : 0010
- 読み出し : L2にはキャッシュされず、メモリへのアクセスが発生
- 書き込み : ストアバ ッ ファーに格納され、ストアバッファがドレインされるとメモリへ書き込まれる
Cacheable and bufferable, do not allocate
- キャッシュ可能、バッファ可、割り当て無し
- AxCACHE : 0011
- 何故か『CoreLink Level 2 Cache Controller L2C-310 Technical Reference Manual』にこのオペレーションの記述が無い
Cacheable write-through, allocate on read
- キャッシュ可能なライトスルー、読み出し割り当て
- AxCACHE : 0110
- 読み出しヒット時 : L2 から読み出し
- 読み出しミス時 : L2 へのラインフィル
- 書き込みヒット時 : ストアバッファに格納され、ストアバッファがドレインされると L2 およびメモリへ書き込まれる
- 書き込みミス時 : ストアバッファに格納され、ストアバッファがドレインされるとメモリへ書き込まれる
Cacheable write-back, allocate on read
- キャッシュ可能なライトバック、読み出し割り当て
- AxCACHE : 0111
- 読み出しヒット時 : L2 から読み出し
- 読み出しミス時 : L2 へのラインフィル
- 書き込みヒット時 : ストアバッファに格納され、ストアバッファがドレインされると L2 へ書き込み、ラインをダーティとマーク付け
- 書き込みミス時 : ストアバッファに格納され、ストアバッファがドレインされると メモリへ書き込まれる
Cacheable write-through, allocate on write
- キャッシュ可能なライトスルー、書き込み割り当て
- AxCACHE : 1010
- 読み出しヒット時 : L2 から読み出し
- 読み出しミス時 : L2にはキャッシュせず、メモリへのアクセスが発生
- 書き込みヒット時 : ストアバッファに格納され、ストアバッファがドレインされると L2 およびメモリへ書き込まれる
- 書き込みミス時 : ストアバ ッファーへ格納。バッファがドレインされると、フルかどうかを確認。フルでなければバッファーをL2 に割り当てる前にメモリに対してワードまたはラインを要求。L2 へ割り当て。メモリへ書き込み。
Cacheable write-back, allocate on write
- キャッシュ可能なライトバック、書き込み割り当て
- AxCACHE : 1011
- 読み出しヒット時 : L2 から読み出し
- 読み出しミス時 : L2にはキャッシュせず、メモリへのアクセスが発生
- 書き込みヒット時 : ストアバッファに格納され、ストアバッファがドレインされると L2 へ書き込み、ラインをダーティとマーク付け
- 書き込みミス時 : ストアバッファへ格納。バッファをドレインする必要がある場合は、フルかどうかを確認。フルでなければバッファを L2 に割り当てる前にメモリに対してワードまたはラインを要求。L2 へ割り当て
Cacheable write-through, allocate on both read and write
- キャッシュ可能なライトスルー、読み出し/書き込み割り当て
- AxCACHE : 1110
- 読み出しヒット時 : L2 から読み出し
- 読み出しミス時 : L2 へのラインフィル
- 書き込みヒット時 : ストアバッファに格納され、ストアバッファがドレインされると L2 およびメモリへ書き込まれる
- 書き込みミス時 : ストアバッファへ格納。バッファをドレインする必要がある場合は、フルかどうかを確認。フルでなければバッファを L2 に割り当てる前にメモリに対してワードまたはラインを要求。L2 へ割り当て。メモリへ書き込み
Cacheable write-back, allocate on both read and write
- キャッシュ可能なライトバック、読み出し/書き込み割り当て
- AxCACHE : 1111
- 読み出しヒット時 : L2 から読み出し
- 読み出しミス時 : L2 へのラインフィル
- 書き込みヒット時 : ストアバッファに格納され、ストアバッファがドレインされると L2 へ書き込み、ラインをダーティとマーク付け
- 書き込みミス時 : ストアバッファへ格納。バッファをドレインする必要がある場合は、フルかどうかを確認。フルでなければバッファを L2 に割り当てる前にメモリに対してワードまたはラインを要求。L2 へ割り当て
まとめ
AxUSER[0]=1、AxCACHE[3:0]=1111 または 1110 を入力するのが良いでしょう。
余談
実はこの件は2017年12月2日のイベント『FPGA+SoC+Linux実践勉強会』にて筆者が「キャッシュのコヒーレンシのトラブルを避けるためにACPを使った方が簡単ですよ」なんて言ってしまったところ、「言われたとおりしたけどACPだとデータが化ける」という報告が数名の方からあって急遽調べた次第です。
・『FPGA+SoC+LinuxでXilinx AXI DMAを試す』(ふがふが)
・『FPGA+SoC+Linux実践勉強会での課題をやってみた3(Vivado 編2 ACPポートを使用)』(FPGAの部屋)
そこで、どうやら AxCACHE の値が Xilinx 推奨の 0011 だとACP でデータ化けすることが判りました。私は自前でDMAコントローラーを作っていて AxCACHE に 1111 を出力していたので気がつきませんでした。いい加減なことを言って申し訳ありません。
あと、Xilinx のフォーラムでもちょっと問題になっていたみたいです。