use crate::bus::PLIC_BASE;
use crate::cpu::WORD;
use crate::exception::Exception;
use std::ops::RangeInclusive;
const SOURCE_PRIORITY: RangeInclusive<u64> = RangeInclusive::new(PLIC_BASE, PLIC_BASE + 0xfff);
const PENDING: RangeInclusive<u64> = RangeInclusive::new(PLIC_BASE + 0x1000, PLIC_BASE + 0x107f);
const ENABLE: RangeInclusive<u64> = RangeInclusive::new(PLIC_BASE + 0x2000, PLIC_BASE + 0x20ff);
const THRESHOLD_AND_CLAIM: RangeInclusive<u64> =
RangeInclusive::new(PLIC_BASE + 0x200000, PLIC_BASE + 0x201007);
pub const PLIC_SCLAIM: u64 = PLIC_BASE + 0x201004;
const WORD_SIZE: u64 = 0x4;
const CONTEXT_OFFSET: u64 = 0x1000;
pub struct Plic {
priority: [u32; 1024],
pending: [u32; 32],
enable: [u32; 64],
threshold: [u32; 2],
claim: [u32; 2],
}
impl Plic {
pub fn new() -> Self {
Self {
priority: [0; 1024],
pending: [0; 32],
enable: [0; 64],
threshold: [0; 2],
claim: [0; 2],
}
}
fn _is_pending(&self, irq: u64) -> bool {
let index = irq.wrapping_div(WORD_SIZE);
return ((self.pending[index as usize] >> irq) & 1) == 1;
}
fn _is_enable(&self, context: u64, irq: u64) -> bool {
let index = irq.wrapping_div(WORD_SIZE) + context * 32;
return ((self.enable[index as usize] >> irq) & 1) == 1;
}
pub fn read(&self, addr: u64, size: u8) -> Result<u64, Exception> {
if size != WORD {
return Err(Exception::LoadAccessFault);
}
match addr {
addr if SOURCE_PRIORITY.contains(&addr) => {
if (addr - SOURCE_PRIORITY.start()).wrapping_rem(WORD_SIZE) != 0 {
return Err(Exception::LoadAccessFault);
}
let index = (addr - SOURCE_PRIORITY.start()).wrapping_div(WORD_SIZE);
println!(
"[read] priority {:#x} {} value {}",
addr, index, self.priority[index as usize]
);
Ok(self.priority[index as usize] as u64)
}
addr if PENDING.contains(&addr) => {
if (addr - PENDING.start()).wrapping_rem(WORD_SIZE) != 0 {
return Err(Exception::LoadAccessFault);
}
let index = (addr - PENDING.start()).wrapping_div(WORD_SIZE);
println!(
"[read] pending {:#x} {} value {}",
addr, index, self.pending[index as usize]
);
Ok(self.pending[index as usize] as u64)
}
addr if ENABLE.contains(&addr) => {
if (addr - ENABLE.start()).wrapping_rem(WORD_SIZE) != 0 {
return Err(Exception::LoadAccessFault);
}
let index = (addr - ENABLE.start()).wrapping_div(WORD_SIZE);
println!(
"[read] enable {:#x} {} value {:#x}",
addr, index, self.enable[index as usize]
);
Ok(self.enable[index as usize] as u64)
}
addr if THRESHOLD_AND_CLAIM.contains(&addr) => {
let context = (addr - THRESHOLD_AND_CLAIM.start()).wrapping_div(CONTEXT_OFFSET);
let offset = addr - (THRESHOLD_AND_CLAIM.start() + CONTEXT_OFFSET * context);
println!(
"[read] threshold and claim {:#x} context {} offset {}",
addr, context, offset
);
if offset == 0 {
println!(
"[read] threshold {:#x} value {}",
addr, self.threshold[context as usize]
);
Ok(self.threshold[context as usize] as u64)
} else if offset == 4 {
println!(
"[read] claim {:#x} value {}",
addr, self.claim[context as usize]
);
Ok(self.claim[context as usize] as u64)
} else {
return Err(Exception::LoadAccessFault);
}
}
_ => return Err(Exception::LoadAccessFault),
}
}
pub fn write(&mut self, addr: u64, value: u64, size: u8) -> Result<(), Exception> {
if size != WORD {
return Err(Exception::StoreAMOAccessFault);
}
match addr {
addr if SOURCE_PRIORITY.contains(&addr) => {
if (addr - SOURCE_PRIORITY.start()).wrapping_rem(WORD_SIZE) != 0 {
return Err(Exception::StoreAMOAccessFault);
}
let index = (addr - SOURCE_PRIORITY.start()).wrapping_div(WORD_SIZE);
println!("[write] priority {:#x} {} value {}", addr, index, value);
self.priority[index as usize] = value as u32;
}
addr if PENDING.contains(&addr) => {
if (addr - PENDING.start()).wrapping_rem(WORD_SIZE) != 0 {
return Err(Exception::StoreAMOAccessFault);
}
let index = (addr - PENDING.start()).wrapping_div(WORD_SIZE);
println!("[write] pending {:#x} {} value {}", addr, index, value);
self.pending[index as usize] = value as u32;
}
addr if ENABLE.contains(&addr) => {
if (addr - ENABLE.start()).wrapping_rem(WORD_SIZE) != 0 {
return Err(Exception::StoreAMOAccessFault);
}
let index = (addr - ENABLE.start()).wrapping_div(WORD_SIZE);
println!("[write] enable {:#x} {} value {:#x}", addr, index, value);
self.enable[index as usize] = value as u32;
}
addr if THRESHOLD_AND_CLAIM.contains(&addr) => {
let context = (addr - THRESHOLD_AND_CLAIM.start()).wrapping_div(CONTEXT_OFFSET);
let offset = addr - (THRESHOLD_AND_CLAIM.start() + CONTEXT_OFFSET * context);
println!(
"[write] threshold and claim {:#x} context {} offset {}",
addr, context, offset
);
if offset == 0 {
println!("[write] threshold {:#x} value {}", addr, value);
self.threshold[context as usize] = value as u32;
} else if offset == 4 {
println!("[write] claim {:#x} value {}", addr, value);
self.claim[context as usize] = value as u32;
} else {
return Err(Exception::StoreAMOAccessFault);
}
}
_ => return Err(Exception::StoreAMOAccessFault),
}
Ok(())
}
}