Zynq の ACP を使う時の AxCACHE 信号とAxUSER 信号の値







# はじめに


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](https://qiita-image-store.s3.amazonaws.com/0/24981/a76868ad-adb8-731b-4efc-e55430ae8ae5.jpeg "Fig.1 Zynq-7000 PS Block Diagram")

Fig.1 Zynq-7000 PS Block Diagram

<br />

このブロック図のように、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

<table border="2">
  <tr>
    <td align="center" colspan="4">AxCACHE[3:0]</td>
    <td align="center" rowspan="2">AXI meaning</td>
    <td align="center" rowspan="2">ARMv6 and ARMv7 equivalent</td>
  </tr>
  <tr>
    <td align="center">WA</td>
    <td align="center">RA</td>
    <td align="center">C</td>
    <td align="center">B</td>
  <tr>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td>Non-cachable, non-bufferable</td>
    <td>Strongly ordered</td>
  </tr>
  <tr>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">1</td>
    <td>Bufferable only</td>
    <td>Device</td>
  </tr>
  <tr>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">1</td>
    <td align="center">0</td>
    <td>Cacheable  but do not allocate</td>
    <td>Outer non-cacheable</td>
  </tr>
  <tr>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">1</td>
    <td align="center">1</td>
    <td>Cacheable and bufferable, do not allocate</td>
    <td>Outer non-cacheable</td>
  </tr>
  <tr>
    <td align="center">0</td>
    <td align="center">1</td>
    <td align="center">1</td>
    <td align="center">0</td>
    <td>Cacheable write-through, allocate on read</td>
    <td>Outer write-through, no allocate on write</td>
  </tr>
  <tr>
    <td align="center">0</td>
    <td align="center">1</td>
    <td align="center">1</td>
    <td align="center">1</td>
    <td>Cacheable write-back, allocate on read</td>
    <td>Outer write-back, no allocate on write</td>
  </tr>
  <tr>
    <td align="center">1</td>
    <td align="center">0</td>
    <td align="center">1</td>
    <td align="center">0</td>
    <td>Cacheable write-through, allocate on write</td>
    <td>-</td>
  </tr>
  <tr>
    <td align="center">1</td>
    <td align="center">0</td>
    <td align="center">1</td>
    <td align="center">1</td>
    <td>Cacheable write-back, allocate on write</td>
    <td>-</td>
  </tr>
  <tr>
    <td align="center">1</td>
    <td align="center">1</td>
    <td align="center">1</td>
    <td align="center">0</td>
    <td>Cacheable write-through, allocate on both read and write</td>
    <td>-</td>
  </tr>
  <tr>
    <td align="center">1</td>
    <td align="center">1</td>
    <td align="center">1</td>
    <td align="center">1</td>
    <td>Cacheable write-back, allocate on both read and write</td>
    <td>Outer write-back, write allocate</td>
  </tr>
</table>

これらのオペレーションに関して、もう少し詳しく説明すると次のようになります。


## 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実践勉強会』](https://fpgax.connpass.com/event/71364/)にて筆者が「キャッシュのコヒーレンシのトラブルを避けるためにACPを使った方が簡単ですよ」なんて言ってしまったところ、「言われたとおりしたけどACPだとデータが化ける」という報告が数名の方からあって急遽調べた次第です。

・[『FPGA+SoC+LinuxでXilinx AXI DMAを試す』(ふがふが)](http://www.fugafuga.org/fpga/fpga_soc_linux_xilinx_dma.html)

・[『FPGA+SoC+Linux実践勉強会での課題をやってみた3（Vivado 編2 ACPポートを使用）』(FPGAの部屋)](http://marsee101.blog19.fc2.com/blog-entry-3996.html)

そこで、どうやら AxCACHE の値が Xilinx 推奨の 0011 だとACP でデータ化けすることが判りました。私は自前でDMAコントローラーを作っていて AxCACHE に 1111 を出力していたので気がつきませんでした。いい加減なことを言って申し訳ありません。



あと、Xilinx のフォーラムでもちょっと問題になっていたみたいです。

https://forums.xilinx.com/t5/Zynq-All-Programmable-SoC/Zynq-ACP-Cohereny-with-Linux-ioremap-cache/m-p/663555/highlight/true#M10942)


# 参考


* [『Zynq-7000 All Programmable SoC Technical Refernce Manual』(UG585)](https://www.xilinx.com/support/documentation/user_guides/ug585-Zynq-7000-TRM.pdf)
* [『CoreLink Level 2 Cache Controller L2C-310 Technical Reference Manual』(Revison:r3p3)](http://infocenter.arm.com/help/topic/com.arm.doc.ddi0246h/DDI0246H_l2c310_r3p3_trm.pdf)