diff --git a/crates/riscv-cpu/src/cpu.rs b/crates/riscv-cpu/src/cpu.rs index 56f40d6..95f50d0 100644 --- a/crates/riscv-cpu/src/cpu.rs +++ b/crates/riscv-cpu/src/cpu.rs @@ -29,7 +29,7 @@ const CSR_STVAL_ADDRESS: u16 = 0x143; const CSR_SIP_ADDRESS: u16 = 0x144; const CSR_SATP_ADDRESS: u16 = 0x180; const CSR_MSTATUS_ADDRESS: u16 = 0x300; -const CSR_MISA_ADDRESS: u16 = 0x301; +// const CSR_MISA_ADDRESS: u16 = 0x301; const CSR_MEDELEG_ADDRESS: u16 = 0x302; const CSR_MIDELEG_ADDRESS: u16 = 0x303; const CSR_MIE_ADDRESS: u16 = 0x304; @@ -44,7 +44,7 @@ const _CSR_PMPCFG0_ADDRESS: u16 = 0x3a0; const _CSR_PMPADDR0_ADDRESS: u16 = 0x3b0; const _CSR_MCYCLE_ADDRESS: u16 = 0xb00; const CSR_CYCLE_ADDRESS: u16 = 0xc00; -const CSR_TIME_ADDRESS: u16 = 0xc01; +// const CSR_TIME_ADDRESS: u16 = 0xc01; const _CSR_INSERT_ADDRESS: u16 = 0xc02; const _CSR_MHARTID_ADDRESS: u16 = 0xf14; @@ -182,8 +182,8 @@ fn _get_trap_type_name(trap_type: &TrapType) -> &'static str { fn get_trap_cause(trap: &Trap, xlen: &Xlen) -> u64 { let interrupt_bit = match xlen { - Xlen::Bit32 => 0x80000000 as u64, - Xlen::Bit64 => 0x8000000000000000 as u64, + Xlen::Bit32 => 0x80000000_u64, + Xlen::Bit64 => 0x8000000000000000_u64, }; match trap.trap_type { TrapType::InstructionAddressMisaligned => 0, @@ -215,6 +215,7 @@ fn get_trap_cause(trap: &Trap, xlen: &Xlen) -> u64 { pub struct CpuBuilder { xlen: Xlen, memory_size: u64, + memory_base: u64, } impl CpuBuilder { @@ -222,6 +223,7 @@ impl CpuBuilder { CpuBuilder { xlen: Xlen::Bit64, memory_size: 0, + memory_base: DEFAULT_MEMORY_BASE, } } @@ -236,14 +238,31 @@ impl CpuBuilder { } pub fn build(self) -> Cpu { - let mut cpu = Cpu::new(); + let mut cpu = Cpu::new(self.memory_base); cpu.update_xlen(self.xlen.clone()); + cpu.mmu.init_memory(self.memory_size); cpu } } +impl Default for CpuBuilder { + fn default() -> Self { + Self::new() + } +} + impl Default for Cpu { fn default() -> Self { + Self::new(DEFAULT_MEMORY_BASE) + } +} + +impl Cpu { + /// Creates a new `Cpu`. + /// + /// # Arguments + /// * `Terminal` + pub fn new(memory_base: u64) -> Self { Cpu { clock: 0, xlen: Xlen::Bit64, @@ -253,24 +272,14 @@ impl Default for Cpu { f: [0.0; 32], pc: 0, csr: [0; CSR_CAPACITY], - mmu: Mmu::new(Xlen::Bit64), + mmu: Mmu::new(Xlen::Bit64, memory_base), reservation: 0, is_reservation_set: false, _dump_flag: false, decode_cache: DecodeCache::new(), unsigned_data_mask: 0xffffffffffffffff, - memory_base: DEFAULT_MEMORY_BASE, + memory_base, } - } -} - -impl Cpu { - /// Creates a new `Cpu`. - /// - /// # Arguments - /// * `Terminal` - pub fn new() -> Self { - Default::default() // let mut cpu = ; // cpu.x[0xb] = 0x1020; // I don't know why but Linux boot seems to require this initialization // cpu.write_csr_raw(CSR_MISA_ADDRESS, 0x800000008014312f); @@ -406,10 +415,9 @@ impl Cpu { /// # Arguments /// * `word` word instruction data decoded fn decode_and_get_instruction_index(&self, word: u32) -> Result { - for i in 0..INSTRUCTION_NUM { - let inst = &INSTRUCTIONS[i]; + for (idx, inst) in INSTRUCTIONS.iter().enumerate() { if (word & inst.mask) == inst.data { - return Ok(i); + return Ok(idx); } } Err(()) @@ -520,7 +528,6 @@ impl Cpu { self.read_csr_raw(CSR_MIP_ADDRESS) & !MIP_STIP, ); self.wfi = false; - return; } } @@ -595,7 +602,9 @@ impl Cpu { if new_privilege_encoding < current_privilege_encoding { return false; - } else if current_privilege_encoding == new_privilege_encoding { + } + + if current_privilege_encoding == new_privilege_encoding { match self.privilege_mode { PrivilegeMode::Machine => { if current_mie == 0 { @@ -1463,7 +1472,7 @@ impl Cpu { let mut s = format!("PC:{:016x} ", self.unsigned_data(self.pc as i64)); s += &format!("{:08x} ", original_word); s += &format!("{} ", inst.name); - s += &format!("{}", (inst.disassemble)(self, word, self.pc, true)); + s += &(inst.disassemble)(self, word, self.pc, true).to_string(); s } @@ -1511,7 +1520,7 @@ fn parse_format_b(word: u32) -> FormatB { fn dump_format_b(cpu: &mut Cpu, word: u32, address: u64, evaluate: bool) -> String { let f = parse_format_b(word); let mut s = String::new(); - s += &format!("{}", get_register_name(f.rs1)); + s += get_register_name(f.rs1); if evaluate { s += &format!(":{:x}", cpu.x[f.rs1]); } @@ -1540,7 +1549,7 @@ fn parse_format_csr(word: u32) -> FormatCSR { fn dump_format_csr(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> String { let f = parse_format_csr(word); let mut s = String::new(); - s += &format!("{}", get_register_name(f.rd)); + s += get_register_name(f.rd); if evaluate { s += &format!(":{:x}", cpu.x[f.rd]); } @@ -1580,7 +1589,7 @@ fn parse_format_i(word: u32) -> FormatI { fn dump_format_i(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> String { let f = parse_format_i(word); let mut s = String::new(); - s += &format!("{}", get_register_name(f.rd)); + s += get_register_name(f.rd); if evaluate { s += &format!(":{:x}", cpu.x[f.rd]); } @@ -1595,7 +1604,7 @@ fn dump_format_i(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> Str fn dump_format_i_mem(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> String { let f = parse_format_i(word); let mut s = String::new(); - s += &format!("{}", get_register_name(f.rd)); + s += get_register_name(f.rd); if evaluate { s += &format!(":{:x}", cpu.x[f.rd]); } @@ -1603,7 +1612,7 @@ fn dump_format_i_mem(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> if evaluate { s += &format!(":{:x}", cpu.x[f.rs1]); } - s += &format!(")"); + s += ")"; s } @@ -1631,7 +1640,7 @@ fn parse_format_j(word: u32) -> FormatJ { fn dump_format_j(cpu: &mut Cpu, word: u32, address: u64, evaluate: bool) -> String { let f = parse_format_j(word); let mut s = String::new(); - s += &format!("{}", get_register_name(f.rd)); + s += get_register_name(f.rd); if evaluate { s += &format!(":{:x}", cpu.x[f.rd]); } @@ -1656,7 +1665,7 @@ fn parse_format_r(word: u32) -> FormatR { fn dump_format_r(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> String { let f = parse_format_r(word); let mut s = String::new(); - s += &format!("{}", get_register_name(f.rd)); + s += get_register_name(f.rd); if evaluate { s += &format!(":{:x}", cpu.x[f.rd]); } @@ -1691,7 +1700,7 @@ fn parse_format_r2(word: u32) -> FormatR2 { fn dump_format_r2(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> String { let f = parse_format_r2(word); let mut s = String::new(); - s += &format!("{}", get_register_name(f.rd)); + s += get_register_name(f.rd); if evaluate { s += &format!(":{:x}", cpu.x[f.rd]); } @@ -1735,7 +1744,7 @@ fn parse_format_s(word: u32) -> FormatS { fn dump_format_s(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> String { let f = parse_format_s(word); let mut s = String::new(); - s += &format!("{}", get_register_name(f.rs2)); + s += get_register_name(f.rs2); if evaluate { s += &format!(":{:x}", cpu.x[f.rs2]); } @@ -1743,7 +1752,7 @@ fn dump_format_s(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> Str if evaluate { s += &format!(":{:x}", cpu.x[f.rs1]); } - s += &format!(")"); + s += ")"; s } @@ -1762,14 +1771,14 @@ fn parse_format_u(word: u32) -> FormatU { } | // imm[63:32] = [31] ((word as u64) & 0xfffff000) // imm[31:12] = [31:12] - ) as u64, + ), } } fn dump_format_u(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> String { let f = parse_format_u(word); let mut s = String::new(); - s += &format!("{}", get_register_name(f.rd)); + s += get_register_name(f.rd); if evaluate { s += &format!(":{:x}", cpu.x[f.rd]); } @@ -2407,10 +2416,10 @@ const INSTRUCTIONS: [Instruction; INSTRUCTION_NUM] = [ PrivilegeMode::Machine => TrapType::EnvironmentCallFromMMode, PrivilegeMode::Reserved => panic!("Unknown Privilege mode"), }; - return Err(Trap { + Err(Trap { trap_type: exception_type, value: address, - }); + }) }, disassemble: dump_empty, }, @@ -2780,7 +2789,7 @@ const INSTRUCTIONS: [Instruction; INSTRUCTION_NUM] = [ disassemble: |cpu, word, _address, evaluate| { let f = parse_format_i(word); let mut s = String::new(); - s += &format!("{}", get_register_name(f.rd)); + s += get_register_name(f.rd); if evaluate { s += &format!(":{:x}", cpu.x[f.rd]); } @@ -2788,7 +2797,7 @@ const INSTRUCTIONS: [Instruction; INSTRUCTION_NUM] = [ if evaluate { s += &format!(":{:x}", cpu.x[f.rs1]); } - s += &format!(")"); + s += ")"; s }, }, @@ -3372,7 +3381,7 @@ const INSTRUCTIONS: [Instruction; INSTRUCTION_NUM] = [ name: "SRAIW", operation: |cpu, word, _address| { let f = parse_format_r(word); - let shamt = ((word >> 20) & 0x1f) as u32; + let shamt = (word >> 20) & 0x1f; cpu.x[f.rd] = ((cpu.x[f.rs1] as i32) >> shamt) as i64; Ok(()) }, @@ -3744,7 +3753,7 @@ mod test_cpu { use super::*; fn create_cpu() -> Cpu { - Cpu::new() + Cpu::default() } #[test] @@ -3938,10 +3947,7 @@ mod test_cpu { cpu.get_mut_mmu().init_memory(4); cpu.update_pc(memory_base); // write WFI instruction - match cpu - .get_mut_mmu() - .store_word(memory_base, wfi_instruction) - { + match cpu.get_mut_mmu().store_word(memory_base, wfi_instruction) { Ok(()) => {} Err(_e) => panic!("Failed to store"), }; @@ -4046,10 +4052,7 @@ mod test_cpu { Err(_e) => panic!("Failed to store"), }; // Write non-compressed "addi x1, x1, 1" instruction - match cpu - .get_mut_mmu() - .store_word(memory_base + 4, 0x00108093) - { + match cpu.get_mut_mmu().store_word(memory_base + 4, 0x00108093) { Ok(()) => {} Err(_e) => panic!("Failed to store"), }; diff --git a/crates/riscv-cpu/src/memory.rs b/crates/riscv-cpu/src/memory.rs index afe3b0d..1ce7bce 100644 --- a/crates/riscv-cpu/src/memory.rs +++ b/crates/riscv-cpu/src/memory.rs @@ -29,7 +29,7 @@ impl Memory { /// * `address` pub fn read_byte(&self, address: u64) -> u8 { let index = (address >> 3) as usize; - let pos = ((address % 8) as u64) * 8; + let pos = (address % 8) * 8; (self.data[index] >> pos) as u8 } @@ -40,7 +40,7 @@ impl Memory { pub fn read_halfword(&self, address: u64) -> u16 { if (address % 2) == 0 { let index = (address >> 3) as usize; - let pos = ((address % 8) as u64) * 8; + let pos = (address % 8) * 8; (self.data[index] >> pos) as u16 } else { self.read_bytes(address, 2) as u16 @@ -54,7 +54,7 @@ impl Memory { pub fn read_word(&self, address: u64) -> u32 { if (address % 4) == 0 { let index = (address >> 3) as usize; - let pos = ((address % 8) as u64) * 8; + let pos = (address % 8) * 8; (self.data[index] >> pos) as u32 } else { self.read_bytes(address, 4) as u32 @@ -82,7 +82,7 @@ impl Memory { /// * `address` /// * `width` up to eight pub fn read_bytes(&self, address: u64, width: u64) -> u64 { - let mut data = 0 as u64; + let mut data = 0; for i in 0..width { data |= (self.read_byte(address.wrapping_add(i)) as u64) << (i * 8); } @@ -96,7 +96,7 @@ impl Memory { /// * `value` pub fn write_byte(&mut self, address: u64, value: u8) { let index = (address >> 3) as usize; - let pos = ((address % 8) as u64) * 8; + let pos = (address % 8) * 8; self.data[index] = (self.data[index] & !(0xff << pos)) | ((value as u64) << pos); } @@ -108,7 +108,7 @@ impl Memory { pub fn write_halfword(&mut self, address: u64, value: u16) { if (address % 2) == 0 { let index = (address >> 3) as usize; - let pos = ((address % 8) as u64) * 8; + let pos = (address % 8) * 8; self.data[index] = (self.data[index] & !(0xffff << pos)) | ((value as u64) << pos); } else { self.write_bytes(address, value as u64, 2); @@ -123,7 +123,7 @@ impl Memory { pub fn write_word(&mut self, address: u64, value: u32) { if (address % 4) == 0 { let index = (address >> 3) as usize; - let pos = ((address % 8) as u64) * 8; + let pos = (address % 8) * 8; self.data[index] = (self.data[index] & !(0xffffffff << pos)) | ((value as u64) << pos); } else { self.write_bytes(address, value as u64, 4); @@ -164,6 +164,12 @@ impl Memory { /// # Arguments /// * `address` pub fn validate_address(&self, address: u64) -> bool { - return (address as usize) < self.data.len() + (address as usize) < self.data.len() } } + +impl Default for Memory { + fn default() -> Self { + Self::new() + } +} diff --git a/crates/riscv-cpu/src/mmu.rs b/crates/riscv-cpu/src/mmu.rs index 5980ef6..3866f8a 100644 --- a/crates/riscv-cpu/src/mmu.rs +++ b/crates/riscv-cpu/src/mmu.rs @@ -1,7 +1,3 @@ -/// DRAM base address. Offset from this base address -/// is the address in main memory. -pub const DRAM_BASE: u64 = 0x80000000; - use std::collections::HashMap; use crate::{ @@ -15,7 +11,7 @@ use crate::{ /// It may also be said Bus. /// @TODO: Memory protection is not implemented yet. We should support. pub struct Mmu { - clock: u64, + // clock: u64, xlen: Xlen, ppn: u64, addressing_mode: AddressingMode, @@ -72,7 +68,7 @@ impl Mmu { /// # Arguments /// * `xlen` /// * `terminal` - pub fn new(xlen: Xlen) -> Self { + pub fn new(xlen: Xlen, dram_base: u64) -> Self { // // Load default device tree binary content // let content = include_bytes!("./device/dtb.dtb"); // for i in 0..content.len() { @@ -80,12 +76,12 @@ impl Mmu { // } Mmu { - clock: 0, + // clock: 0, xlen, ppn: 0, addressing_mode: AddressingMode::None, privilege_mode: PrivilegeMode::Machine, - memory: MemoryWrapper::new(), + memory: MemoryWrapper::new(dram_base), mstatus: 0, page_cache_enabled: false, fetch_page_cache: HashMap::default(), @@ -179,15 +175,12 @@ impl Mmu { /// # Arguments /// * `v_address` Virtual address fn fetch(&mut self, v_address: u64) -> Result { - match self.translate_address(v_address, &MemoryAccessType::Execute) { - Ok(p_address) => Ok(self.load_raw(p_address)), - Err(()) => { - return Err(Trap { - trap_type: TrapType::InstructionPageFault, - value: v_address, - }) - } - } + self.translate_address(v_address, &MemoryAccessType::Execute) + .map(|p_address| self.load_raw(p_address)) + .map_err(|()| Trap { + trap_type: TrapType::InstructionPageFault, + value: v_address, + }) } /// Fetches instruction four bytes. This method takes virtual address @@ -211,7 +204,7 @@ impl Mmu { } } false => { - let mut data = 0 as u32; + let mut data = 0; for i in 0..width { match self.fetch(v_address.wrapping_add(i)) { Ok(byte) => data |= (byte as u32) << (i * 8), @@ -270,7 +263,7 @@ impl Mmu { }), }, false => { - let mut data = 0 as u64; + let mut data = 0; for i in 0..width { match self.load(v_address.wrapping_add(i)) { Ok(byte) => data |= (byte as u64) << (i * 8), @@ -288,10 +281,7 @@ impl Mmu { /// # Arguments /// * `v_address` Virtual address pub fn load_halfword(&mut self, v_address: u64) -> Result { - match self.load_bytes(v_address, 2) { - Ok(data) => Ok(data as u16), - Err(e) => Err(e), - } + self.load_bytes(v_address, 2).map(|data| data as u16) } /// Loads four bytes. This method takes virtual address and translates @@ -300,10 +290,7 @@ impl Mmu { /// # Arguments /// * `v_address` Virtual address pub fn load_word(&mut self, v_address: u64) -> Result { - match self.load_bytes(v_address, 4) { - Ok(data) => Ok(data as u32), - Err(e) => Err(e), - } + self.load_bytes(v_address, 4).map(|data| data as u32) } /// Loads eight bytes. This method takes virtual address and translates @@ -312,10 +299,7 @@ impl Mmu { /// # Arguments /// * `v_address` Virtual address pub fn load_doubleword(&mut self, v_address: u64) -> Result { - match self.load_bytes(v_address, 8) { - Ok(data) => Ok(data as u64), - Err(e) => Err(e), - } + self.load_bytes(v_address, 8) } /// Store an byte. This method takes virtual address and translates @@ -325,16 +309,12 @@ impl Mmu { /// * `v_address` Virtual address /// * `value` pub fn store(&mut self, v_address: u64, value: u8) -> Result<(), Trap> { - match self.translate_address(v_address, &MemoryAccessType::Write) { - Ok(p_address) => { - self.store_raw(p_address, value); - Ok(()) - } - Err(()) => Err(Trap { + self.translate_address(v_address, &MemoryAccessType::Write) + .map(|p_address| self.store_raw(p_address, value)) + .map_err(|()| Trap { trap_type: TrapType::StorePageFault, value: v_address, - }), - } + }) } /// Stores multiple bytes. This method takes virtual address and translates @@ -408,7 +388,7 @@ impl Mmu { /// * `v_address` Virtual address /// * `value` data written pub fn store_doubleword(&mut self, v_address: u64, value: u64) -> Result<(), Trap> { - self.store_bytes(v_address, value as u64, 8) + self.store_bytes(v_address, value, 8) } /// Loads a byte from main memory or peripheral devices depending on @@ -417,22 +397,7 @@ impl Mmu { /// # Arguments /// * `p_address` Physical address fn load_raw(&mut self, p_address: u64) -> u8 { - let effective_address = self.get_effective_address(p_address); - // @TODO: Mapping should be configurable with dtb - match effective_address >= DRAM_BASE { - true => self.memory.read_byte(effective_address), - false => match effective_address { - // // I don't know why but dtb data seems to be stored from 0x1020 on Linux. - // // It might be from self.x[0xb] initialization? - // // And DTB size is arbitray. - // 0x00001020..=0x00001fff => self.dtb[effective_address as usize - 0x1020], - // 0x02000000..=0x0200ffff => self.clint.load(effective_address), - // 0x0C000000..=0x0fffffff => self.plic.load(effective_address), - // 0x10000000..=0x100000ff => self.uart.load(effective_address), - // 0x10001000..=0x10001FFF => self.disk.load(effective_address), - _ => panic!("Unknown memory mapping {:X}.", effective_address), - }, - } + self.memory.read_byte(self.get_effective_address(p_address)) } /// Loads two bytes from main memory or peripheral devices depending on @@ -441,20 +406,8 @@ impl Mmu { /// # Arguments /// * `p_address` Physical address fn load_halfword_raw(&mut self, p_address: u64) -> u16 { - let effective_address = self.get_effective_address(p_address); - match effective_address >= DRAM_BASE - && effective_address.wrapping_add(1) > effective_address - { - // Fast path. Directly load main memory at a time. - true => self.memory.read_halfword(effective_address), - false => { - let mut data = 0 as u16; - for i in 0..2 { - data |= (self.load_raw(effective_address.wrapping_add(i)) as u16) << (i * 8) - } - data - } - } + self.memory + .read_halfword(self.get_effective_address(p_address)) } /// Loads four bytes from main memory or peripheral devices depending on @@ -463,20 +416,7 @@ impl Mmu { /// # Arguments /// * `p_address` Physical address pub fn load_word_raw(&mut self, p_address: u64) -> u32 { - let effective_address = self.get_effective_address(p_address); - match effective_address >= DRAM_BASE - && effective_address.wrapping_add(3) > effective_address - { - // Fast path. Directly load main memory at a time. - true => self.memory.read_word(effective_address), - false => { - let mut data = 0 as u32; - for i in 0..4 { - data |= (self.load_raw(effective_address.wrapping_add(i)) as u32) << (i * 8) - } - data - } - } + self.memory.read_word(self.get_effective_address(p_address)) } /// Loads eight bytes from main memory or peripheral devices depending on @@ -485,20 +425,8 @@ impl Mmu { /// # Arguments /// * `p_address` Physical address fn load_doubleword_raw(&mut self, p_address: u64) -> u64 { - let effective_address = self.get_effective_address(p_address); - match effective_address >= DRAM_BASE - && effective_address.wrapping_add(7) > effective_address - { - // Fast path. Directly load main memory at a time. - true => self.memory.read_doubleword(effective_address), - false => { - let mut data = 0 as u64; - for i in 0..8 { - data |= (self.load_raw(effective_address.wrapping_add(i)) as u64) << (i * 8) - } - data - } - } + self.memory + .read_doubleword(self.get_effective_address(p_address)) } /// Stores a byte to main memory or peripheral devices depending on @@ -508,18 +436,8 @@ impl Mmu { /// * `p_address` Physical address /// * `value` data written pub fn store_raw(&mut self, p_address: u64, value: u8) { - let effective_address = self.get_effective_address(p_address); - // @TODO: Mapping should be configurable with dtb - match effective_address >= DRAM_BASE { - true => self.memory.write_byte(effective_address, value), - false => match effective_address { - // 0x02000000..=0x0200ffff => self.clint.store(effective_address, value), - // 0x0c000000..=0x0fffffff => self.plic.store(effective_address, value), - // 0x10000000..=0x100000ff => self.uart.store(effective_address, value), - // 0x10001000..=0x10001FFF => self.disk.store(effective_address, value), - _ => panic!("Unknown memory mapping {:X}.", effective_address), - }, - }; + self.memory + .write_byte(self.get_effective_address(p_address), value) } /// Stores two bytes to main memory or peripheral devices depending on @@ -529,21 +447,8 @@ impl Mmu { /// * `p_address` Physical address /// * `value` data written fn store_halfword_raw(&mut self, p_address: u64, value: u16) { - let effective_address = self.get_effective_address(p_address); - match effective_address >= DRAM_BASE - && effective_address.wrapping_add(1) > effective_address - { - // Fast path. Directly store to main memory at a time. - true => self.memory.write_halfword(effective_address, value), - false => { - for i in 0..2 { - self.store_raw( - effective_address.wrapping_add(i), - ((value >> (i * 8)) & 0xff) as u8, - ); - } - } - } + self.memory + .write_halfword(self.get_effective_address(p_address), value) } /// Stores four bytes to main memory or peripheral devices depending on @@ -553,21 +458,8 @@ impl Mmu { /// * `p_address` Physical address /// * `value` data written fn store_word_raw(&mut self, p_address: u64, value: u32) { - let effective_address = self.get_effective_address(p_address); - match effective_address >= DRAM_BASE - && effective_address.wrapping_add(3) > effective_address - { - // Fast path. Directly store to main memory at a time. - true => self.memory.write_word(effective_address, value), - false => { - for i in 0..4 { - self.store_raw( - effective_address.wrapping_add(i), - ((value >> (i * 8)) & 0xff) as u8, - ); - } - } - } + self.memory + .write_word(self.get_effective_address(p_address), value) } /// Stores eight bytes to main memory or peripheral devices depending on @@ -577,21 +469,8 @@ impl Mmu { /// * `p_address` Physical address /// * `value` data written fn store_doubleword_raw(&mut self, p_address: u64, value: u64) { - let effective_address = self.get_effective_address(p_address); - match effective_address >= DRAM_BASE - && effective_address.wrapping_add(7) > effective_address - { - // Fast path. Directly store to main memory at a time. - true => self.memory.write_doubleword(effective_address, value), - false => { - for i in 0..8 { - self.store_raw( - effective_address.wrapping_add(i), - ((value >> (i * 8)) & 0xff) as u8, - ); - } - } - } + self.memory + .write_doubleword(self.get_effective_address(p_address), value) } /// Checks if passed virtual address is valid (pointing a certain device) or not. @@ -599,25 +478,15 @@ impl Mmu { /// /// # Arguments /// * `v_address` Virtual address - pub fn validate_address(&mut self, v_address: u64) -> Result { - // @TODO: Support other access types? - let p_address = match self.translate_address(v_address, &MemoryAccessType::DontCare) { - Ok(address) => address, - Err(()) => return Err(()), - }; - let effective_address = self.get_effective_address(p_address); - let valid = match effective_address >= DRAM_BASE { - true => self.memory.validate_address(effective_address), - false => match effective_address { - 0x00001020..=0x00001fff => true, - 0x02000000..=0x0200ffff => true, - 0x0C000000..=0x0fffffff => true, - 0x10000000..=0x100000ff => true, - 0x10001000..=0x10001FFF => true, - _ => false, - }, - }; - Ok(valid) + pub fn validate_address(&mut self, v_address: u64) -> Option { + if let Ok(p_address) = self.translate_address(v_address, &MemoryAccessType::DontCare) { + Some( + self.memory + .validate_address(self.get_effective_address(p_address)), + ) + } else { + None + } } fn translate_address( @@ -668,7 +537,7 @@ impl Mmu { }, PrivilegeMode::User | PrivilegeMode::Supervisor => { let vpns = [(address >> 12) & 0x3ff, (address >> 22) & 0x3ff]; - self.traverse_page(address, 2 - 1, self.ppn, &vpns, &access_type) + self.traverse_page(address, 2 - 1, self.ppn, &vpns, access_type) } _ => Ok(address), }, @@ -704,7 +573,7 @@ impl Mmu { (address >> 21) & 0x1ff, (address >> 30) & 0x1ff, ]; - self.traverse_page(address, 3 - 1, self.ppn, &vpns, &access_type) + self.traverse_page(address, 3 - 1, self.ppn, &vpns, access_type) } _ => Ok(address), }, @@ -867,16 +736,16 @@ impl Mmu { } } -/// [`Memory`](../memory/struct.Memory.html) wrapper. Converts physical address to the one in memory -/// using [`DRAM_BASE`](constant.DRAM_BASE.html) and accesses [`Memory`](../memory/struct.Memory.html). pub struct MemoryWrapper { memory: Memory, + dram_base: u64, } impl MemoryWrapper { - fn new() -> Self { + fn new(dram_base: u64) -> Self { MemoryWrapper { memory: Memory::new(), + dram_base, } } @@ -886,77 +755,79 @@ impl MemoryWrapper { pub fn read_byte(&mut self, p_address: u64) -> u8 { debug_assert!( - p_address >= DRAM_BASE, - "Memory address must equals to or bigger than DRAM_BASE. {:X}", + p_address >= self.dram_base, + "Memory address must equals to or bigger than self.dram_base. {:X}", p_address ); - self.memory.read_byte(p_address - DRAM_BASE) + self.memory.read_byte(p_address - self.dram_base) } pub fn read_halfword(&mut self, p_address: u64) -> u16 { debug_assert!( - p_address >= DRAM_BASE && p_address.wrapping_add(1) >= DRAM_BASE, - "Memory address must equals to or bigger than DRAM_BASE. {:X}", + p_address >= self.dram_base && p_address.wrapping_add(1) >= self.dram_base, + "Memory address must equals to or bigger than self.dram_base. {:X}", p_address ); - self.memory.read_halfword(p_address - DRAM_BASE) + self.memory.read_halfword(p_address - self.dram_base) } pub fn read_word(&mut self, p_address: u64) -> u32 { debug_assert!( - p_address >= DRAM_BASE && p_address.wrapping_add(3) >= DRAM_BASE, - "Memory address must equals to or bigger than DRAM_BASE. {:X}", + p_address >= self.dram_base && p_address.wrapping_add(3) >= self.dram_base, + "Memory address must equals to or bigger than self.dram_base. {:X}", p_address ); - self.memory.read_word(p_address - DRAM_BASE) + self.memory.read_word(p_address - self.dram_base) } pub fn read_doubleword(&mut self, p_address: u64) -> u64 { debug_assert!( - p_address >= DRAM_BASE && p_address.wrapping_add(7) >= DRAM_BASE, - "Memory address must equals to or bigger than DRAM_BASE. {:X}", + p_address >= self.dram_base && p_address.wrapping_add(7) >= self.dram_base, + "Memory address must equals to or bigger than self.dram_base. {:X}", p_address ); - self.memory.read_doubleword(p_address - DRAM_BASE) + self.memory.read_doubleword(p_address - self.dram_base) } pub fn write_byte(&mut self, p_address: u64, value: u8) { debug_assert!( - p_address >= DRAM_BASE, - "Memory address must equals to or bigger than DRAM_BASE. {:X}", + p_address >= self.dram_base, + "Memory address must equals to or bigger than self.dram_base. {:X}", p_address ); - self.memory.write_byte(p_address - DRAM_BASE, value) + self.memory.write_byte(p_address - self.dram_base, value) } pub fn write_halfword(&mut self, p_address: u64, value: u16) { debug_assert!( - p_address >= DRAM_BASE && p_address.wrapping_add(1) >= DRAM_BASE, - "Memory address must equals to or bigger than DRAM_BASE. {:X}", + p_address >= self.dram_base && p_address.wrapping_add(1) >= self.dram_base, + "Memory address must equals to or bigger than self.dram_base. {:X}", p_address ); - self.memory.write_halfword(p_address - DRAM_BASE, value) + self.memory + .write_halfword(p_address - self.dram_base, value) } pub fn write_word(&mut self, p_address: u64, value: u32) { debug_assert!( - p_address >= DRAM_BASE && p_address.wrapping_add(3) >= DRAM_BASE, - "Memory address must equals to or bigger than DRAM_BASE. {:X}", + p_address >= self.dram_base && p_address.wrapping_add(3) >= self.dram_base, + "Memory address must equals to or bigger than self.dram_base. {:X}", p_address ); - self.memory.write_word(p_address - DRAM_BASE, value) + self.memory.write_word(p_address - self.dram_base, value) } pub fn write_doubleword(&mut self, p_address: u64, value: u64) { debug_assert!( - p_address >= DRAM_BASE && p_address.wrapping_add(7) >= DRAM_BASE, - "Memory address must equals to or bigger than DRAM_BASE. {:X}", + p_address >= self.dram_base && p_address.wrapping_add(7) >= self.dram_base, + "Memory address must equals to or bigger than self.dram_base. {:X}", p_address ); - self.memory.write_doubleword(p_address - DRAM_BASE, value) + self.memory + .write_doubleword(p_address - self.dram_base, value) } pub fn validate_address(&self, address: u64) -> bool { - self.memory.validate_address(address - DRAM_BASE) + self.memory.validate_address(address - self.dram_base) } }