前回の日記で、RISC-Vにおける動作モードの管理が良く分からないと書いたが、良く考えるとちゃんと仕様書に書いてあった。
RISC-Vでは、システムレジスタであるmstatusを使って複数の動作モードの遷移を管理している。
このルールに基いて、特権モードを移行すれば良い。さっそく実装していこう。
1. RISC-Vにおける特権モードの遷移
単純にmstatusを遷移させていく。
PrivMode current_priv = m_env->GetPrivMode (); UDWord_t mstatus; uint32_t csr_status = m_env->CSRRead (SYSREG_ADDR_MSTATUS, &mstatus); PrivMode next_priv_field = static_cast<PrivMode>((mstatus >> 4) & 3); UDWord_t next_mstatus = static_cast<PrivMode>((mstatus & 0x0ffff) >> 3) | (mstatus & 0xffff0000); m_env->CSRWrite (SYSREG_ADDR_MSTATUS, next_mstatus);
また、これ以外にも遷移を示すメッセージを表示させていたのだが、これもmstatusに応じて表示を変える必要がある。これは時間が無いので、あとでやろう。
2. MMUの動作記述
MMUの実装も進めている。ページテーブルのVビットとDビットについても実装をしないと、テストはパスしない。
ストアにおいて、
という部分の実装がうまくいっていなかった。ちゃんと修正しなければ。あとコードが汚いので改善する。
Addr_t phy_addr = vaddr & 0x0fff; DWord_t pte_val; if (GetVmMode() == Vm_Sv39) { int level; Addr_t pte_addr; for (level = 2; level >= 0; level--) { Byte_t *p_pte; p_pte = reinterpret_cast<Byte_t *>(&pte_val); Addr_t va_vpn_i = vaddr >> (12 + 9 * level * 4); pte_addr = pte_base + va_vpn_i; LoadMemoryDebug (pte_addr, Size_DWord, p_pte); memcpy (&pte_val, p_pte, 4); pte_val |= 0x20; if (!(pte_val & 0x01)) { std::cout << "<Generate Exception from " << GetPrivMode() << '\n'; GenerateException (Except_InstAccessFault); break; } if ((pte_val & 0x01) && ((pte_val >> 1) & 0x0f) >= 2) { if (IsAllowedAccess ((pte_val >> 1) & 0x0f, acc_type, GetPrivMode())) { if (acc_type == WriteMemType) { pte_val |= 0x40; } break; } else { GenerateException (Except_StoreAccessFault); break; } break; } UWord_t vpn_mask = (0x1ff << (level * 9 + 10)); phy_addr |= (pte_val & vpn_mask); } for (; level >= 0; level--) { UWord_t vpn_mask = (0x1ff << (level * 9 + 10)); phy_addr |= (vaddr & vpn_mask); } Byte_t *pte_byte = reinterpret_cast<Byte_t *>(&pte_val); StoreMemory (pte_addr, Size_DWord, pte_byte); std::cout << std::hex << " <PyhAddr = " << std::hex << phy_addr << ">\n"; } else { phy_addr = vaddr; }