arty_e21/
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 the SiFive E21 Bitstream running on the Arty FPGA
6
7#![no_std]
8#![no_main]
9
10use arty_e21_chip::chip::ArtyExxDefaultPeripherals;
11use capsules_core::virtualizers::virtual_alarm::{MuxAlarm, VirtualMuxAlarm};
12
13use kernel::capabilities;
14use kernel::component::Component;
15use kernel::hil;
16use kernel::platform::{KernelResources, SyscallDriverLookup};
17use kernel::process::ProcessArray;
18use kernel::scheduler::priority::PrioritySched;
19use kernel::{create_capability, debug, static_init};
20
21#[allow(dead_code)]
22mod timer_test;
23
24pub mod io;
25
26// State for loading and holding applications.
27
28// Number of concurrent processes this platform supports.
29const NUM_PROCS: usize = 4;
30
31// How should the kernel respond when a process faults.
32const FAULT_RESPONSE: capsules_system::process_policies::PanicFaultPolicy =
33    capsules_system::process_policies::PanicFaultPolicy {};
34
35/// Static variables used by io.rs.
36static mut PROCESSES: Option<&'static ProcessArray<NUM_PROCS>> = None;
37
38// Reference to the chip for panic dumps.
39static mut CHIP: Option<&'static arty_e21_chip::chip::ArtyExx<ArtyExxDefaultPeripherals>> = None;
40static mut PROCESS_PRINTER: Option<&'static capsules_system::process_printer::ProcessPrinterText> =
41    None;
42
43kernel::stack_size! {0x1000}
44
45/// A structure representing this platform that holds references to all
46/// capsules for this platform.
47struct ArtyE21 {
48    console: &'static capsules_core::console::Console<'static>,
49    gpio: &'static capsules_core::gpio::GPIO<'static, arty_e21_chip::gpio::GpioPin<'static>>,
50    alarm: &'static capsules_core::alarm::AlarmDriver<
51        'static,
52        VirtualMuxAlarm<'static, arty_e21_chip::chip::ArtyExxClint<'static>>,
53    >,
54    led: &'static capsules_core::led::LedDriver<
55        'static,
56        hil::led::LedHigh<'static, arty_e21_chip::gpio::GpioPin<'static>>,
57        3,
58    >,
59    button: &'static capsules_core::button::Button<'static, arty_e21_chip::gpio::GpioPin<'static>>,
60    // ipc: kernel::ipc::IPC<NUM_PROCS>,
61    scheduler: &'static PrioritySched,
62}
63
64/// Mapping of integer syscalls to objects that implement syscalls.
65impl SyscallDriverLookup for ArtyE21 {
66    fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
67    where
68        F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
69    {
70        match driver_num {
71            capsules_core::console::DRIVER_NUM => f(Some(self.console)),
72            capsules_core::gpio::DRIVER_NUM => f(Some(self.gpio)),
73
74            capsules_core::alarm::DRIVER_NUM => f(Some(self.alarm)),
75            capsules_core::led::DRIVER_NUM => f(Some(self.led)),
76            capsules_core::button::DRIVER_NUM => f(Some(self.button)),
77
78            // kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)),
79            _ => f(None),
80        }
81    }
82}
83
84impl KernelResources<arty_e21_chip::chip::ArtyExx<'static, ArtyExxDefaultPeripherals<'static>>>
85    for ArtyE21
86{
87    type SyscallDriverLookup = Self;
88    type SyscallFilter = ();
89    type ProcessFault = ();
90    type Scheduler = PrioritySched;
91    type SchedulerTimer = ();
92    type WatchDog = ();
93    type ContextSwitchCallback = ();
94
95    fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
96        self
97    }
98    fn syscall_filter(&self) -> &Self::SyscallFilter {
99        &()
100    }
101    fn process_fault(&self) -> &Self::ProcessFault {
102        &()
103    }
104    fn scheduler(&self) -> &Self::Scheduler {
105        self.scheduler
106    }
107    fn scheduler_timer(&self) -> &Self::SchedulerTimer {
108        &()
109    }
110    fn watchdog(&self) -> &Self::WatchDog {
111        &()
112    }
113    fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
114        &()
115    }
116}
117
118/// This is in a separate, inline(never) function so that its stack frame is
119/// removed when this function returns. Otherwise, the stack space used for
120/// these static_inits is wasted.
121#[inline(never)]
122unsafe fn start() -> (
123    &'static kernel::Kernel,
124    ArtyE21,
125    &'static arty_e21_chip::chip::ArtyExx<'static, ArtyExxDefaultPeripherals<'static>>,
126) {
127    let peripherals = static_init!(ArtyExxDefaultPeripherals, ArtyExxDefaultPeripherals::new());
128    peripherals.init();
129
130    let chip = static_init!(
131        arty_e21_chip::chip::ArtyExx<ArtyExxDefaultPeripherals>,
132        arty_e21_chip::chip::ArtyExx::new(&peripherals.machinetimer, peripherals)
133    );
134    CHIP = Some(chip);
135    chip.initialize();
136
137    let process_mgmt_cap = create_capability!(capabilities::ProcessManagementCapability);
138
139    // Create an array to hold process references.
140    let processes = components::process_array::ProcessArrayComponent::new()
141        .finalize(components::process_array_component_static!(NUM_PROCS));
142    PROCESSES = Some(processes);
143
144    let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(processes.as_slice()));
145
146    // Configure kernel debug gpios as early as possible
147    kernel::debug::assign_gpios(
148        Some(&peripherals.gpio_port[0]), // Blue
149        Some(&peripherals.gpio_port[1]), // Green
150        Some(&peripherals.gpio_port[8]),
151    );
152
153    let process_printer = components::process_printer::ProcessPrinterTextComponent::new()
154        .finalize(components::process_printer_text_component_static!());
155    PROCESS_PRINTER = Some(process_printer);
156
157    // Create a shared UART channel for the console and for kernel debug.
158    let uart_mux = components::console::UartMuxComponent::new(&peripherals.uart0, 115200)
159        .finalize(components::uart_mux_component_static!());
160
161    let console = components::console::ConsoleComponent::new(
162        board_kernel,
163        capsules_core::console::DRIVER_NUM,
164        uart_mux,
165    )
166    .finalize(components::console_component_static!());
167
168    // Create a shared virtualization mux layer on top of a single hardware
169    // alarm.
170    let mux_alarm = static_init!(
171        MuxAlarm<'static, arty_e21_chip::chip::ArtyExxClint>,
172        MuxAlarm::new(&peripherals.machinetimer)
173    );
174    hil::time::Alarm::set_alarm_client(&peripherals.machinetimer, mux_alarm);
175
176    // Alarm
177    let alarm = components::alarm::AlarmDriverComponent::new(
178        board_kernel,
179        capsules_core::alarm::DRIVER_NUM,
180        mux_alarm,
181    )
182    .finalize(components::alarm_component_static!(
183        arty_e21_chip::chip::ArtyExxClint
184    ));
185
186    // TEST for timer
187    //
188    // let virtual_alarm_test = static_init!(
189    //     VirtualMuxAlarm<'static, arty_e21_chip::chip::ArtyExxClint>,
190    //     VirtualMuxAlarm::new(mux_alarm)
191    // );
192    // let timertest = static_init!(
193    //     timer_test::TimerTest<'static, VirtualMuxAlarm<'static, arty_e21_chip::chip::ArtyExxClint>>,
194    //     timer_test::TimerTest::new(virtual_alarm_test)
195    // );
196    // virtual_alarm_test.set_client(timertest);
197
198    // LEDs
199    let led = components::led::LedsComponent::new().finalize(components::led_component_static!(
200        hil::led::LedHigh<'static, arty_e21_chip::gpio::GpioPin>,
201        hil::led::LedHigh::new(&peripherals.gpio_port[2]), // Red
202        hil::led::LedHigh::new(&peripherals.gpio_port[1]), // Green
203        hil::led::LedHigh::new(&peripherals.gpio_port[0]), // Blue
204    ));
205
206    // BUTTONs
207    let button = components::button::ButtonComponent::new(
208        board_kernel,
209        capsules_core::button::DRIVER_NUM,
210        components::button_component_helper!(
211            arty_e21_chip::gpio::GpioPin,
212            (
213                &peripherals.gpio_port[4],
214                kernel::hil::gpio::ActivationMode::ActiveHigh,
215                kernel::hil::gpio::FloatingState::PullNone
216            )
217        ),
218    )
219    .finalize(components::button_component_static!(
220        arty_e21_chip::gpio::GpioPin
221    ));
222
223    // set GPIO driver controlling remaining GPIO pins
224    let gpio = components::gpio::GpioComponent::new(
225        board_kernel,
226        capsules_core::gpio::DRIVER_NUM,
227        components::gpio_component_helper!(
228            arty_e21_chip::gpio::GpioPin,
229            0 => &peripherals.gpio_port[7],
230            1 => &peripherals.gpio_port[5],
231            2 => &peripherals.gpio_port[6]
232        ),
233    )
234    .finalize(components::gpio_component_static!(
235        arty_e21_chip::gpio::GpioPin
236    ));
237
238    chip.enable_all_interrupts();
239
240    let scheduler = components::sched::priority::PriorityComponent::new(board_kernel)
241        .finalize(components::priority_component_static!());
242
243    let artye21 = ArtyE21 {
244        console,
245        gpio,
246        alarm,
247        led,
248        button,
249        // ipc: kernel::ipc::IPC::new(board_kernel),
250        scheduler,
251    };
252
253    // Create virtual device for kernel debug.
254    components::debug_writer::DebugWriterComponent::new(
255        uart_mux,
256        create_capability!(capabilities::SetDebugWriterCapability),
257    )
258    .finalize(components::debug_writer_component_static!());
259
260    // arty_e21_chip::uart::UART0.initialize_gpio_pins(&peripherals.gpio_port[17], &peripherals.gpio_port[16]);
261
262    debug!("Initialization complete. Entering main loop.");
263
264    // Uncomment to run tests
265    //timertest.start();
266    /*components::test::multi_alarm_test::MultiAlarmTestComponent::new(mux_alarm)
267    .finalize(components::multi_alarm_test_component_buf!(arty_e21_chip::chip::ArtyExxClint))
268    .run();*/
269
270    // These symbols are defined in the linker script.
271    extern "C" {
272        /// Beginning of the ROM region containing app images.
273        static _sapps: u8;
274        /// End of the ROM region containing app images.
275        static _eapps: u8;
276        /// Beginning of the RAM region for app memory.
277        static mut _sappmem: u8;
278        /// End of the RAM region for app memory.
279        static _eappmem: u8;
280    }
281
282    kernel::process::load_processes(
283        board_kernel,
284        chip,
285        core::slice::from_raw_parts(
286            core::ptr::addr_of!(_sapps),
287            core::ptr::addr_of!(_eapps) as usize - core::ptr::addr_of!(_sapps) as usize,
288        ),
289        core::slice::from_raw_parts_mut(
290            core::ptr::addr_of_mut!(_sappmem),
291            core::ptr::addr_of!(_eappmem) as usize - core::ptr::addr_of!(_sappmem) as usize,
292        ),
293        &FAULT_RESPONSE,
294        &process_mgmt_cap,
295    )
296    .unwrap_or_else(|err| {
297        debug!("Error loading processes!");
298        debug!("{:?}", err);
299    });
300
301    (board_kernel, artye21, chip)
302}
303
304/// Main function called after RAM initialized.
305#[no_mangle]
306pub unsafe fn main() {
307    let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
308
309    let (board_kernel, board, chip) = start();
310    board_kernel.kernel_loop(
311        &board,
312        chip,
313        None::<&kernel::ipc::IPC<0>>,
314        &main_loop_capability,
315    );
316}