@ -1,4 +1,4 @@
|
||||
use std::sync::{Arc, RwLock, mpsc::Receiver};
|
||||
use std::sync::{mpsc::Receiver, Arc, RwLock};
|
||||
|
||||
pub use super::mmu::Memory;
|
||||
use super::mmu::{AddressingMode, Mmu};
|
||||
@ -58,9 +58,9 @@ pub enum TickResult {
|
||||
Ok,
|
||||
ExitThread(u64),
|
||||
PauseEmulation(Receiver<([i64; 8], Option<(Vec<u8>, u64)>)>),
|
||||
CpuTrap(Trap),
|
||||
}
|
||||
|
||||
|
||||
/// Emulates a RISC-V CPU core
|
||||
pub struct Cpu {
|
||||
clock: u64,
|
||||
@ -343,7 +343,6 @@ impl Cpu {
|
||||
|
||||
/// Runs program one cycle. Fetch, decode, and execution are completed in a cycle so far.
|
||||
pub fn tick(&mut self) -> TickResult {
|
||||
let instruction_address = self.pc;
|
||||
match self.tick_operate() {
|
||||
Ok(()) => {}
|
||||
Err(Trap {
|
||||
@ -358,7 +357,7 @@ impl Cpu {
|
||||
}) => {
|
||||
return TickResult::ExitThread(self.read_register(10) as u64);
|
||||
}
|
||||
Err(e) => self.handle_exception(e, instruction_address),
|
||||
Err(e) => return TickResult::CpuTrap(e),
|
||||
}
|
||||
self.mmu.tick(&mut self.csr[CSR_MIP_ADDRESS as usize]);
|
||||
self.handle_interrupt(self.pc);
|
||||
@ -781,7 +780,7 @@ impl Cpu {
|
||||
// println!("Fetching word from {:08x}...", self.pc);
|
||||
self.mmu.fetch_word(self.pc).map_err(|e| {
|
||||
self.pc = self.pc.wrapping_add(4); // @TODO: What if instruction is compressed?
|
||||
// println!("Fetch error: {:x?}", e);
|
||||
// println!("Fetch error: {:x?}", e);
|
||||
e
|
||||
})
|
||||
}
|
||||
|
@ -1,171 +1,170 @@
|
||||
/// Emulates main memory.
|
||||
pub struct Memory {
|
||||
/// Memory content
|
||||
data: Vec<u64>
|
||||
/// Memory content
|
||||
data: Vec<u64>,
|
||||
}
|
||||
|
||||
impl Memory {
|
||||
/// Creates a new `Memory`
|
||||
pub fn new() -> Self {
|
||||
Memory {
|
||||
data: vec![]
|
||||
}
|
||||
}
|
||||
/// Creates a new `Memory`
|
||||
pub fn new() -> Self {
|
||||
Memory { data: vec![] }
|
||||
}
|
||||
|
||||
/// Initializes memory content.
|
||||
/// This method is expected to be called only once.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `capacity`
|
||||
pub fn init(&mut self, capacity: u64) {
|
||||
for _i in 0..((capacity + 7) / 8) {
|
||||
self.data.push(0);
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads a byte from memory.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `address`
|
||||
pub fn read_byte(&self, address: u64) -> u8 {
|
||||
let index = (address >> 3) as usize;
|
||||
let pos = (address % 8) * 8;
|
||||
(self.data[index] >> pos) as u8
|
||||
}
|
||||
/// Initializes memory content.
|
||||
/// This method is expected to be called only once.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `capacity`
|
||||
pub fn init(&mut self, capacity: u64) {
|
||||
for _i in 0..((capacity + 7) / 8) {
|
||||
self.data.push(0);
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads two bytes from memory.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `address`
|
||||
pub fn read_halfword(&self, address: u64) -> u16 {
|
||||
if (address % 2) == 0 {
|
||||
let index = (address >> 3) as usize;
|
||||
let pos = (address % 8) * 8;
|
||||
(self.data[index] >> pos) as u16
|
||||
} else {
|
||||
self.read_bytes(address, 2) as u16
|
||||
}
|
||||
}
|
||||
/// Reads a byte from memory.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `address`
|
||||
pub fn read_byte(&self, address: u64) -> u8 {
|
||||
let index = (address >> 3) as usize;
|
||||
let pos = (address % 8) * 8;
|
||||
(self.data[index] >> pos) as u8
|
||||
}
|
||||
|
||||
/// Reads four bytes from memory.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `address`
|
||||
pub fn read_word(&self, address: u64) -> u32 {
|
||||
if (address % 4) == 0 {
|
||||
let index = (address >> 3) as usize;
|
||||
let pos = (address % 8) * 8;
|
||||
(self.data[index] >> pos) as u32
|
||||
} else {
|
||||
self.read_bytes(address, 4) as u32
|
||||
}
|
||||
}
|
||||
/// Reads two bytes from memory.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `address`
|
||||
pub fn read_halfword(&self, address: u64) -> u16 {
|
||||
if (address % 2) == 0 {
|
||||
let index = (address >> 3) as usize;
|
||||
let pos = (address % 8) * 8;
|
||||
(self.data[index] >> pos) as u16
|
||||
} else {
|
||||
self.read_bytes(address, 2) as u16
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads eight bytes from memory.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `address`
|
||||
pub fn read_doubleword(&self, address: u64) -> u64 {
|
||||
if (address % 8) == 0 {
|
||||
let index = (address >> 3) as usize;
|
||||
self.data[index]
|
||||
} else if (address % 4) == 0 {
|
||||
(self.read_word(address) as u64) | ((self.read_word(address.wrapping_add(4)) as u64) << 4)
|
||||
} else {
|
||||
self.read_bytes(address, 8)
|
||||
}
|
||||
}
|
||||
/// Reads four bytes from memory.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `address`
|
||||
pub fn read_word(&self, address: u64) -> u32 {
|
||||
if (address % 4) == 0 {
|
||||
let index = (address >> 3) as usize;
|
||||
let pos = (address % 8) * 8;
|
||||
(self.data[index] >> pos) as u32
|
||||
} else {
|
||||
self.read_bytes(address, 4) as u32
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads multiple bytes from memory.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `address`
|
||||
/// * `width` up to eight
|
||||
pub fn read_bytes(&self, address: u64, width: u64) -> u64 {
|
||||
let mut data = 0;
|
||||
for i in 0..width {
|
||||
data |= (self.read_byte(address.wrapping_add(i)) as u64) << (i * 8);
|
||||
}
|
||||
data
|
||||
}
|
||||
/// Reads eight bytes from memory.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `address`
|
||||
pub fn read_doubleword(&self, address: u64) -> u64 {
|
||||
if (address % 8) == 0 {
|
||||
let index = (address >> 3) as usize;
|
||||
self.data[index]
|
||||
} else if (address % 4) == 0 {
|
||||
(self.read_word(address) as u64)
|
||||
| ((self.read_word(address.wrapping_add(4)) as u64) << 4)
|
||||
} else {
|
||||
self.read_bytes(address, 8)
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes a byte to memory.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `address`
|
||||
/// * `value`
|
||||
pub fn write_byte(&mut self, address: u64, value: u8) {
|
||||
let index = (address >> 3) as usize;
|
||||
let pos = (address % 8) * 8;
|
||||
self.data[index] = (self.data[index] & !(0xff << pos)) | ((value as u64) << pos);
|
||||
}
|
||||
/// Reads multiple bytes from memory.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `address`
|
||||
/// * `width` up to eight
|
||||
pub fn read_bytes(&self, address: u64, width: u64) -> u64 {
|
||||
let mut data = 0;
|
||||
for i in 0..width {
|
||||
data |= (self.read_byte(address.wrapping_add(i)) as u64) << (i * 8);
|
||||
}
|
||||
data
|
||||
}
|
||||
|
||||
/// Writes two bytes to memory.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `address`
|
||||
/// * `value`
|
||||
pub fn write_halfword(&mut self, address: u64, value: u16) {
|
||||
if (address % 2) == 0 {
|
||||
let index = (address >> 3) as usize;
|
||||
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);
|
||||
}
|
||||
}
|
||||
/// Writes a byte to memory.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `address`
|
||||
/// * `value`
|
||||
pub fn write_byte(&mut self, address: u64, value: u8) {
|
||||
let index = (address >> 3) as usize;
|
||||
let pos = (address % 8) * 8;
|
||||
self.data[index] = (self.data[index] & !(0xff << pos)) | ((value as u64) << pos);
|
||||
}
|
||||
|
||||
/// Writes four bytes to memory.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `address`
|
||||
/// * `value`
|
||||
pub fn write_word(&mut self, address: u64, value: u32) {
|
||||
if (address % 4) == 0 {
|
||||
let index = (address >> 3) as usize;
|
||||
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);
|
||||
}
|
||||
}
|
||||
/// Writes two bytes to memory.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `address`
|
||||
/// * `value`
|
||||
pub fn write_halfword(&mut self, address: u64, value: u16) {
|
||||
if (address % 2) == 0 {
|
||||
let index = (address >> 3) as usize;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes eight bytes to memory.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `address`
|
||||
/// * `value`
|
||||
pub fn write_doubleword(&mut self, address: u64, value: u64) {
|
||||
if (address % 8) == 0 {
|
||||
let index = (address >> 3) as usize;
|
||||
self.data[index] = value;
|
||||
} else if (address % 4) == 0 {
|
||||
self.write_word(address, (value & 0xffffffff) as u32);
|
||||
self.write_word(address.wrapping_add(4), (value >> 32) as u32);
|
||||
} else {
|
||||
self.write_bytes(address, value, 8);
|
||||
}
|
||||
}
|
||||
/// Writes four bytes to memory.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `address`
|
||||
/// * `value`
|
||||
pub fn write_word(&mut self, address: u64, value: u32) {
|
||||
if (address % 4) == 0 {
|
||||
let index = (address >> 3) as usize;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// Write multiple bytes to memory.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `address`
|
||||
/// * `value`
|
||||
/// * `width` up to eight
|
||||
pub fn write_bytes(&mut self, address: u64, value: u64, width: u64) {
|
||||
for i in 0..width {
|
||||
self.write_byte(address.wrapping_add(i), (value >> (i * 8)) as u8);
|
||||
}
|
||||
}
|
||||
/// Writes eight bytes to memory.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `address`
|
||||
/// * `value`
|
||||
pub fn write_doubleword(&mut self, address: u64, value: u64) {
|
||||
if (address % 8) == 0 {
|
||||
let index = (address >> 3) as usize;
|
||||
self.data[index] = value;
|
||||
} else if (address % 4) == 0 {
|
||||
self.write_word(address, (value & 0xffffffff) as u32);
|
||||
self.write_word(address.wrapping_add(4), (value >> 32) as u32);
|
||||
} else {
|
||||
self.write_bytes(address, value, 8);
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if the address is valid memory address
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `address`
|
||||
pub fn validate_address(&self, address: u64) -> bool {
|
||||
(address as usize) < self.data.len()
|
||||
}
|
||||
/// Write multiple bytes to memory.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `address`
|
||||
/// * `value`
|
||||
/// * `width` up to eight
|
||||
pub fn write_bytes(&mut self, address: u64, value: u64, width: u64) {
|
||||
for i in 0..width {
|
||||
self.write_byte(address.wrapping_add(i), (value >> (i * 8)) as u8);
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if the address is valid memory address
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `address`
|
||||
pub fn validate_address(&self, address: u64) -> bool {
|
||||
(address as usize) < self.data.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Memory {
|
||||
|
Reference in New Issue
Block a user