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