riscv-cpu: fix clippy warnings
Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
parent
82d818879f
commit
9e51cb8c32
@ -29,7 +29,7 @@ const CSR_STVAL_ADDRESS: u16 = 0x143;
|
|||||||
const CSR_SIP_ADDRESS: u16 = 0x144;
|
const CSR_SIP_ADDRESS: u16 = 0x144;
|
||||||
const CSR_SATP_ADDRESS: u16 = 0x180;
|
const CSR_SATP_ADDRESS: u16 = 0x180;
|
||||||
const CSR_MSTATUS_ADDRESS: u16 = 0x300;
|
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_MEDELEG_ADDRESS: u16 = 0x302;
|
||||||
const CSR_MIDELEG_ADDRESS: u16 = 0x303;
|
const CSR_MIDELEG_ADDRESS: u16 = 0x303;
|
||||||
const CSR_MIE_ADDRESS: u16 = 0x304;
|
const CSR_MIE_ADDRESS: u16 = 0x304;
|
||||||
@ -44,7 +44,7 @@ const _CSR_PMPCFG0_ADDRESS: u16 = 0x3a0;
|
|||||||
const _CSR_PMPADDR0_ADDRESS: u16 = 0x3b0;
|
const _CSR_PMPADDR0_ADDRESS: u16 = 0x3b0;
|
||||||
const _CSR_MCYCLE_ADDRESS: u16 = 0xb00;
|
const _CSR_MCYCLE_ADDRESS: u16 = 0xb00;
|
||||||
const CSR_CYCLE_ADDRESS: u16 = 0xc00;
|
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_INSERT_ADDRESS: u16 = 0xc02;
|
||||||
const _CSR_MHARTID_ADDRESS: u16 = 0xf14;
|
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 {
|
fn get_trap_cause(trap: &Trap, xlen: &Xlen) -> u64 {
|
||||||
let interrupt_bit = match xlen {
|
let interrupt_bit = match xlen {
|
||||||
Xlen::Bit32 => 0x80000000 as u64,
|
Xlen::Bit32 => 0x80000000_u64,
|
||||||
Xlen::Bit64 => 0x8000000000000000 as u64,
|
Xlen::Bit64 => 0x8000000000000000_u64,
|
||||||
};
|
};
|
||||||
match trap.trap_type {
|
match trap.trap_type {
|
||||||
TrapType::InstructionAddressMisaligned => 0,
|
TrapType::InstructionAddressMisaligned => 0,
|
||||||
@ -215,6 +215,7 @@ fn get_trap_cause(trap: &Trap, xlen: &Xlen) -> u64 {
|
|||||||
pub struct CpuBuilder {
|
pub struct CpuBuilder {
|
||||||
xlen: Xlen,
|
xlen: Xlen,
|
||||||
memory_size: u64,
|
memory_size: u64,
|
||||||
|
memory_base: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CpuBuilder {
|
impl CpuBuilder {
|
||||||
@ -222,6 +223,7 @@ impl CpuBuilder {
|
|||||||
CpuBuilder {
|
CpuBuilder {
|
||||||
xlen: Xlen::Bit64,
|
xlen: Xlen::Bit64,
|
||||||
memory_size: 0,
|
memory_size: 0,
|
||||||
|
memory_base: DEFAULT_MEMORY_BASE,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,14 +238,31 @@ impl CpuBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(self) -> Cpu {
|
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.update_xlen(self.xlen.clone());
|
||||||
|
cpu.mmu.init_memory(self.memory_size);
|
||||||
cpu
|
cpu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for CpuBuilder {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for Cpu {
|
impl Default for Cpu {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
Self::new(DEFAULT_MEMORY_BASE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Cpu {
|
||||||
|
/// Creates a new `Cpu`.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `Terminal`
|
||||||
|
pub fn new(memory_base: u64) -> Self {
|
||||||
Cpu {
|
Cpu {
|
||||||
clock: 0,
|
clock: 0,
|
||||||
xlen: Xlen::Bit64,
|
xlen: Xlen::Bit64,
|
||||||
@ -253,24 +272,14 @@ impl Default for Cpu {
|
|||||||
f: [0.0; 32],
|
f: [0.0; 32],
|
||||||
pc: 0,
|
pc: 0,
|
||||||
csr: [0; CSR_CAPACITY],
|
csr: [0; CSR_CAPACITY],
|
||||||
mmu: Mmu::new(Xlen::Bit64),
|
mmu: Mmu::new(Xlen::Bit64, memory_base),
|
||||||
reservation: 0,
|
reservation: 0,
|
||||||
is_reservation_set: false,
|
is_reservation_set: false,
|
||||||
_dump_flag: false,
|
_dump_flag: false,
|
||||||
decode_cache: DecodeCache::new(),
|
decode_cache: DecodeCache::new(),
|
||||||
unsigned_data_mask: 0xffffffffffffffff,
|
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 = ;
|
// let mut cpu = ;
|
||||||
// cpu.x[0xb] = 0x1020; // I don't know why but Linux boot seems to require this initialization
|
// 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);
|
// cpu.write_csr_raw(CSR_MISA_ADDRESS, 0x800000008014312f);
|
||||||
@ -406,10 +415,9 @@ impl Cpu {
|
|||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `word` word instruction data decoded
|
/// * `word` word instruction data decoded
|
||||||
fn decode_and_get_instruction_index(&self, word: u32) -> Result<usize, ()> {
|
fn decode_and_get_instruction_index(&self, word: u32) -> Result<usize, ()> {
|
||||||
for i in 0..INSTRUCTION_NUM {
|
for (idx, inst) in INSTRUCTIONS.iter().enumerate() {
|
||||||
let inst = &INSTRUCTIONS[i];
|
|
||||||
if (word & inst.mask) == inst.data {
|
if (word & inst.mask) == inst.data {
|
||||||
return Ok(i);
|
return Ok(idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(())
|
Err(())
|
||||||
@ -520,7 +528,6 @@ impl Cpu {
|
|||||||
self.read_csr_raw(CSR_MIP_ADDRESS) & !MIP_STIP,
|
self.read_csr_raw(CSR_MIP_ADDRESS) & !MIP_STIP,
|
||||||
);
|
);
|
||||||
self.wfi = false;
|
self.wfi = false;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -595,7 +602,9 @@ impl Cpu {
|
|||||||
|
|
||||||
if new_privilege_encoding < current_privilege_encoding {
|
if new_privilege_encoding < current_privilege_encoding {
|
||||||
return false;
|
return false;
|
||||||
} else if current_privilege_encoding == new_privilege_encoding {
|
}
|
||||||
|
|
||||||
|
if current_privilege_encoding == new_privilege_encoding {
|
||||||
match self.privilege_mode {
|
match self.privilege_mode {
|
||||||
PrivilegeMode::Machine => {
|
PrivilegeMode::Machine => {
|
||||||
if current_mie == 0 {
|
if current_mie == 0 {
|
||||||
@ -1463,7 +1472,7 @@ impl Cpu {
|
|||||||
let mut s = format!("PC:{:016x} ", self.unsigned_data(self.pc as i64));
|
let mut s = format!("PC:{:016x} ", self.unsigned_data(self.pc as i64));
|
||||||
s += &format!("{:08x} ", original_word);
|
s += &format!("{:08x} ", original_word);
|
||||||
s += &format!("{} ", inst.name);
|
s += &format!("{} ", inst.name);
|
||||||
s += &format!("{}", (inst.disassemble)(self, word, self.pc, true));
|
s += &(inst.disassemble)(self, word, self.pc, true).to_string();
|
||||||
s
|
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 {
|
fn dump_format_b(cpu: &mut Cpu, word: u32, address: u64, evaluate: bool) -> String {
|
||||||
let f = parse_format_b(word);
|
let f = parse_format_b(word);
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
s += &format!("{}", get_register_name(f.rs1));
|
s += get_register_name(f.rs1);
|
||||||
if evaluate {
|
if evaluate {
|
||||||
s += &format!(":{:x}", cpu.x[f.rs1]);
|
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 {
|
fn dump_format_csr(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> String {
|
||||||
let f = parse_format_csr(word);
|
let f = parse_format_csr(word);
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
s += &format!("{}", get_register_name(f.rd));
|
s += get_register_name(f.rd);
|
||||||
if evaluate {
|
if evaluate {
|
||||||
s += &format!(":{:x}", cpu.x[f.rd]);
|
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 {
|
fn dump_format_i(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> String {
|
||||||
let f = parse_format_i(word);
|
let f = parse_format_i(word);
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
s += &format!("{}", get_register_name(f.rd));
|
s += get_register_name(f.rd);
|
||||||
if evaluate {
|
if evaluate {
|
||||||
s += &format!(":{:x}", cpu.x[f.rd]);
|
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 {
|
fn dump_format_i_mem(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> String {
|
||||||
let f = parse_format_i(word);
|
let f = parse_format_i(word);
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
s += &format!("{}", get_register_name(f.rd));
|
s += get_register_name(f.rd);
|
||||||
if evaluate {
|
if evaluate {
|
||||||
s += &format!(":{:x}", cpu.x[f.rd]);
|
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 {
|
if evaluate {
|
||||||
s += &format!(":{:x}", cpu.x[f.rs1]);
|
s += &format!(":{:x}", cpu.x[f.rs1]);
|
||||||
}
|
}
|
||||||
s += &format!(")");
|
s += ")";
|
||||||
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 {
|
fn dump_format_j(cpu: &mut Cpu, word: u32, address: u64, evaluate: bool) -> String {
|
||||||
let f = parse_format_j(word);
|
let f = parse_format_j(word);
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
s += &format!("{}", get_register_name(f.rd));
|
s += get_register_name(f.rd);
|
||||||
if evaluate {
|
if evaluate {
|
||||||
s += &format!(":{:x}", cpu.x[f.rd]);
|
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 {
|
fn dump_format_r(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> String {
|
||||||
let f = parse_format_r(word);
|
let f = parse_format_r(word);
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
s += &format!("{}", get_register_name(f.rd));
|
s += get_register_name(f.rd);
|
||||||
if evaluate {
|
if evaluate {
|
||||||
s += &format!(":{:x}", cpu.x[f.rd]);
|
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 {
|
fn dump_format_r2(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> String {
|
||||||
let f = parse_format_r2(word);
|
let f = parse_format_r2(word);
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
s += &format!("{}", get_register_name(f.rd));
|
s += get_register_name(f.rd);
|
||||||
if evaluate {
|
if evaluate {
|
||||||
s += &format!(":{:x}", cpu.x[f.rd]);
|
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 {
|
fn dump_format_s(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> String {
|
||||||
let f = parse_format_s(word);
|
let f = parse_format_s(word);
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
s += &format!("{}", get_register_name(f.rs2));
|
s += get_register_name(f.rs2);
|
||||||
if evaluate {
|
if evaluate {
|
||||||
s += &format!(":{:x}", cpu.x[f.rs2]);
|
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 {
|
if evaluate {
|
||||||
s += &format!(":{:x}", cpu.x[f.rs1]);
|
s += &format!(":{:x}", cpu.x[f.rs1]);
|
||||||
}
|
}
|
||||||
s += &format!(")");
|
s += ")";
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1762,14 +1771,14 @@ fn parse_format_u(word: u32) -> FormatU {
|
|||||||
} | // imm[63:32] = [31]
|
} | // imm[63:32] = [31]
|
||||||
((word as u64) & 0xfffff000)
|
((word as u64) & 0xfffff000)
|
||||||
// imm[31:12] = [31:12]
|
// imm[31:12] = [31:12]
|
||||||
) as u64,
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dump_format_u(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> String {
|
fn dump_format_u(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> String {
|
||||||
let f = parse_format_u(word);
|
let f = parse_format_u(word);
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
s += &format!("{}", get_register_name(f.rd));
|
s += get_register_name(f.rd);
|
||||||
if evaluate {
|
if evaluate {
|
||||||
s += &format!(":{:x}", cpu.x[f.rd]);
|
s += &format!(":{:x}", cpu.x[f.rd]);
|
||||||
}
|
}
|
||||||
@ -2407,10 +2416,10 @@ const INSTRUCTIONS: [Instruction; INSTRUCTION_NUM] = [
|
|||||||
PrivilegeMode::Machine => TrapType::EnvironmentCallFromMMode,
|
PrivilegeMode::Machine => TrapType::EnvironmentCallFromMMode,
|
||||||
PrivilegeMode::Reserved => panic!("Unknown Privilege mode"),
|
PrivilegeMode::Reserved => panic!("Unknown Privilege mode"),
|
||||||
};
|
};
|
||||||
return Err(Trap {
|
Err(Trap {
|
||||||
trap_type: exception_type,
|
trap_type: exception_type,
|
||||||
value: address,
|
value: address,
|
||||||
});
|
})
|
||||||
},
|
},
|
||||||
disassemble: dump_empty,
|
disassemble: dump_empty,
|
||||||
},
|
},
|
||||||
@ -2780,7 +2789,7 @@ const INSTRUCTIONS: [Instruction; INSTRUCTION_NUM] = [
|
|||||||
disassemble: |cpu, word, _address, evaluate| {
|
disassemble: |cpu, word, _address, evaluate| {
|
||||||
let f = parse_format_i(word);
|
let f = parse_format_i(word);
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
s += &format!("{}", get_register_name(f.rd));
|
s += get_register_name(f.rd);
|
||||||
if evaluate {
|
if evaluate {
|
||||||
s += &format!(":{:x}", cpu.x[f.rd]);
|
s += &format!(":{:x}", cpu.x[f.rd]);
|
||||||
}
|
}
|
||||||
@ -2788,7 +2797,7 @@ const INSTRUCTIONS: [Instruction; INSTRUCTION_NUM] = [
|
|||||||
if evaluate {
|
if evaluate {
|
||||||
s += &format!(":{:x}", cpu.x[f.rs1]);
|
s += &format!(":{:x}", cpu.x[f.rs1]);
|
||||||
}
|
}
|
||||||
s += &format!(")");
|
s += ")";
|
||||||
s
|
s
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -3372,7 +3381,7 @@ const INSTRUCTIONS: [Instruction; INSTRUCTION_NUM] = [
|
|||||||
name: "SRAIW",
|
name: "SRAIW",
|
||||||
operation: |cpu, word, _address| {
|
operation: |cpu, word, _address| {
|
||||||
let f = parse_format_r(word);
|
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;
|
cpu.x[f.rd] = ((cpu.x[f.rs1] as i32) >> shamt) as i64;
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
@ -3744,7 +3753,7 @@ mod test_cpu {
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
fn create_cpu() -> Cpu {
|
fn create_cpu() -> Cpu {
|
||||||
Cpu::new()
|
Cpu::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -3938,10 +3947,7 @@ mod test_cpu {
|
|||||||
cpu.get_mut_mmu().init_memory(4);
|
cpu.get_mut_mmu().init_memory(4);
|
||||||
cpu.update_pc(memory_base);
|
cpu.update_pc(memory_base);
|
||||||
// write WFI instruction
|
// write WFI instruction
|
||||||
match cpu
|
match cpu.get_mut_mmu().store_word(memory_base, wfi_instruction) {
|
||||||
.get_mut_mmu()
|
|
||||||
.store_word(memory_base, wfi_instruction)
|
|
||||||
{
|
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(_e) => panic!("Failed to store"),
|
Err(_e) => panic!("Failed to store"),
|
||||||
};
|
};
|
||||||
@ -4046,10 +4052,7 @@ mod test_cpu {
|
|||||||
Err(_e) => panic!("Failed to store"),
|
Err(_e) => panic!("Failed to store"),
|
||||||
};
|
};
|
||||||
// Write non-compressed "addi x1, x1, 1" instruction
|
// Write non-compressed "addi x1, x1, 1" instruction
|
||||||
match cpu
|
match cpu.get_mut_mmu().store_word(memory_base + 4, 0x00108093) {
|
||||||
.get_mut_mmu()
|
|
||||||
.store_word(memory_base + 4, 0x00108093)
|
|
||||||
{
|
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(_e) => panic!("Failed to store"),
|
Err(_e) => panic!("Failed to store"),
|
||||||
};
|
};
|
||||||
|
@ -29,7 +29,7 @@ impl Memory {
|
|||||||
/// * `address`
|
/// * `address`
|
||||||
pub fn read_byte(&self, address: u64) -> u8 {
|
pub fn read_byte(&self, address: u64) -> u8 {
|
||||||
let index = (address >> 3) as usize;
|
let index = (address >> 3) as usize;
|
||||||
let pos = ((address % 8) as u64) * 8;
|
let pos = (address % 8) * 8;
|
||||||
(self.data[index] >> pos) as u8
|
(self.data[index] >> pos) as u8
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ impl Memory {
|
|||||||
pub fn read_halfword(&self, address: u64) -> u16 {
|
pub fn read_halfword(&self, address: u64) -> u16 {
|
||||||
if (address % 2) == 0 {
|
if (address % 2) == 0 {
|
||||||
let index = (address >> 3) as usize;
|
let index = (address >> 3) as usize;
|
||||||
let pos = ((address % 8) as u64) * 8;
|
let pos = (address % 8) * 8;
|
||||||
(self.data[index] >> pos) as u16
|
(self.data[index] >> pos) as u16
|
||||||
} else {
|
} else {
|
||||||
self.read_bytes(address, 2) as u16
|
self.read_bytes(address, 2) as u16
|
||||||
@ -54,7 +54,7 @@ impl Memory {
|
|||||||
pub fn read_word(&self, address: u64) -> u32 {
|
pub fn read_word(&self, address: u64) -> u32 {
|
||||||
if (address % 4) == 0 {
|
if (address % 4) == 0 {
|
||||||
let index = (address >> 3) as usize;
|
let index = (address >> 3) as usize;
|
||||||
let pos = ((address % 8) as u64) * 8;
|
let pos = (address % 8) * 8;
|
||||||
(self.data[index] >> pos) as u32
|
(self.data[index] >> pos) as u32
|
||||||
} else {
|
} else {
|
||||||
self.read_bytes(address, 4) as u32
|
self.read_bytes(address, 4) as u32
|
||||||
@ -82,7 +82,7 @@ impl Memory {
|
|||||||
/// * `address`
|
/// * `address`
|
||||||
/// * `width` up to eight
|
/// * `width` up to eight
|
||||||
pub fn read_bytes(&self, address: u64, width: u64) -> u64 {
|
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 {
|
for i in 0..width {
|
||||||
data |= (self.read_byte(address.wrapping_add(i)) as u64) << (i * 8);
|
data |= (self.read_byte(address.wrapping_add(i)) as u64) << (i * 8);
|
||||||
}
|
}
|
||||||
@ -96,7 +96,7 @@ impl Memory {
|
|||||||
/// * `value`
|
/// * `value`
|
||||||
pub fn write_byte(&mut self, address: u64, value: u8) {
|
pub fn write_byte(&mut self, address: u64, value: u8) {
|
||||||
let index = (address >> 3) as usize;
|
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);
|
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) {
|
pub fn write_halfword(&mut self, address: u64, value: u16) {
|
||||||
if (address % 2) == 0 {
|
if (address % 2) == 0 {
|
||||||
let index = (address >> 3) as usize;
|
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);
|
self.data[index] = (self.data[index] & !(0xffff << pos)) | ((value as u64) << pos);
|
||||||
} else {
|
} else {
|
||||||
self.write_bytes(address, value as u64, 2);
|
self.write_bytes(address, value as u64, 2);
|
||||||
@ -123,7 +123,7 @@ impl Memory {
|
|||||||
pub fn write_word(&mut self, address: u64, value: u32) {
|
pub fn write_word(&mut self, address: u64, value: u32) {
|
||||||
if (address % 4) == 0 {
|
if (address % 4) == 0 {
|
||||||
let index = (address >> 3) as usize;
|
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);
|
self.data[index] = (self.data[index] & !(0xffffffff << pos)) | ((value as u64) << pos);
|
||||||
} else {
|
} else {
|
||||||
self.write_bytes(address, value as u64, 4);
|
self.write_bytes(address, value as u64, 4);
|
||||||
@ -164,6 +164,12 @@ impl Memory {
|
|||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `address`
|
/// * `address`
|
||||||
pub fn validate_address(&self, address: u64) -> bool {
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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 std::collections::HashMap;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -15,7 +11,7 @@ use crate::{
|
|||||||
/// It may also be said Bus.
|
/// It may also be said Bus.
|
||||||
/// @TODO: Memory protection is not implemented yet. We should support.
|
/// @TODO: Memory protection is not implemented yet. We should support.
|
||||||
pub struct Mmu {
|
pub struct Mmu {
|
||||||
clock: u64,
|
// clock: u64,
|
||||||
xlen: Xlen,
|
xlen: Xlen,
|
||||||
ppn: u64,
|
ppn: u64,
|
||||||
addressing_mode: AddressingMode,
|
addressing_mode: AddressingMode,
|
||||||
@ -72,7 +68,7 @@ impl Mmu {
|
|||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `xlen`
|
/// * `xlen`
|
||||||
/// * `terminal`
|
/// * `terminal`
|
||||||
pub fn new(xlen: Xlen) -> Self {
|
pub fn new(xlen: Xlen, dram_base: u64) -> Self {
|
||||||
// // Load default device tree binary content
|
// // Load default device tree binary content
|
||||||
// let content = include_bytes!("./device/dtb.dtb");
|
// let content = include_bytes!("./device/dtb.dtb");
|
||||||
// for i in 0..content.len() {
|
// for i in 0..content.len() {
|
||||||
@ -80,12 +76,12 @@ impl Mmu {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
Mmu {
|
Mmu {
|
||||||
clock: 0,
|
// clock: 0,
|
||||||
xlen,
|
xlen,
|
||||||
ppn: 0,
|
ppn: 0,
|
||||||
addressing_mode: AddressingMode::None,
|
addressing_mode: AddressingMode::None,
|
||||||
privilege_mode: PrivilegeMode::Machine,
|
privilege_mode: PrivilegeMode::Machine,
|
||||||
memory: MemoryWrapper::new(),
|
memory: MemoryWrapper::new(dram_base),
|
||||||
mstatus: 0,
|
mstatus: 0,
|
||||||
page_cache_enabled: false,
|
page_cache_enabled: false,
|
||||||
fetch_page_cache: HashMap::default(),
|
fetch_page_cache: HashMap::default(),
|
||||||
@ -179,15 +175,12 @@ impl Mmu {
|
|||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `v_address` Virtual address
|
/// * `v_address` Virtual address
|
||||||
fn fetch(&mut self, v_address: u64) -> Result<u8, Trap> {
|
fn fetch(&mut self, v_address: u64) -> Result<u8, Trap> {
|
||||||
match self.translate_address(v_address, &MemoryAccessType::Execute) {
|
self.translate_address(v_address, &MemoryAccessType::Execute)
|
||||||
Ok(p_address) => Ok(self.load_raw(p_address)),
|
.map(|p_address| self.load_raw(p_address))
|
||||||
Err(()) => {
|
.map_err(|()| Trap {
|
||||||
return Err(Trap {
|
trap_type: TrapType::InstructionPageFault,
|
||||||
trap_type: TrapType::InstructionPageFault,
|
value: v_address,
|
||||||
value: v_address,
|
})
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetches instruction four bytes. This method takes virtual address
|
/// Fetches instruction four bytes. This method takes virtual address
|
||||||
@ -211,7 +204,7 @@ impl Mmu {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
false => {
|
false => {
|
||||||
let mut data = 0 as u32;
|
let mut data = 0;
|
||||||
for i in 0..width {
|
for i in 0..width {
|
||||||
match self.fetch(v_address.wrapping_add(i)) {
|
match self.fetch(v_address.wrapping_add(i)) {
|
||||||
Ok(byte) => data |= (byte as u32) << (i * 8),
|
Ok(byte) => data |= (byte as u32) << (i * 8),
|
||||||
@ -270,7 +263,7 @@ impl Mmu {
|
|||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
false => {
|
false => {
|
||||||
let mut data = 0 as u64;
|
let mut data = 0;
|
||||||
for i in 0..width {
|
for i in 0..width {
|
||||||
match self.load(v_address.wrapping_add(i)) {
|
match self.load(v_address.wrapping_add(i)) {
|
||||||
Ok(byte) => data |= (byte as u64) << (i * 8),
|
Ok(byte) => data |= (byte as u64) << (i * 8),
|
||||||
@ -288,10 +281,7 @@ impl Mmu {
|
|||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `v_address` Virtual address
|
/// * `v_address` Virtual address
|
||||||
pub fn load_halfword(&mut self, v_address: u64) -> Result<u16, Trap> {
|
pub fn load_halfword(&mut self, v_address: u64) -> Result<u16, Trap> {
|
||||||
match self.load_bytes(v_address, 2) {
|
self.load_bytes(v_address, 2).map(|data| data as u16)
|
||||||
Ok(data) => Ok(data as u16),
|
|
||||||
Err(e) => Err(e),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads four bytes. This method takes virtual address and translates
|
/// Loads four bytes. This method takes virtual address and translates
|
||||||
@ -300,10 +290,7 @@ impl Mmu {
|
|||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `v_address` Virtual address
|
/// * `v_address` Virtual address
|
||||||
pub fn load_word(&mut self, v_address: u64) -> Result<u32, Trap> {
|
pub fn load_word(&mut self, v_address: u64) -> Result<u32, Trap> {
|
||||||
match self.load_bytes(v_address, 4) {
|
self.load_bytes(v_address, 4).map(|data| data as u32)
|
||||||
Ok(data) => Ok(data as u32),
|
|
||||||
Err(e) => Err(e),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads eight bytes. This method takes virtual address and translates
|
/// Loads eight bytes. This method takes virtual address and translates
|
||||||
@ -312,10 +299,7 @@ impl Mmu {
|
|||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `v_address` Virtual address
|
/// * `v_address` Virtual address
|
||||||
pub fn load_doubleword(&mut self, v_address: u64) -> Result<u64, Trap> {
|
pub fn load_doubleword(&mut self, v_address: u64) -> Result<u64, Trap> {
|
||||||
match self.load_bytes(v_address, 8) {
|
self.load_bytes(v_address, 8)
|
||||||
Ok(data) => Ok(data as u64),
|
|
||||||
Err(e) => Err(e),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Store an byte. This method takes virtual address and translates
|
/// Store an byte. This method takes virtual address and translates
|
||||||
@ -325,16 +309,12 @@ impl Mmu {
|
|||||||
/// * `v_address` Virtual address
|
/// * `v_address` Virtual address
|
||||||
/// * `value`
|
/// * `value`
|
||||||
pub fn store(&mut self, v_address: u64, value: u8) -> Result<(), Trap> {
|
pub fn store(&mut self, v_address: u64, value: u8) -> Result<(), Trap> {
|
||||||
match self.translate_address(v_address, &MemoryAccessType::Write) {
|
self.translate_address(v_address, &MemoryAccessType::Write)
|
||||||
Ok(p_address) => {
|
.map(|p_address| self.store_raw(p_address, value))
|
||||||
self.store_raw(p_address, value);
|
.map_err(|()| Trap {
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Err(()) => Err(Trap {
|
|
||||||
trap_type: TrapType::StorePageFault,
|
trap_type: TrapType::StorePageFault,
|
||||||
value: v_address,
|
value: v_address,
|
||||||
}),
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores multiple bytes. This method takes virtual address and translates
|
/// Stores multiple bytes. This method takes virtual address and translates
|
||||||
@ -408,7 +388,7 @@ impl Mmu {
|
|||||||
/// * `v_address` Virtual address
|
/// * `v_address` Virtual address
|
||||||
/// * `value` data written
|
/// * `value` data written
|
||||||
pub fn store_doubleword(&mut self, v_address: u64, value: u64) -> Result<(), Trap> {
|
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
|
/// Loads a byte from main memory or peripheral devices depending on
|
||||||
@ -417,22 +397,7 @@ impl Mmu {
|
|||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `p_address` Physical address
|
/// * `p_address` Physical address
|
||||||
fn load_raw(&mut self, p_address: u64) -> u8 {
|
fn load_raw(&mut self, p_address: u64) -> u8 {
|
||||||
let effective_address = self.get_effective_address(p_address);
|
self.memory.read_byte(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),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads two bytes from main memory or peripheral devices depending on
|
/// Loads two bytes from main memory or peripheral devices depending on
|
||||||
@ -441,20 +406,8 @@ impl Mmu {
|
|||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `p_address` Physical address
|
/// * `p_address` Physical address
|
||||||
fn load_halfword_raw(&mut self, p_address: u64) -> u16 {
|
fn load_halfword_raw(&mut self, p_address: u64) -> u16 {
|
||||||
let effective_address = self.get_effective_address(p_address);
|
self.memory
|
||||||
match effective_address >= DRAM_BASE
|
.read_halfword(self.get_effective_address(p_address))
|
||||||
&& 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads four bytes from main memory or peripheral devices depending on
|
/// Loads four bytes from main memory or peripheral devices depending on
|
||||||
@ -463,20 +416,7 @@ impl Mmu {
|
|||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `p_address` Physical address
|
/// * `p_address` Physical address
|
||||||
pub fn load_word_raw(&mut self, p_address: u64) -> u32 {
|
pub fn load_word_raw(&mut self, p_address: u64) -> u32 {
|
||||||
let effective_address = self.get_effective_address(p_address);
|
self.memory.read_word(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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads eight bytes from main memory or peripheral devices depending on
|
/// Loads eight bytes from main memory or peripheral devices depending on
|
||||||
@ -485,20 +425,8 @@ impl Mmu {
|
|||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `p_address` Physical address
|
/// * `p_address` Physical address
|
||||||
fn load_doubleword_raw(&mut self, p_address: u64) -> u64 {
|
fn load_doubleword_raw(&mut self, p_address: u64) -> u64 {
|
||||||
let effective_address = self.get_effective_address(p_address);
|
self.memory
|
||||||
match effective_address >= DRAM_BASE
|
.read_doubleword(self.get_effective_address(p_address))
|
||||||
&& 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores a byte to main memory or peripheral devices depending on
|
/// Stores a byte to main memory or peripheral devices depending on
|
||||||
@ -508,18 +436,8 @@ impl Mmu {
|
|||||||
/// * `p_address` Physical address
|
/// * `p_address` Physical address
|
||||||
/// * `value` data written
|
/// * `value` data written
|
||||||
pub fn store_raw(&mut self, p_address: u64, value: u8) {
|
pub fn store_raw(&mut self, p_address: u64, value: u8) {
|
||||||
let effective_address = self.get_effective_address(p_address);
|
self.memory
|
||||||
// @TODO: Mapping should be configurable with dtb
|
.write_byte(self.get_effective_address(p_address), value)
|
||||||
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),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores two bytes to main memory or peripheral devices depending on
|
/// Stores two bytes to main memory or peripheral devices depending on
|
||||||
@ -529,21 +447,8 @@ impl Mmu {
|
|||||||
/// * `p_address` Physical address
|
/// * `p_address` Physical address
|
||||||
/// * `value` data written
|
/// * `value` data written
|
||||||
fn store_halfword_raw(&mut self, p_address: u64, value: u16) {
|
fn store_halfword_raw(&mut self, p_address: u64, value: u16) {
|
||||||
let effective_address = self.get_effective_address(p_address);
|
self.memory
|
||||||
match effective_address >= DRAM_BASE
|
.write_halfword(self.get_effective_address(p_address), value)
|
||||||
&& 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,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores four bytes to main memory or peripheral devices depending on
|
/// Stores four bytes to main memory or peripheral devices depending on
|
||||||
@ -553,21 +458,8 @@ impl Mmu {
|
|||||||
/// * `p_address` Physical address
|
/// * `p_address` Physical address
|
||||||
/// * `value` data written
|
/// * `value` data written
|
||||||
fn store_word_raw(&mut self, p_address: u64, value: u32) {
|
fn store_word_raw(&mut self, p_address: u64, value: u32) {
|
||||||
let effective_address = self.get_effective_address(p_address);
|
self.memory
|
||||||
match effective_address >= DRAM_BASE
|
.write_word(self.get_effective_address(p_address), value)
|
||||||
&& 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,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores eight bytes to main memory or peripheral devices depending on
|
/// Stores eight bytes to main memory or peripheral devices depending on
|
||||||
@ -577,21 +469,8 @@ impl Mmu {
|
|||||||
/// * `p_address` Physical address
|
/// * `p_address` Physical address
|
||||||
/// * `value` data written
|
/// * `value` data written
|
||||||
fn store_doubleword_raw(&mut self, p_address: u64, value: u64) {
|
fn store_doubleword_raw(&mut self, p_address: u64, value: u64) {
|
||||||
let effective_address = self.get_effective_address(p_address);
|
self.memory
|
||||||
match effective_address >= DRAM_BASE
|
.write_doubleword(self.get_effective_address(p_address), value)
|
||||||
&& 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,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if passed virtual address is valid (pointing a certain device) or not.
|
/// Checks if passed virtual address is valid (pointing a certain device) or not.
|
||||||
@ -599,25 +478,15 @@ impl Mmu {
|
|||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `v_address` Virtual address
|
/// * `v_address` Virtual address
|
||||||
pub fn validate_address(&mut self, v_address: u64) -> Result<bool, ()> {
|
pub fn validate_address(&mut self, v_address: u64) -> Option<bool> {
|
||||||
// @TODO: Support other access types?
|
if let Ok(p_address) = self.translate_address(v_address, &MemoryAccessType::DontCare) {
|
||||||
let p_address = match self.translate_address(v_address, &MemoryAccessType::DontCare) {
|
Some(
|
||||||
Ok(address) => address,
|
self.memory
|
||||||
Err(()) => return Err(()),
|
.validate_address(self.get_effective_address(p_address)),
|
||||||
};
|
)
|
||||||
let effective_address = self.get_effective_address(p_address);
|
} else {
|
||||||
let valid = match effective_address >= DRAM_BASE {
|
None
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn translate_address(
|
fn translate_address(
|
||||||
@ -668,7 +537,7 @@ impl Mmu {
|
|||||||
},
|
},
|
||||||
PrivilegeMode::User | PrivilegeMode::Supervisor => {
|
PrivilegeMode::User | PrivilegeMode::Supervisor => {
|
||||||
let vpns = [(address >> 12) & 0x3ff, (address >> 22) & 0x3ff];
|
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),
|
_ => Ok(address),
|
||||||
},
|
},
|
||||||
@ -704,7 +573,7 @@ impl Mmu {
|
|||||||
(address >> 21) & 0x1ff,
|
(address >> 21) & 0x1ff,
|
||||||
(address >> 30) & 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),
|
_ => 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 {
|
pub struct MemoryWrapper {
|
||||||
memory: Memory,
|
memory: Memory,
|
||||||
|
dram_base: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MemoryWrapper {
|
impl MemoryWrapper {
|
||||||
fn new() -> Self {
|
fn new(dram_base: u64) -> Self {
|
||||||
MemoryWrapper {
|
MemoryWrapper {
|
||||||
memory: Memory::new(),
|
memory: Memory::new(),
|
||||||
|
dram_base,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -886,77 +755,79 @@ impl MemoryWrapper {
|
|||||||
|
|
||||||
pub fn read_byte(&mut self, p_address: u64) -> u8 {
|
pub fn read_byte(&mut self, p_address: u64) -> u8 {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
p_address >= DRAM_BASE,
|
p_address >= self.dram_base,
|
||||||
"Memory address must equals to or bigger than DRAM_BASE. {:X}",
|
"Memory address must equals to or bigger than self.dram_base. {:X}",
|
||||||
p_address
|
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 {
|
pub fn read_halfword(&mut self, p_address: u64) -> u16 {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
p_address >= DRAM_BASE && p_address.wrapping_add(1) >= DRAM_BASE,
|
p_address >= self.dram_base && p_address.wrapping_add(1) >= self.dram_base,
|
||||||
"Memory address must equals to or bigger than DRAM_BASE. {:X}",
|
"Memory address must equals to or bigger than self.dram_base. {:X}",
|
||||||
p_address
|
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 {
|
pub fn read_word(&mut self, p_address: u64) -> u32 {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
p_address >= DRAM_BASE && p_address.wrapping_add(3) >= DRAM_BASE,
|
p_address >= self.dram_base && p_address.wrapping_add(3) >= self.dram_base,
|
||||||
"Memory address must equals to or bigger than DRAM_BASE. {:X}",
|
"Memory address must equals to or bigger than self.dram_base. {:X}",
|
||||||
p_address
|
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 {
|
pub fn read_doubleword(&mut self, p_address: u64) -> u64 {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
p_address >= DRAM_BASE && p_address.wrapping_add(7) >= DRAM_BASE,
|
p_address >= self.dram_base && p_address.wrapping_add(7) >= self.dram_base,
|
||||||
"Memory address must equals to or bigger than DRAM_BASE. {:X}",
|
"Memory address must equals to or bigger than self.dram_base. {:X}",
|
||||||
p_address
|
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) {
|
pub fn write_byte(&mut self, p_address: u64, value: u8) {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
p_address >= DRAM_BASE,
|
p_address >= self.dram_base,
|
||||||
"Memory address must equals to or bigger than DRAM_BASE. {:X}",
|
"Memory address must equals to or bigger than self.dram_base. {:X}",
|
||||||
p_address
|
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) {
|
pub fn write_halfword(&mut self, p_address: u64, value: u16) {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
p_address >= DRAM_BASE && p_address.wrapping_add(1) >= DRAM_BASE,
|
p_address >= self.dram_base && p_address.wrapping_add(1) >= self.dram_base,
|
||||||
"Memory address must equals to or bigger than DRAM_BASE. {:X}",
|
"Memory address must equals to or bigger than self.dram_base. {:X}",
|
||||||
p_address
|
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) {
|
pub fn write_word(&mut self, p_address: u64, value: u32) {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
p_address >= DRAM_BASE && p_address.wrapping_add(3) >= DRAM_BASE,
|
p_address >= self.dram_base && p_address.wrapping_add(3) >= self.dram_base,
|
||||||
"Memory address must equals to or bigger than DRAM_BASE. {:X}",
|
"Memory address must equals to or bigger than self.dram_base. {:X}",
|
||||||
p_address
|
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) {
|
pub fn write_doubleword(&mut self, p_address: u64, value: u64) {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
p_address >= DRAM_BASE && p_address.wrapping_add(7) >= DRAM_BASE,
|
p_address >= self.dram_base && p_address.wrapping_add(7) >= self.dram_base,
|
||||||
"Memory address must equals to or bigger than DRAM_BASE. {:X}",
|
"Memory address must equals to or bigger than self.dram_base. {:X}",
|
||||||
p_address
|
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 {
|
pub fn validate_address(&self, address: u64) -> bool {
|
||||||
self.memory.validate_address(address - DRAM_BASE)
|
self.memory.validate_address(address - self.dram_base)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user