CH32V003の割込み周りについて

このリサーチにあたっては、uchanさんのCH32V003の割り込みネストを調査と、redditのWCH 高速割り込みに関するメモ : r/RISCVを参考にしました。

CH32V003のコアは、ネストした割込みをサポートしていますが、逆に、それを有効にしないと、割込みのネストは一切できない仕様になっています。

どういうことかというと、割込み処理中にmstatusレジスタの割込み許可ビットmieを1にしても、割込みはかかりません。実証コードを以下の sample1 で示します。

https://gist.github.com/metanest/007368c511066732aeebe30f6a893735#file-sample1-c

UIAPduinoにch32funで実装したコードです。SysTickハンドラでLEDを高速明滅させつつ、ソフトウェア割込みを時々起こすようになっています。ソフトウェア割込みの実行中に、割込みを許可( https://gist.github.com/metanest/007368c511066732aeebe30f6a893735#file-sample1-c-L52 )していますが、SysTick 割込みは掛からないままです。

これを無理やり割り込めるようにするサンプルが sample2 です。

https://gist.github.com/metanest/007368c511066732aeebe30f6a893735#file-sample2-c

interrupt_enablerという関数がミソで、割込みの終了を偽装することで( https://gist.github.com/metanest/007368c511066732aeebe30f6a893735#file-sample2-c-L37 )割込みを受け付けるようになります。

さて、ではきちんとコアの機能を利用して、割込みのネストを許可してみます。sample3 になります。

https://gist.github.com/metanest/007368c511066732aeebe30f6a893735#file-sample3-c

INTSYSCRレジスタのビット1(INESTEN)をセットすることで( https://gist.github.com/metanest/007368c511066732aeebe30f6a893735#file-sample3-c-L76 )、割込みのネストを許可し、次の行でソフトウェア割込みをネスト可に設定しています。

今度は、ソフトウェア割込み中は、明示して禁止しないと、割込みは許可の状態になっています。これは仕様で、QingKeV2 Microprocessor Manualの29頁に「in the QingKe V2 series microprocessors, MIE is not updated to 0 at this time before entering the last level of interrupt」と書かれています。

ここで一つ謎があります。生成されるコードを見るとわかりますが、GCCのinterruptアトリビュートで生成されるコードは、mepcとmstatusの保存と復帰をしていません。にもかかわらず、ネストした割込みからの多段の復帰がちゃんと行われています。これはどういうことでしょうか。

これを確認しているのが sample4 です。

https://gist.github.com/metanest/007368c511066732aeebe30f6a893735#file-sample4-c

ネストした割込みからのmretの前と後で、mepcが書き換わっていることを検出しています(検出するとLEDの明滅が遅くなる)。ネストした割込みに入る時、mepc(と、おそらくmstatus)が、ハードウェアによって保存され、mretで復原されるのでしょう。

これはドキュメント化されていませんが、以上の挙動から推察できます。