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_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"),
|
||||
};
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user