引き続きRISC-VのISSをメンテナンスして、OSのポーティングと調整を行っているのだが、そういえばベンチマークセットの動作確認をやっている途中で忘れていた。
ISSの調整ついでに、失敗したパタンについて何が起きているのかを見ていこう。
Dhrystoneベンチマークを動作させる
dhrystoneは、riscv-testsリポジトリ内に格納されている。
これをそのまま実行すると、パタンが正常に終了してくれないという問題があった。通常のテストパタンセットでは、mtohostシステムレジスタに1を書き込むと成功、それ以外を書き込むと失敗となっている。 mtohostには、よくわからない値が格納されていて終了していた。
151988:M:MBar:[00000cf0] 00e7b023 : sd tp,sp,0x00|zero tp=>0000000000024ac0 sp=>0000000000000040 (0000000000024ac0)<=00000040 151989:M:MBar:[00000cf4] 06063703 : ld sp,s10,0x060 s10=>0000000000024b50 (0000000000024bb0)=>0000002e sp<=000000000000002e 151990:M:MBar:[00000cf8] 00a7b423 : sd tp,s8,0x00|s6 tp=>0000000000024ac0 s8=>0000000000000001 (0000000000024ac8)<=00000001 151991:M:MBar:[00000cfc] 00d7b823 : sd tp,s11,0x00|v0 tp=>0000000000024ac0 s11=>0000000000005280 (0000000000024ad0)<=00000080 151992:M:MBar:[00000d00] 00e7bc23 : sd tp,sp,0x00|a6 tp=>0000000000024ac0 sp=>000000000000002e (0000000000024ad8)<=0000002e 151993:M:MBar:[00000d04] 0330000f : fence 151994:M:MBar:[00000d08] 78079073 : csrrw zero,0x780,tp mtohost=>0000000000000000 tp=>0000000000024ac0 mtohost<=0000000000024ac0
これ、ルーチンを追いかけていくと、printfなどを利用するとプログラム内でmtohostにアクセスするらしい。なのでこのmtohostへの書き込みは終了コードを出しているわけではなく、普通にprintfをしているようだった。 ちょっとわかりにくいが、とりあえずmtohostで0か1が出力される以外は終了しないようにしておこう。
その中で、プログラムを追いかけていたのだが、ちゃんとeretでユーザモードに戻ってくれない場所がある。
RISC-Vのeret命令について
eret命令は、スーパバイザコードや割り込みによって割り込みコードに分岐した場合、ユーザコードに戻るために利用される命令だ。eret命令は、mstatusのbitを読み取り、PRV,IEのモード情報をmstatus内からポップする。 より具体的には、mstatusには複数割り込みに備えてPRV,IEビットがスタックできるようになっており、eretはそのスタックをポップしてユーザモードに戻るわけだ。
あれ、よく考えると、eretの逆、つまり特権モードに移るための命令であるecallには、mstatusにpushする操作を追加していたかな?
確認すると追加されていなかったので、ecallのルーチンにmstatusを操作するコードを追加した。 これで、ecallでモード情報をmstatusにpush、eretでモード情報をmstatusからpop、という操作が実現される。
UDWord_t curr_mstatus; m_env->CSRRead (SYSREG_ADDR_MSTATUS, &curr_mstatus); UDWord_t next_mstatus = (curr_mstatus << 3) | (static_cast<UDWord_t>(curr_priv) << 1); m_env->CSRWrite (SYSREG_ADDR_MSTATUS, next_mstatus);
Dhrystoneベンチマークの修正
上記の修正を行って改めてdhrystoneを走らせていたのだが、どうやら終了しない。調べてみると実機のタイマー情報を利用して終了判定をしているようだ。
/**************/ /* Stop timer */ /**************/ Stop_Timer(); setStats(0); User_Time = End_Time - Begin_Time; if (User_Time < Too_Small_Time) { printf("Measured time too small to obtain meaningful results\n"); Number_Of_Runs = Number_Of_Runs * 10; printf("\n"); } else Done = true; }
タイマー情報を使われるとシミュレーションにもかなりの長い時間が使われてしまうため、ここはベンチマークを書き換えて終了するようにした。
/**************/ /* Stop timer */ /**************/ Stop_Timer(); setStats(0); User_Time = End_Time - Begin_Time; // if (User_Time < Too_Small_Time) // { // printf("Measured time too small to obtain meaningful results\n"); // Number_Of_Runs = Number_Of_Runs * 10; // printf("\n"); // } else Done = true; Done = true; }
とりあえずこれで良し。
と思ったらSupervisorのアドレッシングモードがまじめに動き出したのでユーザモードを使うパタンが落ちだしたなあ。。。修正しないと。