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_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"),
}; };

View File

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

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