use crate::registers::top_earlgrey::RV_PLIC_BASE_ADDR;
use kernel::utilities::cells::VolatileCell;
use kernel::utilities::registers::interfaces::{Readable, Writeable};
use kernel::utilities::registers::LocalRegisterCopy;
use kernel::utilities::registers::{register_bitfields, register_structs, ReadOnly, ReadWrite};
use kernel::utilities::StaticRef;
pub const PLIC_BASE: StaticRef<PlicRegisters> =
unsafe { StaticRef::new(RV_PLIC_BASE_ADDR as *const PlicRegisters) };
pub static mut PLIC: Plic = Plic::new(PLIC_BASE);
pub const PLIC_REGS: usize = 6;
pub const PLIC_IRQ_NUM: usize = 185;
register_structs! {
pub PlicRegisters {
(0x000 => priority: [ReadWrite<u32, priority::Register>; PLIC_IRQ_NUM]),
(0x2e4 => _reserved0),
(0x1000 => pending: [ReadOnly<u32>; PLIC_REGS]),
(0x1018 => _reserved1),
(0x2000 => enable: [ReadWrite<u32>; PLIC_REGS]),
(0x2018 => _reserved2),
(0x200000 => threshold: ReadWrite<u32, priority::Register>),
(0x200004 => claim: ReadWrite<u32>),
(0x200008 => _reserved3),
(0x4000000 => msip: ReadWrite<u32>),
(0x4000004 => _reserved4),
(0x4004000 => alert_test: ReadWrite<u32>),
(0x4004004 => @END),
}
}
register_bitfields![u32,
priority [
Priority OFFSET(0) NUMBITS(2) []
]
];
pub struct Plic {
registers: StaticRef<PlicRegisters>,
saved: [VolatileCell<LocalRegisterCopy<u32>>; PLIC_REGS],
}
impl Plic {
pub const fn new(base: StaticRef<PlicRegisters>) -> Self {
Plic {
registers: base,
saved: [
VolatileCell::new(LocalRegisterCopy::new(0)),
VolatileCell::new(LocalRegisterCopy::new(0)),
VolatileCell::new(LocalRegisterCopy::new(0)),
VolatileCell::new(LocalRegisterCopy::new(0)),
VolatileCell::new(LocalRegisterCopy::new(0)),
VolatileCell::new(LocalRegisterCopy::new(0)),
],
}
}
pub fn clear_all_pending(&self) {
unimplemented!()
}
pub fn enable_all(&self) {
for enable in self.registers.enable.iter() {
enable.set(0xFFFF_FFFF);
}
for priority in self.registers.priority.iter() {
priority.write(priority::Priority.val(3));
}
self.registers.threshold.write(priority::Priority.val(1));
}
pub fn disable(&self, index: u32) {
if index >= PLIC_IRQ_NUM as u32 {
panic!("Invalid IRQ: {}", index);
};
let offset = (index / 32) as usize;
let mask = !(1 << (index % 32));
self.registers.enable[offset].set(self.registers.enable[offset].get() & mask);
}
pub fn disable_all(&self) {
for enable in self.registers.enable.iter() {
enable.set(0);
}
}
pub fn next_pending(&self) -> Option<u32> {
let claim = self.registers.claim.get();
if claim == 0 {
None
} else {
Some(claim)
}
}
pub unsafe fn save_interrupt(&self, index: u32) {
if index >= PLIC_IRQ_NUM as u32 {
panic!("Invalid IRQ: {}", index);
};
let offset = (index / 32) as usize;
let mask = 1 << (index % 32);
let new_saved = self.saved[offset].get().get() | mask;
self.saved[offset].set(LocalRegisterCopy::new(new_saved));
}
pub fn get_saved_interrupts(&self) -> Option<u32> {
for (i, pending) in self.saved.iter().enumerate() {
let saved = pending.get().get();
if saved != 0 {
return Some(saved.trailing_zeros() + (i as u32 * 32));
}
}
None
}
pub unsafe fn complete(&self, index: u32) {
self.registers.claim.set(index);
if index >= PLIC_IRQ_NUM as u32 {
panic!("Invalid IRQ: {}", index);
};
let offset = (index / 32) as usize;
let mask = !(1 << (index % 32));
let new_saved = self.saved[offset].get().get() & mask;
self.saved[offset].set(LocalRegisterCopy::new(new_saved));
}
}