summaryrefslogtreecommitdiff
path: root/bsp/env/freedom-e300-hifive1
diff options
context:
space:
mode:
authorMegan Wachs <megan@sifive.com>2016-11-30 10:55:18 -0800
committerGitHub <noreply@github.com>2016-11-30 10:55:18 -0800
commitae5f878d6acadabaa671a7a30b87e16eb1d718a7 (patch)
tree20749a4e80815136d2129486b25202427b9ea30b /bsp/env/freedom-e300-hifive1
parente12b0338d24597f12263322216fbe4e6c6b8e12a (diff)
Bump Everything to Match new Freedom Repo (#8)
* Bump tool versions * Use version of OpenOCD which can load programs into flash * Bump OpenOCD to Handle ISSI Flash Programming * Update Header files * add initial support for hifive1 * add dhrystone * add clock helper functions * add openocd cfg file * Demo_GPIO checkpoint -- compiles and runs but no blinky LEDs * Remove riscv-tests submodule * Remove FPGA files, as they are no longer relevant to this Repository * Add openocd_upload script * Add Pinmux Mappings Adding the pinmux mappings to the Platform Header * Add IOF Mappings to platform header * Re-order the IOF Mapping declarations * Add more useful things to platform headers * Get GPIO Demo working again (except interrupts aren't working) * Update README with more OS packages needed A bare ubuntu-16.04.1-server installation could not run `make tools` without these packages. * bump openocd to get SCKDIV fix * Remove duplicated help text for run_debug target * Add package to README that is needed for openocd build Without this package I was seeing two different failures like below when running `make tools`. /home/scottj/freedom-e-sdk/openocd/configure: line 4533: syntax error near unexpected token `0.23' /home/scottj/freedom-e-sdk/openocd/configure: line 4533: `PKG_PROG_PKG_CONFIG(0.23)' Makefile:70: recipe for target '/home/scottj/freedom-e-sdk/toolchain/bin/openocd' failed make: *** [/home/scottj/freedom-e-sdk/toolchain/bin/openocd] Error 2 ... or ... + autoconf configure.ac:12: error: possibly undefined macro: AC_MSG_WARN If this token and others are legitimate, please use m4_pattern_allow. See the Autoconf documentation. configure.ac:240: error: possibly undefined macro: AC_MSG_NOTICE configure.ac:342: error: possibly undefined macro: AC_DEFINE Makefile:70: recipe for target '/home/scottj/freedom-e-sdk/toolchain/bin/openocd' failed make: *** [/home/scottj/freedom-e-sdk/toolchain/bin/openocd] Error 1 * Bump OpenOCD to not overwrite SCKDIV when flashing * Roll back CoreMark
Diffstat (limited to 'bsp/env/freedom-e300-hifive1')
-rw-r--r--bsp/env/freedom-e300-hifive1/entry.S81
-rw-r--r--bsp/env/freedom-e300-hifive1/init.c187
-rw-r--r--bsp/env/freedom-e300-hifive1/link.lds163
-rw-r--r--bsp/env/freedom-e300-hifive1/openocd.cfg21
-rw-r--r--bsp/env/freedom-e300-hifive1/platform.h129
5 files changed, 581 insertions, 0 deletions
diff --git a/bsp/env/freedom-e300-hifive1/entry.S b/bsp/env/freedom-e300-hifive1/entry.S
new file mode 100644
index 0000000..c8ec662
--- /dev/null
+++ b/bsp/env/freedom-e300-hifive1/entry.S
@@ -0,0 +1,81 @@
+/*-
+ * Copyright (c) 2013-2015 Marko Zec, University of Zagreb
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+/*
+ * Copy data, clear BSS, set small data index register and jump into main().
+ *
+ * Assumes that the loader has already properly:
+ * 1) set stack pointer
+ * 2) set return address
+ * 3) invalidated caches
+ */
+
+ .section .init
+ .globl _start
+ .type _start,@function
+
+_start:
+ la gp, _gp
+ la sp, _sp
+
+ /* Load data sections */
+ la s0, _data
+ la s1, _edata
+ la s2, _data_lma
+ j 2f
+1:
+ lw t0, (s2)
+ sw t0, (s0)
+ addi s2, s2, 4
+ addi s0, s0, 4
+2:
+ bltu s0, s1, 1b
+
+ la s1, _end /* End of BSS section, word aligned */
+ la s0, __bss_start /* Start of BSS section, word aligned */
+ j bss_bzero_enter
+
+ /* The loader doesn't bzero the BSS, so we must do it here. */
+bss_bzero_loop:
+ sw zero, (s0)
+ addi s0, s0, 4
+bss_bzero_enter:
+ bne s0, s1, bss_bzero_loop
+
+ la s0, __init_array_start
+ la s1, __init_array_end
+ move s2, ra
+ j ctor_loop_enter
+
+ctor_loop:
+ lw a0, (s0)
+ addi s0, s0, 4
+ jalr a0
+ctor_loop_enter:
+ bne s0, s1, ctor_loop
+ move ra, s2
+ j _init
diff --git a/bsp/env/freedom-e300-hifive1/init.c b/bsp/env/freedom-e300-hifive1/init.c
new file mode 100644
index 0000000..d085f6c
--- /dev/null
+++ b/bsp/env/freedom-e300-hifive1/init.c
@@ -0,0 +1,187 @@
+#include <stdint.h>
+#include <unistd.h>
+
+#include "platform.h"
+#include "encoding.h"
+
+uint32_t cpu_freq = 0;
+
+extern int main(int argc, char** argv);
+
+uint32_t mtime_lo(void)
+{
+ return *(volatile uint32_t *)(CLINT_BASE_ADDR + CLINT_MTIME);
+}
+
+uint32_t mcycle_lo(void)
+{
+ uint32_t t;
+ asm volatile ("csrr %0, mcycle" : "=r" (t));
+ return t;
+}
+
+static void use_hfrosc(int div, int trim)
+{
+ // Make sure the HFROSC is running at its default setting
+ PRCI_REG(PRCI_HFROSCCFG) = (ROSC_DIV(div) | ROSC_TRIM(trim) | ROSC_EN(1));
+ while ((PRCI_REG(PRCI_HFROSCCFG) & ROSC_RDY(1)) == 0) ;
+ PRCI_REG(PRCI_PLLCFG) &= ~PLL_SEL(1);
+}
+
+static void use_pll(int refsel, int bypass, int r, int f, int q)
+{
+ // Ensure that we aren't running off the PLL before we mess with it.
+ if (PRCI_REG(PRCI_PLLCFG) & PLL_SEL(1)) {
+ // Make sure the HFROSC is running at its default setting
+ use_hfrosc(4, 16);
+ }
+
+ // Set PLL Source to be HFXOSC if available.
+ uint32_t config_value = 0;
+
+ config_value |= PLL_REFSEL(refsel);
+
+ if (bypass) {
+ // Bypass
+ config_value |= PLL_BYPASS(1);
+
+ PRCI_REG(PRCI_PLLCFG) = config_value;
+
+ // If we don't have an HFXTAL, this doesn't really matter.
+ // Set our Final output divide to divide-by-1:
+ PRCI_REG(PRCI_PLLDIV) = (PLL_FINAL_DIV_BY_1(1) | PLL_FINAL_DIV(0));
+ } else {
+ // In case we are executing from QSPI,
+ // (which is quite likely) we need to
+ // set the QSPI clock divider appropriately
+ // before boosting the clock frequency.
+
+ // Div = f_sck/2
+ SPI0_REG(SPI_REG_SCKDIV) = 8;
+
+ // Set DIV Settings for PLL
+ // Both HFROSC and HFXOSC are modeled as ideal
+ // 16MHz sources (assuming dividers are set properly for
+ // HFROSC).
+ // (Legal values of f_REF are 6-48MHz)
+
+ // Set DIVR to divide-by-2 to get 8MHz frequency
+ // (legal values of f_R are 6-12 MHz)
+
+ config_value |= PLL_BYPASS(1);
+ config_value |= PLL_R(r);
+
+ // Set DIVF to get 512Mhz frequncy
+ // There is an implied multiply-by-2, 16Mhz.
+ // So need to write 32-1
+ // (legal values of f_F are 384-768 MHz)
+ config_value |= PLL_F(f);
+
+ // Set DIVQ to divide-by-2 to get 256 MHz frequency
+ // (legal values of f_Q are 50-400Mhz)
+ config_value |= PLL_Q(q);
+
+ // Set our Final output divide to divide-by-1:
+ PRCI_REG(PRCI_PLLDIV) = (PLL_FINAL_DIV_BY_1(1) | PLL_FINAL_DIV(0));
+
+ PRCI_REG(PRCI_PLLCFG) = config_value;
+
+ // Un-Bypass the PLL.
+ PRCI_REG(PRCI_PLLCFG) &= ~PLL_BYPASS(1);
+
+ // Wait for PLL Lock
+ // Note that the Lock signal can be glitchy.
+ // Need to wait 100 us
+ // RTC is running at 32kHz.
+ // So wait 4 ticks of RTC.
+ uint32_t now = mtime_lo();
+ while (mtime_lo() - now < 4) ;
+
+ // Now it is safe to check for PLL Lock
+ while ((PRCI_REG(PRCI_PLLCFG) & PLL_LOCK(1)) == 0) ;
+ }
+
+ // Switch over to PLL Clock source
+ PRCI_REG(PRCI_PLLCFG) |= PLL_SEL(1);
+}
+
+static void use_default_clocks()
+{
+ // Turn off the LFROSC
+ AON_REG(AON_LFROSC) &= ~ROSC_EN(1);
+
+ // Use HFROSC
+ use_hfrosc(4, 16);
+}
+
+void measure_cpu_freq(size_t n, size_t mtime_freq)
+{
+ uint32_t start_mtime = mtime_lo();
+ uint32_t start_mcycle = mcycle_lo();
+
+ while (mtime_lo() - start_mtime < n) ;
+
+ uint32_t end_mtime = mtime_lo();
+ uint32_t end_mcycle = mcycle_lo();
+
+ cpu_freq = (end_mcycle-start_mcycle)/n*mtime_freq;
+}
+
+uint32_t get_cpu_freq()
+{
+ return cpu_freq;
+}
+
+static void uart_init(size_t baud_rate)
+{
+ GPIO_REG(GPIO_IOF_SEL) &= ~IOF0_UART0_MASK;
+ GPIO_REG(GPIO_IOF_EN) |= IOF0_UART0_MASK;
+ UART0_REG(UART_REG_DIV) = get_cpu_freq() / baud_rate - 1;
+ UART0_REG(UART_REG_TXCTRL) |= UART_TXEN;
+}
+
+
+
+#ifdef USE_PLIC
+extern void handle_m_ext_interrupt();
+#endif
+
+#ifdef USE_M_TIME
+extern void handle_m_time_interrupt();
+#endif
+
+uintptr_t handle_trap(uintptr_t mcause, uintptr_t epc)
+{
+ if (0){
+#ifdef USE_PLIC
+ // External Machine-Level interrupt from PLIC
+ } else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT)) {
+ handle_m_ext_interrupt();
+#endif
+#ifdef USE_M_TIME
+ // External Machine-Level interrupt from PLIC
+ } else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == IRQ_M_TIMER)){
+ handle_m_time_interrupt();
+#endif
+ }
+ else {
+ write(1, "trap\n", 5);
+ _exit(1 + mcause);
+ }
+ return epc;
+}
+
+
+void _init()
+{
+ use_default_clocks();
+ use_pll(0, 0, 1, 31, 1);
+ measure_cpu_freq(1000, 32768);
+ uart_init(115200);
+
+ printf("core freq at %d Hz\n", get_cpu_freq());
+
+ write_csr(mtvec, &handle_trap);
+
+ _exit(main(0, NULL));
+}
diff --git a/bsp/env/freedom-e300-hifive1/link.lds b/bsp/env/freedom-e300-hifive1/link.lds
new file mode 100644
index 0000000..e25baf4
--- /dev/null
+++ b/bsp/env/freedom-e300-hifive1/link.lds
@@ -0,0 +1,163 @@
+OUTPUT_ARCH( "riscv" )
+
+ENTRY( _start )
+
+MEMORY
+{
+ flash (rxai!w) : ORIGIN = 0x20400000, LENGTH = 512M
+ ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = 16K
+}
+
+PHDRS
+{
+ flash PT_LOAD;
+ ram_init PT_LOAD;
+ ram PT_NULL;
+}
+
+SECTIONS
+{
+ __stack_size = DEFINED(__stack_size) ? __stack_size : 2K;
+
+ .init :
+ {
+ KEEP (*(SORT_NONE(.init)))
+ } >flash AT>flash :flash
+
+ .text :
+ {
+ *(.text .text.*)
+ *(.gnu.linkonce.t.*)
+ } >flash AT>flash :flash
+
+ .fini :
+ {
+ KEEP (*(SORT_NONE(.fini)))
+ } >flash AT>flash :flash
+
+ PROVIDE (__etext = .);
+ PROVIDE (_etext = .);
+ PROVIDE (etext = .);
+
+ .rodata :
+ {
+ *(.rdata)
+ *(.rodata .rodata.*)
+ *(.gnu.linkonce.r.*)
+ } >flash AT>flash :flash
+
+ .lalign :
+ {
+ . = ALIGN(4);
+ PROVIDE( _data_lma = . );
+ } >flash AT>flash :flash
+
+ .dalign :
+ {
+ . = ALIGN(4);
+ PROVIDE( _data = . );
+ } >ram AT>flash :ram_init
+
+ .preinit_array :
+ {
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP (*(.preinit_array))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+ } >ram AT>flash :ram_init
+
+ .init_array :
+ {
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
+ KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
+ PROVIDE_HIDDEN (__init_array_end = .);
+ } >ram AT>flash :ram_init
+
+ .fini_array :
+ {
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
+ KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
+ PROVIDE_HIDDEN (__fini_array_end = .);
+ } >ram AT>flash :ram_init
+
+ .ctors :
+ {
+ /* gcc uses crtbegin.o to find the start of
+ the constructors, so we make sure it is
+ first. Because this is a wildcard, it
+ doesn't matter if the user does not
+ actually link against crtbegin.o; the
+ linker won't look for a file to match a
+ wildcard. The wildcard also means that it
+ doesn't matter which directory crtbegin.o
+ is in. */
+ KEEP (*crtbegin.o(.ctors))
+ KEEP (*crtbegin?.o(.ctors))
+ /* We don't want to include the .ctor section from
+ the crtend.o file until after the sorted ctors.
+ The .ctor section from the crtend file contains the
+ end of ctors marker and it must be last */
+ KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ } >ram AT>flash :ram_init
+
+ .dtors :
+ {
+ KEEP (*crtbegin.o(.dtors))
+ KEEP (*crtbegin?.o(.dtors))
+ KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ } >ram AT>flash :ram_init
+
+ .data :
+ {
+ *(.data .data.*)
+ *(.gnu.linkonce.d.*)
+ } >ram AT>flash :ram_init
+
+ .srodata :
+ {
+ PROVIDE( _gp = . + 0x800 );
+ *(.srodata.cst16)
+ *(.srodata.cst8)
+ *(.srodata.cst4)
+ *(.srodata.cst2)
+ *(.srodata .srodata.*)
+ } >ram AT>flash :ram_init
+
+ .sdata :
+ {
+ *(.sdata .sdata.*)
+ *(.gnu.linkonce.s.*)
+ } >ram AT>flash :ram_init
+
+ . = ALIGN(4);
+ PROVIDE( _edata = . );
+ PROVIDE( edata = . );
+
+ PROVIDE( _fbss = . );
+ PROVIDE( __bss_start = . );
+ .bss :
+ {
+ *(.sbss*)
+ *(.gnu.linkonce.sb.*)
+ *(.bss .bss.*)
+ *(.gnu.linkonce.b.*)
+ *(COMMON)
+ . = ALIGN(4);
+ } >ram AT>ram :ram
+
+ . = ALIGN(8);
+ PROVIDE( _end = . );
+ PROVIDE( end = . );
+
+ .stack ORIGIN(ram) + LENGTH(ram) - __stack_size :
+ {
+ PROVIDE( _heap_end = . );
+ . = __stack_size;
+ PROVIDE( _sp = . );
+ } >ram AT>ram :ram
+}
diff --git a/bsp/env/freedom-e300-hifive1/openocd.cfg b/bsp/env/freedom-e300-hifive1/openocd.cfg
new file mode 100644
index 0000000..9a260ed
--- /dev/null
+++ b/bsp/env/freedom-e300-hifive1/openocd.cfg
@@ -0,0 +1,21 @@
+adapter_khz 10000
+
+interface ftdi
+ftdi_device_desc "Dual RS232-HS"
+ftdi_vid_pid 0x0403 0x6010
+
+ftdi_layout_init 0x0008 0x001b
+ftdi_layout_signal nSRST -oe 0x0020
+
+set _CHIPNAME riscv
+jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x10e31913
+
+set _TARGETNAME $_CHIPNAME.cpu
+target create $_TARGETNAME riscv -chain-position $_TARGETNAME
+$_TARGETNAME configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1
+
+flash bank my_first_flash fespi 0x20000000 0 0 0 $_TARGETNAME
+init
+#reset
+halt
+flash protect 0 64 last off
diff --git a/bsp/env/freedom-e300-hifive1/platform.h b/bsp/env/freedom-e300-hifive1/platform.h
new file mode 100644
index 0000000..f0c763a
--- /dev/null
+++ b/bsp/env/freedom-e300-hifive1/platform.h
@@ -0,0 +1,129 @@
+// See LICENSE for license details.
+
+#ifndef _SIFIVE_PLATFORM_H
+#define _SIFIVE_PLATFORM_H
+
+// Some things missing from the official encoding.h
+#define MCAUSE_INT 0x80000000
+#define MCAUSE_CAUSE 0x7FFFFFFF
+
+#include "sifive/const.h"
+#include "sifive/devices/aon.h"
+#include "sifive/devices/clint.h"
+#include "sifive/devices/gpio.h"
+#include "sifive/devices/otp.h"
+#include "sifive/devices/plic.h"
+#include "sifive/devices/prci.h"
+#include "sifive/devices/pwm.h"
+#include "sifive/devices/spi.h"
+#include "sifive/devices/uart.h"
+
+/****************************************************************************
+ * Platform definitions
+ *****************************************************************************/
+
+// Memory map
+#define MASKROM_BASE_ADDR _AC(0x00001000,UL)
+#define TRAPVEC_TABLE_BASE_ADDR _AC(0x00001010,UL)
+#define OTP_MMAP_ADDR _AC(0x00020000,UL)
+#define CLINT_BASE_ADDR _AC(0x02000000,UL)
+#define PLIC_BASE_ADDR _AC(0x0C000000,UL)
+#define AON_BASE_ADDR _AC(0x10000000,UL)
+#define PRCI_BASE_ADDR _AC(0x10008000,UL)
+#define OTP_BASE_ADDR _AC(0x10010000,UL)
+#define GPIO_BASE_ADDR _AC(0x10012000,UL)
+#define UART0_BASE_ADDR _AC(0x10013000,UL)
+#define SPI0_BASE_ADDR _AC(0x10014000,UL)
+#define PWM0_BASE_ADDR _AC(0x10015000,UL)
+#define UART1_BASE_ADDR _AC(0x10023000,UL)
+#define SPI1_BASE_ADDR _AC(0x10024000,UL)
+#define PWM1_BASE_ADDR _AC(0x10025000,UL)
+#define SPI2_BASE_ADDR _AC(0x10034000,UL)
+#define PWM2_BASE_ADDR _AC(0x10035000,UL)
+#define SPI0_MMAP_ADDR _AC(0x20000000,UL)
+#define MEM_BASE_ADDR _AC(0x80000000,UL)
+
+// IOF masks
+#define IOF0_SPI1_MASK _AC(0x000007FC,UL)
+#define SPI11_NUM_SS (4)
+#define IOF_SPI1_SS0 (2u)
+#define IOF_SPI1_SS1 (8u)
+#define IOF_SPI1_SS2 (9u)
+#define IOF_SPI1_SS3 (10u)
+#define IOF_SPI1_MOSI (3u)
+#define IOF_SPI1_MISO (4u)
+#define IOF_SPI1_SCK (5u)
+#define IOF_SPI1_DQ0 (3u)
+#define IOF_SPI1_DQ1 (4u)
+#define IOF_SPI1_DQ2 (6u)
+#define IOF_SPI1_DQ3 (7u)
+
+#define IOF0_SPI2_MASK _AC(0xFC000000,UL)
+#define SPI2_NUM_SS (1)
+#define IOF_SPI2_SS0 (26u)
+#define IOF_SPI2_MOSI (27u)
+#define IOF_SPI2_MISO (28u)
+#define IOF_SPI2_SCK (29u)
+#define IOF_SPI2_DQ0 (27u)
+#define IOF_SPI2_DQ1 (28u)
+#define IOF_SPI2_DQ2 (30u)
+#define IOF_SPI2_DQ3 (31u)
+
+//#define IOF0_I2C_MASK _AC(0x00003000,UL)
+
+#define IOF0_UART0_MASK _AC(0x00030000, UL)
+#define IOF_UART0_RX (16u)
+#define IOF_UART0_TX (17u)
+
+#define IOF0_UART1_MASK _AC(0x03000000, UL)
+#define IOF_UART1_RX (24u)
+#define IOF_UART1_TX (25u)
+
+#define IOF1_PWM0_MASK _AC(0x0000000F, UL)
+#define IOF1_PWM1_MASK _AC(0x00780000, UL)
+#define IOF1_PWM2_MASK _AC(0x00003C00, UL)
+
+// Interrupt numbers
+#define INT_RESERVED 0
+#define INT_WDOGCMP 1
+#define INT_RTCCMP 2
+#define INT_UART0_BASE 3
+#define INT_UART1_BASE 4
+#define INT_SPI0_BASE 5
+#define INT_SPI1_BASE 6
+#define INT_SPI2_BASE 7
+#define INT_GPIO_BASE 8
+#define INT_PWM0_BASE 40
+#define INT_PWM1_BASE 44
+#define INT_PWM2_BASE 48
+
+// Helper functions
+#define _REG32(p, i) (*(volatile uint32_t *) ((p) + (i)))
+#define _REG32P(p, i) ((volatile uint32_t *) ((p) + (i)))
+#define AON_REG(offset) _REG32(AON_BASE_ADDR, offset)
+#define CLINT_REG(offset) _REG32(CLINT_BASE_ADDR, offset)
+#define GPIO_REG(offset) _REG32(GPIO_BASE_ADDR, offset)
+#define OTP_REG(offset) _REG32(OTP_BASE_ADDR, offset)
+#define PLIC_REG(offset) _REG32(PLIC_BASE_ADDR, offset)
+#define PRCI_REG(offset) _REG32(PRCI_BASE_ADDR, offset)
+#define PWM0_REG(offset) _REG32(PWM0_BASE_ADDR, offset)
+#define PWM1_REG(offset) _REG32(PWM1_BASE_ADDR, offset)
+#define PWM2_REG(offset) _REG32(PWM2_BASE_ADDR, offset)
+#define SPI0_REG(offset) _REG32(SPI0_BASE_ADDR, offset)
+#define SPI1_REG(offset) _REG32(SPI1_BASE_ADDR, offset)
+#define SPI2_REG(offset) _REG32(SPI2_BASE_ADDR, offset)
+#define UART0_REG(offset) _REG32(UART0_BASE_ADDR, offset)
+#define UART1_REG(offset) _REG32(UART1_BASE_ADDR, offset)
+
+// Misc
+
+#include <stdint.h>
+
+#define PLIC_NUM_INTERRUPTS 52
+#define PLIC_NUM_PRIORITIES 7
+
+#include "hifive1.h"
+
+uint32_t get_cpu_freq();
+
+#endif /* _SIFIVE_PLATFORM_H */