use crate::bus::CLINT_BASE;
use crate::cpu::{BYTE, DOUBLEWORD, HALFWORD, WORD};
use crate::csr::{State, MIP, MSIP_BIT, MTIP_BIT};
use crate::exception::Exception;
const CLINT_MSIP: u64 = CLINT_BASE;
const CLINT_MSIP_END: u64 = CLINT_MSIP + 4;
const CLINT_MTIMECMP: u64 = CLINT_BASE + 0x4000;
const CLINT_MTIMECMP_END: u64 = CLINT_MTIMECMP + 8;
const CLINT_MTIME: u64 = CLINT_BASE + 0xbff8;
const CLINT_MTIME_END: u64 = CLINT_MTIME + 8;
pub struct Clint {
msip: u32,
mtimecmp: u64,
mtime: u64,
}
impl Clint {
pub fn new() -> Self {
Self {
msip: 0,
mtimecmp: 0,
mtime: 0,
}
}
pub fn increment(&mut self, state: &mut State) {
self.mtime = self.mtime.wrapping_add(1);
if (self.msip & 1) != 0 {
state.write(MIP, state.read(MIP) | MSIP_BIT);
}
if self.mtimecmp > self.mtime {
state.write(MIP, state.read(MIP) & !MTIP_BIT);
}
if self.mtime >= self.mtimecmp {
state.write(MIP, state.read(MIP) | MTIP_BIT);
}
}
pub fn read(&self, addr: u64, size: u8) -> Result<u64, Exception> {
let (reg, offset) = match addr {
CLINT_MSIP..=CLINT_MSIP_END => (self.msip as u64, addr - CLINT_MSIP),
CLINT_MTIMECMP..=CLINT_MTIMECMP_END => (self.mtimecmp, addr - CLINT_MTIMECMP),
CLINT_MTIME..=CLINT_MTIME_END => (self.mtime, addr - CLINT_MTIME),
_ => return Err(Exception::LoadAccessFault),
};
match size {
BYTE => Ok((reg >> (offset * 8)) & 0xff),
HALFWORD => Ok((reg >> (offset * 8)) & 0xffff),
WORD => Ok((reg >> (offset * 8)) & 0xffffffff),
DOUBLEWORD => Ok(reg),
_ => return Err(Exception::LoadAccessFault),
}
}
pub fn write(&mut self, addr: u64, value: u64, size: u8) -> Result<(), Exception> {
let (mut reg, offset) = match addr {
CLINT_MSIP..=CLINT_MSIP_END => (self.msip as u64, addr - CLINT_MSIP),
CLINT_MTIMECMP..=CLINT_MTIMECMP_END => (self.mtimecmp, addr - CLINT_MTIMECMP),
CLINT_MTIME..=CLINT_MTIME_END => (self.mtime, addr - CLINT_MTIME),
_ => return Err(Exception::StoreAMOAccessFault),
};
match size {
BYTE => {
reg = reg & (!(0xff << (offset * 8)));
reg = reg | ((value & 0xff) << (offset * 8));
}
HALFWORD => {
reg = reg & (!(0xffff << (offset * 8)));
reg = reg | ((value & 0xffff) << (offset * 8));
}
WORD => {
reg = reg & (!(0xffffffff << (offset * 8)));
reg = reg | ((value & 0xffffffff) << (offset * 8));
}
DOUBLEWORD => {
reg = value;
}
_ => return Err(Exception::StoreAMOAccessFault),
}
match addr {
CLINT_MSIP..=CLINT_MSIP_END => self.msip = reg as u32,
CLINT_MTIMECMP..=CLINT_MTIMECMP_END => self.mtimecmp = reg,
CLINT_MTIME..=CLINT_MTIME_END => self.mtime = reg,
_ => return Err(Exception::StoreAMOAccessFault),
}
Ok(())
}
}