RISC-V の実装や命令セットシミュレータ (Instruction Set Simulator) を作ったとき、その実装の正当性をチェックするためにriscv-toolsのテストパタンを使用するという方法がある。
riscv-testsにはいくつかの種類があって、
- rv32ui-p (32-bitモード、整数命令、Physical Addressing モード)
- rv64uf-v (64-bitモード、浮動小数点命令、Virtual Addressingモード)
で、Virtual Addressingモードのテストパタンの検証なのだけれども結構ややこしいことになっている。 RISC-V の ISSであるSpikeで観測してみた。
spike -l rv64ui-v-add &> rv64ui-v-add.spike.log
sret命令は、割り込み処理から戻るための命令だ。この実装の実体は、ISSの実装から見ることができる。
- riscv-isa-sim/riscv/insns/sret.h
require_privilege(get_field(STATE.mstatus, MSTATUS_TSR) ? PRV_M : PRV_S);
set_pc_and_serialize(p->get_state()->sepc);
reg_t s = STATE.mstatus;
reg_t prev_prv = get_field(s, MSTATUS_SPP);
s = set_field(s, MSTATUS_SIE, get_field(s, MSTATUS_SPIE));
s = set_field(s, MSTATUS_SPIE, 1);
s = set_field(s, MSTATUS_SPP, PRV_U);
p->set_privilege(prev_prv);
p->set_csr(CSR_MSTATUS, s);
中身を理解するのは少し難しいのだが、mstatusシステムレジスタの中身を理解しなければならないだろう。
MPP / SPP / UPPレジスタは、モード遷移で現在のモードに移動してきた前のモードを保持している。
MPP : M-Mode に遷移してきたとき、一つ前のモード (S-Mode or U-Mode) SPP : S-Mode に遷移してきたとき、一つ前のモード (U-Mode) UPP : U-Modeに遷移してきたとき、一つ前のモード (なし)
実行結果をみてみると、
core 0: 0x00000000800000b4 (0x0f053f03) ld t5, 240(a0) core 0: 0x00000000800000b8 (0x0f853f83) ld t6, 248(a0) core 0: 0x00000000800000bc (0x05053503) ld a0, 80(a0) core 0: 0x00000000800000c0 (0x10200073) sret core 0: exception trap_instruction_page_fault, epc 0x0000000000002ac8 core 0: tval 0x0000000000002ac8 core 0: 0xffffffffffe000c4 (0x14011173) csrrw sp, sscratch, sp core 0: 0xffffffffffe000c8 (0x00113423) sd ra, 8(sp) core 0: 0xffffffffffe000cc (0x00313c23) sd gp, 24(sp) core 0: 0xffffffffffe000d0 (0x02413023) sd tp, 32(sp)
まず、sret命令を実行してsepcからアドレスをPCに設定したのだが、このときにアドレス変換のページテーブル参照に失敗して、例外を発生した。 ところが、medelegレジスタのPage Table Fault には1が設定されており、M-Modeで処理されるはずの例外はS-Modeに移譲され、S-Modeで実行が継続される。
core 0: 0xffffffffffe000b8 (0x0f853f83) ld t6, 248(a0) core 0: 0xffffffffffe000bc (0x05053503) ld a0, 80(a0) core 0: 0xffffffffffe000c0 (0x10200073) sret core 0: 0x0000000000002ac8 (0x00000093) li ra, 0 core 0: 0x0000000000002acc (0x00000113) li sp, 0 core 0: 0x0000000000002ad0 (0x00208f33) add t5, ra, sp
つぎにsretで戻ってきたときに例外から戻ってきて、正しくページテーブル変換ができるようになって戻ってくる。