// Copyright 2015-2016 David Li
// This file is part of rustv.
// rustv is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// rustv is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with rustv. If not, see .
use std::rc::Rc;
use std::cell::RefCell;
use isa::{self, Instruction, IsaType};
#[derive(Clone, Debug, PartialEq)]
pub enum MemoryError {
InvalidAddress,
CacheMiss {
/// How many cycles to stall
stall_cycles: u32,
/// Whether the load or store should be retried
retry: bool,
},
}
pub type Result = ::std::result::Result;
pub trait MemoryInterface {
fn latency(&self) -> u32;
fn step(&mut self);
// fn prefetch(&mut self, address: isa::Address);
// fn invalidate(&mut self, address: isa::Address);
fn is_address_accessible(&self, address: isa::Address) -> bool;
fn read_word(&mut self, address: isa::Address) -> Result;
fn write_word(&mut self, address: isa::Address, value: isa::Word) -> Result<()>;
fn read_instruction(&mut self, address: isa::Address) -> Option {
match self.read_word(address) {
Ok(word) => Some(Instruction::new(word)),
Err(_) => None,
}
}
// TODO: check address more thoroughly
fn read_halfword(&mut self, address: isa::Address) -> Result {
let result = self.read_word(address);
let offset = (address & 0b10).0;
match result {
Ok(word) => match offset {
0 => Ok((word & 0xFFFF).as_half_word()),
2 => Ok(((word & 0xFFFF0000) >> 16).as_half_word()),
_ => panic!("Invalid halfword offset: address {:x}", address),
},
Err(e) => Err(e),
}
}
fn write_halfword(&mut self, address: isa::Address, value: isa::HalfWord) -> Result<()> {
let result = self.read_word(address);
let offset = (address & 0b10).0;
let value = value.as_word();
match result {
Ok(word) => {
let value = match offset {
0 => (word & 0xFFFF0000) | value,
2 => (word & 0x0000FFFF) | (value << 16),
_ => panic!("Invalid halfword offset: address {:x}", address),
};
self.write_word(address, value)
},
Err(e) => Err(e),
}
}
fn read_byte(&mut self, address: isa::Address) -> Result {
let result = self.read_word(address);
let offset = (address % 4).0;
match result {
Ok(word) => match offset {
0 => Ok((word & 0xFF).as_byte()),
1 => Ok(((word & 0xFF00) >> 8).as_byte()),
2 => Ok(((word & 0xFF0000) >> 16).as_byte()),
3 => Ok(((word & 0xFF000000) >> 24).as_byte()),
_ => panic!("Invalid byte offset: {:x}", address),
},
Err(e) => Err(e),
}
}
fn write_byte(&mut self, address: isa::Address, value: isa::Byte) -> Result<()> {
let result = self.read_word(address);
let offset = (address % 4).0;
let value = value.as_word();
match result {
Ok(word) => {
let value = match offset {
0 => (word & !(0xFF)) | value,
1 => (word & !(0xFF00)) | (value << 8),
2 => (word & !(0xFF0000)) | (value << 16),
3 => (word & !(0xFF000000)) | (value << 24),
_ => panic!("Invalid byte offset: {:x}", address),
};
self.write_word(address, value)
},
Err(e) => Err(e),
}
}
}
pub struct CacheMetadata {
/// How many sets are in the cache
pub num_sets: usize,
/// How many ways are in a set
pub num_ways: usize,
/// How many words are in a block/line
pub num_block_words: usize,
/// The tags currently in the cache, in order of set, then way
pub tags: Vec