ZYNQとメモリのキャッシュ

ZYNQでPSとPL部のメモリを共有して使う際に気をつけなければいけない点についての備忘録.
特にPS部でLinuxを動かす場合は顕著に影響が出ると思われる.

PSとコヒーレンシ

PSはARMコアであるためDDRメモリをそのまま使用するだけではなくキャッシュを用いて高速化を図っているためにARMコアによってメモリの内容を書き換えてもキャッシュにだけ即時反映されDDRメモリには古いデータが残ります.
そのままPL側から単純に読むとデータが異なってしまうコヒーレンシが問題となります.

PSをベアメタル等で使用している場合には命令によってメモリへのキャッシュ反映を任意で行うことができます.
しかし, Linuxを動かしている場合にはキャッシュの反映を制御出来ないのでDDRメモリとキャッシュで相違が発生してしまいPl側から欲しいデータを得ることができません.

ACP(Accelerator Coherency Port)

キャッシュとメモリの一貫性を保ちつつメモリにアクセスする際に使用するのがACPです.
PLでよく使用されるAXI HP, GPは直接DDRコントローラへアクセス(赤矢印)しますが, ACPではL2キャッシュ経由でDDRコントローラへアクセス(紫矢印)します.
最初にL2キャッシュ内に目的のメモリアドレスに対応するキャッシュがないかを確認します.
目的のデータが含まれているのであればそれが返され, そうでなければDDRコントローラへアクセスしてデータを取得する流れとなっています.

Zynq-7000-TRM P.60

ACPを使う

ACPは最初からZynqのブロックには表示されないので有効化します.
ACP Slave AXI Interfaceの「S AXI ACP Interface」と「Tie off AxUSER」にチェックを入れます.
AxUSERはAXIインタフェースの一部で普通はプログラムから指定するのですが
ZynqのACPのAXIインタフェースにはそのポートが出ていないので(何故?)ここで指定する必要があります.

プログラム上ではAxCACHEの値を設定します.
VivadoのAXI4 Peripheral作成機能で作ったインタフェースのテンプレートにはAxCACHEについて以下のような記述があります.

Update value to 4’b0011 if coherent accesses to be used via the Zynq ACP port. Not Allocated, Modifiable, not Bufferable. Not Bufferable since this example is meant to test memory, not intermediate cache.

4’b0011とあるのですが実際に動かすと不十分で,一部が化けているような意図しないデータが得られました.4’b1111か4’b1110に設定すると問題なく動きました.
ついでにAxUSERは1’b1に設定しておきます.

CoreLink Level 2 Cache Controller L2C-310 Technical Reference / Cache attributes

まとめ

ARMコアと連携する際にはL2キャッシュの存在を気にする必要がある.
目的のデータが得られなかったり化けたりする.
ACPはZynqの設定からACPの有効化と同時に「Tie off AxUSER」も有効にする必要がある.
プログラムではAxUSERを1’b1, AxCACHEを4’b1111か4’b1110に設定.

コメント

タイトルとURLをコピーしました