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