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