use std::fmt;
use std::ops::{Bound, Range, RangeBounds};
pub type CsrAddress = u16;
pub const MXLEN: usize = 64;
pub const CSR_SIZE: usize = 4096;
pub const USTATUS: CsrAddress = 0x000;
pub const UTVEC: CsrAddress = 0x005;
pub const UEPC: CsrAddress = 0x041;
pub const UCAUSE: CsrAddress = 0x042;
pub const UTVAL: CsrAddress = 0x043;
pub const FFLAGS: CsrAddress = 0x001;
pub const FRB: CsrAddress = 0x002;
pub const FCSR: CsrAddress = 0x003;
pub const TIME: CsrAddress = 0xc01;
pub const SSTATUS: CsrAddress = 0x100;
pub const SEDELEG: CsrAddress = 0x102;
pub const SIDELEG: CsrAddress = 0x103;
pub const SIE: CsrAddress = 0x104;
pub const STVEC: CsrAddress = 0x105;
pub const SSCRATCH: CsrAddress = 0x140;
pub const SEPC: CsrAddress = 0x141;
pub const SCAUSE: CsrAddress = 0x142;
pub const STVAL: CsrAddress = 0x143;
pub const SIP: CsrAddress = 0x144;
pub const SATP: CsrAddress = 0x180;
pub const SSTATUS_SIE: u64 = 0x00000002;
pub const SSTATUS_SPIE: u64 = 0x00000020;
pub const SSTATUS_SPP: u64 = 0x00000100;
pub const SSTATUS_FS: u64 = 0x00006000;
pub const SSTATUS_XS: u64 = 0x00018000;
pub const SSTATUS_SUM: u64 = 0x00040000;
pub const SSTATUS_MXR: u64 = 0x00080000;
pub const SSTATUS_UXL: u64 = 0x0000000300000000;
pub const MVENDORID: CsrAddress = 0xf11;
pub const MARCHID: CsrAddress = 0xf12;
pub const MIMPID: CsrAddress = 0xf13;
pub const MHARTID: CsrAddress = 0xf14;
pub const MSTATUS: CsrAddress = 0x300;
pub const MISA: CsrAddress = 0x301;
pub const MEDELEG: CsrAddress = 0x302;
pub const MIDELEG: CsrAddress = 0x303;
pub const MIE: CsrAddress = 0x304;
pub const MTVEC: CsrAddress = 0x305;
pub const MCOUNTEREN: CsrAddress = 0x306;
pub const MSCRATCH: CsrAddress = 0x340;
pub const MEPC: CsrAddress = 0x341;
pub const MCAUSE: CsrAddress = 0x342;
pub const MTVAL: CsrAddress = 0x343;
pub const MIP: CsrAddress = 0x344;
pub const PMPCFG0: CsrAddress = 0x3a0;
pub const PMPADDR0: CsrAddress = 0x3b0;
pub const SSIP_BIT: u64 = 1 << 1;
pub const MSIP_BIT: u64 = 1 << 3;
pub const STIP_BIT: u64 = 1 << 5;
pub const MTIP_BIT: u64 = 1 << 7;
pub const SEIP_BIT: u64 = 1 << 9;
pub const MEIP_BIT: u64 = 1 << 11;
pub struct State {
csrs: [u64; CSR_SIZE],
}
impl fmt::Display for State {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
format!(
"{}\n{}\n{}",
format!(
"mstatus={:>#18x} mtvec={:>#18x} mepc={:>#18x}\n mcause={:>#18x} medeleg={:>#18x} mideleg={:>#18x}",
self.read(MSTATUS),
self.read(MTVEC),
self.read(MEPC),
self.read(MCAUSE),
self.read(MEDELEG),
self.read(MIDELEG),
),
format!(
"sstatus={:>#18x} stvec={:>#18x} sepc={:>#18x}\n scause={:>#18x} sedeleg={:>#18x} sideleg={:>#18x}",
self.read(SSTATUS),
self.read(STVEC),
self.read(SEPC),
self.read(SCAUSE),
self.read(SEDELEG),
self.read(SIDELEG),
),
format!(
"ustatus={:>#18x} utvec={:>#18x} uepc={:>#18x}\n ucause={:>#18x}",
self.read(USTATUS),
self.read(UTVEC),
self.read(UEPC),
self.read(UCAUSE),
),
)
)
}
}
impl State {
pub fn new() -> Self {
let mut csrs = [0; CSR_SIZE];
let misa: u64 = (2 << 62) | (1 << 18) | (1 << 12) | (1 << 8) | (1 << 5) | (1 << 3) | (1 << 2) | 1; csrs[MISA as usize] = misa;
Self { csrs }
}
pub fn increment_time(&mut self) {
self.csrs[TIME as usize] = self.csrs[TIME as usize].wrapping_add(1);
}
pub fn read(&self, addr: CsrAddress) -> u64 {
match addr {
SSTATUS => {
let mask = SSTATUS_SIE
| SSTATUS_SPIE
| SSTATUS_SPP
| SSTATUS_FS
| SSTATUS_XS
| SSTATUS_SUM
| SSTATUS_MXR
| SSTATUS_UXL;
self.csrs[MSTATUS as usize] & mask
}
SIE => self.csrs[MIE as usize] & self.csrs[MIDELEG as usize],
SIP => self.csrs[MIP as usize] & self.csrs[MIDELEG as usize],
_ => self.csrs[addr as usize],
}
}
pub fn write(&mut self, addr: CsrAddress, val: u64) {
match addr {
MVENDORID => {}
MARCHID => {}
MIMPID => {}
MHARTID => {}
SSTATUS => {
let mask = SSTATUS_SIE
| SSTATUS_SPIE
| SSTATUS_SPP
| SSTATUS_FS
| SSTATUS_XS
| SSTATUS_SUM
| SSTATUS_MXR;
self.csrs[MSTATUS as usize] = (self.csrs[MSTATUS as usize] & !mask) | (val & mask);
}
SIE => {
self.csrs[MIE as usize] = (self.csrs[MIE as usize] & !self.csrs[MIDELEG as usize])
| (val & self.csrs[MIDELEG as usize]);
}
SIP => {
let mask = SSIP_BIT & self.csrs[MIDELEG as usize];
self.csrs[MIP as usize] = (self.csrs[MIP as usize] & !mask) | (val & mask);
}
_ => self.csrs[addr as usize] = val,
}
}
pub fn read_bit(&self, addr: CsrAddress, bit: usize) -> u64 {
if bit >= MXLEN {
}
if (self.read(addr) & (1 << bit)) != 0 {
1
} else {
0
}
}
pub fn read_bits<T: RangeBounds<usize>>(&self, addr: CsrAddress, range: T) -> u64 {
let range = to_range(&range, MXLEN);
if (range.start >= MXLEN) | (range.end > MXLEN) | (range.start >= range.end) {
}
let mut bitmask = 0;
if range.end != 64 {
bitmask = !0 << range.end;
}
(self.read(addr) as u64 & !bitmask) >> range.start
}
pub fn write_bit(&mut self, addr: CsrAddress, bit: usize, val: u64) {
if bit >= MXLEN {
}
if val > 1 {
}
if val == 1 {
self.write(addr, self.read(addr) | 1 << bit);
} else if val == 0 {
self.write(addr, self.read(addr) & !(1 << bit));
}
}
pub fn write_bits<T: RangeBounds<usize>>(&mut self, addr: CsrAddress, range: T, val: u64) {
let range = to_range(&range, MXLEN);
if (range.start >= MXLEN) | (range.end > MXLEN) | (range.start >= range.end) {
}
let bitmask = (!0 << range.end) | !(!0 << range.start);
self.write(addr, (self.read(addr) & bitmask) | (val << range.start))
}
pub fn reset(&mut self) {
self.csrs = [0; CSR_SIZE];
let misa: u64 = (2 << 62) | (1 << 18) | (1 << 12) | (1 << 8) | (1 << 5) | (1 << 3) | (1 << 2) | 1; self.csrs[MISA as usize] = misa;
}
}
fn to_range<T: RangeBounds<usize>>(generic_range: &T, bit_length: usize) -> Range<usize> {
let start = match generic_range.start_bound() {
Bound::Excluded(&val) => val + 1,
Bound::Included(&val) => val,
Bound::Unbounded => 0,
};
let end = match generic_range.end_bound() {
Bound::Excluded(&val) => val,
Bound::Included(&val) => val + 1,
Bound::Unbounded => bit_length,
};
start..end
}