FPGA開発日記

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

RISC-VのPlatform Level Interrupt Controller (PLIC)について (1. 動作概要とレジスタ定義)

Platform Level Interrupt Controllerといい、コア外部から挿入される割り込みを処理するためのモジュールと考えてよい。当初PLICの仕様はRISC-Vの命令仕様と同様のグループで定義されていたが、命令仕様とは関係ないので分離して別ページで管理されている。

もう一つに多様な概念として、CLINT (Core Local Interrupt Controller)というものある。PLICとは異なり、コアのより近い場所で発生する割込みを処理するために使用する。

CLINTはタイマ割り込みとソフトウェア割り込み(コア間割り込みのようなもの)を制御するが、PLICは外部デバイスからの割り込みなど、もう少しシステムよりの割り込み処理を行う。

PLICが定義するレジスタ

PLICは割り込みを処理するための単なる配線群ではない。システムからは複数の割り込みがCPUに対して挿入され、どのような優先度でどの割り込みをどのCPUに挿入するかという制御をPLICによって決定する。

  1. 複数の割り込みが挿入されたとき
  2. どのような優先度で処理され
  3. どのターゲット(CPU)に通知されるのか

ということを、PLICの内部に定義されているレジスタによって制御する。

PLICのレジスタは、制御する種類によってサイズが異なるので注意。つまり

  1. 割り込み要因毎に定義されているレジスタ
  2. ターゲットCPU(HARTS)毎に定義されているレジスタ

ということを考慮して仕組みを眺める必要がある。

1. 割り込みの優先度

各割り込み要因毎に設定できるレジスタ。それぞれの割り込み要因がどの程度の優先度を持っているのかを指定する。優先度は、値が大きいほど大きくなる。

指定する優先度の数は任意だが、要因毎に設定可能なレジスタのサイズの最大値が32ビットなので、それを超えることはできない。逆に言えば、各要因で4バイトずつレジスタが定義されている。

メモリマップは以下の表のようになっており、割り込み要因のサイズは最大で1023個指定できる。

割り込み要因 オフセット サイズ 説明
0 0 32ビット以下
1 4 32ビット以下
1023 0xFFC 32ビット以下

2. Pendingビット

複数の割り込みが同時にPLICに挿入された場合、優先度の高いものを一つ選んでターゲットのHARTに通知する。当然この時優先度の低いものは通知することができないので、この割り込みはPending状態となる。

Pending状態である割り込みを保持しておくためのレジスタが定義されている。これは数だけ定義されたレジスタであるが、割り込み要因毎に1ビットあれば十分なので、32ビットのレジスタ1つで32種類のPendingビットが保持されている。

逆に言えば、上記のように最大1024個の割り込み要因が存在する場合、1024/32 = 32個のPendingレジスタが定義される。

割り込み要因 オフセット サイズ 説明
31 - 0 0x1000 32ビット
63-32 0x1004 32ビット
1023 - 992 0x107c 32ビット

実装の観点から言うと、1つの要因のみPLICに挿入されたとしても、ターゲットのHARTにより割り込みが取り込まれるまではPendingビットが1に設定されている。「取り込まれる」というのはHARTによってPLICのCLAIMレジスタが読み込まれることを言い、HARTによりPLICで通知された割り込み要因を調査したことによって、Pendingビットが解除されるという仕組みである。

3. 割り込みEnable

割り込みEnableビットは、以下の2つのことを制御する

  • どの種類の割込みが
  • どのターゲット(HARTS)に対して挿入可能か

この2つを制御するのが割り込みEnableレジスタであり、したがってレジスタは2次元的な配置を取っている。

ターゲット(HART) 割込み要因 オフセット サイズ 説明
0 31 - 0 0x2000 32 割込み要因31-0がターゲット0に対して挿入可能か
0 63 - 32 0x2004 32 割込み要因63-32がターゲット0に対して挿入可能か
0 1023 - 992 0x207c 32 割込み要因1023 - 992がターゲット0に対して挿入可能か
1 31 - 0 0x2080 32 割込み要因31-0がターゲット1に対して挿入可能か
1 63 - 32 0x2084 32 割込み要因63-32がターゲット1に対して挿入可能か
1 1023 - 992 0x21fc 32 割込み要因1023 - 992がターゲット1に対して挿入可能か
15871 31 - 0 0x1f1f80 32 割込み要因31-0がターゲット15871に対して挿入可能か
15871 63 - 32 0x1f1f84 32 割込み要因63-32がターゲット15871に対して挿入可能か
15871 1023 - 992 0x1f1ffc 32 割込み要因1023 - 992がターゲット15871に対して挿入可能か

4. 優先度のスレッショルド

これはターゲット(HART)毎に定義されたレジスタで、割り込み要因のスレッショルドを指定する。つまり、ターゲット向けに通知される割り込みの優先度が、スレッショルドの値よりも小さい場合は通知されない。

ターゲット(HART) オフセット サイズ 説明
0 0x200000 32 HART0向けの優先度スレッショルド
1 0x201000 32 HART1向けの優先度スレッショルド
2 0x202000 32 HART2向けの優先度スレッショルド
15871 0x3fff000 32 HART15871向けの優先度スレッショルド

もう一つ、重要なレジスタとしてclaim/completeレジスタというものがある。これは、HARTが割込み要因をチェックする際に参照するレジスタで、HART毎にどの割り込み要因が入っているのかというのを示している。

さらに、このレジスタには副次的な作用がある。

このレジスタをReadすることによって上記のPendingレジスタが解放され、さらに別の割込み要因が挿入できるようになる。

さらに、このレジスタをWriteすることによって当該割込み要因がCompleteする。Completeすることによって、同じ割込み要因からさらに新しい割り込みが挿入することができるようになる。

ターゲット(HART) オフセット サイズ 説明
0 0x200004 32 HART0向けのclaim/completeレジスタ
1 0x201004 32 HART1向けのclaim/completeレジスタ
2 0x202004 32 HART2向けのclaim/completeレジスタ
15871 0x3fff004 32 HART15871向けのclaim/completeレジスタ