#![no_std]
#![cfg_attr(not(doc), no_main)]
use core::ptr::{addr_of, addr_of_mut};
use capsules_core::virtualizers::virtual_alarm::{MuxAlarm, VirtualMuxAlarm};
use kernel::capabilities;
use kernel::component::Component;
use kernel::hil::led::LedHigh;
use kernel::hil::time::{Alarm, Timer};
use kernel::platform::chip::InterruptService;
use kernel::platform::scheduler_timer::VirtualSchedulerTimer;
use kernel::platform::{KernelResources, SyscallDriverLookup};
use kernel::scheduler::mlfq::MLFQSched;
use kernel::utilities::registers::interfaces::ReadWriteable;
use kernel::utilities::StaticRef;
use kernel::{create_capability, debug, static_init};
use rv32i::csr;
mod io;
mod litex_generated_constants;
use litex_generated_constants as socc;
struct LiteXSimInterruptablePeripherals {
gpio0: &'static litex_vexriscv::gpio::LiteXGPIOController<'static, socc::SoCRegisterFmt>,
uart0: &'static litex_vexriscv::uart::LiteXUart<'static, socc::SoCRegisterFmt>,
timer0: &'static litex_vexriscv::timer::LiteXTimer<
'static,
socc::SoCRegisterFmt,
socc::ClockFrequency,
>,
ethmac0: &'static litex_vexriscv::liteeth::LiteEth<'static, socc::SoCRegisterFmt>,
}
impl LiteXSimInterruptablePeripherals {
pub fn init(&'static self) {
kernel::deferred_call::DeferredCallClient::register(self.uart0);
}
}
impl InterruptService for LiteXSimInterruptablePeripherals {
unsafe fn service_interrupt(&self, interrupt: u32) -> bool {
match interrupt as usize {
socc::UART_INTERRUPT => {
self.uart0.service_interrupt();
true
}
socc::TIMER0_INTERRUPT => {
self.timer0.service_interrupt();
true
}
socc::ETHMAC_INTERRUPT => {
self.ethmac0.service_interrupt();
true
}
socc::GPIO_INTERRUPT => {
self.gpio0.service_interrupt();
true
}
_ => false,
}
}
}
const NUM_PROCS: usize = 4;
static mut PROCESSES: [Option<&'static dyn kernel::process::Process>; NUM_PROCS] =
[None; NUM_PROCS];
struct LiteXSimPanicReferences {
chip: Option<&'static litex_vexriscv::chip::LiteXVexRiscv<LiteXSimInterruptablePeripherals>>,
uart: Option<&'static litex_vexriscv::uart::LiteXUart<'static, socc::SoCRegisterFmt>>,
process_printer: Option<&'static capsules_system::process_printer::ProcessPrinterText>,
}
static mut PANIC_REFERENCES: LiteXSimPanicReferences = LiteXSimPanicReferences {
chip: None,
uart: None,
process_printer: None,
};
const FAULT_RESPONSE: capsules_system::process_policies::PanicFaultPolicy =
capsules_system::process_policies::PanicFaultPolicy {};
#[no_mangle]
#[link_section = ".stack_buffer"]
pub static mut STACK_MEMORY: [u8; 0x2000] = [0; 0x2000];
struct LiteXSim {
gpio_driver: &'static capsules_core::gpio::GPIO<
'static,
litex_vexriscv::gpio::LiteXGPIOPin<'static, 'static, socc::SoCRegisterFmt>,
>,
button_driver: &'static capsules_core::button::Button<
'static,
litex_vexriscv::gpio::LiteXGPIOPin<'static, 'static, socc::SoCRegisterFmt>,
>,
led_driver: &'static capsules_core::led::LedDriver<
'static,
LedHigh<
'static,
litex_vexriscv::gpio::LiteXGPIOPin<'static, 'static, socc::SoCRegisterFmt>,
>,
8,
>,
console: &'static capsules_core::console::Console<'static>,
lldb: &'static capsules_core::low_level_debug::LowLevelDebug<
'static,
capsules_core::virtualizers::virtual_uart::UartDevice<'static>,
>,
alarm: &'static capsules_core::alarm::AlarmDriver<
'static,
VirtualMuxAlarm<
'static,
litex_vexriscv::timer::LiteXAlarm<
'static,
'static,
socc::SoCRegisterFmt,
socc::ClockFrequency,
>,
>,
>,
ipc: kernel::ipc::IPC<{ NUM_PROCS as u8 }>,
scheduler: &'static MLFQSched<
'static,
VirtualMuxAlarm<
'static,
litex_vexriscv::timer::LiteXAlarm<
'static,
'static,
socc::SoCRegisterFmt,
socc::ClockFrequency,
>,
>,
>,
scheduler_timer: &'static VirtualSchedulerTimer<
VirtualMuxAlarm<
'static,
litex_vexriscv::timer::LiteXAlarm<
'static,
'static,
socc::SoCRegisterFmt,
socc::ClockFrequency,
>,
>,
>,
}
impl SyscallDriverLookup for LiteXSim {
fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
where
F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
{
match driver_num {
capsules_core::button::DRIVER_NUM => f(Some(self.button_driver)),
capsules_core::led::DRIVER_NUM => f(Some(self.led_driver)),
capsules_core::gpio::DRIVER_NUM => f(Some(self.gpio_driver)),
capsules_core::console::DRIVER_NUM => f(Some(self.console)),
capsules_core::alarm::DRIVER_NUM => f(Some(self.alarm)),
capsules_core::low_level_debug::DRIVER_NUM => f(Some(self.lldb)),
kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)),
_ => f(None),
}
}
}
impl KernelResources<litex_vexriscv::chip::LiteXVexRiscv<LiteXSimInterruptablePeripherals>>
for LiteXSim
{
type SyscallDriverLookup = Self;
type SyscallFilter = ();
type ProcessFault = ();
type Scheduler = MLFQSched<
'static,
VirtualMuxAlarm<
'static,
litex_vexriscv::timer::LiteXAlarm<
'static,
'static,
socc::SoCRegisterFmt,
socc::ClockFrequency,
>,
>,
>;
type SchedulerTimer = VirtualSchedulerTimer<
VirtualMuxAlarm<
'static,
litex_vexriscv::timer::LiteXAlarm<
'static,
'static,
socc::SoCRegisterFmt,
socc::ClockFrequency,
>,
>,
>;
type WatchDog = ();
type ContextSwitchCallback = ();
fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
self
}
fn syscall_filter(&self) -> &Self::SyscallFilter {
&()
}
fn process_fault(&self) -> &Self::ProcessFault {
&()
}
fn scheduler(&self) -> &Self::Scheduler {
self.scheduler
}
fn scheduler_timer(&self) -> &Self::SchedulerTimer {
self.scheduler_timer
}
fn watchdog(&self) -> &Self::WatchDog {
&()
}
fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
&()
}
}
#[inline(never)]
unsafe fn start() -> (
&'static kernel::Kernel,
LiteXSim,
&'static litex_vexriscv::chip::LiteXVexRiscv<LiteXSimInterruptablePeripherals>,
) {
extern "C" {
static _sapps: u8;
static _eapps: u8;
static mut _sappmem: u8;
static _eappmem: u8;
static _stext: u8;
static _etext: u8;
static _sflash: u8;
static _eflash: u8;
static _ssram: u8;
static _esram: u8;
}
rv32i::configure_trap_handler();
let pmp = rv32i::pmp::kernel_protection::KernelProtectionPMP::new(
rv32i::pmp::kernel_protection::FlashRegion(
rv32i::pmp::NAPOTRegionSpec::new(
core::ptr::addr_of!(_sflash),
core::ptr::addr_of!(_eflash) as usize - core::ptr::addr_of!(_sflash) as usize,
)
.unwrap(),
),
rv32i::pmp::kernel_protection::RAMRegion(
rv32i::pmp::NAPOTRegionSpec::new(
core::ptr::addr_of!(_ssram),
core::ptr::addr_of!(_esram) as usize - core::ptr::addr_of!(_ssram) as usize,
)
.unwrap(),
),
rv32i::pmp::kernel_protection::MMIORegion(
rv32i::pmp::NAPOTRegionSpec::new(
0xf0000000 as *const u8, 0x10000000, )
.unwrap(),
),
rv32i::pmp::kernel_protection::KernelTextRegion(
rv32i::pmp::TORRegionSpec::new(
core::ptr::addr_of!(_stext),
core::ptr::addr_of!(_etext),
)
.unwrap(),
),
)
.unwrap();
let process_mgmt_cap = create_capability!(capabilities::ProcessManagementCapability);
let memory_allocation_cap = create_capability!(capabilities::MemoryAllocationCapability);
let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(&*addr_of!(PROCESSES)));
let timer0 = static_init!(
litex_vexriscv::timer::LiteXTimer<'static, socc::SoCRegisterFmt, socc::ClockFrequency>,
litex_vexriscv::timer::LiteXTimer::new(StaticRef::new(
socc::CSR_TIMER0_BASE
as *const litex_vexriscv::timer::LiteXTimerRegisters<socc::SoCRegisterFmt>
),)
);
let timer0_uptime = static_init!(
litex_vexriscv::timer::LiteXTimerUptime<
'static,
socc::SoCRegisterFmt,
socc::ClockFrequency,
>,
litex_vexriscv::timer::LiteXTimerUptime::new(timer0)
);
let litex_alarm = static_init!(
litex_vexriscv::timer::LiteXAlarm<
'static,
'static,
socc::SoCRegisterFmt,
socc::ClockFrequency,
>,
litex_vexriscv::timer::LiteXAlarm::new(timer0_uptime, timer0)
);
timer0.set_timer_client(litex_alarm);
litex_alarm.initialize();
let mux_alarm = static_init!(
MuxAlarm<
'static,
litex_vexriscv::timer::LiteXAlarm<
'static,
'static,
socc::SoCRegisterFmt,
socc::ClockFrequency,
>,
>,
MuxAlarm::new(litex_alarm)
);
litex_alarm.set_alarm_client(mux_alarm);
let virtual_alarm_user = static_init!(
VirtualMuxAlarm<
'static,
litex_vexriscv::timer::LiteXAlarm<
'static,
'static,
socc::SoCRegisterFmt,
socc::ClockFrequency,
>,
>,
VirtualMuxAlarm::new(mux_alarm)
);
virtual_alarm_user.setup();
let alarm = static_init!(
capsules_core::alarm::AlarmDriver<
'static,
VirtualMuxAlarm<
'static,
litex_vexriscv::timer::LiteXAlarm<
'static,
'static,
socc::SoCRegisterFmt,
socc::ClockFrequency,
>,
>,
>,
capsules_core::alarm::AlarmDriver::new(
virtual_alarm_user,
board_kernel.create_grant(capsules_core::alarm::DRIVER_NUM, &memory_allocation_cap)
)
);
virtual_alarm_user.set_alarm_client(alarm);
let systick_virtual_alarm = static_init!(
VirtualMuxAlarm<
'static,
litex_vexriscv::timer::LiteXAlarm<
'static,
'static,
socc::SoCRegisterFmt,
socc::ClockFrequency,
>,
>,
VirtualMuxAlarm::new(mux_alarm)
);
systick_virtual_alarm.setup();
let scheduler_timer = static_init!(
VirtualSchedulerTimer<
VirtualMuxAlarm<
'static,
litex_vexriscv::timer::LiteXAlarm<
'static,
'static,
socc::SoCRegisterFmt,
socc::ClockFrequency,
>,
>,
>,
VirtualSchedulerTimer::new(systick_virtual_alarm)
);
let uart0 = static_init!(
litex_vexriscv::uart::LiteXUart<socc::SoCRegisterFmt>,
litex_vexriscv::uart::LiteXUart::new(
StaticRef::new(
socc::CSR_UART_BASE
as *const litex_vexriscv::uart::LiteXUartRegisters<socc::SoCRegisterFmt>,
),
None, )
);
uart0.initialize();
PANIC_REFERENCES.uart = Some(uart0);
let uart_mux = components::console::UartMuxComponent::new(uart0, 115200)
.finalize(components::uart_mux_component_static!());
let ethmac0_rxbuf0 = static_init!([u8; 1522], [0; 1522]);
let ethmac0 = static_init!(
litex_vexriscv::liteeth::LiteEth<socc::SoCRegisterFmt>,
litex_vexriscv::liteeth::LiteEth::new(
StaticRef::new(
socc::CSR_ETHMAC_BASE
as *const litex_vexriscv::liteeth::LiteEthMacRegisters<socc::SoCRegisterFmt>,
),
socc::MEM_ETHMAC_BASE,
socc::MEM_ETHMAC_SIZE,
socc::ETHMAC_SLOT_SIZE,
socc::ETHMAC_RX_SLOTS,
socc::ETHMAC_TX_SLOTS,
ethmac0_rxbuf0,
)
);
ethmac0.initialize();
type GPIOPin = litex_vexriscv::gpio::LiteXGPIOPin<'static, 'static, socc::SoCRegisterFmt>;
let gpio0 = static_init!(
litex_vexriscv::gpio::LiteXGPIOController<'static, socc::SoCRegisterFmt>,
litex_vexriscv::gpio::LiteXGPIOController::new(
StaticRef::new(
socc::CSR_GPIO_BASE
as *const litex_vexriscv::gpio::LiteXGPIORegisters<socc::SoCRegisterFmt>
),
32, ),
);
gpio0.initialize();
let gpio_driver = components::gpio::GpioComponent::new(
board_kernel,
capsules_core::gpio::DRIVER_NUM,
components::gpio_component_helper_owned!(
GPIOPin,
16 => gpio0.get_gpio_pin(16).unwrap(),
17 => gpio0.get_gpio_pin(17).unwrap(),
18 => gpio0.get_gpio_pin(18).unwrap(),
19 => gpio0.get_gpio_pin(19).unwrap(),
20 => gpio0.get_gpio_pin(20).unwrap(),
21 => gpio0.get_gpio_pin(21).unwrap(),
22 => gpio0.get_gpio_pin(22).unwrap(),
23 => gpio0.get_gpio_pin(23).unwrap(),
24 => gpio0.get_gpio_pin(24).unwrap(),
25 => gpio0.get_gpio_pin(25).unwrap(),
26 => gpio0.get_gpio_pin(26).unwrap(),
27 => gpio0.get_gpio_pin(27).unwrap(),
28 => gpio0.get_gpio_pin(28).unwrap(),
29 => gpio0.get_gpio_pin(29).unwrap(),
30 => gpio0.get_gpio_pin(30).unwrap(),
31 => gpio0.get_gpio_pin(31).unwrap(),
),
)
.finalize(components::gpio_component_static!(GPIOPin));
let led_gpios = static_init!(
[GPIOPin; 8],
[
gpio0.get_gpio_pin(0).unwrap(),
gpio0.get_gpio_pin(1).unwrap(),
gpio0.get_gpio_pin(2).unwrap(),
gpio0.get_gpio_pin(3).unwrap(),
gpio0.get_gpio_pin(4).unwrap(),
gpio0.get_gpio_pin(5).unwrap(),
gpio0.get_gpio_pin(6).unwrap(),
gpio0.get_gpio_pin(7).unwrap(),
]
);
let led_driver =
components::led::LedsComponent::new().finalize(components::led_component_static!(
kernel::hil::led::LedHigh<GPIOPin>,
LedHigh::new(&led_gpios[0]),
LedHigh::new(&led_gpios[1]),
LedHigh::new(&led_gpios[2]),
LedHigh::new(&led_gpios[3]),
LedHigh::new(&led_gpios[4]),
LedHigh::new(&led_gpios[5]),
LedHigh::new(&led_gpios[6]),
LedHigh::new(&led_gpios[7]),
));
let button_driver = components::button::ButtonComponent::new(
board_kernel,
capsules_core::button::DRIVER_NUM,
components::button_component_helper_owned!(
GPIOPin,
(
gpio0.get_gpio_pin(8).unwrap(),
kernel::hil::gpio::ActivationMode::ActiveHigh,
kernel::hil::gpio::FloatingState::PullNone
),
(
gpio0.get_gpio_pin(9).unwrap(),
kernel::hil::gpio::ActivationMode::ActiveHigh,
kernel::hil::gpio::FloatingState::PullNone
),
(
gpio0.get_gpio_pin(10).unwrap(),
kernel::hil::gpio::ActivationMode::ActiveHigh,
kernel::hil::gpio::FloatingState::PullNone
),
(
gpio0.get_gpio_pin(11).unwrap(),
kernel::hil::gpio::ActivationMode::ActiveHigh,
kernel::hil::gpio::FloatingState::PullNone
),
(
gpio0.get_gpio_pin(12).unwrap(),
kernel::hil::gpio::ActivationMode::ActiveHigh,
kernel::hil::gpio::FloatingState::PullNone
),
(
gpio0.get_gpio_pin(13).unwrap(),
kernel::hil::gpio::ActivationMode::ActiveHigh,
kernel::hil::gpio::FloatingState::PullNone
),
(
gpio0.get_gpio_pin(14).unwrap(),
kernel::hil::gpio::ActivationMode::ActiveHigh,
kernel::hil::gpio::FloatingState::PullNone
),
(
gpio0.get_gpio_pin(15).unwrap(),
kernel::hil::gpio::ActivationMode::ActiveHigh,
kernel::hil::gpio::FloatingState::PullNone
),
),
)
.finalize(components::button_component_static!(GPIOPin));
let interrupt_service = static_init!(
LiteXSimInterruptablePeripherals,
LiteXSimInterruptablePeripherals {
gpio0,
uart0,
timer0,
ethmac0,
}
);
interrupt_service.init();
let chip = static_init!(
litex_vexriscv::chip::LiteXVexRiscv<
LiteXSimInterruptablePeripherals,
>,
litex_vexriscv::chip::LiteXVexRiscv::new(
"Verilated LiteX on VexRiscv",
interrupt_service,
pmp,
)
);
PANIC_REFERENCES.chip = Some(chip);
let process_printer = components::process_printer::ProcessPrinterTextComponent::new()
.finalize(components::process_printer_text_component_static!());
PANIC_REFERENCES.process_printer = Some(process_printer);
csr::CSR
.mie
.modify(csr::mie::mie::mext::SET + csr::mie::mie::msoft::SET);
csr::CSR.mstatus.modify(csr::mstatus::mstatus::mie::SET);
chip.unmask_interrupts();
let console = components::console::ConsoleComponent::new(
board_kernel,
capsules_core::console::DRIVER_NUM,
uart_mux,
)
.finalize(components::console_component_static!());
components::debug_writer::DebugWriterComponent::new(uart_mux)
.finalize(components::debug_writer_component_static!());
let lldb = components::lldb::LowLevelDebugComponent::new(
board_kernel,
capsules_core::low_level_debug::DRIVER_NUM,
uart_mux,
)
.finalize(components::low_level_debug_component_static!());
let scheduler = components::sched::mlfq::MLFQComponent::new(mux_alarm, &*addr_of!(PROCESSES))
.finalize(components::mlfq_component_static!(
litex_vexriscv::timer::LiteXAlarm<
'static,
'static,
socc::SoCRegisterFmt,
socc::ClockFrequency,
>,
NUM_PROCS
));
let litex_sim = LiteXSim {
gpio_driver,
button_driver,
led_driver,
console,
alarm,
lldb,
ipc: kernel::ipc::IPC::new(
board_kernel,
kernel::ipc::DRIVER_NUM,
&memory_allocation_cap,
),
scheduler,
scheduler_timer,
};
debug!("Verilated LiteX+VexRiscv: initialization complete, entering main loop.");
kernel::process::load_processes(
board_kernel,
chip,
core::slice::from_raw_parts(
core::ptr::addr_of!(_sapps),
core::ptr::addr_of!(_eapps) as usize - core::ptr::addr_of!(_sapps) as usize,
),
core::slice::from_raw_parts_mut(
core::ptr::addr_of_mut!(_sappmem),
core::ptr::addr_of!(_eappmem) as usize - core::ptr::addr_of!(_sappmem) as usize,
),
&mut *addr_of_mut!(PROCESSES),
&FAULT_RESPONSE,
&process_mgmt_cap,
)
.unwrap_or_else(|err| {
debug!("Error loading processes!");
debug!("{:?}", err);
});
(board_kernel, litex_sim, chip)
}
#[no_mangle]
pub unsafe fn main() {
let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
let (board_kernel, board, chip) = start();
board_kernel.kernel_loop(&board, chip, Some(&board.ipc), &main_loop_capability);
}