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