Rework basically the whole sw/matcha tree.

Change-Id: I2f72d4799a5aa14f6eef1a534b91e4cc13e3ccae
diff --git a/platform/src/chip.rs b/platform/src/chip.rs
new file mode 100644
index 0000000..b063c46
--- /dev/null
+++ b/platform/src/chip.rs
@@ -0,0 +1,287 @@
+//! High-level setup and interrupt mapping for the chip.
+
+use core::fmt::Write;
+use core::hint::unreachable_unchecked;
+use kernel;
+use kernel::debug;
+use kernel::hil::time::Alarm;
+use rv32i::csr::{mcause, mie::mie, mip::mip, mtvec::mtvec, CSR};
+use rv32i::syscall::SysCall;
+use rv32i::PMPConfigMacro;
+
+use crate::timer;
+use crate::uart;
+use matcha_hal::plic;
+
+PMPConfigMacro!(4);
+
+pub const CHIP_NAME: &str = "sim_verilator";
+pub const CHIP_CPU_FREQ: u32 = 500_000;
+pub const CHIP_PERIPH_FREQ: u32 = 125_000;
+pub const CHIP_UART_BPS: u32 = 9600;
+
+pub const UART0_TX_WATERMARK: u32 = 1;
+pub const UART0_RX_PARITY_ERR: u32 = 8;
+
+pub struct Matcha<A: 'static + Alarm<'static>> {
+    userspace_kernel_boundary: SysCall,
+    pmp: PMP,
+    scheduler_timer: kernel::VirtualSchedulerTimer<A>,
+}
+
+impl<A: 'static + Alarm<'static>> Matcha<A> {
+    pub unsafe fn new(alarm: &'static A) -> Self {
+        Self {
+            userspace_kernel_boundary: SysCall::new(),
+            pmp: PMP::new(),
+            scheduler_timer: kernel::VirtualSchedulerTimer::new(alarm),
+        }
+    }
+
+    pub unsafe fn enable_plic_interrupts(&self) {
+        plic::disable_all();
+        plic::clear_all_pending();
+        plic::enable_all();
+    }
+
+    unsafe fn handle_plic_interrupts(&self) {
+        while let Some(interrupt) = plic::next_pending() {
+            match interrupt {
+                UART0_TX_WATERMARK..=UART0_RX_PARITY_ERR => uart::UART0.handle_interrupt(),
+                _ => debug!("Pidx {}", interrupt),
+            }
+            plic::complete(interrupt);
+        }
+    }
+}
+
+impl<A: 'static + Alarm<'static>> kernel::Chip for Matcha<A> {
+    type MPU = PMP;
+    type UserspaceKernelBoundary = SysCall;
+    type SchedulerTimer = kernel::VirtualSchedulerTimer<A>;
+    type WatchDog = ();
+
+    fn mpu(&self) -> &Self::MPU {
+        &self.pmp
+    }
+
+    fn scheduler_timer(&self) -> &Self::SchedulerTimer {
+        &self.scheduler_timer
+    }
+
+    fn watchdog(&self) -> &Self::WatchDog {
+        &()
+    }
+
+    fn userspace_kernel_boundary(&self) -> &SysCall {
+        &self.userspace_kernel_boundary
+    }
+
+    fn service_pending_interrupts(&self) {
+        loop {
+            let mip = CSR.mip.extract();
+
+            if mip.is_set(mip::mtimer) {
+                unsafe {
+                    timer::TIMER.service_interrupt();
+                }
+            }
+            if mip.is_set(mip::mext) {
+                unsafe {
+                    self.handle_plic_interrupts();
+                }
+            }
+
+            if !mip.matches_any(mip::mext::SET + mip::mtimer::SET) {
+                break;
+            }
+        }
+
+        // Re-enable all MIE interrupts that we care about. Since we looped
+        // until we handled them all, we can re-enable all of them.
+        CSR.mie.modify(mie::mext::SET + mie::mtimer::SET);
+    }
+
+    fn has_pending_interrupts(&self) -> bool {
+        let mip = CSR.mip.extract();
+        mip.matches_any(mip::mext::SET + mip::mtimer::SET)
+    }
+
+    fn sleep(&self) {
+        unsafe {
+            //pwrmgr::PWRMGR.enable_low_power();
+            //self.check_until_true_or_interrupt(|| pwrmgr::PWRMGR.check_clock_propagation(), None);
+            rv32i::support::wfi();
+        }
+    }
+
+    unsafe fn atomic<F, R>(&self, f: F) -> R
+    where
+        F: FnOnce() -> R,
+    {
+        rv32i::support::atomic(f)
+    }
+
+    unsafe fn print_state(&self, writer: &mut dyn Write) {
+        let _ = writer.write_fmt(format_args!(
+            "\r\n---| Matcha configuration for {} |---",
+            crate::chip::CHIP_NAME
+        ));
+        rv32i::print_riscv_state(writer);
+    }
+}
+
+fn handle_exception(exception: mcause::Exception) {
+    match exception {
+        mcause::Exception::UserEnvCall | mcause::Exception::SupervisorEnvCall => (),
+
+        mcause::Exception::InstructionMisaligned
+        | mcause::Exception::InstructionFault
+        | mcause::Exception::IllegalInstruction
+        | mcause::Exception::Breakpoint
+        | mcause::Exception::LoadMisaligned
+        | mcause::Exception::LoadFault
+        | mcause::Exception::StoreMisaligned
+        | mcause::Exception::StoreFault
+        | mcause::Exception::MachineEnvCall
+        | mcause::Exception::InstructionPageFault
+        | mcause::Exception::LoadPageFault
+        | mcause::Exception::StorePageFault
+        | mcause::Exception::Unknown => {
+            panic!("fatal exception");
+        }
+    }
+}
+
+unsafe fn handle_interrupt(intr: mcause::Interrupt) {
+    match intr {
+        mcause::Interrupt::UserSoft
+        | mcause::Interrupt::UserTimer
+        | mcause::Interrupt::UserExternal => {
+            panic!("unexpected user-mode interrupt");
+        }
+        mcause::Interrupt::SupervisorExternal
+        | mcause::Interrupt::SupervisorTimer
+        | mcause::Interrupt::SupervisorSoft => {
+            panic!("unexpected supervisor-mode interrupt");
+        }
+
+        mcause::Interrupt::MachineSoft => {
+            CSR.mie.modify(mie::msoft::CLEAR);
+        }
+        mcause::Interrupt::MachineTimer => {
+            CSR.mie.modify(mie::mtimer::CLEAR);
+        }
+        mcause::Interrupt::MachineExternal => {
+            CSR.mie.modify(mie::mext::CLEAR);
+        }
+
+        mcause::Interrupt::Unknown => {
+            panic!("interrupt of unknown cause");
+        }
+    }
+}
+
+/// Trap handler for board/chip specific code.
+///
+/// For the Ibex this gets called when an interrupt occurs while the chip is
+/// in kernel mode. All we need to do is check which interrupt occurred and
+/// disable it.
+#[export_name = "_start_trap_rust"]
+pub unsafe extern "C" fn start_trap_rust() {
+    match mcause::Trap::from(CSR.mcause.extract()) {
+        mcause::Trap::Interrupt(interrupt) => {
+            handle_interrupt(interrupt);
+        }
+        mcause::Trap::Exception(exception) => {
+            handle_exception(exception);
+        }
+    }
+}
+
+/// Function that gets called if an interrupt occurs while an app was running.
+/// mcause is passed in, and this function should correctly handle disabling the
+/// interrupt that fired so that it does not trigger again.
+#[export_name = "_disable_interrupt_trap_handler"]
+pub unsafe extern "C" fn disable_interrupt_trap_handler(mcause_val: u32) {
+    match mcause::Trap::from(mcause_val) {
+        mcause::Trap::Interrupt(interrupt) => {
+            handle_interrupt(interrupt);
+        }
+        _ => {
+            panic!("unexpected non-interrupt\n");
+        }
+    }
+}
+
+pub unsafe fn configure_trap_handler() {
+    // The Ibex CPU does not support non-vectored trap entries.
+    CSR.mtvec
+        .write(mtvec::trap_addr.val(_start_trap_vectored as u32 >> 2) + mtvec::mode::Vectored)
+}
+
+// Mock implementation for crate tests that does not include the section
+// specifier, as the test will not use our linker script, and the host
+// compilation environment may not allow the section name.
+#[cfg(not(any(target_arch = "riscv32", target_os = "none")))]
+pub extern "C" fn _start_trap_vectored() {
+    unsafe {
+        unreachable_unchecked();
+    }
+}
+
+#[cfg(all(target_arch = "riscv32", target_os = "none"))]
+#[link_section = ".riscv.trap_vectored"]
+#[export_name = "_start_trap_vectored"]
+#[naked]
+pub extern "C" fn _start_trap_vectored() -> ! {
+    unsafe {
+        // According to the Ibex user manual:
+        // [NMI] has interrupt ID 31, i.e., it has the highest priority of all
+        // interrupts and the core jumps to the trap-handler base address (in
+        // mtvec) plus 0x7C to handle the NMI.
+        //
+        // Below are 32 (non-compressed) jumps to cover the entire possible
+        // range of vectored traps.
+        #[cfg(all(target_arch = "riscv32", target_os = "none"))]
+        llvm_asm!("
+            j _start_trap
+            j _start_trap
+            j _start_trap
+            j _start_trap
+            j _start_trap
+            j _start_trap
+            j _start_trap
+            j _start_trap
+            j _start_trap
+            j _start_trap
+            j _start_trap
+            j _start_trap
+            j _start_trap
+            j _start_trap
+            j _start_trap
+            j _start_trap
+            j _start_trap
+            j _start_trap
+            j _start_trap
+            j _start_trap
+            j _start_trap
+            j _start_trap
+            j _start_trap
+            j _start_trap
+            j _start_trap
+            j _start_trap
+            j _start_trap
+            j _start_trap
+            j _start_trap
+            j _start_trap
+            j _start_trap
+            j _start_trap
+        "
+        :
+        :
+        :
+        : "volatile");
+        unreachable_unchecked()
+    }
+}