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
31type ChipHw = arty_e21_chip::chip::ArtyExx<'static, ArtyExxDefaultPeripherals<'static>>;
32
33// How should the kernel respond when a process faults.
34const FAULT_RESPONSE: capsules_system::process_policies::PanicFaultPolicy =
35    capsules_system::process_policies::PanicFaultPolicy {};
36
37/// Static variables used by io.rs.
38static mut PROCESSES: Option<&'static ProcessArray<NUM_PROCS>> = 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
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    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    // Create an array to hold process references.
147    let processes = components::process_array::ProcessArrayComponent::new()
148        .finalize(components::process_array_component_static!(NUM_PROCS));
149    PROCESSES = Some(processes);
150
151    let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(processes.as_slice()));
152
153    // Configure kernel debug gpios as early as possible
154    let debug_gpios = static_init!(
155        [&'static dyn kernel::hil::gpio::Pin; 3],
156        [
157            // Blue
158            &peripherals.gpio_port[0],
159            // Green
160            &peripherals.gpio_port[1],
161            &peripherals.gpio_port[8],
162        ]
163    );
164    kernel::debug::initialize_debug_gpio::<
165        <ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider,
166    >();
167    kernel::debug::assign_gpios(debug_gpios);
168
169    let process_printer = components::process_printer::ProcessPrinterTextComponent::new()
170        .finalize(components::process_printer_text_component_static!());
171    PROCESS_PRINTER = Some(process_printer);
172
173    // Create a shared UART channel for the console and for kernel debug.
174    let uart_mux = components::console::UartMuxComponent::new(&peripherals.uart0, 115200)
175        .finalize(components::uart_mux_component_static!());
176
177    let console = components::console::ConsoleComponent::new(
178        board_kernel,
179        capsules_core::console::DRIVER_NUM,
180        uart_mux,
181    )
182    .finalize(components::console_component_static!());
183
184    // Create a shared virtualization mux layer on top of a single hardware
185    // alarm.
186    let mux_alarm = static_init!(
187        MuxAlarm<'static, arty_e21_chip::chip::ArtyExxClint>,
188        MuxAlarm::new(&peripherals.machinetimer)
189    );
190    hil::time::Alarm::set_alarm_client(&peripherals.machinetimer, mux_alarm);
191
192    // Alarm
193    let alarm = components::alarm::AlarmDriverComponent::new(
194        board_kernel,
195        capsules_core::alarm::DRIVER_NUM,
196        mux_alarm,
197    )
198    .finalize(components::alarm_component_static!(
199        arty_e21_chip::chip::ArtyExxClint
200    ));
201
202    // TEST for timer
203    //
204    // let virtual_alarm_test = static_init!(
205    //     VirtualMuxAlarm<'static, arty_e21_chip::chip::ArtyExxClint>,
206    //     VirtualMuxAlarm::new(mux_alarm)
207    // );
208    // let timertest = static_init!(
209    //     timer_test::TimerTest<'static, VirtualMuxAlarm<'static, arty_e21_chip::chip::ArtyExxClint>>,
210    //     timer_test::TimerTest::new(virtual_alarm_test)
211    // );
212    // virtual_alarm_test.set_client(timertest);
213
214    // LEDs
215    let led = components::led::LedsComponent::new().finalize(components::led_component_static!(
216        hil::led::LedHigh<'static, arty_e21_chip::gpio::GpioPin>,
217        hil::led::LedHigh::new(&peripherals.gpio_port[2]), // Red
218        hil::led::LedHigh::new(&peripherals.gpio_port[1]), // Green
219        hil::led::LedHigh::new(&peripherals.gpio_port[0]), // Blue
220    ));
221
222    // BUTTONs
223    let button = components::button::ButtonComponent::new(
224        board_kernel,
225        capsules_core::button::DRIVER_NUM,
226        components::button_component_helper!(
227            arty_e21_chip::gpio::GpioPin,
228            (
229                &peripherals.gpio_port[4],
230                kernel::hil::gpio::ActivationMode::ActiveHigh,
231                kernel::hil::gpio::FloatingState::PullNone
232            )
233        ),
234    )
235    .finalize(components::button_component_static!(
236        arty_e21_chip::gpio::GpioPin
237    ));
238
239    // set GPIO driver controlling remaining GPIO pins
240    let gpio = components::gpio::GpioComponent::new(
241        board_kernel,
242        capsules_core::gpio::DRIVER_NUM,
243        components::gpio_component_helper!(
244            arty_e21_chip::gpio::GpioPin,
245            0 => &peripherals.gpio_port[7],
246            1 => &peripherals.gpio_port[5],
247            2 => &peripherals.gpio_port[6]
248        ),
249    )
250    .finalize(components::gpio_component_static!(
251        arty_e21_chip::gpio::GpioPin
252    ));
253
254    chip.enable_all_interrupts();
255
256    let scheduler = components::sched::priority::PriorityComponent::new(board_kernel)
257        .finalize(components::priority_component_static!());
258
259    let artye21 = ArtyE21 {
260        console,
261        gpio,
262        alarm,
263        led,
264        button,
265        // ipc: kernel::ipc::IPC::new(board_kernel),
266        scheduler,
267    };
268
269    // Create virtual device for kernel debug.
270    components::debug_writer::DebugWriterComponent::new::<
271        <ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider,
272    >(
273        uart_mux,
274        create_capability!(capabilities::SetDebugWriterCapability),
275    )
276    .finalize(components::debug_writer_component_static!());
277
278    // arty_e21_chip::uart::UART0.initialize_gpio_pins(&peripherals.gpio_port[17], &peripherals.gpio_port[16]);
279
280    debug!("Initialization complete. Entering main loop.");
281
282    // Uncomment to run tests
283    //timertest.start();
284    /*components::test::multi_alarm_test::MultiAlarmTestComponent::new(mux_alarm)
285    .finalize(components::multi_alarm_test_component_buf!(arty_e21_chip::chip::ArtyExxClint))
286    .run();*/
287
288    // These symbols are defined in the linker script.
289    extern "C" {
290        /// Beginning of the ROM region containing app images.
291        static _sapps: u8;
292        /// End of the ROM region containing app images.
293        static _eapps: u8;
294        /// Beginning of the RAM region for app memory.
295        static mut _sappmem: u8;
296        /// End of the RAM region for app memory.
297        static _eappmem: u8;
298    }
299
300    kernel::process::load_processes(
301        board_kernel,
302        chip,
303        core::slice::from_raw_parts(
304            core::ptr::addr_of!(_sapps),
305            core::ptr::addr_of!(_eapps) as usize - core::ptr::addr_of!(_sapps) as usize,
306        ),
307        core::slice::from_raw_parts_mut(
308            core::ptr::addr_of_mut!(_sappmem),
309            core::ptr::addr_of!(_eappmem) as usize - core::ptr::addr_of!(_sappmem) as usize,
310        ),
311        &FAULT_RESPONSE,
312        &process_mgmt_cap,
313    )
314    .unwrap_or_else(|err| {
315        debug!("Error loading processes!");
316        debug!("{:?}", err);
317    });
318
319    (board_kernel, artye21, chip)
320}
321
322/// Main function called after RAM initialized.
323#[no_mangle]
324pub unsafe fn main() {
325    let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
326
327    let (board_kernel, board, chip) = start();
328    board_kernel.kernel_loop(
329        &board,
330        chip,
331        None::<&kernel::ipc::IPC<0>>,
332        &main_loop_capability,
333    );
334}