litex_sim/
main.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Board file for a LiteX SoC running in a Verilated simulation
6
7#![no_std]
8#![no_main]
9
10use capsules_core::virtualizers::virtual_alarm::{MuxAlarm, VirtualMuxAlarm};
11use kernel::capabilities;
12use kernel::component::Component;
13use kernel::debug::PanicResources;
14use kernel::hil::led::LedHigh;
15use kernel::hil::time::{Alarm, Timer};
16use kernel::platform::chip::InterruptService;
17use kernel::platform::{KernelResources, SyscallDriverLookup};
18use kernel::utilities::registers::interfaces::ReadWriteable;
19use kernel::utilities::single_thread_value::SingleThreadValue;
20use kernel::utilities::StaticRef;
21use kernel::{create_capability, debug, static_init};
22use rv32i::csr;
23
24mod io;
25mod litex_generated_constants;
26
27// This module contains the LiteX SoC configuration options, register
28// positions, interrupt mappings and other implementation details of
29// the generated bitstream.
30//
31// Its values are used throughout the file, hence import it under a
32// short name.
33use litex_generated_constants as socc;
34
35/// Structure for dynamic interrupt mapping, depending on the SoC
36/// configuration
37///
38/// This struct is deliberately kept in the board crate. Because of
39/// the configurable nature of LiteX, it does not make sense to define
40/// a default interrupt mapping, as the interrupt numbers are
41/// generated sequentially for all softcores.
42struct LiteXSimInterruptablePeripherals {
43    gpio0: &'static litex_vexriscv::gpio::LiteXGPIOController<'static, socc::SoCRegisterFmt>,
44    uart0: &'static litex_vexriscv::uart::LiteXUart<'static, socc::SoCRegisterFmt>,
45    timer0: &'static litex_vexriscv::timer::LiteXTimer<
46        'static,
47        socc::SoCRegisterFmt,
48        socc::ClockFrequency,
49    >,
50    ethmac0: &'static litex_vexriscv::liteeth::LiteEth<
51        'static,
52        { socc::ETHMAC_TX_SLOTS },
53        socc::SoCRegisterFmt,
54    >,
55}
56
57impl LiteXSimInterruptablePeripherals {
58    // Resolve any recursive dependencies and set up deferred calls:
59    pub fn init(&'static self) {
60        kernel::deferred_call::DeferredCallClient::register(self.uart0);
61    }
62}
63
64impl InterruptService for LiteXSimInterruptablePeripherals {
65    unsafe fn service_interrupt(&self, interrupt: u32) -> bool {
66        match interrupt as usize {
67            socc::UART_INTERRUPT => {
68                self.uart0.service_interrupt();
69                true
70            }
71            socc::TIMER0_INTERRUPT => {
72                self.timer0.service_interrupt();
73                true
74            }
75            socc::ETHMAC_INTERRUPT => {
76                self.ethmac0.service_interrupt();
77                true
78            }
79            socc::GPIO_INTERRUPT => {
80                self.gpio0.service_interrupt();
81                true
82            }
83            _ => false,
84        }
85    }
86}
87
88const NUM_PROCS: usize = 4;
89
90type ChipHw = litex_vexriscv::chip::LiteXVexRiscv<LiteXSimInterruptablePeripherals>;
91type AlarmHw =
92    litex_vexriscv::timer::LiteXAlarm<'static, 'static, socc::SoCRegisterFmt, socc::ClockFrequency>;
93type SchedulerTimerHw =
94    components::virtual_scheduler_timer::VirtualSchedulerTimerComponentType<AlarmHw>;
95type ProcessPrinterInUse = capsules_system::process_printer::ProcessPrinterText;
96type SchedulerInUse = components::sched::mlfq::MLFQComponentType<AlarmHw>;
97
98/// Resources for when a board panics used by io.rs.
99static PANIC_RESOURCES: SingleThreadValue<PanicResources<ChipHw, ProcessPrinterInUse>> =
100    SingleThreadValue::new();
101
102// How should the kernel respond when a process faults.
103const FAULT_RESPONSE: capsules_system::process_policies::PanicFaultPolicy =
104    capsules_system::process_policies::PanicFaultPolicy {};
105
106kernel::stack_size! {0x2000}
107
108/// A structure representing this platform that holds references to all
109/// capsules for this platform.
110struct LiteXSim {
111    gpio_driver: &'static capsules_core::gpio::GPIO<
112        'static,
113        litex_vexriscv::gpio::LiteXGPIOPin<'static, 'static, socc::SoCRegisterFmt>,
114    >,
115    button_driver: &'static capsules_core::button::Button<
116        'static,
117        litex_vexriscv::gpio::LiteXGPIOPin<'static, 'static, socc::SoCRegisterFmt>,
118    >,
119    led_driver: &'static capsules_core::led::LedDriver<
120        'static,
121        LedHigh<
122            'static,
123            litex_vexriscv::gpio::LiteXGPIOPin<'static, 'static, socc::SoCRegisterFmt>,
124        >,
125        8,
126    >,
127    console: &'static capsules_core::console::Console<'static>,
128    lldb: &'static capsules_core::low_level_debug::LowLevelDebug<
129        'static,
130        capsules_core::virtualizers::virtual_uart::UartDevice<'static>,
131    >,
132    alarm: &'static capsules_core::alarm::AlarmDriver<'static, VirtualMuxAlarm<'static, AlarmHw>>,
133    ipc: kernel::ipc::IPC<{ NUM_PROCS as u8 }>,
134    scheduler: &'static SchedulerInUse,
135    scheduler_timer: &'static SchedulerTimerHw,
136}
137
138/// Mapping of integer syscalls to objects that implement syscalls.
139impl SyscallDriverLookup for LiteXSim {
140    fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
141    where
142        F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
143    {
144        match driver_num {
145            capsules_core::button::DRIVER_NUM => f(Some(self.button_driver)),
146            capsules_core::led::DRIVER_NUM => f(Some(self.led_driver)),
147            capsules_core::gpio::DRIVER_NUM => f(Some(self.gpio_driver)),
148            capsules_core::console::DRIVER_NUM => f(Some(self.console)),
149            capsules_core::alarm::DRIVER_NUM => f(Some(self.alarm)),
150            capsules_core::low_level_debug::DRIVER_NUM => f(Some(self.lldb)),
151            kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)),
152            _ => f(None),
153        }
154    }
155}
156
157impl KernelResources<litex_vexriscv::chip::LiteXVexRiscv<LiteXSimInterruptablePeripherals>>
158    for LiteXSim
159{
160    type SyscallDriverLookup = Self;
161    type SyscallFilter = ();
162    type ProcessFault = ();
163    type Scheduler = SchedulerInUse;
164    type SchedulerTimer = SchedulerTimerHw;
165    type WatchDog = ();
166    type ContextSwitchCallback = ();
167
168    fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
169        self
170    }
171    fn syscall_filter(&self) -> &Self::SyscallFilter {
172        &()
173    }
174    fn process_fault(&self) -> &Self::ProcessFault {
175        &()
176    }
177    fn scheduler(&self) -> &Self::Scheduler {
178        self.scheduler
179    }
180    fn scheduler_timer(&self) -> &Self::SchedulerTimer {
181        self.scheduler_timer
182    }
183    fn watchdog(&self) -> &Self::WatchDog {
184        &()
185    }
186    fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
187        &()
188    }
189}
190
191/// This is in a separate, inline(never) function so that its stack frame is
192/// removed when this function returns. Otherwise, the stack space used for
193/// these static_inits is wasted.
194#[inline(never)]
195unsafe fn start() -> (
196    &'static kernel::Kernel,
197    LiteXSim,
198    &'static litex_vexriscv::chip::LiteXVexRiscv<LiteXSimInterruptablePeripherals>,
199) {
200    // These symbols are defined in the linker script.
201    extern "C" {
202        /// Beginning of the ROM region containing app images.
203        static _sapps: u8;
204        /// End of the ROM region containing app images.
205        static _eapps: u8;
206        /// Beginning of the RAM region for app memory.
207        static mut _sappmem: u8;
208        /// End of the RAM region for app memory.
209        static _eappmem: u8;
210        /// The start of the kernel text (Included only for kernel PMP)
211        static _stext: u8;
212        /// The end of the kernel text (Included only for kernel PMP)
213        static _etext: u8;
214        /// The start of the kernel / app / storage flash (Included only for kernel PMP)
215        static _sflash: u8;
216        /// The end of the kernel / app / storage flash (Included only for kernel PMP)
217        static _eflash: u8;
218        /// The start of the kernel / app RAM (Included only for kernel PMP)
219        static _ssram: u8;
220        /// The end of the kernel / app RAM (Included only for kernel PMP)
221        static _esram: u8;
222    }
223
224    // ---------- BASIC INITIALIZATION ----------
225
226    // Basic setup of the riscv platform.
227    rv32i::configure_trap_handler();
228
229    // Initialize deferred calls very early.
230    kernel::deferred_call::initialize_deferred_call_state_unsafe::<
231        <ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider,
232    >();
233
234    // Bind global variables to this thread.
235    let _ = PANIC_RESOURCES
236        .bind_to_thread_unsafe::<<ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider>(
237            PanicResources::new(),
238        );
239
240    // Set up memory protection immediately after setting the trap handler, to
241    // ensure that much of the board initialization routine runs with PMP kernel
242    // memory protection.
243    let pmp = rv32i::pmp::kernel_protection::KernelProtectionPMP::new(
244        rv32i::pmp::kernel_protection::FlashRegion(
245            rv32i::pmp::NAPOTRegionSpec::from_start_end(
246                core::ptr::addr_of!(_sflash),
247                core::ptr::addr_of!(_eflash),
248            )
249            .unwrap(),
250        ),
251        rv32i::pmp::kernel_protection::RAMRegion(
252            rv32i::pmp::NAPOTRegionSpec::from_start_end(
253                core::ptr::addr_of!(_ssram),
254                core::ptr::addr_of!(_esram),
255            )
256            .unwrap(),
257        ),
258        rv32i::pmp::kernel_protection::MMIORegion(
259            rv32i::pmp::NAPOTRegionSpec::from_start_size(
260                0xf0000000 as *const u8, // start
261                0x10000000,              // size
262            )
263            .unwrap(),
264        ),
265        rv32i::pmp::kernel_protection::KernelTextRegion(
266            rv32i::pmp::TORRegionSpec::from_start_end(
267                core::ptr::addr_of!(_stext),
268                core::ptr::addr_of!(_etext),
269            )
270            .unwrap(),
271        ),
272    )
273    .unwrap();
274
275    // initialize capabilities
276    let process_mgmt_cap = create_capability!(capabilities::ProcessManagementCapability);
277    let memory_allocation_cap = create_capability!(capabilities::MemoryAllocationCapability);
278
279    // Create an array to hold process references.
280    let processes = components::process_array::ProcessArrayComponent::new()
281        .finalize(components::process_array_component_static!(NUM_PROCS));
282    PANIC_RESOURCES.get().map(|resources| {
283        resources.processes.put(processes.as_slice());
284    });
285
286    // Setup space to store the core kernel data structure.
287    let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(processes.as_slice()));
288
289    // --------- TIMER & UPTIME CORE; ALARM INITIALIZATION ----------
290
291    // Initialize the hardware timer
292    let timer0 = static_init!(
293        litex_vexriscv::timer::LiteXTimer<'static, socc::SoCRegisterFmt, socc::ClockFrequency>,
294        litex_vexriscv::timer::LiteXTimer::new(StaticRef::new(
295            socc::CSR_TIMER0_BASE
296                as *const litex_vexriscv::timer::LiteXTimerRegisters<socc::SoCRegisterFmt>
297        ),)
298    );
299
300    // The SoC is expected to feature the 64-bit uptime extension to the timer hardware
301    let timer0_uptime = static_init!(
302        litex_vexriscv::timer::LiteXTimerUptime<
303            'static,
304            socc::SoCRegisterFmt,
305            socc::ClockFrequency,
306        >,
307        litex_vexriscv::timer::LiteXTimerUptime::new(timer0)
308    );
309
310    // Create the LiteXAlarm based on the hardware LiteXTimer core and
311    // the uptime peripheral
312    let litex_alarm = static_init!(
313        AlarmHw,
314        litex_vexriscv::timer::LiteXAlarm::new(timer0_uptime, timer0)
315    );
316    timer0.set_timer_client(litex_alarm);
317    litex_alarm.initialize();
318
319    // Create a shared virtualization mux layer on top of a single hardware
320    // alarm.
321    let mux_alarm = static_init!(MuxAlarm<'static, AlarmHw>, MuxAlarm::new(litex_alarm));
322    litex_alarm.set_alarm_client(mux_alarm);
323
324    // Userspace alarm driver
325    let virtual_alarm_user = static_init!(
326        VirtualMuxAlarm<'static, AlarmHw>,
327        VirtualMuxAlarm::new(mux_alarm)
328    );
329    virtual_alarm_user.setup();
330
331    let alarm = static_init!(
332        capsules_core::alarm::AlarmDriver<'static, VirtualMuxAlarm<'static, AlarmHw>>,
333        capsules_core::alarm::AlarmDriver::new(
334            virtual_alarm_user,
335            board_kernel.create_grant(capsules_core::alarm::DRIVER_NUM, &memory_allocation_cap)
336        )
337    );
338    virtual_alarm_user.set_alarm_client(alarm);
339
340    let scheduler_timer =
341        components::virtual_scheduler_timer::VirtualSchedulerTimerComponent::new(mux_alarm)
342            .finalize(components::virtual_scheduler_timer_component_static!(
343                AlarmHw
344            ));
345
346    // ---------- UART ----------
347
348    // Initialize the HW UART
349    let uart0 = static_init!(
350        litex_vexriscv::uart::LiteXUart<socc::SoCRegisterFmt>,
351        litex_vexriscv::uart::LiteXUart::new(
352            StaticRef::new(
353                socc::CSR_UART_BASE
354                    as *const litex_vexriscv::uart::LiteXUartRegisters<socc::SoCRegisterFmt>,
355            ),
356            None, // LiteX simulator has no UART phy
357        )
358    );
359    uart0.initialize();
360
361    // Create a shared UART channel for the console and for kernel debug.
362    //
363    // The baudrate is ingnored, as no UART phy is present in the
364    // verilated simulation.
365    let uart_mux = components::console::UartMuxComponent::new(uart0, 115200)
366        .finalize(components::uart_mux_component_static!());
367
368    // ---------- ETHERNET ----------
369
370    // ETHMAC peripheral
371    let ethmac0 = static_init!(
372        litex_vexriscv::liteeth::LiteEth<{socc::ETHMAC_TX_SLOTS}, socc::SoCRegisterFmt>,
373        litex_vexriscv::liteeth::LiteEth::new(
374            StaticRef::new(
375                socc::CSR_ETHMAC_BASE
376                    as *const litex_vexriscv::liteeth::LiteEthMacRegisters<socc::SoCRegisterFmt>,
377            ),
378            socc::MEM_ETHMAC_BASE,
379            socc::MEM_ETHMAC_SIZE,
380            socc::ETHMAC_SLOT_SIZE,
381            socc::ETHMAC_RX_SLOTS,
382            socc::ETHMAC_TX_SLOTS,
383        )
384    );
385
386    // Initialize the ETHMAC controller
387    ethmac0.initialize();
388
389    // --------- GPIO CONTROLLER ----------
390    type GPIOPin = litex_vexriscv::gpio::LiteXGPIOPin<'static, 'static, socc::SoCRegisterFmt>;
391
392    // GPIO hardware controller
393    let gpio0 = static_init!(
394        litex_vexriscv::gpio::LiteXGPIOController<'static, socc::SoCRegisterFmt>,
395        litex_vexriscv::gpio::LiteXGPIOController::new(
396            StaticRef::new(
397                socc::CSR_GPIO_BASE
398                    as *const litex_vexriscv::gpio::LiteXGPIORegisters<socc::SoCRegisterFmt>
399            ),
400            32, // 32 GPIOs in the simulation
401        ),
402    );
403    gpio0.initialize();
404
405    // --------- GPIO DRIVER ----------
406
407    let gpio_driver = components::gpio::GpioComponent::new(
408        board_kernel,
409        capsules_core::gpio::DRIVER_NUM,
410        components::gpio_component_helper_owned!(
411            GPIOPin,
412            16 => gpio0.get_gpio_pin(16).unwrap(),
413            17 => gpio0.get_gpio_pin(17).unwrap(),
414            18 => gpio0.get_gpio_pin(18).unwrap(),
415            19 => gpio0.get_gpio_pin(19).unwrap(),
416            20 => gpio0.get_gpio_pin(20).unwrap(),
417            21 => gpio0.get_gpio_pin(21).unwrap(),
418            22 => gpio0.get_gpio_pin(22).unwrap(),
419            23 => gpio0.get_gpio_pin(23).unwrap(),
420            24 => gpio0.get_gpio_pin(24).unwrap(),
421            25 => gpio0.get_gpio_pin(25).unwrap(),
422            26 => gpio0.get_gpio_pin(26).unwrap(),
423            27 => gpio0.get_gpio_pin(27).unwrap(),
424            28 => gpio0.get_gpio_pin(28).unwrap(),
425            29 => gpio0.get_gpio_pin(29).unwrap(),
426            30 => gpio0.get_gpio_pin(30).unwrap(),
427            31 => gpio0.get_gpio_pin(31).unwrap(),
428        ),
429    )
430    .finalize(components::gpio_component_static!(GPIOPin));
431
432    // ---------- LED DRIVER ----------
433
434    let led_gpios = static_init!(
435        [GPIOPin; 8],
436        [
437            gpio0.get_gpio_pin(0).unwrap(),
438            gpio0.get_gpio_pin(1).unwrap(),
439            gpio0.get_gpio_pin(2).unwrap(),
440            gpio0.get_gpio_pin(3).unwrap(),
441            gpio0.get_gpio_pin(4).unwrap(),
442            gpio0.get_gpio_pin(5).unwrap(),
443            gpio0.get_gpio_pin(6).unwrap(),
444            gpio0.get_gpio_pin(7).unwrap(),
445        ]
446    );
447
448    let led_driver =
449        components::led::LedsComponent::new().finalize(components::led_component_static!(
450            kernel::hil::led::LedHigh<GPIOPin>,
451            LedHigh::new(&led_gpios[0]),
452            LedHigh::new(&led_gpios[1]),
453            LedHigh::new(&led_gpios[2]),
454            LedHigh::new(&led_gpios[3]),
455            LedHigh::new(&led_gpios[4]),
456            LedHigh::new(&led_gpios[5]),
457            LedHigh::new(&led_gpios[6]),
458            LedHigh::new(&led_gpios[7]),
459        ));
460
461    // ---------- BUTTON ----------
462
463    let button_driver = components::button::ButtonComponent::new(
464        board_kernel,
465        capsules_core::button::DRIVER_NUM,
466        components::button_component_helper_owned!(
467            GPIOPin,
468            (
469                gpio0.get_gpio_pin(8).unwrap(),
470                kernel::hil::gpio::ActivationMode::ActiveHigh,
471                kernel::hil::gpio::FloatingState::PullNone
472            ),
473            (
474                gpio0.get_gpio_pin(9).unwrap(),
475                kernel::hil::gpio::ActivationMode::ActiveHigh,
476                kernel::hil::gpio::FloatingState::PullNone
477            ),
478            (
479                gpio0.get_gpio_pin(10).unwrap(),
480                kernel::hil::gpio::ActivationMode::ActiveHigh,
481                kernel::hil::gpio::FloatingState::PullNone
482            ),
483            (
484                gpio0.get_gpio_pin(11).unwrap(),
485                kernel::hil::gpio::ActivationMode::ActiveHigh,
486                kernel::hil::gpio::FloatingState::PullNone
487            ),
488            (
489                gpio0.get_gpio_pin(12).unwrap(),
490                kernel::hil::gpio::ActivationMode::ActiveHigh,
491                kernel::hil::gpio::FloatingState::PullNone
492            ),
493            (
494                gpio0.get_gpio_pin(13).unwrap(),
495                kernel::hil::gpio::ActivationMode::ActiveHigh,
496                kernel::hil::gpio::FloatingState::PullNone
497            ),
498            (
499                gpio0.get_gpio_pin(14).unwrap(),
500                kernel::hil::gpio::ActivationMode::ActiveHigh,
501                kernel::hil::gpio::FloatingState::PullNone
502            ),
503            (
504                gpio0.get_gpio_pin(15).unwrap(),
505                kernel::hil::gpio::ActivationMode::ActiveHigh,
506                kernel::hil::gpio::FloatingState::PullNone
507            ),
508        ),
509    )
510    .finalize(components::button_component_static!(GPIOPin));
511
512    // ---------- INITIALIZE CHIP, ENABLE INTERRUPTS ----------
513
514    let interrupt_service = static_init!(
515        LiteXSimInterruptablePeripherals,
516        LiteXSimInterruptablePeripherals {
517            gpio0,
518            uart0,
519            timer0,
520            ethmac0,
521        }
522    );
523    interrupt_service.init();
524
525    let chip = static_init!(
526        litex_vexriscv::chip::LiteXVexRiscv<
527            LiteXSimInterruptablePeripherals,
528        >,
529        litex_vexriscv::chip::LiteXVexRiscv::new(
530            "Verilated LiteX on VexRiscv",
531            interrupt_service,
532            pmp,
533        )
534    );
535    PANIC_RESOURCES.get().map(|resources| {
536        resources.chip.put(chip);
537    });
538
539    let process_printer = components::process_printer::ProcessPrinterTextComponent::new()
540        .finalize(components::process_printer_text_component_static!());
541    PANIC_RESOURCES.get().map(|resources| {
542        resources.printer.put(process_printer);
543    });
544
545    // Enable RISC-V interrupts globally
546    csr::CSR
547        .mie
548        .modify(csr::mie::mie::mext::SET + csr::mie::mie::msoft::SET);
549    csr::CSR.mstatus.modify(csr::mstatus::mstatus::mie::SET);
550
551    // Unmask all interrupt sources in the interrupt controller
552    chip.unmask_interrupts();
553
554    // Setup the console.
555    let console = components::console::ConsoleComponent::new(
556        board_kernel,
557        capsules_core::console::DRIVER_NUM,
558        uart_mux,
559    )
560    .finalize(components::console_component_static!());
561    // Create the debugger object that handles calls to `debug!()`.
562    components::debug_writer::DebugWriterComponent::new_unsafe(
563        uart_mux,
564        create_capability!(capabilities::SetDebugWriterCapability),
565        || unsafe {
566            kernel::debug::initialize_debug_writer_wrapper_unsafe::<
567                <ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider,
568            >();
569        },
570    )
571    .finalize(components::debug_writer_component_static!());
572
573    let lldb = components::lldb::LowLevelDebugComponent::new(
574        board_kernel,
575        capsules_core::low_level_debug::DRIVER_NUM,
576        uart_mux,
577    )
578    .finalize(components::low_level_debug_component_static!());
579
580    let scheduler = components::sched::mlfq::MLFQComponent::new(mux_alarm, processes)
581        .finalize(components::mlfq_component_static!(AlarmHw, NUM_PROCS));
582
583    let litex_sim = LiteXSim {
584        gpio_driver,
585        button_driver,
586        led_driver,
587        console,
588        alarm,
589        lldb,
590        ipc: kernel::ipc::IPC::new(
591            board_kernel,
592            kernel::ipc::DRIVER_NUM,
593            &memory_allocation_cap,
594        ),
595        scheduler,
596        scheduler_timer,
597    };
598
599    debug!("Verilated LiteX+VexRiscv: initialization complete, entering main loop.");
600
601    kernel::process::load_processes(
602        board_kernel,
603        chip,
604        core::slice::from_raw_parts(
605            core::ptr::addr_of!(_sapps),
606            core::ptr::addr_of!(_eapps) as usize - core::ptr::addr_of!(_sapps) as usize,
607        ),
608        core::slice::from_raw_parts_mut(
609            core::ptr::addr_of_mut!(_sappmem),
610            core::ptr::addr_of!(_eappmem) as usize - core::ptr::addr_of!(_sappmem) as usize,
611        ),
612        &FAULT_RESPONSE,
613        &process_mgmt_cap,
614    )
615    .unwrap_or_else(|err| {
616        debug!("Error loading processes!");
617        debug!("{:?}", err);
618    });
619
620    (board_kernel, litex_sim, chip)
621}
622
623/// Main function called after RAM initialized.
624#[no_mangle]
625pub unsafe fn main() {
626    let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
627
628    let (board_kernel, board, chip) = start();
629    board_kernel.kernel_loop(&board, chip, Some(&board.ipc), &main_loop_capability);
630}