FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

自作CPUコアのアトミックアクセス系と面倒なLSU周りの解析 (3. データキャッシュとL2のコヒーレンス周りで出したバグのまとめ)

ここ数日で自作CPUコアのバグを集中的に直した(現実逃避)ので、バグの概要をメモ。 ほとんどが外部からのスヌープ処理に関する部分。スヌープのタイミングが微妙にずれるとコアからデータを正しく引き抜けずに難しい。

  • 同じタイミングで2つの命令が何度もリプレイする場合の対処

今の実装では、LSUのパイプラインを2つもっていて、それぞれにリプレイキューを持たせている。 例えばLSU[0]で通常のロード命令を動かしていて、LSU[1]でアトミックアクセス命令を動かしているものとする。 ロード命令のほうが若く、アトミックアクセス命令が古いとする。

同時にL1Dキャッシュにアクセスし、バンクがぶつかったので、静的に優先度がつけられているLSU[1]にバンクコンフリクトが通知される。 ところがLSU[0]のロード命令は自分よりも古いアトミックアクセス命令が存在していることをSTQの検索で検知したので、リプレイキューに入ってある程度待ってから再開することにした。 全く同じタイミングで、LSU[1]のアトミックアクセス命令もリプレイのためにリプレイキューに入る。 面倒なので、それぞれのLSUパイプラインでリプレイキューを持っており、独立して管理される。

問題は、これは完全に偶然なのだが、2つのリプレイキューから当該命令がリプレイされるタイミングが全く同じで、同じようにコンフリクトとハザードが発生して2つの命令とも何度もリプレイキューに入りなおしてしまい、ここでデッドロックが発生する。

  • 解決策:

結局、コンフリクトが起きているとき、どちらかはアクセスに成功しているので、拒否されたほうのリクエストの優先度を上げるような論理を追加し、2回目の時はコンフリクトが起きても優先的に処理されるようにした。これにより、常にバスの権利が回ってこなくなる状況は回避された。

  • L1Dキャッシュに今まさにアクセスしているデータをスヌープするときのタイミング

自分のコアは、L1Dキャッシュに書き込みを起こすと同時に既存のデータを抜き出し、それをEvictionデータとして取り出す。 しかし、非常に似たようなタイミングでL1Dキャッシュにスヌープ操作を行うと、既に抜き出されたデータを探そうとしてデータが存在しない事態となり、スヌープができない可能性がある。

  • 解決策:

したがって、L1Dを誰かがアップデートしている最中はスヌープを強制的に行わず、コア内の書き込みアドレスとEvictionアドレスをチェックし、どちらかに引っかかればスヌープするという処理を新たに挿入した。

  • ストアバッファにデータが存在しているときにMSHRから同じキャッシュブロックにリクエストが入る

これは、L1DキャッシュからのEvictionデータをL2に書き戻すとき、待ち合わせのためのEvictionバッファを検索するポートがないため、MSHRに同じキャッシュブロックのリクエストが割り当てられた場合優先度によってEvictionバッファの掃き出しよりもMSHRの読み込み要求が優先されてしまい、矛盾が起きるというもの。

  • 解決策:

これは単純でMSHRの各エントリはストアEvictionバッファのアドレスを監視しておけばよい。もし同じアドレスに対して要求しようとしていれば、Evctionバッファが空になるまで待ち合わせをする。