Rename RISC-V_RV32_SiFive_HiFive1-FreedomStudio directory to RISC-V_RV32_SiFive_HiFive1-RevB-FreedomStudio as it targets Rev B of the hardware.

This commit is contained in:
Richard Barry 2020-01-01 22:05:35 +00:00
parent 4b943b35e0
commit dfc1bf8ec3
189 changed files with 0 additions and 0 deletions

View file

@ -0,0 +1,59 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__BUTTON_H
#define METAL__BUTTON_H
/*!
* @file button.h
* API for interfacing with physical buttons
*/
#include <metal/interrupt.h>
struct metal_button;
struct metal_button_vtable {
int (*button_exist)(struct metal_button *button, char *label);
struct metal_interrupt* (*interrupt_controller)(struct metal_button *button);
int (*get_interrupt_id)(struct metal_button *button);
};
/*!
* @brief A button device handle
*
* A `struct metal_button` is an implementation-defined object which represents
* a button on a development board.
*/
struct metal_button {
const struct metal_button_vtable *vtable;
};
/*!
* @brief Get a reference to a button
*
* @param label The DeviceTree label for the button
* @return A handle for the button
*/
struct metal_button* metal_button_get(char *label);
/*!
* @brief Get the interrupt controller for a button
*
* @param button The handle for the button
* @return A pointer to the interrupt controller responsible for handling
* button interrupts.
*/
__inline__ struct metal_interrupt*
metal_button_interrupt_controller(struct metal_button *button) { return button->vtable->interrupt_controller(button); }
/*!
* @brief Get the interrupt id for a button
*
* @param button The handle for the button
* @return The interrupt id corresponding to a button.
*/
__inline__ int metal_button_get_interrupt_id(struct metal_button *button) { return button->vtable->get_interrupt_id(button); }
#endif

View file

@ -0,0 +1,96 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__CACHE_H
#define METAL__CACHE_H
/*!
* @file cache.h
*
* @brief API for configuring caches
*/
#include <stdint.h>
struct metal_cache;
struct __metal_cache_vtable {
void (*init)(struct metal_cache *cache, int ways);
int (*get_enabled_ways)(struct metal_cache *cache);
int (*set_enabled_ways)(struct metal_cache *cache, int ways);
};
/*!
* @brief a handle for a cache
*/
struct metal_cache {
const struct __metal_cache_vtable *vtable;
};
/*!
* @brief Initialize a cache
* @param cache The handle for the cache to initialize
* @param ways The number of ways to enable
*
* Initializes a cache with the requested number of ways enabled.
*/
__inline__ void metal_cache_init(struct metal_cache *cache, int ways) {
cache->vtable->init(cache, ways);
}
/*!
* @brief Get the current number of enabled cache ways
* @param cache The handle for the cache
* @return The current number of enabled cache ways
*/
__inline__ int metal_cache_get_enabled_ways(struct metal_cache *cache) {
return cache->vtable->get_enabled_ways(cache);
}
/*!
* @brief Enable the requested number of cache ways
* @param cache The handle for the cache
* @param ways The number of ways to enabled
* @return 0 if the ways are successfully enabled
*/
__inline__ int metal_cache_set_enabled_ways(struct metal_cache *cache, int ways) {
return cache->vtable->set_enabled_ways(cache, ways);
}
/*!
* @brief Check if dcache is supported on the core
* @param hartid The core to check
* @return 1 if dcache is present
*/
int metal_dcache_l1_available(int hartid);
/*!
* @brief Flush dcache for L1 on the requested core with write back
* @param hartid The core to flush
* @param address The virtual address of cacheline to invalidate
* @return None
*/
void metal_dcache_l1_flush(int hartid, uintptr_t address);
/*!
* @brief Discard dcache for L1 on the requested core with no write back
* @param hartid The core to discard
* @param address The virtual address of cacheline to invalidate
* @return None
*/
void metal_dcache_l1_discard(int hartid, uintptr_t address);
/*!
* @brief Check if icache is supported on the core
* @param hartid The core to check
* @return 1 if icache is present
*/
int metal_icache_l1_available(int hartid);
/*!
* @brief Flush icache for L1 on the requested core
* @param hartid The core to flush
* @return None
*/
void metal_icache_l1_flush(int hartid);
#endif

View file

@ -0,0 +1,154 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__CLOCK_H
#define METAL__CLOCK_H
/*!
* @file clock.h
* @brief API for manipulating clock sources
*
* The clock interface allows for controlling the rate of various clocks in the system.
*/
struct metal_clock;
#include <stddef.h>
/* The generic interface to all clocks. */
struct __metal_clock_vtable {
long (*get_rate_hz)(const struct metal_clock *clk);
long (*set_rate_hz)(struct metal_clock *clk, long hz);
};
/*!
* @brief Function signature of clock rate change callbacks
*/
typedef void (*metal_clock_rate_change_callback)(void *priv);
struct _metal_clock_callback_t;
struct _metal_clock_callback_t {
/* The callback function */
metal_clock_rate_change_callback callback;
/* Private data for the callback function */
void *priv;
struct _metal_clock_callback_t *_next;
};
/*!
* @brief Type for the linked list of callbacks for clock rate changes
*/
typedef struct _metal_clock_callback_t metal_clock_callback;
/*!
* @brief Call all callbacks in the linked list, if any are registered
*/
__inline__ void _metal_clock_call_all_callbacks(const metal_clock_callback *const list) {
const metal_clock_callback *current = list;
while (current) {
current->callback(current->priv);
current = current->_next;
}
}
/*!
* @brief Append a callback to the linked list and return the head of the list
*/
__inline__ metal_clock_callback *_metal_clock_append_to_callbacks(metal_clock_callback *list, metal_clock_callback *const cb) {
cb->_next = NULL;
if (!list) {
return cb;
}
metal_clock_callback *current = list;
while ((current->_next) != NULL) {
current = current->_next;
}
current->_next = cb;
return list;
}
/*!
* @struct metal_clock
* @brief The handle for a clock
*
* Clocks are defined as a pointer to a `struct metal_clock`, the contents of which
* are implementation defined. Users of the clock interface must call functions
* which accept a `struct metal_clock *` as an argument to interract with the clock.
*
* Note that no mechanism for obtaining a pointer to a `struct metal_clock` has been
* defined, making it impossible to call any of these functions without invoking
* implementation-defined behavior.
*/
struct metal_clock {
const struct __metal_clock_vtable *vtable;
/* Pre-rate change callback linked list */
metal_clock_callback *_pre_rate_change_callback;
/* Post-rate change callback linked list */
metal_clock_callback *_post_rate_change_callback;
};
/*!
* @brief Returns the current rate of the given clock
*
* @param clk The handle for the clock
* @return The current rate of the clock in Hz
*/
__inline__ long metal_clock_get_rate_hz(const struct metal_clock *clk) { return clk->vtable->get_rate_hz(clk); }
/*!
* @brief Set the current rate of a clock
*
* @param clk The handle for the clock
* @param hz The desired rate in Hz
* @return The new rate of the clock in Hz.
*
* Attempts to set the current rate of the given clock to as close as possible
* to the given rate in Hz. Returns the actual value that's been selected, which
* could be anything!
*
* Prior to and after the rate change of the clock, this will call the registered
* pre- and post-rate change callbacks.
*/
__inline__ long metal_clock_set_rate_hz(struct metal_clock *clk, long hz)
{
_metal_clock_call_all_callbacks(clk->_pre_rate_change_callback);
long out = clk->vtable->set_rate_hz(clk, hz);
_metal_clock_call_all_callbacks(clk->_post_rate_change_callback);
return out;
}
/*!
* @brief Register a callback that must be called before a rate change
*
* @param clk The handle for the clock
* @param cb The callback to be registered
*/
__inline__ void metal_clock_register_pre_rate_change_callback(struct metal_clock *clk, metal_clock_callback *cb)
{
clk->_pre_rate_change_callback = _metal_clock_append_to_callbacks(clk->_pre_rate_change_callback, cb);
}
/*!
* @brief Registers a callback that must be called after a rate change
*
* @param clk The handle for the clock
* @param cb The callback to be registered
*/
__inline__ void metal_clock_register_post_rate_change_callback(struct metal_clock *clk, metal_clock_callback *cb)
{
clk->_post_rate_change_callback = _metal_clock_append_to_callbacks(clk->_post_rate_change_callback, cb);
}
#endif

View file

@ -0,0 +1,22 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__COMPILER_H
#define METAL__COMPILER_H
#define __METAL_DECLARE_VTABLE(type) \
extern const struct type type;
#define __METAL_DEFINE_VTABLE(type) \
const struct type type
#define __METAL_GET_FIELD(reg, mask) \
(((reg) & (mask)) / ((mask) & ~((mask) << 1)))
/* Set field with mask for a given value */
#define __METAL_SET_FIELD(reg, mask, val) \
(((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask)))
void _metal_trap(int ecode);
#endif

View file

@ -0,0 +1,271 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
/*! @file cpu.h
* @brief API for accessing CPU capabilities.
*/
#ifndef METAL__CPU_H
#define METAL__CPU_H
#include <stdint.h>
#include <metal/interrupt.h>
struct metal_cpu;
/*!
* @brief Function signature for exception handlers
*/
typedef void (*metal_exception_handler_t) (struct metal_cpu *cpu, int ecode);
struct metal_cpu_vtable {
unsigned long long (*mcycle_get)(struct metal_cpu *cpu);
unsigned long long (*timebase_get)(struct metal_cpu *cpu);
unsigned long long (*mtime_get)(struct metal_cpu *cpu);
int (*mtimecmp_set)(struct metal_cpu *cpu, unsigned long long time);
struct metal_interrupt* (*tmr_controller_interrupt)(struct metal_cpu *cpu);
int (*get_tmr_interrupt_id)(struct metal_cpu *cpu);
struct metal_interrupt* (*sw_controller_interrupt)(struct metal_cpu *cpu);
int (*get_sw_interrupt_id)(struct metal_cpu *cpu);
int (*set_sw_ipi)(struct metal_cpu *cpu, int hartid);
int (*clear_sw_ipi)(struct metal_cpu *cpu, int hartid);
int (*get_msip)(struct metal_cpu *cpu, int hartid);
struct metal_interrupt* (*controller_interrupt)(struct metal_cpu *cpu);
int (*exception_register)(struct metal_cpu *cpu, int ecode, metal_exception_handler_t handler);
int (*get_ilen)(struct metal_cpu *cpu, uintptr_t epc);
uintptr_t (*get_epc)(struct metal_cpu *cpu);
int (*set_epc)(struct metal_cpu *cpu, uintptr_t epc);
};
/*! @brief A device handle for a CPU hart
*/
struct metal_cpu {
const struct metal_cpu_vtable *vtable;
};
/*! @brief Get a reference to a CPU hart
*
* @param hartid The ID of the desired CPU hart
* @return A pointer to the CPU device handle
*/
struct metal_cpu* metal_cpu_get(unsigned int hartid);
/*! @brief Get the hartid of the CPU hart executing this function
*
* @return The hartid of the current CPU hart */
int metal_cpu_get_current_hartid(void);
/*! @brief Get the number of CPU harts
*
* @return The number of CPU harts */
int metal_cpu_get_num_harts(void);
/*! @brief Get the CPU cycle count timer value
*
* Get the value of the cycle count timer for a given CPU
*
* @param cpu The CPU device handle
* @return The value of the CPU cycle count timer
*/
__inline__ unsigned long long metal_cpu_get_timer(struct metal_cpu *cpu)
{ return cpu->vtable->mcycle_get(cpu); }
/*! @brief Get the timebase of the CPU
*
* Get the value of the timebase of the cycle count timer
*
* @param cpu The CPU device handle
* @return The value of the cycle count timer timebase
*/
__inline__ unsigned long long metal_cpu_get_timebase(struct metal_cpu *cpu)
{ return cpu->vtable->timebase_get(cpu); }
/*! @brief Get the value of the mtime RTC
*
* Get the value of the mtime real-time clock. The CPU interrupt controller
* must be initialized before this function is called or the return value
* will be 0.
*
* @param cpu The CPU device handle
* @return The value of mtime, or 0 if failure
*/
__inline__ unsigned long long metal_cpu_get_mtime(struct metal_cpu *cpu)
{ return cpu->vtable->mtime_get(cpu); }
/*! @brief Set the value of the RTC mtimecmp RTC
*
* Set the value of the mtime real-time clock compare register. The CPU
* interrupt controller must be initialized before this function is called
* or the return value will be -1;
*
* @param cpu The CPU device handle
* @param time The value to set the compare register to
* @return The value of mtimecmp or -1 if error
*/
__inline__ int metal_cpu_set_mtimecmp(struct metal_cpu *cpu, unsigned long long time)
{ return cpu->vtable->mtimecmp_set(cpu, time); }
/*! @brief Get a reference to RTC timer interrupt controller
*
* Get a reference to the interrupt controller for the real-time clock interrupt.
* The controller returned by this function must be initialized before any interrupts
* are registered or enabled with it.
*
* @param cpu The CPU device handle
* @return A pointer to the timer interrupt handle
*/
__inline__ struct metal_interrupt* metal_cpu_timer_interrupt_controller(struct metal_cpu *cpu)
{ return cpu->vtable->tmr_controller_interrupt(cpu); }
/*! @brief Get the RTC timer interrupt id
*
* Get the interrupt ID of the real-time clock interrupt
*
* @param cpu The CPU device handle
* @return The timer interrupt ID
*/
__inline__ int metal_cpu_timer_get_interrupt_id(struct metal_cpu *cpu)
{ return cpu->vtable->get_tmr_interrupt_id(cpu); }
/*! @brief Get a reference to the software interrupt controller
*
* Get a reference to the interrupt controller for the software/inter-process
* interrupt. The controller returned by this function must be initialized before
* any interrupts are registered or enabled with it.
*
* @param cpu The CPU device handle
* @return A pointer to the software interrupt handle
*/
__inline__ struct metal_interrupt* metal_cpu_software_interrupt_controller(struct metal_cpu *cpu)
{ return cpu->vtable->sw_controller_interrupt(cpu); }
/*! @brief Get the software interrupt id
*
* Get the interrupt ID for the software/inter-process interrupt
*
* @param cpu The CPU device handle
* @return the software interrupt ID
*/
__inline__ int metal_cpu_software_get_interrupt_id(struct metal_cpu *cpu)
{ return cpu->vtable->get_sw_interrupt_id(cpu); }
/*!
* @brief Set the inter-process interrupt for a hart
*
* Trigger a software/inter-process interrupt for a hart. The CPU interrupt
* controller for the CPU handle passed to this function must be initialized
* before this function is called.
*
* @param cpu The CPU device handle
* @param hartid The CPU hart ID to be interrupted
* @return 0 upon success
*/
__inline__ int metal_cpu_software_set_ipi(struct metal_cpu *cpu, int hartid)
{ return cpu->vtable->set_sw_ipi(cpu, hartid); }
/*!
* @brief Clear the inter-process interrupt for a hart
*
* Clear the software/inter-process interrupt for a hart. The CPU interrupt
* controller for the CPU handle passed to this function must be initialized
* before this function is called.
*
* @param cpu The CPU device handle
* @param hartid The CPU hart ID to clear
* @return 0 upon success
*/
__inline__ int metal_cpu_software_clear_ipi(struct metal_cpu *cpu, int hartid)
{ return cpu->vtable->clear_sw_ipi(cpu, hartid); }
/*!
* @brief Get the value of MSIP for the given hart
*
* Get the value of the machine software interrupt pending bit for
* the given hart. The CPU interrupt controller for the CPU handle passed
* as argument to this function must be initialized before this function
* is called.
*
* @param cpu the CPU device handle
* @param hartid The CPU hart to read
* @return 0 upon success
*/
__inline__ int metal_cpu_get_msip(struct metal_cpu *cpu, int hartid)
{ return cpu->vtable->get_msip(cpu, hartid); }
/*!
* @brief Get the interrupt controller for the CPU
*
* Get the CPU interrupt controller. The controller returned by this
* function must be initialized before any interrupts are registered
* or enabled and before any exception handlers are registered with
* this CPU.
*
* @param cpu The CPU device handle
* @return The handle for the CPU interrupt controller
*/
__inline__ struct metal_interrupt* metal_cpu_interrupt_controller(struct metal_cpu *cpu)
{ return cpu->vtable->controller_interrupt(cpu); }
/*!
* @brief Register an exception handler
*
* Register an exception handler for the CPU. The CPU interrupt controller must be initialized
* before this function is called.
*
* @param cpu The CPU device handle
* @param ecode The exception code to register a handler for
* @param handler Callback function for the exception handler
* @return 0 upon success
*/
__inline__ int metal_cpu_exception_register(struct metal_cpu *cpu, int ecode, metal_exception_handler_t handler)
{ return cpu->vtable->exception_register(cpu, ecode, handler); }
/*!
* @brief Get the length of an instruction in bytes
*
* Get the length of an instruction in bytes.
*
* On RISC-V platforms, this is useful for detecting whether an instruction is
* compressed (2 bytes long) or uncompressed (4 bytes long).
*
* This function is useful in conjuction with `metal_cpu_get_exception_pc()`
* and `metal_cpu_set_exception_pc()` in order to cause the exception handler to
* return execution after the faulting instruction.
*
* @param cpu The CPU device handle
* @param epc The address of the instruction to measure
* @return the length of the instruction in bytes
*/
__inline__ int metal_cpu_get_instruction_length(struct metal_cpu *cpu, uintptr_t epc)
{ return cpu->vtable->get_ilen(cpu, epc); }
/*!
* @brief Get the program counter of the current exception.
*
* This function must be called within an exception handler. The behavior is
* undefined outside of an exception handler.
*
* @param cpu The CPU device handle
* @return The value of the program counter at the time of the exception
*/
__inline__ uintptr_t metal_cpu_get_exception_pc(struct metal_cpu *cpu)
{ return cpu->vtable->get_epc(cpu); }
/*!
* @brief Set the exception program counter
*
* This function must be called within an exception handler. The behavior
* is undefined outside of an exception handler.
*
* This function can be used to cause an exception handler to return execution
* to an address other than the one that caused the exception.
*
* @param cpu the CPU device handle
* @param epc The address to set the exception program counter to
* @return 0 upon success
*/
__inline__ int metal_cpu_set_exception_pc(struct metal_cpu *cpu, uintptr_t epc)
{ return cpu->vtable->set_epc(cpu, epc); }
#endif

View file

@ -0,0 +1,22 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__FIXED_CLOCK_H
#define METAL__DRIVERS__FIXED_CLOCK_H
struct __metal_driver_fixed_clock;
#include <metal/compiler.h>
#include <metal/clock.h>
struct __metal_driver_vtable_fixed_clock {
struct __metal_clock_vtable clock;
};
__METAL_DECLARE_VTABLE(__metal_driver_vtable_fixed_clock)
struct __metal_driver_fixed_clock {
struct metal_clock clock;
};
#endif

View file

@ -0,0 +1,22 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__FIXED_FACTOR_CLOCK_H
#define METAL__DRIVERS__FIXED_FACTOR_CLOCK_H
struct __metal_driver_fixed_factor_clock;
#include <metal/compiler.h>
#include <metal/clock.h>
struct __metal_driver_vtable_fixed_factor_clock {
struct __metal_clock_vtable clock;
};
__METAL_DECLARE_VTABLE(__metal_driver_vtable_fixed_factor_clock)
struct __metal_driver_fixed_factor_clock {
struct metal_clock clock;
};
#endif

View file

@ -0,0 +1,24 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__RISCV_CLINT0_H
#define METAL__DRIVERS__RISCV_CLINT0_H
#include <metal/compiler.h>
#include <metal/drivers/riscv_cpu.h>
struct __metal_driver_vtable_riscv_clint0 {
struct metal_interrupt_vtable clint_vtable;
};
__METAL_DECLARE_VTABLE(__metal_driver_vtable_riscv_clint0)
#define __METAL_MACHINE_MACROS
#include <metal/machine.h>
struct __metal_driver_riscv_clint0 {
struct metal_interrupt controller;
int init_done;
};
#undef __METAL_MACHINE_MACROS
#endif

View file

@ -0,0 +1,192 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__RISCV_CPU_H
#define METAL__DRIVERS__RISCV_CPU_H
#include <stdint.h>
#include <metal/cpu.h>
#include <metal/compiler.h>
#define METAL_MAX_CORES 8
#define METAL_MAX_MI 32 /* Per ISA MCause interrupts 32+ are Reserved */
#define METAL_MAX_ME 12 /* Per ISA Exception codes 12+ are Reserved */
#define METAL_DEFAULT_RTC_FREQ 32768
#define METAL_DISABLE 0
#define METAL_ENABLE 1
#define METAL_ISA_A_EXTENSIONS 0x0001
#define METAL_ISA_C_EXTENSIONS 0x0004
#define METAL_ISA_D_EXTENSIONS 0x0008
#define METAL_ISA_E_EXTENSIONS 0x0010
#define METAL_ISA_F_EXTENSIONS 0x0020
#define METAL_ISA_G_EXTENSIONS 0x0040
#define METAL_ISA_I_EXTENSIONS 0x0100
#define METAL_ISA_M_EXTENSIONS 0x1000
#define METAL_ISA_N_EXTENSIONS 0x2000
#define METAL_ISA_Q_EXTENSIONS 0x10000
#define METAL_ISA_S_EXTENSIONS 0x40000
#define METAL_ISA_U_EXTENSIONS 0x100000
#define METAL_ISA_V_EXTENSIONS 0x200000
#define METAL_ISA_XL32_EXTENSIONS 0x40000000UL
#define METAL_ISA_XL64_EXTENSIONS 0x8000000000000000UL
#define METAL_ISA_XL128_EXTENSIONS 0xC000000000000000UL
#define METAL_MTVEC_DIRECT 0x00
#define METAL_MTVEC_VECTORED 0x01
#define METAL_MTVEC_CLIC 0x02
#define METAL_MTVEC_CLIC_VECTORED 0x03
#define METAL_MTVEC_CLIC_RESERVED 0x3C
#define METAL_MTVEC_MASK 0x3F
#if __riscv_xlen == 32
#define METAL_MCAUSE_INTR 0x80000000UL
#define METAL_MCAUSE_CAUSE 0x000003FFUL
#else
#define METAL_MCAUSE_INTR 0x8000000000000000UL
#define METAL_MCAUSE_CAUSE 0x00000000000003FFUL
#endif
#define METAL_MCAUSE_MINHV 0x40000000UL
#define METAL_MCAUSE_MPP 0x30000000UL
#define METAL_MCAUSE_MPIE 0x08000000UL
#define METAL_MCAUSE_MPIL 0x00FF0000UL
#define METAL_MSTATUS_MIE 0x00000008UL
#define METAL_MSTATUS_MPIE 0x00000080UL
#define METAL_MSTATUS_MPP 0x00001800UL
#define METAL_MSTATUS_FS_INIT 0x00002000UL
#define METAL_MSTATUS_FS_CLEAN 0x00004000UL
#define METAL_MSTATUS_FS_DIRTY 0x00006000UL
#define METAL_MSTATUS_MPRV 0x00020000UL
#define METAL_MSTATUS_MXR 0x00080000UL
#define METAL_MINTSTATUS_MIL 0xFF000000UL
#define METAL_MINTSTATUS_SIL 0x0000FF00UL
#define METAL_MINTSTATUS_UIL 0x000000FFUL
#define METAL_LOCAL_INTR(X) (16 + X)
#define METAL_MCAUSE_EVAL(cause) (cause & METAL_MCAUSE_INTR)
#define METAL_INTERRUPT(cause) (METAL_MCAUSE_EVAL(cause) ? 1 : 0)
#define METAL_EXCEPTION(cause) (METAL_MCAUSE_EVAL(cause) ? 0 : 1)
#define METAL_SW_INTR_EXCEPTION (METAL_MCAUSE_INTR + 3)
#define METAL_TMR_INTR_EXCEPTION (METAL_MCAUSE_INTR + 7)
#define METAL_EXT_INTR_EXCEPTION (METAL_MCAUSE_INTR + 11)
#define METAL_LOCAL_INTR_EXCEPTION(X) (METAL_MCAUSE_INTR + METAL_LOCAL_INTR(X))
#define METAL_LOCAL_INTR_RESERVE0 1
#define METAL_LOCAL_INTR_RESERVE1 2
#define METAL_LOCAL_INTR_RESERVE2 4
#define METAL_LOCAL_INTERRUPT_SW 8 /* Bit3 0x008 */
#define METAL_LOCAL_INTR_RESERVE4 16
#define METAL_LOCAL_INTR_RESERVE5 32
#define METAL_LOCAL_INTR_RESERVE6 64
#define METAL_LOCAL_INTERRUPT_TMR 128 /* Bit7 0x080 */
#define METAL_LOCAL_INTR_RESERVE8 256
#define METAL_LOCAL_INTR_RESERVE9 512
#define METAL_LOCAL_INTR_RESERVE10 1024
#define METAL_LOCAL_INTERRUPT_EXT 2048 /* Bit11 0x800 */
/* Bit12 to Bit15 are Reserved */
#define METAL_LOCAL_INTERRUPT(X) (0x10000 << X) /* Bit16+ Start of Custom Local Interrupt */
#define METAL_MIE_INTERRUPT METAL_MSTATUS_MIE
#define METAL_INSN_LENGTH_MASK 3
#define METAL_INSN_NOT_COMPRESSED 3
typedef enum {
METAL_MACHINE_PRIVILEGE_MODE,
METAL_SUPERVISOR_PRIVILEGE_MODE,
METAL_USER_PRIVILEGE_MODE,
} metal_privilege_mode_e;
typedef enum {
METAL_INTERRUPT_ID_BASE,
METAL_INTERRUPT_ID_SW = (METAL_INTERRUPT_ID_BASE + 3),
METAL_INTERRUPT_ID_TMR = (METAL_INTERRUPT_ID_BASE + 7),
METAL_INTERRUPT_ID_EXT = (METAL_INTERRUPT_ID_BASE + 11),
METAL_INTERRUPT_ID_CSW = (METAL_INTERRUPT_ID_BASE + 12),
METAL_INTERRUPT_ID_LC0 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(0)),
METAL_INTERRUPT_ID_LC1 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(1)),
METAL_INTERRUPT_ID_LC2 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(2)),
METAL_INTERRUPT_ID_LC3 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(3)),
METAL_INTERRUPT_ID_LC4 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(4)),
METAL_INTERRUPT_ID_LC5 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(5)),
METAL_INTERRUPT_ID_LC6 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(6)),
METAL_INTERRUPT_ID_LC7 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(7)),
METAL_INTERRUPT_ID_LC8 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(8)),
METAL_INTERRUPT_ID_LC9 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(9)),
METAL_INTERRUPT_ID_LC10 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(10)),
METAL_INTERRUPT_ID_LC11 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(11)),
METAL_INTERRUPT_ID_LC12 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(12)),
METAL_INTERRUPT_ID_LC13 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(13)),
METAL_INTERRUPT_ID_LC14 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(14)),
METAL_INTERRUPT_ID_LC15 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(15)),
METAL_INTERRUPT_ID_LCMX,
METAL_INTERRUPT_ID_GL0 = METAL_INTERRUPT_ID_LCMX,
METAL_INTERRUPT_ID_GLMX = (METAL_MCAUSE_CAUSE + 1),
} metal_interrupt_id_e;
typedef enum {
METAL_IAM_EXCEPTION_CODE, /* Instruction address misaligned */
METAL_IAF_EXCEPTION_CODE, /* Instruction access faultd */
METAL_II_EXCEPTION_CODE, /* Illegal instruction */
METAL_BREAK_EXCEPTION_CODE, /* Breakpoint */
METAL_LAM_EXCEPTION_CODE, /* Load address misaligned */
METAL_LAF_EXCEPTION_CODE, /* Load access fault */
METAL_SAMOAM_EXCEPTION_CODE, /* Store/AMO address misaligned */
METAL_SAMOAF_EXCEPTION_CODE, /* Store/AMO access fault */
METAL_ECALL_U_EXCEPTION_CODE, /* Environment call from U-mode */
METAL_R9_EXCEPTION_CODE, /* Reserved */
METAL_R10_EXCEPTION_CODE, /* Reserved */
METAL_ECALL_M_EXCEPTION_CODE, /* Environment call from M-mode */
METAL_MAX_EXCEPTION_CODE,
} metal_exception_code_e;
typedef enum {
METAL_TIMER_MTIME_GET = 1,
METAL_SOFTWARE_IPI_CLEAR,
METAL_SOFTWARE_IPI_SET,
METAL_SOFTWARE_MSIP_GET,
METAL_MAX_INTERRUPT_GET,
METAL_INDEX_INTERRUPT_GET,
} metal_interrup_cmd_e;
typedef struct __metal_interrupt_data {
long long pad : 64;
metal_interrupt_handler_t handler;
void *sub_int;
void *exint_data;
} __metal_interrupt_data;
/* CPU interrupt controller */
uintptr_t __metal_myhart_id(void);
struct __metal_driver_vtable_riscv_cpu_intc {
struct metal_interrupt_vtable controller_vtable;
};
void __metal_interrupt_global_enable(void);
void __metal_interrupt_global_disable(void);
metal_vector_mode __metal_controller_interrupt_vector_mode(void);
void __metal_controller_interrupt_vector(metal_vector_mode mode, void *vec_table);
__METAL_DECLARE_VTABLE(__metal_driver_vtable_riscv_cpu_intc)
struct __metal_driver_riscv_cpu_intc {
struct metal_interrupt controller;
int init_done;
uintptr_t metal_mtvec_table[METAL_MAX_MI];
__metal_interrupt_data metal_int_table[METAL_MAX_MI];
metal_exception_handler_t metal_exception_table[METAL_MAX_ME];
};
/* CPU driver*/
struct __metal_driver_vtable_cpu {
struct metal_cpu_vtable cpu_vtable;
};
__METAL_DECLARE_VTABLE(__metal_driver_vtable_cpu)
struct __metal_driver_cpu {
struct metal_cpu cpu;
};
#endif

View file

@ -0,0 +1,31 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__RISCV_PLIC0_H
#define METAL__DRIVERS__RISCV_PLIC0_H
#include <metal/compiler.h>
#include <metal/drivers/riscv_cpu.h>
#define METAL_PLIC_SOURCE_MASK 0x1F
#define METAL_PLIC_SOURCE_SHIFT 5
#define METAL_PLIC_SOURCE_PRIORITY_SHIFT 2
#define METAL_PLIC_SOURCE_PENDING_SHIFT 0
struct __metal_driver_vtable_riscv_plic0 {
struct metal_interrupt_vtable plic_vtable;
};
__METAL_DECLARE_VTABLE(__metal_driver_vtable_riscv_plic0)
#define __METAL_MACHINE_MACROS
#include <metal/machine.h>
struct __metal_driver_riscv_plic0 {
struct metal_interrupt controller;
int init_done;
metal_interrupt_handler_t metal_exint_table[__METAL_PLIC_SUBINTERRUPTS];
__metal_interrupt_data metal_exdata_table[__METAL_PLIC_SUBINTERRUPTS];
};
#undef __METAL_MACHINE_MACROS
#endif

View file

@ -0,0 +1,23 @@
/* Copyright 2019 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__SIFIVE_CCACHE0_H
#define METAL__DRIVERS__SIFIVE_CCACHE0_H
#include <metal/cache.h>
#include <metal/compiler.h>
struct __metal_driver_vtable_sifive_ccache0 {
struct __metal_cache_vtable cache;
};
struct __metal_driver_sifive_ccache0;
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_ccache0)
struct __metal_driver_sifive_ccache0 {
struct metal_cache cache;
};
#endif

View file

@ -0,0 +1,43 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__SIFIVE_CLIC0_H
#define METAL__DRIVERS__SIFIVE_CLIC0_H
#include <metal/compiler.h>
#include <metal/drivers/riscv_cpu.h>
#define METAL_CLIC_MAX_NMBITS 2
#define METAL_CLIC_MAX_NLBITS 8
#define METAL_CLIC_MAX_NVBITS 1
#define METAL_SIFIVE_CLIC0_CLICCFG_NMBITS_MMODE 0x00
#define METAL_SIFIVE_CLIC0_CLICCFG_NMBITS_SMODE1 0x20
#define METAL_SIFIVE_CLIC0_CLICCFG_NMBITS_SMODE2 0x40
#define METAL_SIFIVE_CLIC0_CLICCFG_NMBITS_MASK 0x60
#define METAL_SIFIVE_CLIC0_CLICCFG_NLBITS_MASK 0x1E
#define METAL_SIFIVE_CLIC0_CLICCFG_NVBIT_MASK 0x01
#define METAL_CLIC_ICTRL_SMODE1_MASK 0x7F /* b8 set imply M-mode */
#define METAL_CLIC_ICTRL_SMODE2_MASK 0x3F /* b8 set M-mode, b7 clear U-mode */
#define METAL_MAX_INTERRUPT_LEVEL ((1 << METAL_CLIC_MAX_NLBITS) - 1)
struct __metal_driver_vtable_sifive_clic0 {
struct metal_interrupt_vtable clic_vtable;
};
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_clic0)
#define __METAL_MACHINE_MACROS
#include <metal/machine.h>
struct __metal_driver_sifive_clic0 {
struct metal_interrupt controller;
int init_done;
int pad[14];
metal_interrupt_vector_handler_t metal_mtvt_table[__METAL_CLIC_SUBINTERRUPTS];
__metal_interrupt_data metal_exint_table[__METAL_CLIC_SUBINTERRUPTS];
};
#undef __METAL_MACHINE_MACROS
#endif

View file

@ -0,0 +1,22 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__SIFIVE_FE310_G000_HFROSC_H
#define METAL__DRIVERS__SIFIVE_FE310_G000_HFROSC_H
#include <metal/drivers/sifive_fe310-g000_prci.h>
#include <metal/compiler.h>
#include <metal/clock.h>
#include <metal/io.h>
struct __metal_driver_vtable_sifive_fe310_g000_hfrosc {
struct __metal_clock_vtable clock;
};
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_hfrosc)
struct __metal_driver_sifive_fe310_g000_hfrosc {
struct metal_clock clock;
};
#endif

View file

@ -0,0 +1,20 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__SIFIVE_FE310_G000_HFXOSC_H
#define METAL__DRIVERS__SIFIVE_FE310_G000_HFXOSC_H
#include <metal/clock.h>
#include <metal/drivers/sifive_fe310-g000_prci.h>
struct __metal_driver_vtable_sifive_fe310_g000_hfxosc {
struct __metal_clock_vtable clock;
};
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_hfxosc)
struct __metal_driver_sifive_fe310_g000_hfxosc {
struct metal_clock clock;
};
#endif

View file

@ -0,0 +1,21 @@
/* Copyright 2019 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__SIFIVE_FE310_G000_LFROSC_H
#define METAL__DRIVERS__SIFIVE_FE310_G000_LFROSC_H
#include <metal/compiler.h>
#include <metal/clock.h>
#include <metal/io.h>
struct __metal_driver_vtable_sifive_fe310_g000_lfrosc {
struct __metal_clock_vtable clock;
};
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_lfrosc)
struct __metal_driver_sifive_fe310_g000_lfrosc {
struct metal_clock clock;
};
#endif

View file

@ -0,0 +1,26 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#include <metal/machine/platform.h>
#ifndef METAL__DRIVERS__SIFIVE_FE310_G000_PLL_H
#define METAL__DRIVERS__SIFIVE_FE310_G000_PLL_H
struct __metal_driver_sifive_fe310_g000_pll;
#include <metal/clock.h>
#include <metal/drivers/sifive_fe310-g000_prci.h>
#include <metal/machine.h>
struct __metal_driver_vtable_sifive_fe310_g000_pll {
void (*init)(struct __metal_driver_sifive_fe310_g000_pll *pll);
struct __metal_clock_vtable clock;
};
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_pll)
struct __metal_driver_sifive_fe310_g000_pll {
struct metal_clock clock;
};
#endif

View file

@ -0,0 +1,24 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__SIFIVE_FE310_G000_PRCI_H
#define METAL__DRIVERS__SIFIVE_FE310_G000_PRCI_H
#include <metal/compiler.h>
#include <metal/io.h>
struct __metal_driver_sifive_fe310_g000_prci;
struct __metal_driver_vtable_sifive_fe310_g000_prci {
long (*get_reg)(const struct __metal_driver_sifive_fe310_g000_prci *, long offset);
long (*set_reg)(const struct __metal_driver_sifive_fe310_g000_prci *, long offset, long value);
};
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_prci)
struct __metal_driver_sifive_fe310_g000_prci {
const struct __metal_driver_vtable_sifive_fe310_g000_prci *vtable;
};
#endif

View file

@ -0,0 +1,23 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__SIFIVE_FU540_C000_L2_H
#define METAL__DRIVERS__SIFIVE_FU540_C000_L2_H
#include <metal/cache.h>
#include <metal/compiler.h>
struct __metal_driver_vtable_sifive_fu540_c000_l2 {
struct __metal_cache_vtable cache;
};
struct __metal_driver_sifive_fu540_c000_l2;
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_fu540_c000_l2)
struct __metal_driver_sifive_fu540_c000_l2 {
struct metal_cache cache;
};
#endif

View file

@ -0,0 +1,21 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__SIFIVE_GLOBAL_EXTERNAL_INTERRUPTS0_H
#define METAL__DRIVERS__SIFIVE_GLOBAL_EXTERNAL_INTERRUPTS0_H
#include <metal/compiler.h>
#include <metal/drivers/riscv_cpu.h>
struct __metal_driver_vtable_sifive_global_external_interrupts0 {
struct metal_interrupt_vtable global0_vtable;
};
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_global_external_interrupts0)
struct __metal_driver_sifive_global_external_interrupts0 {
struct metal_interrupt irc;
int init_done;
};
#endif

View file

@ -0,0 +1,21 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__SIFIVE_GPIO_BUTTONS_H
#define METAL__DRIVERS__SIFIVE_GPIO_BUTTONS_H
#include <string.h>
#include <metal/button.h>
#include <metal/compiler.h>
struct __metal_driver_vtable_sifive_button {
struct metal_button_vtable button_vtable;
};
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_button)
struct __metal_driver_sifive_gpio_button {
struct metal_button button;
};
#endif

View file

@ -0,0 +1,21 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__SIFIVE_GPIO_LEDS_H
#define METAL__DRIVERS__SIFIVE_GPIO_LEDS_H
#include <metal/drivers/sifive_gpio0.h>
#include <metal/led.h>
#include <metal/compiler.h>
struct __metal_driver_vtable_sifive_led {
struct metal_led_vtable led_vtable;
};
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_led)
struct __metal_driver_sifive_gpio_led {
struct metal_led led;
};
#endif

View file

@ -0,0 +1,21 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__SIFIVE_GPIO_SWITCHES_H
#define METAL__DRIVERS__SIFIVE_GPIO_SWITCHES_H
#include <metal/drivers/sifive_gpio0.h>
#include <metal/switch.h>
#include <metal/compiler.h>
struct __metal_driver_vtable_sifive_switch {
struct metal_switch_vtable switch_vtable;
};
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_switch)
struct __metal_driver_sifive_gpio_switch {
struct metal_switch flip;
};
#endif

View file

@ -0,0 +1,22 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__SIFIVE_GPIO0_H
#define METAL__DRIVERS__SIFIVE_GPIO0_H
#include <metal/compiler.h>
#include <metal/gpio.h>
struct __metal_driver_vtable_sifive_gpio0 {
const struct __metal_gpio_vtable gpio;
};
//struct __metal_driver_sifive_gpio0;
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_gpio0)
struct __metal_driver_sifive_gpio0 {
struct metal_gpio gpio;
};
#endif

View file

@ -0,0 +1,22 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__SIFIVE_EXTERNAL_INTERRUPTS0_H
#define METAL__DRIVERS__SIFIVE_EXTERNAL_INTERRUPTS0_H
#include <metal/compiler.h>
#include <metal/drivers/riscv_cpu.h>
struct __metal_driver_vtable_sifive_local_external_interrupts0 {
struct metal_interrupt_vtable local0_vtable;
};
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_local_external_interrupts0)
struct __metal_driver_sifive_local_external_interrupts0 {
struct metal_interrupt irc;
int init_done;
};
#endif

View file

@ -0,0 +1,27 @@
/* Copyright 2019 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__SIFIVE_RTC0_H
#define METAL__DRIVERS__SIFIVE_RTC0_H
#include <metal/io.h>
#include <metal/compiler.h>
#include <metal/clock.h>
#include <metal/interrupt.h>
#include <metal/rtc.h>
struct __metal_driver_vtable_sifive_rtc0 {
const struct metal_rtc_vtable rtc;
};
struct __metal_driver_sifive_rtc0;
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_rtc0)
struct __metal_driver_sifive_rtc0 {
const struct metal_rtc rtc;
};
#endif

View file

@ -0,0 +1,26 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__SIFIVE_SPI0_H
#define METAL__DRIVERS__SIFIVE_SPI0_H
#include <metal/drivers/sifive_gpio0.h>
#include <metal/clock.h>
#include <metal/compiler.h>
#include <metal/io.h>
#include <metal/spi.h>
struct __metal_driver_vtable_sifive_spi0 {
const struct metal_spi_vtable spi;
};
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_spi0)
struct __metal_driver_sifive_spi0 {
struct metal_spi spi;
unsigned long baud_rate;
metal_clock_callback pre_rate_change_callback;
metal_clock_callback post_rate_change_callback;
};
#endif

View file

@ -0,0 +1,21 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__SIFIVE_TEST0_H
#define METAL__DRIVERS__SIFIVE_TEST0_H
#include <metal/compiler.h>
#include <metal/shutdown.h>
struct __metal_driver_vtable_sifive_test0 {
const struct __metal_shutdown_vtable shutdown;
};
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_test0)
struct __metal_driver_sifive_test0 {
struct __metal_shutdown shutdown;
};
#endif

View file

@ -0,0 +1,23 @@
/* Copyright 2019 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__SIFIVE_TRACE_H
#define METAL__DRIVERS__SIFIVE_TRACE_H
#include <metal/compiler.h>
#include <metal/io.h>
#include <metal/uart.h>
struct __metal_driver_vtable_sifive_trace {
const struct metal_uart_vtable uart;
};
struct __metal_driver_sifive_trace;
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_trace)
struct __metal_driver_sifive_trace {
struct metal_uart uart;
};
#endif /* METAL__DRIVERS__SIFIVE_TRACE_H */

View file

@ -0,0 +1,30 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__SIFIVE_UART0_H
#define METAL__DRIVERS__SIFIVE_UART0_H
#include <metal/drivers/sifive_gpio0.h>
#include <metal/drivers/riscv_plic0.h>
#include <metal/clock.h>
#include <metal/io.h>
#include <metal/uart.h>
#include <metal/compiler.h>
struct __metal_driver_vtable_sifive_uart0 {
const struct metal_uart_vtable uart;
};
struct __metal_driver_sifive_uart0;
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_uart0)
struct __metal_driver_sifive_uart0 {
struct metal_uart uart;
unsigned long baud_rate;
metal_clock_callback pre_rate_change_callback;
metal_clock_callback post_rate_change_callback;
};
#endif

View file

@ -0,0 +1,26 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__SIFIVE_WDOG0_H
#define METAL__DRIVERS__SIFIVE_WDOG0_H
#include <metal/io.h>
#include <metal/compiler.h>
#include <metal/watchdog.h>
#include <metal/clock.h>
#include <metal/interrupt.h>
struct __metal_driver_vtable_sifive_wdog0 {
const struct metal_watchdog_vtable watchdog;
};
struct __metal_driver_sifive_wdog0;
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_wdog0)
struct __metal_driver_sifive_wdog0 {
const struct metal_watchdog watchdog;
};
#endif

View file

@ -0,0 +1,284 @@
/* Copyright 2019 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__GPIO_H
#define METAL__GPIO_H
#include <metal/compiler.h>
#include <metal/interrupt.h>
/*!
* @file gpio.h
* @brief API for manipulating general-purpose input/output
*/
struct metal_gpio;
struct __metal_gpio_vtable {
int (*disable_input)(struct metal_gpio *, long pins);
int (*enable_input)(struct metal_gpio *, long pins);
long (*input)(struct metal_gpio *);
long (*output)(struct metal_gpio *);
int (*disable_output)(struct metal_gpio *, long pins);
int (*enable_output)(struct metal_gpio *, long pins);
int (*output_set)(struct metal_gpio *, long value);
int (*output_clear)(struct metal_gpio *, long value);
int (*output_toggle)(struct metal_gpio *, long value);
int (*enable_io)(struct metal_gpio *, long pins, long dest);
int (*disable_io)(struct metal_gpio *, long pins);
int (*config_int)(struct metal_gpio *, long pins, int intr_type);
int (*clear_int)(struct metal_gpio *, long pins, int intr_type);
struct metal_interrupt* (*interrupt_controller)(struct metal_gpio *gpio);
int (*get_interrupt_id)(struct metal_gpio *gpio, int pin);
};
#define METAL_GPIO_INT_DISABLE 0
#define METAL_GPIO_INT_RISING 1
#define METAL_GPIO_INT_FALLING 2
#define METAL_GPIO_INT_BOTH_EDGE 3
#define METAL_GPIO_INT_LOW 4
#define METAL_GPIO_INT_HIGH 5
#define METAL_GPIO_INT_BOTH_LEVEL 6
#define METAL_GPIO_INT_MAX 7
/*!
* @struct metal_gpio
* @brief The handle for a GPIO interface
*/
struct metal_gpio {
const struct __metal_gpio_vtable *vtable;
};
/*!
* @brief Get a GPIO device handle
* @param device_num The GPIO device index
* @return The GPIO device handle, or NULL if there is no device at that index
*/
struct metal_gpio *metal_gpio_get_device(unsigned int device_num);
/*!
* @brief enable input on a pin
* @param gpio The handle for the GPIO interface
* @param pin The pin number indexed from 0
* @return 0 if the input is successfully enabled
*/
__inline__ int metal_gpio_enable_input(struct metal_gpio *gpio, int pin) {
if(!gpio) {
return 1;
}
return gpio->vtable->enable_input(gpio, (1 << pin));
}
/*!
* @brief Disable input on a pin
* @param gpio The handle for the GPIO interface
* @param pin The pin number indexed from 0
* @return 0 if the input is successfully disabled
*/
__inline__ int metal_gpio_disable_input(struct metal_gpio *gpio, int pin) {
if(!gpio) {
return 1;
}
return gpio->vtable->disable_input(gpio, (1 << pin));
}
/*!
* @brief Enable output on a pin
* @param gpio The handle for the GPIO interface
* @param pin The pin number indexed from 0
* @return 0 if the output is successfully enabled
*/
__inline__ int metal_gpio_enable_output(struct metal_gpio *gpio, int pin) {
if(!gpio) {
return 1;
}
return gpio->vtable->enable_output(gpio, (1 << pin));
}
/*!
* @brief Disable output on a pin
* @param gpio The handle for the GPIO interface
* @param pin The pin number indexed from 0
* @return 0 if the output is successfully disabled
*/
__inline__ int metal_gpio_disable_output(struct metal_gpio *gpio, int pin) {
if(!gpio) {
return 1;
}
return gpio->vtable->disable_output(gpio, (1 << pin));
}
/*!
* @brief Set the output value of a GPIO pin
* @param gpio The handle for the GPIO interface
* @param pin The pin number indexed from 0
* @param value The value to set the pin to
* @return 0 if the output is successfully set
*/
__inline__ int metal_gpio_set_pin(struct metal_gpio *gpio, int pin, int value) {
if(!gpio) {
return 1;
}
if(value == 0) {
return gpio->vtable->output_clear(gpio, (1 << pin));
} else {
return gpio->vtable->output_set(gpio, (1 << pin));
}
}
/*!
* @brief Get the value of the GPIO pin
* @param gpio The handle for the GPIO interface
* @param pin The pin number indexed from 0
* @return The value of the GPIO pin
*/
__inline__ int metal_gpio_get_input_pin(struct metal_gpio *gpio, int pin) {
if(!gpio) {
return 0;
}
long value = gpio->vtable->input(gpio);
if(value & (1 << pin)) {
return 1;
} else {
return 0;
}
}
/*!
* @brief Get the value of the GPIO pin
* @param gpio The handle for the GPIO interface
* @param pin The pin number indexed from 0
* @return The value of the GPIO pin
*/
__inline__ int metal_gpio_get_output_pin(struct metal_gpio *gpio, int pin) {
if(!gpio) {
return 0;
}
long value = gpio->vtable->output(gpio);
if(value & (1 << pin)) {
return 1;
} else {
return 0;
}
}
/*!
* @brief Clears the value of the GPIO pin
* @param gpio The handle for the GPIO interface
* @param pin The pin number indexed from 0
* @return 0 if the pin is successfully cleared
*/
__inline__ int metal_gpio_clear_pin(struct metal_gpio *gpio, int pin) {
if(!gpio) {
return 1;
}
return gpio->vtable->output_clear(gpio, (1 << pin));
}
/*!
* @brief Toggles the value of the GPIO pin
* @param gpio The handle for the GPIO interface
* @param pin The pin number indexed from 0
* @return 0 if the pin is successfully toggled
*/
__inline__ int metal_gpio_toggle_pin(struct metal_gpio *gpio, int pin) {
if(!gpio) {
return 1;
}
return gpio->vtable->output_toggle(gpio, (1 << pin));
}
/*!
* @brief Enables and sets the pinmux for a GPIO pin
* @param gpio The handle for the GPIO interface
* @param pin The bitmask for the pin to enable pinmux on
* @param io_function The IO function to set
* @return 0 if the pinmux is successfully set
*/
__inline__ int metal_gpio_enable_pinmux(struct metal_gpio *gpio, int pin, int io_function) {
if(!gpio) {
return 1;
}
return gpio->vtable->enable_io(gpio, (1 << pin), (io_function << pin));
}
/*!
* @brief Disables the pinmux for a GPIO pin
* @param gpio The handle for the GPIO interface
* @param pin The bitmask for the pin to disable pinmux on
* @return 0 if the pinmux is successfully set
*/
__inline__ int metal_gpio_disable_pinmux(struct metal_gpio *gpio, int pin) {
if(!gpio) {
return 1;
}
return gpio->vtable->disable_io(gpio, (1 << pin));
}
/*!
* @brief Config gpio interrupt type
* @param gpio The handle for the GPIO interface
* @param pin The bitmask for the pin to enable gpio interrupt
* @param intr_type The interrupt type
* @return 0 if the interrupt mode is setup properly
*/
__inline__ int metal_gpio_config_interrupt(struct metal_gpio *gpio, int pin, int intr_type) {
if(!gpio) {
return 1;
}
return gpio->vtable->config_int(gpio, (1 << pin), intr_type);
}
/*!
* @brief Clear gpio interrupt status
* @param gpio The handle for the GPIO interface
* @param pin The bitmask for the pin to clear gpio interrupt
* @param intr_type The interrupt type to be clear
* @return 0 if the interrupt is cleared
*/
__inline__ int metal_gpio_clear_interrupt(struct metal_gpio *gpio, int pin, int intr_type) {
if(!gpio) {
return 1;
}
return gpio->vtable->clear_int(gpio, (1 << pin), intr_type);
}
/*!
* @brief Get the interrupt controller for a gpio
*
* @param gpio The handle for the gpio
* @return A pointer to the interrupt controller responsible for handling
* gpio interrupts.
*/
__inline__ struct metal_interrupt*
metal_gpio_interrupt_controller(struct metal_gpio *gpio) {
return gpio->vtable->interrupt_controller(gpio);
}
/*!
* @brief Get the interrupt id for a gpio
*
* @param gpio The handle for the gpio
* @param pin The bitmask for the pin to get gpio interrupt id
* @return The interrupt id corresponding to a gpio.
*/
__inline__ int metal_gpio_get_interrupt_id(struct metal_gpio *gpio, int pin) {
return gpio->vtable->get_interrupt_id(gpio, pin);
}
#endif

View file

@ -0,0 +1,461 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__INTERRUPT_H
#define METAL__INTERRUPT_H
/*! @file interrupt.h
* @brief API for registering and manipulating interrupts
*/
#include <stddef.h>
/*!
* @brief Possible interrupt controllers
*/
typedef enum metal_interrupt_controller_ {
METAL_CPU_CONTROLLER = 0,
METAL_CLINT_CONTROLLER = 1,
METAL_CLIC_CONTROLLER = 2,
METAL_PLIC_CONTROLLER = 3
} metal_intr_cntrl_type;
/*!
* @brief Possible mode of interrupts to operate
*/
typedef enum metal_vector_mode_ {
METAL_DIRECT_MODE = 0,
METAL_VECTOR_MODE = 1,
METAL_SELECTIVE_NONVECTOR_MODE = 2,
METAL_SELECTIVE_VECTOR_MODE = 3,
METAL_HARDWARE_VECTOR_MODE = 4
} metal_vector_mode;
/*!
* @brief Possible mode of privilege interrupts to operate
*/
typedef enum metal_intr_priv_mode_ {
METAL_INTR_PRIV_M_MODE = 0,
METAL_INTR_PRIV_MU_MODE = 1,
METAL_INTR_PRIV_MSU_MODE = 2
} metal_intr_priv_mode;
/*!
* @brief Function signature for interrupt callback handlers
*/
typedef void (*metal_interrupt_handler_t) (int, void *);
typedef void (*metal_interrupt_vector_handler_t) (void);
struct metal_interrupt;
struct metal_interrupt_vtable {
void (*interrupt_init)(struct metal_interrupt *controller);
int (*interrupt_set_vector_mode)(struct metal_interrupt *controller, metal_vector_mode mode);
metal_vector_mode (*interrupt_get_vector_mode)(struct metal_interrupt *controller);
int (*interrupt_set_privilege)(struct metal_interrupt *controller, metal_intr_priv_mode priv);
metal_intr_priv_mode (*interrupt_get_privilege)(struct metal_interrupt *controller);
int (*interrupt_clear)(struct metal_interrupt *controller, int id);
int (*interrupt_set)(struct metal_interrupt *controller, int id);
int (*interrupt_register)(struct metal_interrupt *controller, int id,
metal_interrupt_handler_t isr, void *priv_data);
int (*interrupt_vector_register)(struct metal_interrupt *controller, int id,
metal_interrupt_vector_handler_t isr, void *priv_data);
int (*interrupt_enable)(struct metal_interrupt *controller, int id);
int (*interrupt_disable)(struct metal_interrupt *controller, int id);
int (*interrupt_vector_enable)(struct metal_interrupt *controller, int id);
int (*interrupt_vector_disable)(struct metal_interrupt *controller, int id);
unsigned int (*interrupt_get_threshold)(struct metal_interrupt *controller);
int (*interrupt_set_threshold)(struct metal_interrupt *controller, unsigned int threshold);
unsigned int (*interrupt_get_priority)(struct metal_interrupt *controller, int id);
int (*interrupt_set_priority)(struct metal_interrupt *controller, int id, unsigned int priority);
int (*command_request)(struct metal_interrupt *controller, int cmd, void *data);
int (*mtimecmp_set)(struct metal_interrupt *controller, int hartid, unsigned long long time);
};
/*!
* @brief A handle for an interrupt
*/
struct metal_interrupt {
const struct metal_interrupt_vtable *vtable;
};
/*!
* @brief Initialize a given interrupt controller
*
* Initialize a given interrupt controller. This function must be called
* before any interrupts are registered or enabled with the handler. It
* is invalid to initialize an interrupt controller more than once.
*
* @param controller The handle for the interrupt controller
*/
__inline__ void metal_interrupt_init(struct metal_interrupt *controller)
{
controller->vtable->interrupt_init(controller);
}
/*!
* @brief Get the handle for an given interrupt controller type
* @param cntrl The type ofinterrupt controller
* @param id The instance of the interrupt controller
* @return A handle to the interrupt controller (CLINT, CLIC, PLIC), or
* NULL if none is found for the requested label
*/
struct metal_interrupt* metal_interrupt_get_controller(metal_intr_cntrl_type cntrl,
int id);
/*!
* @brief Configure vector mode for an interrupt controller
*
* Configure vector mode for an interrupt controller.
* This function must be called after initialization and before
* configuring individual interrupts, registering ISR.
*
* @param controller The handle for the interrupt controller
* @param mode The vector mode of the interrupt controller.
* @return 0 upon success
*/
__inline__ int metal_interrupt_set_vector_mode(struct metal_interrupt *controller,
metal_vector_mode mode)
{
return controller->vtable->interrupt_set_vector_mode(controller, mode);
}
/*!
* @brief Get vector mode of a given an interrupt controller
*
* Configure vector mode for an interrupt controller.
* This function must be called after initialization and before
* configuring individual interrupts, registering ISR.
*
* @param controller The handle for the interrupt controller
* @param mode The vector mode of the interrupt controller.
* @return The interrupt vector mode
*/
__inline__ metal_vector_mode metal_interrupt_get_vector_mode(struct metal_interrupt *controller)
{
return controller->vtable->interrupt_get_vector_mode(controller);
}
/*!
* @brief Configure privilege mode a of given interrupt controller
*
* Configure privilege mode for a given interrupt controller.
* This function must be called after initialization and before
* configuring individual interrupts, registering ISR.
*
* @param controller The handle for the interrupt controller
* @param privilege The privilege mode of the interrupt controller.
* @return 0 upon success
*/
__inline__ int metal_interrupt_set_privilege(struct metal_interrupt *controller,
metal_intr_priv_mode privilege)
{
return controller->vtable->interrupt_set_privilege(controller, privilege);
}
/*!
* @brief Get privilege mode a of given interrupt controller
*
* Get privilege mode for a given interrupt controller.
* This function must be called after initialization and before
* configuring individual interrupts, registering ISR.
*
* @param controller The handle for the interrupt controller
* @return The interrupt privilege mode
*/
__inline__ metal_intr_priv_mode metal_interrupt_get_privilege(struct metal_interrupt *controller)
{
return controller->vtable->interrupt_get_privilege(controller);
}
/*!
* @brief clear an interrupt
* @param controller The handle for the interrupt controller
* @param id The interrupt ID to trigger
* @return 0 upon success
*/
__inline__ int metal_interrupt_clear(struct metal_interrupt *controller, int id)
{
return controller->vtable->interrupt_clear(controller, id);
}
/*!
* @brief Set an interrupt
* @param controller The handle for the interrupt controller
* @param id The interrupt ID to trigger
* @return 0 upon success
*/
__inline__ int metal_interrupt_set(struct metal_interrupt *controller, int id)
{
return controller->vtable->interrupt_set(controller, id);
}
/*!
* @brief Register an interrupt handler
* @param controller The handle for the interrupt controller
* @param id The interrupt ID to register
* @param handler The interrupt handler callback
* @param priv_data Private data for the interrupt handler
* @return 0 upon success
*/
__inline__ int metal_interrupt_register_handler(struct metal_interrupt *controller,
int id,
metal_interrupt_handler_t handler,
void *priv_data)
{
return controller->vtable->interrupt_register(controller, id, handler, priv_data);
}
/*!
* @brief Register an interrupt vector handler
* @param controller The handle for the interrupt controller
* @param id The interrupt ID to register
* @param handler The interrupt vector handler callback
* @param priv_data Private data for the interrupt handler
* @return 0 upon success
*/
__inline__ int metal_interrupt_register_vector_handler(struct metal_interrupt *controller,
int id,
metal_interrupt_vector_handler_t handler,
void *priv_data)
{
return controller->vtable->interrupt_vector_register(controller, id, handler, priv_data);
}
/*!
* @brief Enable an interrupt
* @param controller The handle for the interrupt controller
* @param id The interrupt ID to enable
* @return 0 upon success
*/
__inline__ int metal_interrupt_enable(struct metal_interrupt *controller, int id)
{
return controller->vtable->interrupt_enable(controller, id);
}
/*!
* @brief Disable an interrupt
* @param controller The handle for the interrupt controller
* @param id The interrupt ID to disable
* @return 0 upon success
*/
__inline__ int metal_interrupt_disable(struct metal_interrupt *controller, int id)
{
return controller->vtable->interrupt_disable(controller, id);
}
/*!
* @brief Set interrupt threshold level
* @param controller The handle for the interrupt controller
* @param threshold The interrupt threshold level
* @return 0 upon success
*/
inline int metal_interrupt_set_threshold(struct metal_interrupt *controller, unsigned int level)
{
return controller->vtable->interrupt_set_threshold(controller, level);
}
/*!
* @brief Get an interrupt threshold level
* @param controller The handle for the interrupt controller
* @return The interrupt threshold level
*/
inline unsigned int metal_interrupt_get_threshold(struct metal_interrupt *controller)
{
return controller->vtable->interrupt_get_threshold(controller);
}
/*!
* @brief Set an interrupt priority level
* @param controller The handle for the interrupt controller
* @param id The interrupt ID to enable
* @param priority The interrupt priority level
* @return 0 upon success
*/
inline int metal_interrupt_set_priority(struct metal_interrupt *controller,
int id, unsigned int priority)
{
return controller->vtable->interrupt_set_priority(controller, id, priority);
}
/*!
* @brief Get an interrupt priority level
* @param controller The handle for the interrupt controller
* @param id The interrupt ID to enable
* @return The interrupt priority level
*/
inline unsigned int metal_interrupt_get_priority(struct metal_interrupt *controller, int id)
{
return controller->vtable->interrupt_get_priority(controller, id);
}
/*!
* @brief Enable an interrupt vector
* @param controller The handle for the interrupt controller
* @param id The interrupt ID to enable
* @return 0 upon success
*/
__inline__ int metal_interrupt_vector_enable(struct metal_interrupt *controller, int id)
{
return controller->vtable->interrupt_vector_enable(controller, id);
}
/*!
* @brief Disable an interrupt vector
* @param controller The handle for the interrupt controller
* @param id The interrupt ID to disable
* @return 0 upon success
*/
__inline__ int metal_interrupt_vector_disable(struct metal_interrupt *controller, int id)
{
return controller->vtable->interrupt_vector_disable(controller, id);
}
/*!
* @brief Default interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_interrupt_vector_handler(void);
/*!
* @brief Metal Software interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_software_interrupt_vector_handler(void);
/*!
* @brief Metal Timer interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_timer_interrupt_vector_handler(void);
/*!
* @brief Metal External interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_external_interrupt_vector_handler(void);
/*!
* @brief Metal Local 0 interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_lc0_interrupt_vector_handler(void);
/*!
* @brief Metal Local 1 interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_lc1_interrupt_vector_handler(void);
/*!
* @brief Metal Local 2 interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_lc2_interrupt_vector_handler(void);
/*!
* @brief Metal Local 3 interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_lc3_interrupt_vector_handler(void);
/*!
* @brief Metal Local 4 interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_lc4_interrupt_vector_handler(void);
/*!
* @brief Metal Local 5 interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_lc5_interrupt_vector_handler(void);
/*!
* @brief Metal Local 6 interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_lc6_interrupt_vector_handler(void);
/*!
* @brief Metal Local 7 interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_lc7_interrupt_vector_handler(void);
/*!
* @brief Metal Local 8 interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_lc8_interrupt_vector_handler(void);
/*!
* @brief Metal Local 9 interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_lc9_interrupt_vector_handler(void);
/*!
* @brief Metal Local 10 interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_lc10_interrupt_vector_handler(void);
/*!
* @brief Metal Local 11 interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_lc11_interrupt_vector_handler(void);
/*!
* @brief Metal Local 12 interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_lc12_interrupt_vector_handler(void);
/*!
* @brief Metal Local 13 interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_lc13_interrupt_vector_handler(void);
/*!
* @brief Metal Local 14 interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_lc14_interrupt_vector_handler(void);
/*!
* @brief Metal Local 15 interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_lc15_interrupt_vector_handler(void);
/* Utilities function to controll, manages devices via a given interrupt controller */
__inline__ int _metal_interrupt_command_request(struct metal_interrupt *controller,
int cmd, void *data)
{
return controller->vtable->command_request(controller, cmd, data);
}
#endif

View file

@ -0,0 +1,22 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__IO_H
#define METAL__IO_H
/* This macro enforces that the compiler will not elide the given access. */
#define __METAL_ACCESS_ONCE(x) (*(__typeof__(*x) volatile *)(x))
/* Allows users to specify arbitrary fences. */
#define __METAL_IO_FENCE(pred, succ) __asm__ volatile ("fence " #pred "," #succ ::: "memory");
/* Types that explicitly describe an address as being used for memory-mapped
* IO. These should only be accessed via __METAL_ACCESS_ONCE. */
typedef unsigned char __metal_io_u8;
typedef unsigned short __metal_io_u16;
typedef unsigned int __metal_io_u32;
#if __riscv_xlen >= 64
typedef unsigned long __metal_io_u64;
#endif
#endif

View file

@ -0,0 +1,21 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__ITIM_H
#define METAL__ITIM_H
/*! @file itim.h
*
* API for manipulating ITIM allocation
*/
/*! @def METAL_PLACE_IN_ITIM
* @brief Link a function into the ITIM
*
* Link a function into the ITIM (Instruction Tightly Integrated
* Memory) if the ITIM is present on the target device.
*/
#define METAL_PLACE_IN_ITIM __attribute__((section(".itim")))
#endif

View file

@ -0,0 +1,68 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__LED_H
#define METAL__LED_H
/*!
* @file led.h
* @brief API for manipulating LEDs
*/
struct metal_led;
struct metal_led_vtable {
int (*led_exist)(struct metal_led *led, char *label);
void (*led_enable)(struct metal_led *led);
void (*led_on)(struct metal_led *led);
void (*led_off)(struct metal_led *led);
void (*led_toggle)(struct metal_led *led);
};
/*!
* @brief A handle for an LED
*/
struct metal_led {
const struct metal_led_vtable *vtable;
};
/*!
* @brief Get a handle for an LED
* @param label The DeviceTree label for the desired LED
* @return A handle to the LED, or NULL if none is found for the requested label
*/
struct metal_led* metal_led_get(char *label);
/*!
* @brief Get a handle for a channel of an RGB LED
* @param label The DeviceTree label for the desired LED
* @param color The color for the LED in the DeviceTree
* @return A handle to the LED, or NULL if none is found for the requested label and color
*/
struct metal_led* metal_led_get_rgb(char *label, char *color);
/*!
* @brief Enable an LED
* @param led The handle for the LED
*/
__inline__ void metal_led_enable(struct metal_led *led) { led->vtable->led_enable(led); }
/*!
* @brief Turn an LED on
* @param led The handle for the LED
*/
__inline__ void metal_led_on(struct metal_led *led) { led->vtable->led_on(led); }
/*!
* @brief Turn an LED off
* @param led The handle for the LED
*/
__inline__ void metal_led_off(struct metal_led *led) { led->vtable->led_off(led); }
/*!
* @brief Toggle the on/off state of an LED
* @param led The handle for the LED
*/
__inline__ void metal_led_toggle(struct metal_led *led) { led->vtable->led_toggle(led); }
#endif

View file

@ -0,0 +1,146 @@
/* Copyright 2019 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__LOCK_H
#define METAL__LOCK_H
#include <metal/machine.h>
#include <metal/memory.h>
#include <metal/compiler.h>
/*!
* @file lock.h
* @brief An API for creating and using a software lock/mutex
*/
/* TODO: How can we make the exception code platform-independant? */
#define _METAL_STORE_AMO_ACCESS_FAULT 7
#define METAL_LOCK_BACKOFF_CYCLES 32
#define METAL_LOCK_BACKOFF_EXPONENT 2
/*!
* @def METAL_LOCK_DECLARE
* @brief Declare a lock
*
* Locks must be declared with METAL_LOCK_DECLARE to ensure that the lock
* is linked into a memory region which supports atomic memory operations.
*/
#define METAL_LOCK_DECLARE(name) \
__attribute__((section(".data.locks"))) \
struct metal_lock name
/*!
* @brief A handle for a lock
*/
struct metal_lock {
int _state;
};
/*!
* @brief Initialize a lock
* @param lock The handle for a lock
* @return 0 if the lock is successfully initialized. A non-zero code indicates failure.
*
* If the lock cannot be initialized, attempts to take or give the lock
* will result in a Store/AMO access fault.
*/
__inline__ int metal_lock_init(struct metal_lock *lock) {
#ifdef __riscv_atomic
/* Get a handle for the memory which holds the lock state */
struct metal_memory *lock_mem = metal_get_memory_from_address((uintptr_t) &(lock->_state));
if(!lock_mem) {
return 1;
}
/* If the memory doesn't support atomics, report an error */
if(!metal_memory_supports_atomics(lock_mem)) {
return 2;
}
lock->_state = 0;
return 0;
#else
return 3;
#endif
}
/*!
* @brief Take a lock
* @param lock The handle for a lock
* @return 0 if the lock is successfully taken
*
* If the lock initialization failed, attempts to take a lock will result in
* a Store/AMO access fault.
*/
__inline__ int metal_lock_take(struct metal_lock *lock) {
#ifdef __riscv_atomic
int old = 1;
int new = 1;
int backoff = 1;
const int max_backoff = METAL_LOCK_BACKOFF_CYCLES * METAL_MAX_CORES;
while(1) {
__asm__ volatile("amoswap.w.aq %[old], %[new], (%[state])"
: [old] "=r" (old)
: [new] "r" (new), [state] "r" (&(lock->_state))
: "memory");
if (old == 0) {
break;
}
for (int i = 0; i < backoff; i++) {
__asm__ volatile("");
}
if (backoff < max_backoff) {
backoff *= METAL_LOCK_BACKOFF_EXPONENT;
}
}
return 0;
#else
/* Store the memory address in mtval like a normal store/amo access fault */
__asm__ ("csrw mtval, %[state]"
:: [state] "r" (&(lock->_state)));
/* Trigger a Store/AMO access fault */
_metal_trap(_METAL_STORE_AMO_ACCESS_FAULT);
/* If execution returns, indicate failure */
return 1;
#endif
}
/*!
* @brief Give back a held lock
* @param lock The handle for a lock
* @return 0 if the lock is successfully given
*
* If the lock initialization failed, attempts to give a lock will result in
* a Store/AMO access fault.
*/
__inline__ int metal_lock_give(struct metal_lock *lock) {
#ifdef __riscv_atomic
__asm__ volatile("amoswap.w.rl x0, x0, (%[state])"
:: [state] "r" (&(lock->_state))
: "memory");
return 0;
#else
/* Store the memory address in mtval like a normal store/amo access fault */
__asm__ ("csrw mtval, %[state]"
:: [state] "r" (&(lock->_state)));
/* Trigger a Store/AMO access fault */
_metal_trap(_METAL_STORE_AMO_ACCESS_FAULT);
/* If execution returns, indicate failure */
return 1;
#endif
}
#endif /* METAL__LOCK_H */

View file

@ -0,0 +1,81 @@
/* Copyright 2019 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__MEMORY_H
#define METAL__MEMORY_H
#include <stdint.h>
#include <stddef.h>
/*!
* @file memory.h
*
* @brief API for enumerating memory blocks
*/
struct _metal_memory_attributes {
unsigned int R : 1;
unsigned int W : 1;
unsigned int X : 1;
unsigned int C : 1;
unsigned int A : 1;
};
/*!
* @brief A handle for a memory block
*/
struct metal_memory {
const uintptr_t _base_address;
const size_t _size;
const struct _metal_memory_attributes _attrs;
};
/*!
* @brief Get the memory block which services the given address
*
* Given a physical memory address, get a handle for the memory block to which
* that address is mapped.
*
* @param address The address to query
* @return The memory block handle, or NULL if the address is not mapped to a memory block
*/
struct metal_memory *metal_get_memory_from_address(const uintptr_t address);
/*!
* @brief Get the base address for a memory block
* @param memory The handle for the memory block
* @return The base address of the memory block
*/
__inline__ uintptr_t metal_memory_get_base_address(const struct metal_memory *memory) {
return memory->_base_address;
}
/*!
* @brief Get the size of a memory block
* @param memory The handle for the memory block
* @return The size of the memory block
*/
__inline__ size_t metal_memory_get_size(const struct metal_memory *memory) {
return memory->_size;
}
/*!
* @brief Query if a memory block supports atomic operations
* @param memory The handle for the memory block
* @return nonzero if the memory block supports atomic operations
*/
__inline__ int metal_memory_supports_atomics(const struct metal_memory *memory) {
return memory->_attrs.A;
}
/*!
* @brief Query if a memory block is cacheable
* @param memory The handle for the memory block
* @return nonzero if the memory block is cachable
*/
__inline__ int metal_memory_is_cachable(const struct metal_memory *memory) {
return memory->_attrs.C;
}
#endif /* METAL__MEMORY_H */

View file

@ -0,0 +1,209 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__PMP_H
#define METAL__PMP_H
/*!
* @file metal/pmp.h
*
* @brief API for Configuring Physical Memory Protection on RISC-V Cores
*
* The Physical Memory Protection (PMP) interface on RISC-V cores
* is a form of memory protection unit which allows for a finite number
* of physical memory regions to be configured with certain access
* permissions.
*
* Additional information about the use and configuration rules for PMPs
* can be found by reading the RISC-V Privileged Architecture Specification.
*/
#include <stddef.h>
#include <metal/machine.h>
struct metal_pmp;
/*!
* @brief Set of available PMP addressing modes
*/
enum metal_pmp_address_mode {
/*! @brief Disable the PMP region */
METAL_PMP_OFF = 0,
/*! @brief Use Top-of-Range mode */
METAL_PMP_TOR = 1,
/*! @brief Use naturally-aligned 4-byte region mode */
METAL_PMP_NA4 = 2,
/*! @brief Use naturally-aligned power-of-two mode */
METAL_PMP_NAPOT = 3
};
/*!
* @brief Configuration for a PMP region
*/
struct metal_pmp_config {
/*! @brief Sets whether reads to the PMP region succeed */
unsigned int R : 1;
/*! @brief Sets whether writes to the PMP region succeed */
unsigned int W : 1;
/*! @brief Sets whether the PMP region is executable */
unsigned int X : 1;
/*! @brief Sets the addressing mode of the PMP region */
enum metal_pmp_address_mode A : 2;
int _pad : 2;
/*! @brief Sets whether the PMP region is locked */
enum metal_pmp_locked {
METAL_PMP_UNLOCKED = 0,
METAL_PMP_LOCKED = 1
} L : 1;
};
/*!
* @brief A handle for the PMP device
*/
struct metal_pmp {
/* The minimum granularity of the PMP region. Set by metal_pmp_init */
uintptr_t _granularity[METAL_MAX_CORES];
};
/*!
* @brief Get the PMP device handle
*/
struct metal_pmp *metal_pmp_get_device(void);
/*!
* @brief Get the number of pmp regions for the hartid
*/
int metal_pmp_num_regions(int hartid);
/*!
* @brief Initialize the PMP
* @param pmp The PMP device handle to be initialized
*
* The PMP initialization routine is optional and may be called as many times
* as is desired. The effect of the initialization routine is to attempt to set
* all regions to unlocked and disabled, as well as to clear the X, W, and R
* bits. Only the pmp configuration of the hart which executes the routine will
* be affected.
*
* If any regions are fused to preset values by the implementation or locked,
* those PMP regions will silently remain uninitialized.
*/
void metal_pmp_init(struct metal_pmp *pmp);
/*!
* @brief Configure a PMP region
* @param pmp The PMP device handle
* @param region The PMP region to configure
* @param config The desired configuration of the PMP region
* @param address The desired address of the PMP region
* @return 0 upon success
*/
int metal_pmp_set_region(struct metal_pmp *pmp, unsigned int region, struct metal_pmp_config config, size_t address);
/*!
* @brief Get the configuration for a PMP region
* @param pmp The PMP device handle
* @param region The PMP region to read
* @param config Variable to store the PMP region configuration
* @param address Variable to store the PMP region address
* @return 0 if the region is read successfully
*/
int metal_pmp_get_region(struct metal_pmp *pmp, unsigned int region, struct metal_pmp_config *config, size_t *address);
/*!
* @brief Lock a PMP region
* @param pmp The PMP device handle
* @param region The PMP region to lock
* @return 0 if the region is successfully locked
*/
int metal_pmp_lock(struct metal_pmp *pmp, unsigned int region);
/*!
* @brief Set the address for a PMP region
* @param pmp The PMP device handle
* @param region The PMP region to set
* @param address The desired address of the PMP region
* @return 0 if the address is successfully set
*/
int metal_pmp_set_address(struct metal_pmp *pmp, unsigned int region, size_t address);
/*!
* @brief Get the address of a PMP region
* @param pmp The PMP device handle
* @param region The PMP region to read
* @return The address of the PMP region, or 0 if the region could not be read
*/
size_t metal_pmp_get_address(struct metal_pmp *pmp, unsigned int region);
/*!
* @brief Set the addressing mode of a PMP region
* @param pmp The PMP device handle
* @param region The PMP region to set
* @param mode The PMP addressing mode to set
* @return 0 if the addressing mode is successfully set
*/
int metal_pmp_set_address_mode(struct metal_pmp *pmp, unsigned int region, enum metal_pmp_address_mode mode);
/*!
* @brief Get the addressing mode of a PMP region
* @param pmp The PMP device handle
* @param region The PMP region to read
* @return The address mode of the PMP region
*/
enum metal_pmp_address_mode metal_pmp_get_address_mode(struct metal_pmp *pmp, unsigned int region);
/*!
* @brief Set the executable bit for a PMP region
* @param pmp The PMP device handle
* @param region The PMP region to set
* @param X The desired value of the executable bit
* @return 0 if the executable bit is successfully set
*/
int metal_pmp_set_executable(struct metal_pmp *pmp, unsigned int region, int X);
/*!
* @brief Get the executable bit for a PMP region
* @param pmp The PMP device handle
* @param region The PMP region to read
* @return the value of the executable bit
*/
int metal_pmp_get_executable(struct metal_pmp *pmp, unsigned int region);
/*!
* @brief Set the writable bit for a PMP region
* @param pmp The PMP device handle
* @param region The PMP region to set
* @param W The desired value of the writable bit
* @return 0 if the writable bit is successfully set
*/
int metal_pmp_set_writeable(struct metal_pmp *pmp, unsigned int region, int W);
/*!
* @brief Get the writable bit for a PMP region
* @param pmp The PMP device handle
* @param region The PMP region to read
* @return the value of the writable bit
*/
int metal_pmp_get_writeable(struct metal_pmp *pmp, unsigned int region);
/*!
* @brief Set the readable bit for a PMP region
* @param pmp The PMP device handle
* @param region The PMP region to set
* @param R The desired value of the readable bit
* @return 0 if the readable bit is successfully set
*/
int metal_pmp_set_readable(struct metal_pmp *pmp, unsigned int region, int R);
/*!
* @brief Set the readable bit for a PMP region
* @param pmp The PMP device handle
* @param region The PMP region to read
* @return the value of the readable bit
*/
int metal_pmp_get_readable(struct metal_pmp *pmp, unsigned int region);
#endif

View file

@ -0,0 +1,122 @@
/* Copyright 2019 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__PRIVILEGE_H
#define METAL__PRIVILEGE_H
/*!
* @file metal/privilege.h
*
* @brief API for manipulating the privilege mode of a RISC-V system
*
* Additional information about privilege modes on RISC-V systems can be found
* by reading the RISC-V Privileged Architecture Specification v1.10.
*/
#include <stdint.h>
enum metal_privilege_mode {
METAL_PRIVILEGE_USER = 0,
METAL_PRIVILEGE_SUPERVISOR = 1,
METAL_PRIVILEGE_MACHINE = 3,
};
#if __riscv_xlen == 32
typedef uint32_t metal_xreg_t;
#elif __riscv_xlen == 64
typedef uint64_t metal_xreg_t;
#endif
#if __riscv_flen == 32
typedef uint32_t metal_freg_t;
#elif __riscv_flen == 64
typedef uint64_t metal_freg_t;
#endif
struct metal_register_file {
metal_xreg_t ra;
metal_xreg_t sp;
metal_xreg_t gp;
metal_xreg_t tp;
metal_xreg_t t0;
metal_xreg_t t1;
metal_xreg_t t2;
metal_xreg_t s0;
metal_xreg_t s1;
metal_xreg_t a0;
metal_xreg_t a1;
metal_xreg_t a2;
metal_xreg_t a3;
metal_xreg_t a4;
metal_xreg_t a5;
#ifndef __riscv_32e
metal_xreg_t a6;
metal_xreg_t a7;
metal_xreg_t s2;
metal_xreg_t s3;
metal_xreg_t s4;
metal_xreg_t s5;
metal_xreg_t s6;
metal_xreg_t s7;
metal_xreg_t s8;
metal_xreg_t s9;
metal_xreg_t s10;
metal_xreg_t s11;
metal_xreg_t t3;
metal_xreg_t t4;
metal_xreg_t t5;
metal_xreg_t t6;
#endif /* __riscv_32e */
#ifdef __riscv_flen
metal_freg_t ft0;
metal_freg_t ft1;
metal_freg_t ft2;
metal_freg_t ft3;
metal_freg_t ft4;
metal_freg_t ft5;
metal_freg_t ft6;
metal_freg_t ft7;
metal_freg_t fs0;
metal_freg_t fs1;
metal_freg_t fa0;
metal_freg_t fa1;
metal_freg_t fa2;
metal_freg_t fa3;
metal_freg_t fa4;
metal_freg_t fa5;
metal_freg_t fa6;
metal_freg_t fa7;
metal_freg_t fs2;
metal_freg_t fs3;
metal_freg_t fs4;
metal_freg_t fs5;
metal_freg_t fs6;
metal_freg_t fs7;
metal_freg_t fs8;
metal_freg_t fs9;
metal_freg_t fs10;
metal_freg_t fs11;
metal_freg_t ft8;
metal_freg_t ft9;
metal_freg_t ft10;
metal_freg_t ft11;
#endif /* __riscv_flen */
};
typedef void (*metal_privilege_entry_point_t)(void);
void metal_privilege_drop_to_mode(enum metal_privilege_mode mode,
struct metal_register_file regfile,
metal_privilege_entry_point_t entry_point);
#endif

View file

@ -0,0 +1,127 @@
/* Copyright 2019 SiFive, Inc. */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__RTC_H
#define METAL__RTC_H
#include <stdint.h>
/*!
* @file rtc.h
* @brief API for Real-Time Clocks
*/
struct metal_rtc;
/*!
* @brief List of RTC run behaviors
*/
enum metal_rtc_run_option {
METAL_RTC_STOP = 0,
METAL_RTC_RUN,
};
struct metal_rtc_vtable {
uint64_t (*get_rate)(const struct metal_rtc *const rtc);
uint64_t (*set_rate)(const struct metal_rtc *const rtc, const uint64_t rate);
uint64_t (*get_compare)(const struct metal_rtc *const rtc);
uint64_t (*set_compare)(const struct metal_rtc *const rtc, const uint64_t compare);
uint64_t (*get_count)(const struct metal_rtc *const rtc);
uint64_t (*set_count)(const struct metal_rtc *const rtc, const uint64_t count);
int (*run)(const struct metal_rtc *const rtc, const enum metal_rtc_run_option option);
struct metal_interrupt *(*get_interrupt)(const struct metal_rtc *const rtc);
int (*get_interrupt_id)(const struct metal_rtc *const rtc);
};
/*!
* @brief Handle for a Real-Time Clock
*/
struct metal_rtc {
const struct metal_rtc_vtable *vtable;
};
/*!
* @brief Get the rate of the RTC
* @return The rate in Hz
*/
inline uint64_t metal_rtc_get_rate(const struct metal_rtc *const rtc) {
return rtc->vtable->get_rate(rtc);
}
/*!
* @brief Set (if possible) the rate of the RTC
* @return The new rate of the RTC (not guaranteed to be the same as requested)
*/
inline uint64_t metal_rtc_set_rate(const struct metal_rtc *const rtc, const uint64_t rate) {
return rtc->vtable->set_rate(rtc, rate);
}
/*!
* @brief Get the compare value of the RTC
* @return The compare value
*/
inline uint64_t metal_rtc_get_compare(const struct metal_rtc *const rtc) {
return rtc->vtable->get_compare(rtc);
}
/*!
* @brief Set the compare value of the RTC
* @return The set compare value (not guaranteed to be exactly the requested value)
*
* The RTC device might impose limits on the maximum compare value or the granularity
* of the compare value.
*/
inline uint64_t metal_rtc_set_compare(const struct metal_rtc *const rtc, const uint64_t compare) {
return rtc->vtable->set_compare(rtc, compare);
}
/*!
* @brief Get the current count of the RTC
* @return The count
*/
inline uint64_t metal_rtc_get_count(const struct metal_rtc *const rtc) {
return rtc->vtable->get_count(rtc);
}
/*!
* @brief Set the current count of the RTC
* @return The set value of the count (not guaranteed to be exactly the requested value)
*
* The RTC device might impose limits on the maximum value of the count
*/
inline uint64_t metal_rtc_set_count(const struct metal_rtc *const rtc, const uint64_t count) {
return rtc->vtable->set_count(rtc, count);
}
/*!
* @brief Start or stop the RTC
* @return 0 if the RTC was successfully started/stopped
*/
inline int metal_rtc_run(const struct metal_rtc *const rtc, const enum metal_rtc_run_option option) {
return rtc->vtable->run(rtc, option);
}
/*!
* @brief Get the interrupt handle for the RTC compare
* @return The interrupt handle
*/
inline struct metal_interrupt *metal_rtc_get_interrupt(const struct metal_rtc *const rtc) {
return rtc->vtable->get_interrupt(rtc);
}
/*!
* @brief Get the interrupt ID for the RTC compare
* @return The interrupt ID
*/
inline int metal_rtc_get_interrupt_id(const struct metal_rtc *const rtc) {
return rtc->vtable->get_interrupt_id(rtc);
}
/*!
* @brief Get the handle for an RTC by index
* @return The RTC handle, or NULL if none is available at that index
*/
struct metal_rtc *metal_rtc_get_device(int index);
#endif

View file

@ -0,0 +1,36 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__SHUTDOWN_H
#define METAL__SHUTDOWN_H
/*!
* @file shutdown.h
* @brief API for shutting down a machine
*/
struct __metal_shutdown;
struct __metal_shutdown_vtable {
void (*exit)(const struct __metal_shutdown *sd, int code) __attribute__((noreturn));
};
struct __metal_shutdown {
const struct __metal_shutdown_vtable *vtable;
};
__inline__ void __metal_shutdown_exit(const struct __metal_shutdown *sd, int code) __attribute__((noreturn));
__inline__ void __metal_shutdown_exit(const struct __metal_shutdown *sd, int code) { sd->vtable->exit(sd, code); }
/*!
* @brief The public METAL shutdown interface
*
* Shuts down the machine, if the machine enables an interface for
* shutting down. When no interface is provided, will cause the machine
* to spin indefinitely.
*
* @param code The return code to set. 0 indicates program success.
*/
void metal_shutdown(int code) __attribute__((noreturn));
#endif

View file

@ -0,0 +1,90 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__SPI_H
#define METAL__SPI_H
struct metal_spi;
/*! @brief The configuration for a SPI transfer */
struct metal_spi_config {
/*! @brief The protocol for the SPI transfer */
enum {
METAL_SPI_SINGLE,
METAL_SPI_DUAL,
METAL_SPI_QUAD
} protocol;
/*! @brief The polarity of the SPI transfer, equivalent to CPOL */
unsigned int polarity : 1;
/*! @brief The phase of the SPI transfer, equivalent to CPHA */
unsigned int phase : 1;
/*! @brief The endianness of the SPI transfer */
unsigned int little_endian : 1;
/*! @brief The active state of the chip select line */
unsigned int cs_active_high : 1;
/*! @brief The chip select ID to activate for the SPI transfer */
unsigned int csid;
/*! @brief The spi command frame number (cycles = num * frame_len) */
unsigned int cmd_num;
/*! @brief The spi address frame number */
unsigned int addr_num;
/*! @brief The spi dummy frame number */
unsigned int dummy_num;
/*! @brief The Dual/Quad spi mode selection.*/
enum {
MULTI_WIRE_ALL,
MULTI_WIRE_DATA_ONLY,
MULTI_WIRE_ADDR_DATA
} multi_wire;
};
struct metal_spi_vtable {
void (*init)(struct metal_spi *spi, int baud_rate);
int (*transfer)(struct metal_spi *spi, struct metal_spi_config *config, size_t len, char *tx_buf, char *rx_buf);
int (*get_baud_rate)(struct metal_spi *spi);
int (*set_baud_rate)(struct metal_spi *spi, int baud_rate);
};
/*! @brief A handle for a SPI device */
struct metal_spi {
const struct metal_spi_vtable *vtable;
};
/*! @brief Get a handle for a SPI device
* @param device_num The index of the desired SPI device
* @return A handle to the SPI device, or NULL if the device does not exist*/
struct metal_spi *metal_spi_get_device(unsigned int device_num);
/*! @brief Initialize a SPI device with a certain baud rate
* @param spi The handle for the SPI device to initialize
* @param baud_rate The baud rate to set the SPI device to
*/
__inline__ void metal_spi_init(struct metal_spi *spi, int baud_rate) { spi->vtable->init(spi, baud_rate); }
/*! @brief Perform a SPI transfer
* @param spi The handle for the SPI device to perform the transfer
* @param config The configuration for the SPI transfer.
* @param len The number of bytes to transfer
* @param tx_buf The buffer to send over the SPI bus. Must be len bytes long. If NULL, the SPI will transfer the value 0.
* @param rx_buf The buffer to receive data into. Must be len bytes long. If NULL, the SPI will ignore received bytes.
* @return 0 if the transfer succeeds
*/
__inline__ int metal_spi_transfer(struct metal_spi *spi, struct metal_spi_config *config, size_t len, char *tx_buf, char *rx_buf) {
return spi->vtable->transfer(spi, config, len, tx_buf, rx_buf);
}
/*! @brief Get the current baud rate of the SPI device
* @param spi The handle for the SPI device
* @return The baud rate in Hz
*/
__inline__ int metal_spi_get_baud_rate(struct metal_spi *spi) { return spi->vtable->get_baud_rate(spi); }
/*! @brief Set the current baud rate of the SPI device
* @param spi The handle for the SPI device
* @param baud_rate The desired baud rate of the SPI device
* @return 0 if the baud rate is successfully changed
*/
__inline__ int metal_spi_set_baud_rate(struct metal_spi *spi, int baud_rate) { return spi->vtable->set_baud_rate(spi, baud_rate); }
#endif

View file

@ -0,0 +1,51 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__SWITCH_H
#define METAL__SWITCH_H
/*!
* @file switch.h
* @brief API for reading toggle switches
*/
#include <metal/interrupt.h>
struct metal_switch;
struct metal_switch_vtable {
int (*switch_exist)(struct metal_switch *sw, char *label);
struct metal_interrupt* (*interrupt_controller)(struct metal_switch *sw);
int (*get_interrupt_id)(struct metal_switch *sw);
};
/*!
* @brief A handle for a switch
*/
struct metal_switch {
const struct metal_switch_vtable *vtable;
};
/*!
* @brief Get a handle for a switch
* @param label The DeviceTree label for the desired switch
* @return A handle to the switch, or NULL if none is found for the requested label
*/
struct metal_switch* metal_switch_get(char *label);
/*!
* @brief Get the interrupt controller for a switch
* @param sw The handle for the switch
* @return The interrupt controller handle
*/
__inline__ struct metal_interrupt*
metal_switch_interrupt_controller(struct metal_switch *sw) { return sw->vtable->interrupt_controller(sw); }
/*!
* @brief Get the interrupt id for a switch
* @param sw The handle for the switch
* @return The interrupt ID for the switch
*/
__inline__ int metal_switch_get_interrupt_id(struct metal_switch *sw) { return sw->vtable->get_interrupt_id(sw); }
#endif

View file

@ -0,0 +1,18 @@
/* Copyright 2019 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__TIME_H
#define METAL__TIME_H
#include <time.h>
/*!
* @file time.h
* @brief API for dealing with time
*/
int metal_gettimeofday(struct timeval *tp, void *tzp);
time_t metal_time(void);
#endif

View file

@ -0,0 +1,36 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__TIMER_H
#define METAL__TIMER_H
/*!
* @file timer.h
* @brief API for reading and manipulating the machine timer
*/
/*!
* @brief Read the machine cycle count
* @param hartid The hart ID to read the cycle count of
* @param cyclecount The variable to hold the value
* @return 0 upon success
*/
int metal_timer_get_cyclecount(int hartid, unsigned long long *cyclecount);
/*!
* @brief Get the machine timebase frequency
* @param hartid The hart ID to read the timebase of
* @param timebase The variable to hold the value
* @return 0 upon success
*/
int metal_timer_get_timebase_frequency(int hartid, unsigned long long *timebase);
/*!
* @brief Set the machine timer tick interval in seconds
* @param hartid The hart ID to read the timebase of
* @param second The number of seconds to set the tick interval to
* @return 0 upon success
*/
int metal_timer_set_tick(int hartid, int second);
#endif

View file

@ -0,0 +1,52 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__TTY_H
#define METAL__TTY_H
/*!
* @file tty.h
* @brief API for emulated serial teriminals
*/
/*!
* @brief Write a character to the default output device
*
* Write a character to the default output device, which for most
* targets is the UART serial port.
*
* putc() does CR/LF mapping.
* putc_raw() does not.
*
* @param c The character to write to the terminal
* @return 0 on success, or -1 on failure.
*/
int metal_tty_putc(int c);
/*!
* @brief Write a raw character to the default output device
*
* Write a character to the default output device, which for most
* targets is the UART serial port.
*
* putc() does CR/LF mapping.
* putc_raw() does not.
*
* @param c The character to write to the terminal
* @return 0 on success, or -1 on failure.
*/
int metal_tty_putc_raw(int c);
/*!
* @brief Get a byte from the default output device
*
* The default output device, is typically the UART serial port.
*
* This call is non-blocking, if nothing is ready c==-1
* if something is ready, then c=[0x00 to 0xff] byte value.
*
* @return 0 on success, or -1 on failure.
*/
int metal_tty_getc(int *c);
#endif

View file

@ -0,0 +1,106 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__UART_H
#define METAL__UART_H
/*!
* @file uart.h
* @brief API for UART serial ports
*/
#include <metal/interrupt.h>
struct metal_uart;
#undef getc
#undef putc
struct metal_uart_vtable {
void (*init)(struct metal_uart *uart, int baud_rate);
int (*putc)(struct metal_uart *uart, int c);
int (*txready)(struct metal_uart *uart);
int (*getc)(struct metal_uart *uart, int *c);
int (*get_baud_rate)(struct metal_uart *uart);
int (*set_baud_rate)(struct metal_uart *uart, int baud_rate);
struct metal_interrupt* (*controller_interrupt)(struct metal_uart *uart);
int (*get_interrupt_id)(struct metal_uart *uart);
};
/*!
* @brief Handle for a UART serial device
*/
struct metal_uart {
const struct metal_uart_vtable *vtable;
};
/*!
* @brief Initialize UART device
* Initialize the UART device described by the UART handle. This function must be called before any
* other method on the UART can be invoked. It is invalid to initialize a UART more than once.
*
* @param uart The UART device handle
* @param baud_rate the baud rate to set the UART to
*/
__inline__ void metal_uart_init(struct metal_uart *uart, int baud_rate) { uart->vtable->init(uart, baud_rate); }
/*!
* @brief Output a character over the UART
* @param uart The UART device handle
* @param c The character to send over the UART
* @return 0 upon success
*/
__inline__ int metal_uart_putc(struct metal_uart *uart, int c) { return uart->vtable->putc(uart, c); }
/*!
* @brief Test, determine if tx output is blocked(full/busy)
* @param uart The UART device handle
* @return 0 not blocked
*/
__inline__ int metal_uart_txready(struct metal_uart *uart) { return uart->vtable->txready(uart); }
/*!
* @brief Read a character sent over the UART
* @param uart The UART device handle
* @param c The varible to hold the read character
* @return 0 upon success
*
* If "c == -1" no char was ready.
* If "c != -1" then C == byte value (0x00 to 0xff)
*/
__inline__ int metal_uart_getc(struct metal_uart *uart, int *c) { return uart->vtable->getc(uart, c); }
/*!
* @brief Get the baud rate of the UART peripheral
* @param uart The UART device handle
* @return The current baud rate of the UART
*/
__inline__ int metal_uart_get_baud_rate(struct metal_uart *uart) { return uart->vtable->get_baud_rate(uart); }
/*!
* @brief Set the baud rate of the UART peripheral
* @param uart The UART device handle
* @param baud_rate The baud rate to configure
* @return the new baud rate of the UART
*/
__inline__ int metal_uart_set_baud_rate(struct metal_uart *uart, int baud_rate) { return uart->vtable->set_baud_rate(uart, baud_rate); }
/*!
* @brief Get the interrupt controller of the UART peripheral
*
* Get the interrupt controller for the UART peripheral. The interrupt
* controller must be initialized before any interrupts can be registered
* or enabled with it.
*
* @param uart The UART device handle
* @return The handle for the UART interrupt controller
*/
__inline__ struct metal_interrupt* metal_uart_interrupt_controller(struct metal_uart *uart) { return uart->vtable->controller_interrupt(uart); }
/*!
* @brief Get the interrupt ID of the UART controller
* @param uart The UART device handle
* @return The UART interrupt id
*/
__inline__ int metal_uart_get_interrupt_id(struct metal_uart *uart) { return uart->vtable->get_interrupt_id(uart); }
#endif

View file

@ -0,0 +1,163 @@
/* Copyright 2019 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__WATCHDOG_H
#define METAL__WATCHDOG_H
/*!
* @file watchdog.h
*
* @brief API for configuring watchdog timers
*/
#include <metal/interrupt.h>
struct metal_watchdog;
/*!
* @brief List of watchdog timer count behaviors
*/
enum metal_watchdog_run_option {
METAL_WATCHDOG_STOP = 0, /*!< Stop the watchdog */
METAL_WATCHDOG_RUN_ALWAYS, /*!< Run the watchdog continuously, even during sleep */
METAL_WATCHDOG_RUN_AWAKE, /*!< Run the watchdog only while the CPU is awake */
};
/*!
* @brief List of behaviors when a watchdog triggers
*/
enum metal_watchdog_result {
METAL_WATCHDOG_NO_RESULT = 0, /*!< When the watchdog triggers, do nothing */
METAL_WATCHDOG_INTERRUPT, /*!< When the watchdog triggers, fire an interrupt */
METAL_WATCHDOG_FULL_RESET, /*!< When the watchdog triggers, cause a full system reset */
};
struct metal_watchdog_vtable {
int (*feed)(const struct metal_watchdog *const wdog);
long int (*get_rate)(const struct metal_watchdog *const wdog);
long int (*set_rate)(const struct metal_watchdog *const wdog, const long int rate);
long int (*get_timeout)(const struct metal_watchdog *const wdog);
long int (*set_timeout)(const struct metal_watchdog *const wdog, const long int timeout);
int (*set_result)(const struct metal_watchdog *const wdog,
const enum metal_watchdog_result result);
int (*run)(const struct metal_watchdog *const wdog,
const enum metal_watchdog_run_option option);
struct metal_interrupt *(*get_interrupt)(const struct metal_watchdog *const wdog);
int (*get_interrupt_id)(const struct metal_watchdog *const wdog);
int (*clear_interrupt)(const struct metal_watchdog *const wdog);
};
/*!
* @brief Handle for a Watchdog Timer
*/
struct metal_watchdog {
const struct metal_watchdog_vtable *vtable;
};
/*!
* @brief Feed the watchdog timer
*/
inline int metal_watchdog_feed(const struct metal_watchdog *const wdog)
{
return wdog->vtable->feed(wdog);
}
/*!
* @brief Get the rate of the watchdog timer in Hz
*
* @return the rate of the watchdog timer
*/
inline long int metal_watchdog_get_rate(const struct metal_watchdog *const wdog)
{
return wdog->vtable->get_rate(wdog);
}
/*!
* @brief Set the rate of the watchdog timer in Hz
*
* There is no guarantee that the new rate will match the requested rate.
*
* @return the new rate of the watchdog timer
*/
inline long int metal_watchdog_set_rate(const struct metal_watchdog *const wdog, const long int rate)
{
return wdog->vtable->set_rate(wdog, rate);
}
/*!
* @brief Get the timeout of the watchdog timer
*
* @return the watchdog timeout value
*/
inline long int metal_watchdog_get_timeout(const struct metal_watchdog *const wdog)
{
return wdog->vtable->get_timeout(wdog);
}
/*!
* @brief Set the timeout of the watchdog timer
*
* The set rate will be the minimimum of the requested and maximum supported rates.
*
* @return the new watchdog timeout value
*/
inline long int metal_watchdog_set_timeout(const struct metal_watchdog *const wdog, const long int timeout)
{
return wdog->vtable->set_timeout(wdog, timeout);
}
/*!
* @brief Sets the result behavior of a watchdog timer timeout
*
* @return 0 if the requested result behavior is supported
*/
inline int metal_watchdog_set_result(const struct metal_watchdog *const wdog,
const enum metal_watchdog_result result)
{
return wdog->vtable->set_result(wdog, result);
}
/*!
* @brief Set the run behavior of the watchdog
*
* Used to enable/disable the watchdog timer
*
* @return 0 if the watchdog was successfully started/stopped
*/
inline int metal_watchdog_run(const struct metal_watchdog *const wdog,
const enum metal_watchdog_run_option option)
{
return wdog->vtable->run(wdog, option);
}
/*!
* @brief Get the interrupt controller for the watchdog interrupt
*/
inline struct metal_interrupt *metal_watchdog_get_interrupt(const struct metal_watchdog *const wdog)
{
return wdog->vtable->get_interrupt(wdog);
}
/*!
* @Brief Get the interrupt id for the watchdog interrupt
*/
inline int metal_watchdog_get_interrupt_id(const struct metal_watchdog *const wdog)
{
return wdog->vtable->get_interrupt_id(wdog);
}
/*!
* @brief Clear the watchdog interrupt
*/
inline int metal_watchdog_clear_interrupt(const struct metal_watchdog *const wdog)
{
return wdog->vtable->clear_interrupt(wdog);
}
/*!
* @brief Get a watchdog handle
*/
struct metal_watchdog *metal_watchdog_get_device(const int index);
#endif /* METAL__WATCHDOG_H */