riscv-cpu: fix clippy warnings

Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
Sean Cross 2023-12-30 10:52:28 +08:00
parent 82d818879f
commit 9e51cb8c32
3 changed files with 141 additions and 261 deletions

View File

@ -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<usize, ()> {
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"),
};

View File

@ -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()
}
}

View File

@ -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<u8, Trap> {
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<u16, Trap> {
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<u32, Trap> {
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<u64, Trap> {
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<bool, ()> {
// @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<bool> {
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)
}
}