[sw, tock] Added timer demo

Adds a simple timer demo that displays a binary counter on the FPGA LEDs
connected to GPIO pins 7-15 and prints "opentitan" in ASCII art over the
UART.

Signed-off-by: Jon Flatley <jflat@google.com>
diff --git a/sw/device/tock/boards/opentitan/src/counter_demo.rs b/sw/device/tock/boards/opentitan/src/counter_demo.rs
new file mode 100644
index 0000000..6f7a5e0
--- /dev/null
+++ b/sw/device/tock/boards/opentitan/src/counter_demo.rs
@@ -0,0 +1,88 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+//! A simple alarm implementation to display a binary counter over GPIO.
+
+use core::cell::Cell;
+use kernel::hil::time::{Alarm, AlarmClient, Frequency};
+use kernel::debug;
+
+pub struct CounterAlarm<'a, A: Alarm<'a>> {
+    alarm: &'a A,
+    /// The current count of the counter
+    count: Cell<u32>,
+    /// How frequently, in ms, to increment the counter
+    interval: Cell<u32>,
+    /// The pins to toggle in order
+    count_pins: &'a [usize],
+    /// Optional text to display over the UART
+    spash_text: &'a [&'a str],
+    /// A counter for lines of the optional text sent
+    spash_count: Cell<u32>,
+}
+
+fn ms_to_tick<'a, A: Alarm<'a>>(ms: u32) -> u32 {
+    let freq = <A::Frequency>::frequency() as u64;
+    let tick = freq * (ms as u64);
+
+    (tick / 1000) as u32
+}
+
+impl<'a, A: Alarm<'a>> CounterAlarm<'a, A> {
+    pub fn new(alarm: &'a A, pins: &'a [usize]) -> CounterAlarm<'a, A> {
+        CounterAlarm {
+            alarm: alarm,
+            count: Cell::new(0),
+            interval: Cell::new(0),
+            count_pins: pins,
+            spash_text: &[],
+            spash_count: Cell::new(0),
+        }
+    }
+
+    pub fn add_spash_text(&mut self, spash: &'a[&'a str]) {
+        self.spash_text = spash;
+    }
+
+    pub fn run(&self, interval_ms: u32) {
+        self.interval.set(ms_to_tick::<A>(interval_ms));
+        let next_trigger = self.alarm.now().wrapping_add(self.interval.get());
+        self.alarm.set_alarm(next_trigger);
+    }
+}
+
+impl<'a, A: Alarm<'a>> AlarmClient for CounterAlarm<'a, A> {
+    fn fired(&self) {
+        let mut count = self.count.get();
+
+        // Toggle GPIO pins for each bit in count
+        for pin in self.count_pins {
+            unsafe {
+                if count & 1 != 0 {
+                    kernel::hil::gpio::Pin::set(&ibex::gpio::PORT[*pin])
+                } else {
+                    kernel::hil::gpio::Pin::clear(&ibex::gpio::PORT[*pin])
+                }
+            }
+            count >>= 1;
+        }
+
+        // Hijack this timer to display optional text
+        if self.spash_count.get() < self.spash_text.len() as u32 {
+            debug!("{}", self.spash_text[self.spash_count.get() as usize]);
+            self.spash_count.set(self.spash_count.get() + 1);
+        }
+
+        // Reset the counter if there were any overflow bits
+        if count > 0 {
+            self.count.set(1);
+        } else {
+            self.count.set(self.count.get() + 1);
+        }
+
+        let next_trigger = self.alarm.now().wrapping_add(self.interval.get());
+
+        self.alarm.set_alarm(next_trigger);
+    }
+}
diff --git a/sw/device/tock/boards/opentitan/src/main.rs b/sw/device/tock/boards/opentitan/src/main.rs
index 2d31af1..a96a015 100644
--- a/sw/device/tock/boards/opentitan/src/main.rs
+++ b/sw/device/tock/boards/opentitan/src/main.rs
@@ -15,6 +15,8 @@
 use kernel::{create_capability, debug, static_init};
 use rv32i::csr;
 
+mod counter_demo;
+
 pub mod io;
 //
 // Actual memory for holding the active process structures. Need an empty list
@@ -42,6 +44,28 @@
 #[link_section = ".stack_buffer"]
 pub static mut STACK_MEMORY: [u8; 0x1000] = [0; 0x1000];
 
+static OT_SPASH: &[&str] = &[
+    "######################################################################################################################################################",
+    "######################################################################################################################################################",
+    "######################################################################################################################################################",
+    "############```*###*```###############################################################################################################################",
+    "############```*###*```###############################################################################``*#############################################",
+    "########````````*#*```````*#################################################################*```######``*####```######################################",
+    "########````****##*****```*#################################################################*```############*```*########*################**##########",
+    "#####```````###########```````#########*``******####```****``*#####**```*`*###*```*#**`*##*````````##*```##````````*##*``````````###``````````*#######",
+    "#####***````##```````##````***########`*#######**###``#######`*###`#######``##*`*######`*###*```#####*```###*```*####*```####*```###```**##*```#######",
+    "##############```````#################`########*`####*#######*`##*`*********##*`#######``###*```#####*```####```*#####``######```###```*####```#######",
+    "#####***````##```````##*```***########`*#######*`###`*#######*`##*`###########*`#######``####```#####*```####```*####*``*####*```###```*####```#######",
+    "#####```````##*******##```````#########***###*`*####```*###*``####*`*####*`###*`#######`*####``````*##```####*``````##*``````````###```#####```#######",
+    "#######*````****###****````#*#############***#######`*##***##########***#######################****#############***######***##########################",
+    "########*```````*#*```````*#########################`*################################################################################################",
+    "############```*###*```###############################################################################################################################",
+    "############```*###*```###############################################################################################################################",
+    "######################################################################################################################################################",
+    "######################################################################################################################################################",
+    "######################################################################################################################################################",
+];
+
 /// A structure representing this platform that holds references to all
 /// capsules for this platform. We've included an alarm and console.
 struct OpenTitan {
@@ -93,13 +117,6 @@
     );
     DynamicDeferredCall::set_global_instance(dynamic_deferred_caller);
 
-    // Configure kernel debug gpios as early as possible
-    kernel::debug::assign_gpios(
-        Some(&ibex::gpio::PORT[7]), // First LED
-        None,
-        None,
-    );
-
     let chip = static_init!(ibex::chip::Ibex, ibex::chip::Ibex::new());
     CHIP = Some(chip);
 
@@ -119,16 +136,6 @@
     )
     .finalize(());
 
-    // Initialise the three GPIOs which are useful for debugging.
-    hil::gpio::Pin::make_output(&ibex::gpio::PORT[8]);
-    hil::gpio::Pin::set(&ibex::gpio::PORT[8]);
-
-    hil::gpio::Pin::make_output(&ibex::gpio::PORT[9]);
-    hil::gpio::Pin::set(&ibex::gpio::PORT[9]);
-
-    hil::gpio::Pin::make_output(&ibex::gpio::PORT[10]);
-    hil::gpio::Pin::set(&ibex::gpio::PORT[10]);
-
     let alarm = &ibex::timer::TIMER;
     alarm.setup();
 
@@ -159,6 +166,26 @@
     // Create the debugger object that handles calls to `debug!()`.
     components::debug_writer::DebugWriterComponent::new(uart_mux).finalize(());
 
+    let counter_demo_mux = static_init!(
+        capsules::virtual_alarm::VirtualMuxAlarm<'static, ibex::timer::RvTimer>,
+        capsules::virtual_alarm::VirtualMuxAlarm::new(mux_alarm)
+    );
+
+    let pins = &[7, 8, 9, 10, 11, 12, 13, 14];
+    for pin in pins {
+        hil::gpio::Pin::make_output(&ibex::gpio::PORT[*pin]);
+    }
+
+    let counter_demo_inst = static_init!(
+        counter_demo::CounterAlarm<'static, capsules::virtual_alarm::VirtualMuxAlarm<ibex::timer::RvTimer>>,
+        counter_demo::CounterAlarm::new(counter_demo_mux, pins)
+    );
+    counter_demo_inst.add_spash_text(OT_SPASH);
+
+    hil::time::Alarm::set_client(counter_demo_mux, counter_demo_inst);
+
+    counter_demo_inst.run(500);
+
     debug!("OpenTitan initialisation complete. Entering main loop");
 
     extern "C" {
@@ -183,8 +210,5 @@
         &process_mgmt_cap,
     );
 
-    // Turn off the fourth GPIO so we know we got here
-    hil::gpio::Pin::clear(&ibex::gpio::PORT[10]);
-
     board_kernel.kernel_loop(&opentitan, chip, None, &main_loop_cap);
 }