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 core::ptr::{addr_of, addr_of_mut};
11
12use arty_e21_chip::chip::ArtyExxDefaultPeripherals;
13use capsules_core::virtualizers::virtual_alarm::{MuxAlarm, VirtualMuxAlarm};
14
15use kernel::capabilities;
16use kernel::component::Component;
17use kernel::hil;
18use kernel::platform::{KernelResources, SyscallDriverLookup};
19use kernel::scheduler::priority::PrioritySched;
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
32// How should the kernel respond when a process faults.
33const FAULT_RESPONSE: capsules_system::process_policies::PanicFaultPolicy =
34    capsules_system::process_policies::PanicFaultPolicy {};
35
36// Actual memory for holding the active process structures.
37static mut PROCESSES: [Option<&'static dyn kernel::process::Process>; NUM_PROCS] =
38    [None, None, None, None];
39
40// Reference to the chip for panic dumps.
41static mut CHIP: Option<&'static arty_e21_chip::chip::ArtyExx<ArtyExxDefaultPeripherals>> = None;
42static mut PROCESS_PRINTER: Option<&'static capsules_system::process_printer::ProcessPrinterText> =
43    None;
44
45/// Dummy buffer that causes the linker to reserve enough space for the stack.
46#[no_mangle]
47#[link_section = ".stack_buffer"]
48pub static mut STACK_MEMORY: [u8; 0x1000] = [0; 0x1000];
49
50/// A structure representing this platform that holds references to all
51/// capsules for this platform.
52struct ArtyE21 {
53    console: &'static capsules_core::console::Console<'static>,
54    gpio: &'static capsules_core::gpio::GPIO<'static, arty_e21_chip::gpio::GpioPin<'static>>,
55    alarm: &'static capsules_core::alarm::AlarmDriver<
56        'static,
57        VirtualMuxAlarm<'static, arty_e21_chip::chip::ArtyExxClint<'static>>,
58    >,
59    led: &'static capsules_core::led::LedDriver<
60        'static,
61        hil::led::LedHigh<'static, arty_e21_chip::gpio::GpioPin<'static>>,
62        3,
63    >,
64    button: &'static capsules_core::button::Button<'static, arty_e21_chip::gpio::GpioPin<'static>>,
65    // ipc: kernel::ipc::IPC<NUM_PROCS>,
66    scheduler: &'static PrioritySched,
67}
68
69/// Mapping of integer syscalls to objects that implement syscalls.
70impl SyscallDriverLookup for ArtyE21 {
71    fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
72    where
73        F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
74    {
75        match driver_num {
76            capsules_core::console::DRIVER_NUM => f(Some(self.console)),
77            capsules_core::gpio::DRIVER_NUM => f(Some(self.gpio)),
78
79            capsules_core::alarm::DRIVER_NUM => f(Some(self.alarm)),
80            capsules_core::led::DRIVER_NUM => f(Some(self.led)),
81            capsules_core::button::DRIVER_NUM => f(Some(self.button)),
82
83            // kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)),
84            _ => f(None),
85        }
86    }
87}
88
89impl KernelResources<arty_e21_chip::chip::ArtyExx<'static, ArtyExxDefaultPeripherals<'static>>>
90    for ArtyE21
91{
92    type SyscallDriverLookup = Self;
93    type SyscallFilter = ();
94    type ProcessFault = ();
95    type Scheduler = PrioritySched;
96    type SchedulerTimer = ();
97    type WatchDog = ();
98    type ContextSwitchCallback = ();
99
100    fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
101        self
102    }
103    fn syscall_filter(&self) -> &Self::SyscallFilter {
104        &()
105    }
106    fn process_fault(&self) -> &Self::ProcessFault {
107        &()
108    }
109    fn scheduler(&self) -> &Self::Scheduler {
110        self.scheduler
111    }
112    fn scheduler_timer(&self) -> &Self::SchedulerTimer {
113        &()
114    }
115    fn watchdog(&self) -> &Self::WatchDog {
116        &()
117    }
118    fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
119        &()
120    }
121}
122
123/// This is in a separate, inline(never) function so that its stack frame is
124/// removed when this function returns. Otherwise, the stack space used for
125/// these static_inits is wasted.
126#[inline(never)]
127unsafe fn start() -> (
128    &'static kernel::Kernel,
129    ArtyE21,
130    &'static arty_e21_chip::chip::ArtyExx<'static, ArtyExxDefaultPeripherals<'static>>,
131) {
132    let peripherals = static_init!(ArtyExxDefaultPeripherals, ArtyExxDefaultPeripherals::new());
133    peripherals.init();
134
135    let chip = static_init!(
136        arty_e21_chip::chip::ArtyExx<ArtyExxDefaultPeripherals>,
137        arty_e21_chip::chip::ArtyExx::new(&peripherals.machinetimer, peripherals)
138    );
139    CHIP = Some(chip);
140    chip.initialize();
141
142    let process_mgmt_cap = create_capability!(capabilities::ProcessManagementCapability);
143
144    let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(&*addr_of!(PROCESSES)));
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        &mut *addr_of_mut!(PROCESSES),
294        &FAULT_RESPONSE,
295        &process_mgmt_cap,
296    )
297    .unwrap_or_else(|err| {
298        debug!("Error loading processes!");
299        debug!("{:?}", err);
300    });
301
302    (board_kernel, artye21, chip)
303}
304
305/// Main function called after RAM initialized.
306#[no_mangle]
307pub unsafe fn main() {
308    let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
309
310    let (board_kernel, board, chip) = start();
311    board_kernel.kernel_loop(
312        &board,
313        chip,
314        None::<&kernel::ipc::IPC<0>>,
315        &main_loop_capability,
316    );
317}