
Rustで作る自作命令セットシミュレータの続き。RV32のテストは動くようになってきたので、次はRV32の仮想アドレスモードの対応について考える。 これも昔作ったC++のRISC-Vシミュレータですでに対応しているので簡単なのだが、いくつかRV32とRV64で切り替えなければならない点がある。
まずはRV32とRV64で動作する仮想アドレスモードが違うということ。RV32ではMBare(物理アドレスモード)とSv32が使用できるあが、RV64ではMBareとSv39, Sv48, Sv57, Sv64が使用できる(Sv57, Sv64はまだ仕様としては未定義)。

さらにSATPシステムレジスタの定義も少し異なる。これもRV64とRV32で区別しなければならない。

したがって、まずはページテーブルウォークの際のSATP参照の実装を変更する必要がある。
swimmer_rust/src/riscv_mmu.rs
let pte_base: Addr64T = match self.m_xlen { 32 => Self::extract_bit_field(satp, 21, 0) as Addr64T, 64 => Self::extract_bit_field(satp, 43, 0) as Addr64T, _ => panic!("Internal Error: XLEN should either 32 or 64"), };
swimmer_rust/src/riscv_core.rs
fn get_vm_mode(&mut self) -> VMMode { let satp_val = self.m_csr.csrrs(CsrAddr::Satp, 0) as Xlen64T; // SATP let mode = match self.m_xlen { 32 => Self::extract_bit_field(satp_val, 31, 31), 64 => Self::extract_bit_field(satp_val, 63, 60), _ => panic!("Internal Error: XLEN should either 32 or 64"), };
XLENの値に応じて変更を行う。ビットフィールドの定義がRV32とRV64で異なっているためだ。
それ以外の所でケアしなければならないことはあまりない。Sv32, Sv39でビットフィールドの定義を変えつつ、実装を追加する。
swimmer_rust/src/riscv_mmu.rs
if self.get_vm_mode() == VMMode::Sv39 && (priv_mode == PrivMode::Supervisor || priv_mode == PrivMode::User) { let ppn_idx: Vec<u8> = vec![12, 21, 30]; let pte_len: Vec<u8> = vec![9, 9, 26]; let pte_idx: Vec<u8> = vec![10, 19, 28]; let vpn_len: Vec<u8> = vec![9, 9, 9]; let vpn_idx: Vec<u8> = vec![12, 21, 30]; let pagesize: u32 = 4096; // num::pow(2, 12); let ptesize: u32 = 8; return self.walk_page_table( vaddr, acc_type, 3, ppn_idx, pte_len, pte_idx, vpn_len, vpn_idx, pagesize, ptesize, ); } else if self.get_vm_mode() == VMMode::Sv32 && (priv_mode == PrivMode::Supervisor || priv_mode == PrivMode::User) { let ppn_idx: Vec<u8> = vec![12, 22]; let pte_len: Vec<u8> = vec![10, 12]; let pte_idx: Vec<u8> = vec![10, 20]; let vpn_len: Vec<u8> = vec![10, 10]; let vpn_idx: Vec<u8> = vec![12, 22]; let pagesize: u32 = 4096; // num::pow(2, 12); let ptesize: u32 = 4; return self.walk_page_table( vaddr, acc_type, 2, ppn_idx, pte_len, pte_idx, vpn_len, vpn_idx, pagesize, ptesize, ); } else { return Ok(vaddr); }
動作確認を行う。
cargo run -- --arch rv32 riscv-tests/isa/rv32ui-v-add.bin | tee rv32ui-v-add.log
20650:S:Sv32:ffffffffffc02234:0046a783:lw x15,0x004(x13) :x13=>ffffffffffc01000 (ffffffffffc01004)=>00000000 x15<=0000000000000000 20651:S:Sv32:ffffffffffc02238:00050813:addi x16,x10,0x000 :x10=>0000000000000001 x16<=0000000000000001 20652:S:Sv32:ffffffffffc0223c:41f55893:srai x17,x10,0x1f :x10=>0000000000000001 x17<=0000000000000000 20653:S:Sv32:ffffffffffc02240:00f76733:or x14,x14,x15 :x14=>0000000000000000 x15=>0000000000000000 x14<=0000000000000000 20654:S:Sv32:ffffffffffc02244:02070663:beq x14,x00,0x2c :x14=>0000000000000000 x00=>0000000000000000 20655:S:Sv32:ffffffffffc02270:0106a023:sw x16,0x0000000(x13) :x16=>0000000000000001 x13=>ffffffffffc01000 (ffffffffffc01000)<=00000001 PASS : riscv-tests/isa/rv32ui-v-add.bin
Passできたようだ。リグレッションテストで確認していこう。