Rustで作る自作命令セットシミュレータの続き。RV32とRV64でテストはある程度動くようになっているので、ここらでリグレッションテストを通して細かいところを修正していこうと思う。
Rust実装の修正
- RV32とRV64で微妙に動作が異なる部分
例えばシフト命令の即値シフト量はRV32だと5ビットだが、RV64だと64ビットになる。
RiscvInstId::SRLI => { let shamt_mask = if self.m_xlen == 32 { 0x1f } else { 0x3f }; let shamt: u32 = (Self::extract_shamt_field(inst) & shamt_mask) as u32; let rs1_data_64 = self.read_reg(rs1) as UXlen64T; let rs1_data = self.uext_xlen(rs1_data_64 as Xlen64T); let data = rs1_data.wrapping_shr(shamt) as Xlen64T; let reg_data = self.sext_xlen(data); self.write_reg(rd, reg_data); }
- 32ビットと64ビットでのアドレス拡張方法
例えばCSRレジスタの値をそのままメモリのフェッチアドレスとして使用するタイプの処理において、RV32では(一応)64ビットで用意されているレジスタを32ビットの切り落としてメモリアドレスとして活用する必要がある。このためにuext_xlen()
関数を使用してアドレス値をRV32とRV64で上手くカットしている。
fn write_bus_hword(&mut self, addr: Addr64T, data: Xlen64T) -> MemResult { return match self.convert_virtual_address(addr, MemAccType::Write) { Ok(phy_addr) => { // ここでいったんRV32とRV64のモードに応じてアドレスの切り落としを行う。 let uext_phy_addr = self.uext_xlen(phy_addr as Xlen64T); let write_mem_trace = TraceInfo::MemWrite { addr: addr, value: data, memresult: MemResult::NoExcept }; self.m_trace.m_trace_info.push(write_mem_trace); self.write_memory_hword(uext_phy_addr, data); MemResult::NoExcept }, Err(result) => result, } }
リグレッションテストの実行
リグレッションテストを実行した結果以下のテストがFailとなった。
failures: rv64ud_p_fclass rv64ud_p_fcmp rv64ud_p_fcvt rv64ud_p_fcvt_w rv64ud_p_fdiv rv64ud_p_fmin rv64ud_p_ldst rv64ud_p_move rv64ud_p_recoding rv64ud_p_structural rv64ud_v_fclass rv64ud_v_fcmp rv64ud_v_fcvt rv64ud_v_fcvt_w rv64ud_v_fdiv rv64ud_v_fmin rv64ud_v_ldst rv64ud_v_move rv64ud_v_recoding rv64ud_v_structural rv64uf_p_fclass rv64uf_p_fcmp rv64uf_p_fcvt rv64uf_p_fcvt_w rv64uf_p_fdiv rv64uf_p_fmin rv64uf_p_move rv64uf_p_recoding rv64uf_v_fclass rv64uf_v_fcmp rv64uf_v_fcvt rv64uf_v_fcvt_w rv64uf_v_fdiv rv64uf_v_fmin rv64uf_v_move rv64uf_v_recoding
浮動小数点系がやはり多い。これはhardfloatのサポートを追加していかなければならない。