diff options
Diffstat (limited to 'FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal')
132 files changed, 10653 insertions, 0 deletions
diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/doc/link_to_docs_in_github.url b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/doc/link_to_docs_in_github.url new file mode 100644 index 000000000..f59b1cedd --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/doc/link_to_docs_in_github.url @@ -0,0 +1,5 @@ +[{000214A0-0000-0000-C000-000000000046}]
+Prop3=19,11
+[InternetShortcut]
+IDList=
+URL=https://github.com/sifive/freedom-metal-docs
diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/crt0.S b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/crt0.S new file mode 100644 index 000000000..920ee4b9f --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/crt0.S @@ -0,0 +1,246 @@ +/* Copyright (c) 2017-2018 SiFive Inc. All rights reserved. + + This copyrighted material is made available to anyone wishing to use, + modify, copy, or redistribute it subject to the terms and conditions + of the FreeBSD License. This program is distributed in the hope that + it will be useful, but WITHOUT ANY WARRANTY expressed or implied, + including the implied warranties of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. A copy of this license is available at + http://www.opensource.org/licenses. +*/ + +/* crt0.S: Entry point for RISC-V METAL programs. */ + +.section .text.libgloss.start +.global _start +.type _start, @function + + /* _start is defined by the METAL to have been called with the following + * arguments: + * a0: the hart ID of the currently executing hart. Harts can start at + * any arbitrary point, it's the C library's job to ensure the code is + * safe. + * a1: a pointer to a description of the machine on which this code is + * currently executing. This is probably 0 on an embedded system + * because they tend to not be dynamically portable. As such, newlib + * ignores this argument. + * a2: a pointer to a function that must be run after the envirnoment has + * been initialized, but before user code can be expected to be run. + * If this is 0 then there is no function to be run. */ +_start: +.cfi_startproc +.cfi_undefined ra + + /* This is a bit funky: it's not usually sane for _start to return, but in + * this case we actually want to in order to signal an error to the METAL. */ + mv s0, ra + + /* Before doing anything we must initialize the global pointer, as we cannot + * safely perform any access that may be relaxed without GP being set. This + * is done with relaxation disabled to avoid relaxing the address calculation + * to just "addi gp, gp, 0". */ +.option push +.option norelax + la gp, __global_pointer$ +.option pop + + /* The METAL is designed for a bare-metal environment and therefor is expected + * to define its own stack pointer. We also align the stack pointer here + * because the only RISC-V ABI that's currently defined mandates 16-byte + * stack alignment. */ + la sp, _sp + + /* Increment by hartid number of stack sizes */ + li t0, 0 + la t1, __stack_size +1: + beq t0, a0, 1f + add sp, sp, t1 + addi t0, t0, 1 + j 1b +1: + andi sp, sp, -16 + + /* If we're not hart 0, skip the initialization work */ + la t0, __metal_boot_hart + bne a0, t0, _skip_init + + /* Embedded systems frequently require relocating the data segment before C + * code can be run -- for example, the data segment may exist in flash upon + * boot and then need to get relocated into a non-persistant writable memory + * before C code can execute. If this is the case we do so here. This step + * is optional: if the METAL provides an environment in which this relocation + * is not necessary then it must simply set metal_segment_data_source_start to + * be equal to metal_segment_data_target_start. */ + la t0, metal_segment_data_source_start + la t1, metal_segment_data_target_start + la t2, metal_segment_data_target_end + + beq t0, t1, 2f + bge t1, t2, 2f + +1: +#if __riscv_xlen == 32 + lw a0, 0(t0) + addi t0, t0, 4 + sw a0, 0(t1) + addi t1, t1, 4 + blt t1, t2, 1b +#else + ld a0, 0(t0) + addi t0, t0, 8 + sd a0, 0(t1) + addi t1, t1, 8 + blt t1, t2, 1b +#endif +2: + + /* Copy the ITIM section */ + la t0, metal_segment_itim_source_start + la t1, metal_segment_itim_target_start + la t2, metal_segment_itim_target_end + + beq t0, t1, 2f + bge t1, t2, 2f + +1: +#if __riscv_xlen == 32 + lw a0, 0(t0) + addi t0, t0, 4 + sw a0, 0(t1) + addi t1, t1, 4 + blt t1, t2, 1b +#else + ld a0, 0(t0) + addi t0, t0, 8 + sd a0, 0(t1) + addi t1, t1, 8 + blt t1, t2, 1b +#endif +2: + + /* Fence all subsequent instruction fetches until after the ITIM writes + complete */ + fence.i + + /* Zero the BSS segment. */ + la t1, metal_segment_bss_target_start + la t2, metal_segment_bss_target_end + + bge t1, t2, 2f + +1: +#if __riscv_xlen == 32 + sw x0, 0(t1) + addi t1, t1, 4 + blt t1, t2, 1b +#else + sd x0, 0(t1) + addi t1, t1, 8 + blt t1, t2, 1b +#endif +2: + + /* At this point we're in an environment that can execute C code. The first + * thing to do is to make the callback to the parent environment if it's been + * requested to do so. */ + beqz a2, 1f + jalr a2 +1: + + /* The RISC-V port only uses new-style constructors and destructors. */ + la a0, __libc_fini_array + call atexit + call __libc_init_array + +_skip_init: + + /* Synchronize harts so that secondary harts wait until hart 0 finishes + initializing */ + call __metal_synchronize_harts + + /* Check RISC-V isa and enable FS bits if Floating Point architecture. */ + csrr a5, misa + li a4, 0x10028 + and a5, a5, a4 + beqz a5, 1f + csrr a5, mstatus + lui a4, 0x2 + or a5, a5, a4 + csrw mstatus, a5 + csrwi fcsr, 0 +1: + + /* This is a C runtime, so main() is defined to have some arguments. Since + * there's nothing sane the METAL can pass we don't bother with that but + * instead just setup as close to a NOP as we can. */ + li a0, 1 /* argc=1 */ + la a1, argv /* argv = {"libgloss", NULL} */ + la a2, envp /* envp = {NULL} */ + call secondary_main + + /* Call exit to handle libc's cleanup routines. Under normal contains this + * shouldn't even get called, but I'm still not using a tail call here + * because returning to the METAL is the right thing to do in pathological + * situations. */ + call exit + + /* And here's where we return. Again, it's a bit odd but the METAL defines + * this as a bad idea (ie, as opposed to leaving it undefined) and at this + * point it's really the only thing left to do. */ + mv ra, s0 + ret + +.cfi_endproc + +/* RISC-V systems always use __libc_{init,fini}_array, but for compatibility we + * define _{init,fini} to do nothing. */ +.global _init +.type _init, @function +.global _fini +.type _fini, @function +_init: +_fini: + ret +.size _init, .-_init +.size _fini, .-_fini + +/* By default, secondary_main will cause secondary harts to spin forever. + * Users can redefine secondary_main themselves to run code on secondary harts */ +.weak secondary_main +.global secondary_main +.type secondary_main, @function + +secondary_main: + addi sp, sp, -16 +#if __riscv_xlen == 32 + sw ra, 4(sp) +#else + sd ra, 8(sp) +#endif + csrr t0, mhartid + la t1, __metal_boot_hart + beq t0, t1, 2f +1: + wfi + j 1b +2: + call main +#if __riscv_xlen == 32 + lw ra, 4(sp) +#else + ld ra, 8(sp) +#endif + addi sp, sp, 16 + ret + +/* This shim allows main() to be passed a set of arguments that can satisfy the + * requirements of the C API. */ +.section .rodata.libgloss.start +argv: +.dc.a name +envp: +.dc.a 0 +name: +.asciz "libgloss" + diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/nanosleep.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/nanosleep.c new file mode 100644 index 000000000..8be22104e --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/nanosleep.c @@ -0,0 +1,9 @@ +#include <errno.h> +#include <sys/time.h> + +int +nanosleep(const struct timespec *rqtp, struct timespec *rmtp) +{ + errno = ENOSYS; + return -1; +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/synchronize_harts.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/synchronize_harts.c new file mode 100644 index 000000000..3e857d1df --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/synchronize_harts.c @@ -0,0 +1,59 @@ +/* Copyright 2019 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine.h> +#include <metal/machine/platform.h> +#include <metal/io.h> +#include <metal/cpu.h> + +#define METAL_REG(base, offset) (((unsigned long)(base) + (offset))) +#define METAL_REGW(base, offset) (__METAL_ACCESS_ONCE((__metal_io_u32 *)METAL_REG((base), (offset)))) +#define METAL_MSIP(base, hart) (METAL_REGW((base),4*(hart))) + +/* + * _synchronize_harts() is called by crt0.S to cause harts > 0 to wait for + * hart 0 to finish copying the datat section, zeroing the BSS, and running + * the libc contstructors. + */ +void _synchronize_harts() { +#if __METAL_DT_MAX_HARTS > 1 + + int hart = metal_cpu_get_current_hartid(); + uintptr_t msip_base = 0; + + /* Get the base address of the MSIP registers */ +#ifdef __METAL_DT_RISCV_CLINT0_HANDLE + msip_base = __metal_driver_sifive_clint0_control_base(__METAL_DT_RISCV_CLINT0_HANDLE); + msip_base += METAL_RISCV_CLINT0_MSIP_BASE; +#elif __METAL_DT_RISCV_CLIC0_HANDLE + msip_base = __metal_driver_sifive_clic0_control_base(__METAL_DT_RISCV_CLIC0_HANDLE); + msip_base += METAL_RISCV_CLIC0_MSIP_BASE; +#else +#warning No handle for CLINT or CLIC found, harts may be unsynchronized after init! +#endif + + /* Disable machine interrupts as a precaution */ + __asm__ volatile("csrc mstatus, %0" :: "r" (METAL_MSTATUS_MIE)); + + if (hart == 0) { + /* Hart 0 waits for all harts to set their MSIP bit */ + for (int i = 1 ; i < __METAL_DT_MAX_HARTS; i++) { + while (METAL_MSIP(msip_base, i) == 0) ; + } + + /* Hart 0 clears everyone's MSIP bit */ + for (int i = 1 ; i < __METAL_DT_MAX_HARTS; i++) { + METAL_MSIP(msip_base, i) = 0; + } + } else { + /* Other harts set their MSIP bit to indicate they're ready */ + METAL_MSIP(msip_base, hart) = 1; + __asm__ volatile ("fence w,rw"); + + /* Wait for hart 0 to clear the MSIP bit */ + while (METAL_MSIP(msip_base, hart) == 1) ; + } + +#endif /* __METAL_DT_MAX_HARTS > 1 */ +} + diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_access.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_access.c new file mode 100644 index 000000000..c0bc1534d --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_access.c @@ -0,0 +1,8 @@ +#include <errno.h> + +int +_access(const char *file, int mode) +{ + errno = ENOSYS; + return -1; +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_chdir.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_chdir.c new file mode 100644 index 000000000..f33d26a44 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_chdir.c @@ -0,0 +1,8 @@ +#include <errno.h> + +int +_chdir(const char *path) +{ + errno = ENOSYS; + return -1; +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_chmod.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_chmod.c new file mode 100644 index 000000000..67412bf7d --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_chmod.c @@ -0,0 +1,9 @@ +#include <errno.h> +#include <sys/types.h> + +int +_chmod(const char *path, mode_t mode) +{ + errno = ENOSYS; + return -1; +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_chown.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_chown.c new file mode 100644 index 000000000..302952eb1 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_chown.c @@ -0,0 +1,9 @@ +#include <sys/types.h> +#include <errno.h> + +int +_chown(const char *path, uid_t owner, gid_t group) +{ + errno = ENOSYS; + return -1; +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_close.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_close.c new file mode 100644 index 000000000..26dd6a59e --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_close.c @@ -0,0 +1,8 @@ +#include <errno.h> + +int +_close(int file) +{ + errno = ENOSYS; + return -1; +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_execve.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_execve.c new file mode 100644 index 000000000..9ae9f7e50 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_execve.c @@ -0,0 +1,8 @@ +#include <errno.h> + +int +_execve(const char *name, char *const argv[], char *const env[]) +{ + errno = ENOMEM; + return -1; +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_exit.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_exit.c new file mode 100644 index 000000000..35f5f1a16 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_exit.c @@ -0,0 +1,8 @@ +#include <metal/shutdown.h> + +void +_exit(int exit_status) +{ + metal_shutdown(exit_status); + while (1); +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_faccessat.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_faccessat.c new file mode 100644 index 000000000..873d52c2e --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_faccessat.c @@ -0,0 +1,8 @@ +#include <errno.h> + +int +_faccessat(int dirfd, const char *file, int mode, int flags) +{ + errno = ENOSYS; + return -1; +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_fork.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_fork.c new file mode 100644 index 000000000..64e67569f --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_fork.c @@ -0,0 +1,8 @@ +#include <errno.h> + +int +_fork() +{ + errno = ENOSYS; + return -1; +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_fstat.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_fstat.c new file mode 100644 index 000000000..fedc28977 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_fstat.c @@ -0,0 +1,9 @@ +#include <errno.h> +#include <sys/stat.h> + +int +_fstat(int file, struct stat *st) +{ + errno = -ENOSYS; + return -1; +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_fstatat.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_fstatat.c new file mode 100644 index 000000000..f2f43bd9e --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_fstatat.c @@ -0,0 +1,9 @@ +#include <errno.h> +#include <sys/stat.h> + +int +_fstatat(int dirfd, const char *file, struct stat *st, int flags) +{ + errno = ENOSYS; + return -1; +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_ftime.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_ftime.c new file mode 100644 index 000000000..65c156398 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_ftime.c @@ -0,0 +1,9 @@ +#include <errno.h> +#include <sys/timeb.h> + +int +_ftime(struct timeb *tp) +{ + errno = ENOSYS; + return -1; +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_getcwd.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_getcwd.c new file mode 100644 index 000000000..82e8404ee --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_getcwd.c @@ -0,0 +1,8 @@ +#include <errno.h> + +char * +_getcwd(char *buf, size_t size) +{ + errno = -ENOSYS; + return NULL; +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_getpid.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_getpid.c new file mode 100644 index 000000000..589ad117c --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_getpid.c @@ -0,0 +1,7 @@ +#include <errno.h> + +int +_getpid() +{ + return 1; +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_gettimeofday.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_gettimeofday.c new file mode 100644 index 000000000..409b2ce2f --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_gettimeofday.c @@ -0,0 +1,21 @@ +#include <errno.h> +#include <metal/timer.h> +#include <sys/time.h> + +int +_gettimeofday(struct timeval *tp, void *tzp) +{ + int rv; + unsigned long long mcc, timebase; + rv = metal_timer_get_cyclecount(0, &mcc); + if (rv != 0) { + return -1; + } + rv = metal_timer_get_timebase_frequency(0, &timebase); + if (rv != 0) { + return -1; + } + tp->tv_sec = mcc / timebase; + tp->tv_usec = mcc % timebase * 1000000 / timebase; + return 0; +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_isatty.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_isatty.c new file mode 100644 index 000000000..dd4f1461b --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_isatty.c @@ -0,0 +1,7 @@ +#include <unistd.h> + +int +_isatty(int file) +{ + return (file == STDOUT_FILENO); +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_kill.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_kill.c new file mode 100644 index 000000000..9003f266f --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_kill.c @@ -0,0 +1,8 @@ +#include <errno.h> + +int +_kill(int pid, int sig) +{ + errno = ENOSYS; + return -1; +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_link.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_link.c new file mode 100644 index 000000000..40d5912bc --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_link.c @@ -0,0 +1,7 @@ +#include <errno.h> + +int _link(const char *old_name, const char *new_name) +{ + errno = ENOSYS; + return -1; +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_lseek.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_lseek.c new file mode 100644 index 000000000..d28a781f8 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_lseek.c @@ -0,0 +1,9 @@ +#include <sys/types.h> +#include <errno.h> + +off_t +_lseek(int file, off_t ptr, int dir) +{ + errno = ENOSYS; + return -1; +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_lstat.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_lstat.c new file mode 100644 index 000000000..97a45855f --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_lstat.c @@ -0,0 +1,8 @@ +#include <errno.h> +#include <sys/stat.h> + +int _lstat(const char *file, struct stat *st) +{ + errno = ENOSYS; + return -1; +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_open.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_open.c new file mode 100644 index 000000000..a59f627f0 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_open.c @@ -0,0 +1,8 @@ +#include <errno.h> + +int +_open(const char *name, int flags, int mode) +{ + errno = ENOSYS; + return -1; +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_openat.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_openat.c new file mode 100644 index 000000000..206de3bde --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_openat.c @@ -0,0 +1,8 @@ +#include <errno.h> + +int +_openat(int dirfd, const char *name, int flags, int mode) +{ + errno = ENOSYS; + return -1; +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_read.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_read.c new file mode 100644 index 000000000..15833cabb --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_read.c @@ -0,0 +1,9 @@ +#include <sys/types.h> +#include <errno.h> + +ssize_t +_read(int file, void *ptr, size_t len) +{ + errno = ENOSYS; + return -1; +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_sbrk.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_sbrk.c new file mode 100644 index 000000000..cc01c8ffb --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_sbrk.c @@ -0,0 +1,39 @@ +#include <sys/types.h> + +/* brk is handled entirely within the C library. This limits METAL programs that + * use the C library to be disallowed from dynamically allocating memory + * without talking to the C library, but that sounds like a sane way to go + * about it. Note that there is no error checking anywhere in this file, users + * will simply get the relevant error when actually trying to use the memory + * that's been allocated. */ +extern char metal_segment_heap_target_start; +extern char metal_segment_heap_target_end; +static char *brk = &metal_segment_heap_target_start; + +int +_brk(void *addr) +{ + brk = addr; + return 0; +} + +char * +_sbrk(ptrdiff_t incr) +{ + char *old = brk; + + /* If __heap_size == 0, we can't allocate memory on the heap */ + if(&metal_segment_heap_target_start == &metal_segment_heap_target_end) { + return (void *)-1; + } + + /* Don't move the break past the end of the heap */ + if ((brk + incr) < &metal_segment_heap_target_end) { + brk += incr; + } else { + brk = &metal_segment_heap_target_end; + return (void *)-1; + } + + return old; +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_stat.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_stat.c new file mode 100644 index 000000000..3c2e41910 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_stat.c @@ -0,0 +1,9 @@ +#include <errno.h> +#include <sys/stat.h> + +int +_stat(const char *file, struct stat *st) +{ + errno = ENOSYS; + return -1; +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_sysconf.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_sysconf.c new file mode 100644 index 000000000..452a252ae --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_sysconf.c @@ -0,0 +1,16 @@ +#include <unistd.h> +#include <time.h> + +/* Get configurable system variables. */ + +long +_sysconf(int name) +{ + switch (name) + { + case _SC_CLK_TCK: + return CLOCKS_PER_SEC; + } + + return -1; +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_times.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_times.c new file mode 100644 index 000000000..6beedcb30 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_times.c @@ -0,0 +1,42 @@ +#include <sys/times.h> +#include <sys/time.h> +#include <metal/timer.h> +#include <errno.h> + +extern int _gettimeofday(struct timeval *, void *); + +/* Timing information for current process. From + newlib/libc/include/sys/times.h the tms struct fields are as follows: + + - clock_t tms_utime : user clock ticks + - clock_t tms_stime : system clock ticks + - clock_t tms_cutime : children's user clock ticks + - clock_t tms_cstime : children's system clock ticks + + Since maven does not currently support processes we set both of the + children's times to zero. Eventually we might want to separately + account for user vs system time, but for now we just return the total + number of cycles since starting the program. */ +clock_t +_times(struct tms *buf) +{ + int rv; + // when called for the first time, initialize t0 + static struct timeval t0; + if (t0.tv_sec == 0 && t0.tv_usec == 0) + _gettimeofday (&t0, 0); + + struct timeval t; + _gettimeofday (&t, 0); + + unsigned long long timebase; + rv = metal_timer_get_timebase_frequency(0, &timebase); + if (rv != 0) { + return -1; + } + + long long utime = (t.tv_sec - t0.tv_sec) * 1000000 + (t.tv_usec - t0.tv_usec); + buf->tms_utime = utime * timebase / 1000000; + buf->tms_stime = buf->tms_cstime = buf->tms_cutime = 0; + return 0; +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_unlink.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_unlink.c new file mode 100644 index 000000000..b369d2017 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_unlink.c @@ -0,0 +1,8 @@ +#include <errno.h> + +int +_unlink(const char *name) +{ + errno = ENOSYS; + return -1; +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_utime.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_utime.c new file mode 100644 index 000000000..33d557aa7 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_utime.c @@ -0,0 +1,9 @@ +#include <errno.h> +struct utimbuf; + +int +_utime(const char *path, const struct utimbuf *times) +{ + errno = ENOSYS; + return -1; +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_wait.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_wait.c new file mode 100644 index 000000000..9d459f14c --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_wait.c @@ -0,0 +1,7 @@ +#include <errno.h> + +int _wait(int *status) +{ + errno = ENOSYS; + return -1; +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_write.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_write.c new file mode 100644 index 000000000..bfcf0cb2b --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/gloss/sys_write.c @@ -0,0 +1,19 @@ +#include <metal/tty.h> +#include <sys/types.h> +#include <errno.h> +#include <unistd.h> + +/* Write to a file. */ +ssize_t +_write(int file, const void *ptr, size_t len) +{ + if (file != STDOUT_FILENO) { + errno = ENOSYS; + return -1; + } + + const char *bptr = ptr; + for (size_t i = 0; i < len; ++i) + metal_tty_putc(bptr[i]); + return 0; +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/button.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/button.h new file mode 100644 index 000000000..3ae1c143e --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/button.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/cache.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/cache.h new file mode 100644 index 000000000..bad026480 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/cache.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/clock.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/clock.h new file mode 100644 index 000000000..622fc9470 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/clock.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/compiler.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/compiler.h new file mode 100644 index 000000000..62c0ea975 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/compiler.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/cpu.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/cpu.h new file mode 100644 index 000000000..dbd3dbfb5 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/cpu.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/fixed-clock.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/fixed-clock.h new file mode 100644 index 000000000..2647c5981 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/fixed-clock.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/fixed-factor-clock.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/fixed-factor-clock.h new file mode 100644 index 000000000..936ce8d77 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/fixed-factor-clock.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/riscv_clint0.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/riscv_clint0.h new file mode 100644 index 000000000..08d571e1c --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/riscv_clint0.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/riscv_cpu.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/riscv_cpu.h new file mode 100644 index 000000000..ca91e0a95 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/riscv_cpu.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/riscv_plic0.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/riscv_plic0.h new file mode 100644 index 000000000..159ee6d69 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/riscv_plic0.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_ccache0.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_ccache0.h new file mode 100644 index 000000000..2153cf384 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_ccache0.h @@ -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 + diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_clic0.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_clic0.h new file mode 100644 index 000000000..7fef38d19 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_clic0.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_fe310-g000_hfrosc.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_fe310-g000_hfrosc.h new file mode 100644 index 000000000..d311f0cf2 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_fe310-g000_hfrosc.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_fe310-g000_hfxosc.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_fe310-g000_hfxosc.h new file mode 100644 index 000000000..b86926fba --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_fe310-g000_hfxosc.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_fe310-g000_lfrosc.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_fe310-g000_lfrosc.h new file mode 100644 index 000000000..64985c6bb --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_fe310-g000_lfrosc.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_fe310-g000_pll.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_fe310-g000_pll.h new file mode 100644 index 000000000..67f818f7b --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_fe310-g000_pll.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_fe310-g000_prci.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_fe310-g000_prci.h new file mode 100644 index 000000000..387130be5 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_fe310-g000_prci.h @@ -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 + diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_fu540-c000_l2.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_fu540-c000_l2.h new file mode 100644 index 000000000..bb98f169e --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_fu540-c000_l2.h @@ -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 + diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_global-external-interrupts0.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_global-external-interrupts0.h new file mode 100644 index 000000000..9e6f2faf6 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_global-external-interrupts0.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_gpio-buttons.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_gpio-buttons.h new file mode 100644 index 000000000..a0caeaba8 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_gpio-buttons.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_gpio-leds.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_gpio-leds.h new file mode 100644 index 000000000..a8dacf116 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_gpio-leds.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_gpio-switches.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_gpio-switches.h new file mode 100644 index 000000000..c9c7839e9 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_gpio-switches.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_gpio0.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_gpio0.h new file mode 100644 index 000000000..cc56dc722 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_gpio0.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_local-external-interrupts0.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_local-external-interrupts0.h new file mode 100644 index 000000000..aa8d63078 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_local-external-interrupts0.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_rtc0.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_rtc0.h new file mode 100644 index 000000000..b0ed143bf --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_rtc0.h @@ -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 + diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_spi0.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_spi0.h new file mode 100644 index 000000000..c4a6848e7 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_spi0.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_test0.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_test0.h new file mode 100644 index 000000000..e87db2c83 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_test0.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_trace.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_trace.h new file mode 100644 index 000000000..3c67522f4 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_trace.h @@ -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 */ diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_uart0.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_uart0.h new file mode 100644 index 000000000..5d585e783 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_uart0.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_wdog0.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_wdog0.h new file mode 100644 index 000000000..12b143d58 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/drivers/sifive_wdog0.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/gpio.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/gpio.h new file mode 100644 index 000000000..7645494ff --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/gpio.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/interrupt.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/interrupt.h new file mode 100644 index 000000000..4f59bd36b --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/interrupt.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/io.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/io.h new file mode 100644 index 000000000..d55b4520a --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/io.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/itim.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/itim.h new file mode 100644 index 000000000..1a2a05b8b --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/itim.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/led.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/led.h new file mode 100644 index 000000000..f2aa39ceb --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/led.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/lock.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/lock.h new file mode 100644 index 000000000..0702cbf16 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/lock.h @@ -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 */ diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/memory.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/memory.h new file mode 100644 index 000000000..9de7d6162 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/memory.h @@ -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 */ + diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/pmp.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/pmp.h new file mode 100644 index 000000000..d948656c8 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/pmp.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/privilege.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/privilege.h new file mode 100644 index 000000000..928a936b1 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/privilege.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/rtc.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/rtc.h new file mode 100644 index 000000000..2e742ea38 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/rtc.h @@ -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 + diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/shutdown.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/shutdown.h new file mode 100644 index 000000000..8d4020b5c --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/shutdown.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/spi.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/spi.h new file mode 100644 index 000000000..635e3c151 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/spi.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/switch.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/switch.h new file mode 100644 index 000000000..61f0efe56 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/switch.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/time.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/time.h new file mode 100644 index 000000000..5c33b6f1b --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/time.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/timer.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/timer.h new file mode 100644 index 000000000..eeae1f60b --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/timer.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/tty.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/tty.h new file mode 100644 index 000000000..fe4c000db --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/tty.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/uart.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/uart.h new file mode 100644 index 000000000..e9e4d0436 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/uart.h @@ -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 diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/watchdog.h b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/watchdog.h new file mode 100644 index 000000000..b5ff48697 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/metal/watchdog.h @@ -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 */ diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/button.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/button.c new file mode 100644 index 000000000..efd645334 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/button.c @@ -0,0 +1,27 @@ +/* Copyright 2018 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/button.h> +#include <metal/machine.h> + +struct metal_button* metal_button_get (char *label) +{ + int i; + struct metal_button *button; + + if ((__METAL_DT_MAX_BUTTONS == 0) || (label == NULL)) { + return NULL; + } + + for (i = 0; i < __METAL_DT_MAX_BUTTONS; i++) { + button = (struct metal_button*)__metal_button_table[i]; + if (button->vtable->button_exist(button, label)) { + return button; + } + } + return NULL; +} + +extern __inline__ struct metal_interrupt* + metal_button_interrupt_controller(struct metal_button *button); +extern __inline__ int metal_button_get_interrupt_id(struct metal_button *button); diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/cache.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/cache.c new file mode 100644 index 000000000..024ba52ad --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/cache.c @@ -0,0 +1,187 @@ +/* Copyright 2018 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/cache.h> +#include <metal/machine.h> + +extern __inline__ void metal_cache_init(struct metal_cache *cache, int ways); +extern __inline__ int metal_cache_get_enabled_ways(struct metal_cache *cache); +extern __inline__ int metal_cache_set_enabled_ways(struct metal_cache *cache, int ways); + +int metal_dcache_l1_available(int hartid) { + switch (hartid) { + case 0: +#ifdef __METAL_CPU_0_DCACHE_HANDLE + return __METAL_CPU_0_DCACHE_HANDLE; +#endif + break; + case 1: +#ifdef __METAL_CPU_1_DCACHE_HANDLE + return __METAL_CPU_1_DCACHE_HANDLE; +#endif + break; + case 2: +#ifdef __METAL_CPU_2_DCACHE_HANDLE + return __METAL_CPU_2_DCACHE_HANDLE; +#endif + break; + case 3: +#ifdef __METAL_CPU_3_DCACHE_HANDLE + return __METAL_CPU_3_DCACHE_HANDLE; +#endif + break; + case 4: +#ifdef __METAL_CPU_4_DCACHE_HANDLE + return __METAL_CPU_4_DCACHE_HANDLE; +#endif + break; + case 5: +#ifdef __METAL_CPU_5_DCACHE_HANDLE + return __METAL_CPU_5_DCACHE_HANDLE; +#endif + break; + case 6: +#ifdef __METAL_CPU_6_DCACHE_HANDLE + return __METAL_CPU_6_DCACHE_HANDLE; +#endif + break; + case 7: +#ifdef __METAL_CPU_7_DCACHE_HANDLE + return __METAL_CPU_7_DCACHE_HANDLE; +#endif + break; + case 8: +#ifdef __METAL_CPU_8_DCACHE_HANDLE + return __METAL_CPU_8_DCACHE_HANDLE; +#endif + break; + } + return 0; +} + +int metal_icache_l1_available(int hartid) { + switch (hartid) { + case 0: +#ifdef __METAL_CPU_0_ICACHE_HANDLE + return __METAL_CPU_0_ICACHE_HANDLE; +#endif + break; + case 1: +#ifdef __METAL_CPU_1_ICACHE_HANDLE + return __METAL_CPU_1_ICACHE_HANDLE; +#endif + break; + case 2: +#ifdef __METAL_CPU_2_ICACHE_HANDLE + return __METAL_CPU_2_ICACHE_HANDLE; +#endif + break; + case 3: +#ifdef __METAL_CPU_3_ICACHE_HANDLE + return __METAL_CPU_3_ICACHE_HANDLE; +#endif + break; + case 4: +#ifdef __METAL_CPU_4_ICACHE_HANDLE + return __METAL_CPU_4_ICACHE_HANDLE; +#endif + break; + case 5: +#ifdef __METAL_CPU_5_ICACHE_HANDLE + return __METAL_CPU_5_ICACHE_HANDLE; +#endif + break; + case 6: +#ifdef __METAL_CPU_6_ICACHE_HANDLE + return __METAL_CPU_6_ICACHE_HANDLE; +#endif + break; + case 7: +#ifdef __METAL_CPU_7_ICACHE_HANDLE + return __METAL_CPU_7_ICACHE_HANDLE; +#endif + break; + case 8: +#ifdef __METAL_CPU_8_ICACHE_HANDLE + return __METAL_CPU_8_ICACHE_HANDLE; +#endif + break; + } + return 0; +} + +/*! + * @brief CFlush.D.L1 instruction is a custom instruction implemented as a + * state machine in L1 Data Cache (D$) with funct3=0, (for core with data caches) + * It is an I type: .insn i opcode, func3, rd, rs1, simm12(signed immediate 12bs) + * 31 28 27 24 23 20 19 16 15 12 11 8 7 4 3 0 + * |--------|--------|--------|--------|--------|--------|--------|--------| + * +-------------+------------+----------+------+--------+-----------------+ + * |sign immediate12b (simm12)| rs1 | func3| rd | opcode | + * |-1-1-1-1 -1-1-0-0 -0-0-0-0|-x-x-x-x-x|0-0-0-|-0-0-0-0|-0-1-1-1 -0-0-1-1| + * +--------------------------+----------+------+--------+-----------------+ + * 31 -0x40 20 15 0 12 x0 7 0x73 0 + * +--------+--------+--------+----------+------+--------+--------+--------+ + * where, + * rs1 = 0x0, CFLUSH.D.L1 writes back and invalidates all lines in the L1 D$ + * rs1 != x0, CFLUSH.D.L1 writes back and invalidates the L1 D$ line containing + * the virtual address in integer register rs1. + */ +void metal_dcache_l1_flush(int hartid, uintptr_t address) +{ + if (metal_dcache_l1_available(hartid)) { + // Using ‘.insn’ pseudo directive: '.insn i opcode, func3, rd, rs1, simm12' + __asm__ __volatile__ (".insn i 0x73, 0, x0, %0, -0x40" : : "r" (address)); + __asm__ __volatile__ ("fence.i"); // FENCE + } +} + +/*! + * @brief CDiscard.D.L1 instruction is a custom instruction implemented as a + * state machine in L1 Data Cache (D$) with funct3=0, (for core with data caches) + * It is an I type: .insn i opcode, func3, rd, rs1, simm12(signed immediate 12bs) + * 31 28 27 24 23 20 19 16 15 12 11 8 7 4 3 0 + * |--------|--------|--------|--------|--------|--------|--------|--------| + * +-------------+------------+----------+------+--------+-----------------+ + * |sign immediate12b (simm12)| rs1 | func3| rd | opcode | + * |-1-1-1-1 -1-1-0-0 -0-0-0-0|-x-x-x-x-x|0-0-0-|-0-0-0-0|-0-1-1-1 -0-0-1-1| + * +--------------------------+----------+------+--------+-----------------+ + * 31 -0x3E 20 15 0 12 x0 7 0x73 0 + * +--------+--------+--------+----------+------+--------+--------+--------+ + * where, + * rs1 = 0x0, CDISCARD.D.L1 invalidates all lines in the L1 D$ with no writes back. + * rs1 != x0, CDISCARD.D.L1 invalidates the L1 D$ line containing the virtual address + * in integer register rs1, with no writes back. + */ +void metal_dcache_l1_discard(int hartid, uintptr_t address) +{ + if (metal_dcache_l1_available(hartid)) { + // Using ‘.insn’ pseudo directive: '.insn i opcode, func3, rd, rs1, simm12' + __asm__ __volatile__ (".insn i 0x73, 0, x0, %0, -0x3E" : : "r" (address)); + __asm__ __volatile__ ("fence.i"); // FENCE + } +} + +/*! + * @brief CFlush.I.L1 instruction is a custom instruction implemented as a state + * machine in L1 Instruction Cache (I$) with funct3=0, (for core with data caches) + * It is an I type: .insn i opcode, func3, rd, rs1, simm12(signed immediate 12bs) + * 31 28 27 24 23 20 19 16 15 12 11 8 7 4 3 0 + * |--------|--------|--------|--------|--------|--------|--------|--------| + * +-------------+------------+----------+------+--------+-----------------+ + * |sign immediate12b (simm12)| rs1 | func3| rd | opcode | + * |-1-1-1-1 -1-1-0-0 -0-0-0-0|-0-0-0-0-0|0-0-0-|-0-0-0-0|-0-1-1-1 -0-0-1-1| + * +--------------------------+----------+------+--------+-----------------+ + * 31 -0x3F 20 15 0 12 x0 7 0x73 0 + * +--------+--------+--------+----------+------+--------+--------+--------+ + * CFLUSH.I.L1 invalidates all lines in the L1 I$. + */ +void metal_icache_l1_flush(int hartid) +{ + if (metal_icache_l1_available(hartid)) { + // Using ‘.insn’ pseudo directive: '.insn i opcode, func3, rd, rs1, simm12' + __asm__ __volatile__ (".insn i 0x73, 0, x0, x0, -0x3F" : : ); + __asm__ __volatile__ ("fence.i"); // FENCE + } +} + diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/clock.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/clock.c new file mode 100644 index 000000000..cc3f4dcf3 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/clock.c @@ -0,0 +1,12 @@ +/* Copyright 2018 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/clock.h> + +extern __inline__ void _metal_clock_call_all_callbacks(const metal_clock_callback *const list); +extern __inline__ metal_clock_callback *_metal_clock_append_to_callbacks(metal_clock_callback *list, metal_clock_callback *const cb); + +extern __inline__ long metal_clock_get_rate_hz(const struct metal_clock *clk); +extern __inline__ long metal_clock_set_rate_hz(struct metal_clock *clk, long hz); +extern __inline__ void metal_clock_register_post_rate_change_callback(struct metal_clock *clk, metal_clock_callback *cb); +extern __inline__ void metal_clock_register_pre_rate_change_callback(struct metal_clock *clk, metal_clock_callback *cb); diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/cpu.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/cpu.c new file mode 100644 index 000000000..25fda5de7 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/cpu.c @@ -0,0 +1,59 @@ +/* Copyright 2018 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/cpu.h> +#include <metal/machine.h> + +struct metal_cpu* metal_cpu_get(unsigned int hartid) +{ + if (hartid < __METAL_DT_MAX_HARTS) { + return (struct metal_cpu *)__metal_cpu_table[hartid]; + } + return NULL; +} + +int metal_cpu_get_current_hartid() +{ +#ifdef __riscv + int mhartid; + __asm__ volatile("csrr %0, mhartid" : "=r" (mhartid)); + return mhartid; +#endif +} + +int metal_cpu_get_num_harts() +{ + return __METAL_DT_MAX_HARTS; +} + +extern __inline__ unsigned long long metal_cpu_get_timer(struct metal_cpu *cpu); + +extern __inline__ unsigned long long metal_cpu_get_timebase(struct metal_cpu *cpu); + +extern __inline__ unsigned long long metal_cpu_get_mtime(struct metal_cpu *cpu); + +extern __inline__ int metal_cpu_set_mtimecmp(struct metal_cpu *cpu, unsigned long long time); + +extern __inline__ struct metal_interrupt* metal_cpu_timer_interrupt_controller(struct metal_cpu *cpu); + +extern __inline__ int metal_cpu_timer_get_interrupt_id(struct metal_cpu *cpu); + +extern __inline__ struct metal_interrupt* metal_cpu_software_interrupt_controller(struct metal_cpu *cpu); + +extern __inline__ int metal_cpu_software_get_interrupt_id(struct metal_cpu *cpu); + +extern __inline__ int metal_cpu_software_set_ipi(struct metal_cpu *cpu, int hartid); + +extern __inline__ int metal_cpu_software_clear_ipi(struct metal_cpu *cpu, int hartid); + +extern __inline__ int metal_cpu_get_msip(struct metal_cpu *cpu, int hartid); + +extern __inline__ struct metal_interrupt* metal_cpu_interrupt_controller(struct metal_cpu *cpu); + +extern __inline__ int metal_cpu_exception_register(struct metal_cpu *cpu, int ecode, metal_exception_handler_t handler); + +extern __inline__ int metal_cpu_get_instruction_length(struct metal_cpu *cpu, uintptr_t epc); + +extern __inline__ uintptr_t metal_cpu_get_exception_pc(struct metal_cpu *cpu); + +extern __inline__ int metal_cpu_set_exception_pc(struct metal_cpu *cpu, uintptr_t epc); diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/fixed-clock.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/fixed-clock.c new file mode 100644 index 000000000..92c61d023 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/fixed-clock.c @@ -0,0 +1,29 @@ +/* Copyright 2018 SiFive, Inc. */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine/platform.h> + +#ifdef METAL_FIXED_CLOCK + +#include <metal/drivers/fixed-clock.h> +#include <stddef.h> +#include <metal/machine.h> + +long __metal_driver_fixed_clock_get_rate_hz(const struct metal_clock *gclk) +{ + return __metal_driver_fixed_clock_rate(gclk); +} + +long __metal_driver_fixed_clock_set_rate_hz(struct metal_clock *gclk, long target_hz) +{ + return __metal_driver_fixed_clock_get_rate_hz(gclk); +} + +__METAL_DEFINE_VTABLE(__metal_driver_vtable_fixed_clock) = { + .clock.get_rate_hz = __metal_driver_fixed_clock_get_rate_hz, + .clock.set_rate_hz = __metal_driver_fixed_clock_set_rate_hz, +}; + +#endif /* METAL_FIXED_CLOCK */ + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/fixed-factor-clock.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/fixed-factor-clock.c new file mode 100644 index 000000000..57d83af87 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/fixed-factor-clock.c @@ -0,0 +1,34 @@ +/* Copyright 2018 SiFive, Inc. */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine/platform.h> + +#ifdef METAL_FIXED_FACTOR_CLOCK + +#include <metal/drivers/fixed-factor-clock.h> +#include <stddef.h> +#include <metal/machine.h> + +long __metal_driver_fixed_factor_clock_get_rate_hz(const struct metal_clock *gclk) +{ + struct metal_clock *parent = __metal_driver_fixed_factor_clock_parent(gclk); + long parent_rate = 1; + if(parent) { + parent_rate = parent->vtable->get_rate_hz(parent); + } + + return __metal_driver_fixed_factor_clock_mult(gclk) * parent_rate / __metal_driver_fixed_factor_clock_div(gclk); +} + +long __metal_driver_fixed_factor_clock_set_rate_hz(struct metal_clock *gclk, long target_hz) +{ + return __metal_driver_fixed_factor_clock_get_rate_hz(gclk); +} + +__METAL_DEFINE_VTABLE(__metal_driver_vtable_fixed_factor_clock) = { + .clock.get_rate_hz = __metal_driver_fixed_factor_clock_get_rate_hz, + .clock.set_rate_hz = __metal_driver_fixed_factor_clock_set_rate_hz, +}; +#endif /* METAL_FIXED_FACTOR_CLOCK */ + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/inline.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/inline.c new file mode 100644 index 000000000..50c0c5c21 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/inline.c @@ -0,0 +1,5 @@ +/* Copyright 2019 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine/inline.h> + diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/riscv_clint0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/riscv_clint0.c new file mode 100644 index 000000000..d0488b317 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/riscv_clint0.c @@ -0,0 +1,283 @@ +/* Copyright 2018 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine/platform.h> + +#ifdef METAL_RISCV_CLINT0 + +#include <metal/io.h> +#include <metal/cpu.h> +#include <metal/drivers/riscv_clint0.h> +#include <metal/machine.h> + +unsigned long long __metal_clint0_mtime_get (struct __metal_driver_riscv_clint0 *clint) +{ + __metal_io_u32 lo, hi; + unsigned long control_base = __metal_driver_sifive_clint0_control_base(&clint->controller); + + /* Guard against rollover when reading */ + do { + hi = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_RISCV_CLINT0_MTIME + 4)); + lo = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_RISCV_CLINT0_MTIME)); + } while (__METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_RISCV_CLINT0_MTIME + 4)) != hi); + + return (((unsigned long long)hi) << 32) | lo; +} + +int __metal_driver_riscv_clint0_mtimecmp_set(struct metal_interrupt *controller, + int hartid, + unsigned long long time) +{ + struct __metal_driver_riscv_clint0 *clint = + (struct __metal_driver_riscv_clint0 *)(controller); + unsigned long control_base = __metal_driver_sifive_clint0_control_base(&clint->controller); + /* Per spec, the RISC-V MTIME/MTIMECMP registers are 64 bit, + * and are NOT internally latched for multiword transfers. + * Need to be careful about sequencing to avoid triggering + * spurious interrupts: For that set the high word to a max + * value first. + */ + __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + (8 * hartid) + METAL_RISCV_CLINT0_MTIMECMP_BASE + 4)) = 0xFFFFFFFF; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + (8 * hartid) + METAL_RISCV_CLINT0_MTIMECMP_BASE)) = (__metal_io_u32)time; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + (8 * hartid) + METAL_RISCV_CLINT0_MTIMECMP_BASE + 4)) = (__metal_io_u32)(time >> 32); + return 0; +} + +static struct metal_interrupt *_get_cpu_intc() +{ + int hartid = 0; + __asm__ volatile("csrr %[hartid], mhartid" + : [hartid] "=r" (hartid) :: "memory"); + + struct metal_cpu *cpu = metal_cpu_get(hartid); + + return metal_cpu_interrupt_controller(cpu); +} + +void __metal_driver_riscv_clint0_init (struct metal_interrupt *controller) +{ + int num_interrupts = __metal_driver_sifive_clint0_num_interrupts(controller); + struct __metal_driver_riscv_clint0 *clint = + (struct __metal_driver_riscv_clint0 *)(controller); + + if ( !clint->init_done ) { + /* Register its interrupts with with parent controller, aka sw and timerto its default isr */ + for (int i = 0; i < num_interrupts; i++) { + struct metal_interrupt *intc = __metal_driver_sifive_clint0_interrupt_parents(controller, i); + int line = __metal_driver_sifive_clint0_interrupt_lines(controller, i); + intc->vtable->interrupt_register(intc, line, NULL, controller); + } + clint->init_done = 1; + } +} + +int __metal_driver_riscv_clint0_register (struct metal_interrupt *controller, + int id, metal_interrupt_handler_t isr, + void *priv) +{ + int rc = -1; + metal_vector_mode mode = __metal_controller_interrupt_vector_mode(); + struct metal_interrupt *intc = NULL; + struct metal_interrupt *cpu_intc = _get_cpu_intc(); + int num_interrupts = __metal_driver_sifive_clint0_num_interrupts(controller); + + if ( (mode != METAL_VECTOR_MODE) && (mode != METAL_DIRECT_MODE) ) { + return rc; + } + + for(int i = 0; i < num_interrupts; i++) { + int line = __metal_driver_sifive_clint0_interrupt_lines(controller, i); + intc = __metal_driver_sifive_clint0_interrupt_parents(controller, i); + if (cpu_intc == intc && id == line) { + break; + } + intc = NULL; + } + + /* Register its interrupts with parent controller */ + if (intc) { + rc = intc->vtable->interrupt_register(intc, id, isr, priv); + } + return rc; +} + +int __metal_driver_riscv_clint0_vector_register (struct metal_interrupt *controller, + int id, metal_interrupt_vector_handler_t isr, + void *priv) +{ + /* Not supported. User can override the 'weak' handler with their own */ + int rc = -1; + return rc; +} + +metal_vector_mode __metal_driver_riscv_clint0_get_vector_mode (struct metal_interrupt *controller) +{ + return __metal_controller_interrupt_vector_mode(); +} + +int __metal_driver_riscv_clint0_set_vector_mode (struct metal_interrupt *controller, metal_vector_mode mode) +{ + int rc = -1; + struct metal_interrupt *intc = _get_cpu_intc(); + + if (intc) { + /* Valid vector modes are VECTOR and DIRECT, anything else is invalid (-1) */ + switch (mode) { + case METAL_VECTOR_MODE: + case METAL_DIRECT_MODE: + rc = intc->vtable->interrupt_set_vector_mode(intc, mode); + break; + case METAL_HARDWARE_VECTOR_MODE: + case METAL_SELECTIVE_NONVECTOR_MODE: + case METAL_SELECTIVE_VECTOR_MODE: + break; + } + } + return rc; +} + +int __metal_driver_riscv_clint0_enable (struct metal_interrupt *controller, int id) +{ + int rc = -1; + + if ( id ) { + struct metal_interrupt *intc = NULL; + struct metal_interrupt *cpu_intc = _get_cpu_intc(); + int num_interrupts = __metal_driver_sifive_clint0_num_interrupts(controller); + + for(int i = 0; i < num_interrupts; i++) { + int line = __metal_driver_sifive_clint0_interrupt_lines(controller, i); + intc = __metal_driver_sifive_clint0_interrupt_parents(controller, i); + if(cpu_intc == intc && id == line) { + break; + } + intc = NULL; + } + + /* Enable its interrupts with parent controller */ + if (intc) { + rc = intc->vtable->interrupt_enable(intc, id); + } + } + + return rc; +} + +int __metal_driver_riscv_clint0_disable (struct metal_interrupt *controller, int id) +{ + int rc = -1; + + if ( id ) { + struct metal_interrupt *intc = NULL; + struct metal_interrupt *cpu_intc = _get_cpu_intc(); + int num_interrupts = __metal_driver_sifive_clint0_num_interrupts(controller); + + for(int i = 0; i < num_interrupts; i++) { + int line = __metal_driver_sifive_clint0_interrupt_lines(controller, i); + intc = __metal_driver_sifive_clint0_interrupt_parents(controller, i); + if(cpu_intc == intc && id == line) { + break; + } + intc = NULL; + } + + /* Disable its interrupts with parent controller */ + if (intc) { + rc = intc->vtable->interrupt_disable(intc, id); + } + } + + return rc; +} + +int __metal_driver_riscv_clint0_command_request (struct metal_interrupt *controller, + int command, void *data) +{ + int hartid; + int rc = -1; + struct __metal_driver_riscv_clint0 *clint = + (struct __metal_driver_riscv_clint0 *)(controller); + unsigned long control_base = __metal_driver_sifive_clint0_control_base(controller); + + switch (command) { + case METAL_TIMER_MTIME_GET: + if (data) { + *(unsigned long long *)data = __metal_clint0_mtime_get(clint); + rc = 0; + } + break; + case METAL_SOFTWARE_IPI_CLEAR: + if (data) { + hartid = *(int *)data; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + + (hartid * 4))) = METAL_DISABLE; + rc = 0; + } + break; + case METAL_SOFTWARE_IPI_SET: + if (data) { + hartid = *(int *)data; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + + (hartid * 4))) = METAL_ENABLE; + /* Callers of this function assume it's blocking, in the sense that + * the IPI is guarnteed to have been delivered before the function + * returns. We can't really guarnteed it's delivered, but we can + * read back the control register after writing it in at least an + * attempt to provide some semblence of ordering here. The fence + * ensures the read is order after the write -- it wouldn't be + * necessary under RVWMO because this is the same address, but we + * don't have an IO memory model so I'm being a bit overkill here. + */ + __METAL_IO_FENCE(o,i); + rc = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + + (hartid * 4))); + rc = 0; + } + break; + case METAL_SOFTWARE_MSIP_GET: + rc = 0; + if (data) { + hartid = *(int *)data; + rc = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + + (hartid * 4))); + } + break; + default: + break; + } + + return rc; +} + +int __metal_driver_riscv_clint0_clear_interrupt (struct metal_interrupt *controller, int id) +{ + int hartid = metal_cpu_get_current_hartid(); + return __metal_driver_riscv_clint0_command_request(controller, + METAL_SOFTWARE_IPI_CLEAR, &hartid); +} + +int __metal_driver_riscv_clint0_set_interrupt (struct metal_interrupt *controller, int id) +{ + int hartid = metal_cpu_get_current_hartid(); + return __metal_driver_riscv_clint0_command_request(controller, + METAL_SOFTWARE_IPI_SET, &hartid); +} + + +__METAL_DEFINE_VTABLE(__metal_driver_vtable_riscv_clint0) = { + .clint_vtable.interrupt_init = __metal_driver_riscv_clint0_init, + .clint_vtable.interrupt_register = __metal_driver_riscv_clint0_register, + .clint_vtable.interrupt_vector_register = __metal_driver_riscv_clint0_vector_register, + .clint_vtable.interrupt_enable = __metal_driver_riscv_clint0_enable, + .clint_vtable.interrupt_disable = __metal_driver_riscv_clint0_disable, + .clint_vtable.interrupt_get_vector_mode = __metal_driver_riscv_clint0_get_vector_mode, + .clint_vtable.interrupt_set_vector_mode = __metal_driver_riscv_clint0_set_vector_mode, + .clint_vtable.interrupt_clear = __metal_driver_riscv_clint0_clear_interrupt, + .clint_vtable.interrupt_set = __metal_driver_riscv_clint0_set_interrupt, + .clint_vtable.command_request = __metal_driver_riscv_clint0_command_request, + .clint_vtable.mtimecmp_set = __metal_driver_riscv_clint0_mtimecmp_set, +}; + +#endif /* METAL_RISCV_CLINT0 */ + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/riscv_cpu.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/riscv_cpu.c new file mode 100644 index 000000000..b693f312a --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/riscv_cpu.c @@ -0,0 +1,999 @@ +/* Copyright 2018 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <stdint.h> +#include <metal/io.h> +#include <metal/shutdown.h> +#include <metal/machine.h> + +extern void __metal_vector_table(); +unsigned long long __metal_driver_cpu_mtime_get(struct metal_cpu *cpu); +int __metal_driver_cpu_mtimecmp_set(struct metal_cpu *cpu, unsigned long long time); + +struct metal_cpu *__metal_driver_cpu_get(int hartid) +{ + if (hartid < __METAL_DT_MAX_HARTS) { + return &(__metal_cpu_table[hartid]->cpu); + } + return (struct metal_cpu *)NULL; +} + +uintptr_t __metal_myhart_id (void) +{ + uintptr_t myhart; + __asm__ volatile ("csrr %0, mhartid" : "=r"(myhart)); + return myhart; +} + +void __metal_zero_memory (unsigned char *base, unsigned int size) +{ + volatile unsigned char *ptr; + for (ptr = base; ptr < (base + size); ptr++){ + *ptr = 0; + } +} + +void __metal_interrupt_global_enable (void) { + uintptr_t m; + __asm__ volatile ("csrrs %0, mstatus, %1" : "=r"(m) : "r"(METAL_MIE_INTERRUPT)); +} + +void __metal_interrupt_global_disable (void) { + uintptr_t m; + __asm__ volatile ("csrrc %0, mstatus, %1" : "=r"(m) : "r"(METAL_MIE_INTERRUPT)); +} + +void __metal_interrupt_software_enable (void) { + uintptr_t m; + __asm__ volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_SW)); +} + +void __metal_interrupt_software_disable (void) { + uintptr_t m; + __asm__ volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_SW)); +} + +void __metal_interrupt_timer_enable (void) { + uintptr_t m; + __asm__ volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_TMR)); +} + +void __metal_interrupt_timer_disable (void) { + uintptr_t m; + __asm__ volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_TMR)); +} + +void __metal_interrupt_external_enable (void) { + uintptr_t m; + __asm__ volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_EXT)); +} + +void __metal_interrupt_external_disable (void) { + unsigned long m; + __asm__ volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_EXT)); +} + +void __metal_interrupt_local_enable (int id) { + uintptr_t b = 1 << id; + uintptr_t m; + __asm__ volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(b)); +} + +void __metal_interrupt_local_disable (int id) { + uintptr_t b = 1 << id; + uintptr_t m; + __asm__ volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(b)); +} + +void __metal_default_exception_handler (struct metal_cpu *cpu, int ecode) { + metal_shutdown(100); +} + +void __metal_default_interrupt_handler (int id, void *priv) { + metal_shutdown(200); +} + +/* The metal_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_interrupt_vector_handler (void) { + metal_shutdown(300); +} + +/* The metal_software_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_software_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_SW].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_SW].handler(METAL_INTERRUPT_ID_SW, priv); + } +} + +void __metal_default_sw_handler (int id, void *priv) { + uintptr_t mcause; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + __asm__ volatile ("csrr %0, mcause" : "=r"(mcause)); + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + intc->metal_exception_table[mcause & METAL_MCAUSE_CAUSE]((struct metal_cpu *)cpu, id); + } +} + +/* The metal_timer_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_timer_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_TMR].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_TMR].handler(METAL_INTERRUPT_ID_TMR, priv); + } +} + +void __metal_default_timer_handler (int id, void *priv) { + struct metal_cpu *cpu = __metal_driver_cpu_get(__metal_myhart_id()); + unsigned long long time = __metal_driver_cpu_mtime_get(cpu); + + /* Set a 10 cycle timer */ + __metal_driver_cpu_mtimecmp_set(cpu, time + 10); +} + +/* The metal_external_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_external_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_EXT].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_EXT].handler(METAL_INTERRUPT_ID_EXT, priv); + } +} + +void __metal_exception_handler(void) __attribute__((interrupt, aligned(128))); +void __metal_exception_handler (void) { + int id; + void *priv; + uintptr_t mcause, mepc, mtval, mtvec; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + __asm__ volatile ("csrr %0, mcause" : "=r"(mcause)); + __asm__ volatile ("csrr %0, mepc" : "=r"(mepc)); + __asm__ volatile ("csrr %0, mtval" : "=r"(mtval)); + __asm__ volatile ("csrr %0, mtvec" : "=r"(mtvec)); + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + id = mcause & METAL_MCAUSE_CAUSE; + if (mcause & METAL_MCAUSE_INTR) { + if ((id < METAL_INTERRUPT_ID_CSW) || + ((mtvec & METAL_MTVEC_MASK) == METAL_MTVEC_DIRECT)) { + priv = intc->metal_int_table[id].exint_data; + intc->metal_int_table[id].handler(id, priv); + return; + } + if ((mtvec & METAL_MTVEC_MASK) == METAL_MTVEC_CLIC) { + uintptr_t mtvt; + metal_interrupt_handler_t mtvt_handler; + + __asm__ volatile ("csrr %0, 0x307" : "=r"(mtvt)); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_SW].sub_int; + mtvt_handler = (metal_interrupt_handler_t)*(uintptr_t *)mtvt; + mtvt_handler(id, priv); + return; + } + } else { + intc->metal_exception_table[id]((struct metal_cpu *)cpu, id); + } + } +} + +/* The metal_lc0_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_lc0_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC0].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_LC0].handler(METAL_INTERRUPT_ID_LC0, priv); + } +} + +/* The metal_lc1_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_lc1_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC1].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_LC1].handler(METAL_INTERRUPT_ID_LC1, priv); + } +} + +/* The metal_lc2_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_lc2_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC2].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_LC2].handler(METAL_INTERRUPT_ID_LC2, priv); + } +} + +/* The metal_lc3_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_lc3_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC3].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_LC3].handler(METAL_INTERRUPT_ID_LC3, priv); + } +} + +/* The metal_lc4_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_lc4_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC4].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_LC4].handler(METAL_INTERRUPT_ID_LC4, priv); + } +} + +/* The metal_lc5_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_lc5_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC5].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_LC5].handler(METAL_INTERRUPT_ID_LC5, priv); + } +} + +/* The metal_lc6_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_lc6_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC6].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_LC6].handler(METAL_INTERRUPT_ID_LC6, priv); + } +} + +/* The metal_lc7_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_lc7_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC7].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_LC7].handler(METAL_INTERRUPT_ID_LC7, priv); + } +} + +/* The metal_lc8_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_lc8_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC8].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_LC8].handler(METAL_INTERRUPT_ID_LC8, priv); + } +} + +/* The metal_lc9_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_lc9_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC9].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_LC9].handler(METAL_INTERRUPT_ID_LC9, priv); + } +} + +/* The metal_lc10_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_lc10_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC10].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_LC10].handler(METAL_INTERRUPT_ID_LC10, priv); + } +} + +/* The metal_lc11_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_lc11_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC11].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_LC11].handler(METAL_INTERRUPT_ID_LC11, priv); + } +} + +/* The metal_lc12_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_lc12_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC12].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_LC12].handler(METAL_INTERRUPT_ID_LC12, priv); + } +} + +/* The metal_lc13_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_lc13_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC13].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_LC13].handler(METAL_INTERRUPT_ID_LC13, priv); + } +} + +/* The metal_lc14_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_lc14_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC14].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_LC14].handler(METAL_INTERRUPT_ID_LC14, priv); + } +} + +/* The metal_lc15_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_lc15_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC15].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_LC15].handler(METAL_INTERRUPT_ID_LC15, priv); + } +} + +metal_vector_mode __metal_controller_interrupt_vector_mode (void) +{ + uintptr_t val; + + asm volatile ("csrr %0, mtvec" : "=r"(val)); + val &= METAL_MTVEC_MASK; + + switch (val) { + case METAL_MTVEC_CLIC: + return METAL_SELECTIVE_VECTOR_MODE; + case METAL_MTVEC_CLIC_VECTORED: + return METAL_HARDWARE_VECTOR_MODE; + case METAL_MTVEC_VECTORED: + return METAL_VECTOR_MODE; + } + return METAL_DIRECT_MODE; +} + +void __metal_controller_interrupt_vector (metal_vector_mode mode, void *vec_table) +{ + uintptr_t trap_entry, val; + + __asm__ volatile ("csrr %0, mtvec" : "=r"(val)); + val &= ~(METAL_MTVEC_CLIC_VECTORED | METAL_MTVEC_CLIC_RESERVED); + trap_entry = (uintptr_t)vec_table; + + switch (mode) { + case METAL_SELECTIVE_NONVECTOR_MODE: + case METAL_SELECTIVE_VECTOR_MODE: + __asm__ volatile ("csrw 0x307, %0" :: "r"(trap_entry)); + __asm__ volatile ("csrw mtvec, %0" :: "r"(val | METAL_MTVEC_CLIC)); + break; + case METAL_HARDWARE_VECTOR_MODE: + __asm__ volatile ("csrw 0x307, %0" :: "r"(trap_entry)); + __asm__ volatile ("csrw mtvec, %0" :: "r"(val | METAL_MTVEC_CLIC_VECTORED)); + break; + case METAL_VECTOR_MODE: + __asm__ volatile ("csrw mtvec, %0" :: "r"(trap_entry | METAL_MTVEC_VECTORED)); + break; + case METAL_DIRECT_MODE: + __asm__ volatile ("csrw mtvec, %0" :: "r"(trap_entry & ~METAL_MTVEC_CLIC_VECTORED)); + break; + } +} + +int __metal_valid_interrupt_id (int id) +{ + switch (id) { + case METAL_INTERRUPT_ID_SW: + case METAL_INTERRUPT_ID_TMR: + case METAL_INTERRUPT_ID_EXT: + case METAL_INTERRUPT_ID_LC0: + case METAL_INTERRUPT_ID_LC1: + case METAL_INTERRUPT_ID_LC2: + case METAL_INTERRUPT_ID_LC3: + case METAL_INTERRUPT_ID_LC4: + case METAL_INTERRUPT_ID_LC5: + case METAL_INTERRUPT_ID_LC6: + case METAL_INTERRUPT_ID_LC7: + case METAL_INTERRUPT_ID_LC8: + case METAL_INTERRUPT_ID_LC9: + case METAL_INTERRUPT_ID_LC10: + case METAL_INTERRUPT_ID_LC11: + case METAL_INTERRUPT_ID_LC12: + case METAL_INTERRUPT_ID_LC13: + case METAL_INTERRUPT_ID_LC14: + case METAL_INTERRUPT_ID_LC15: + return 1; + default: + break; + } + + return 0; +} + + +int __metal_local_interrupt_enable (struct metal_interrupt *controller, + metal_interrupt_id_e id, int enable) +{ + int rc = 0; + + if ( !controller) { + return -1; + } + + switch (id) { + case METAL_INTERRUPT_ID_BASE: + if (enable) { + __metal_interrupt_global_enable(); + } else { + __metal_interrupt_global_disable(); + } + break; + case METAL_INTERRUPT_ID_SW: + if (enable) { + __metal_interrupt_software_enable(); + } else { + __metal_interrupt_software_disable(); + } + break; + case METAL_INTERRUPT_ID_TMR: + if (enable) { + __metal_interrupt_timer_enable(); + } else { + __metal_interrupt_timer_disable(); + } + break; + case METAL_INTERRUPT_ID_EXT: + if (enable) { + __metal_interrupt_external_enable(); + } else { + __metal_interrupt_external_disable(); + } + break; + case METAL_INTERRUPT_ID_LC0: + case METAL_INTERRUPT_ID_LC1: + case METAL_INTERRUPT_ID_LC2: + case METAL_INTERRUPT_ID_LC3: + case METAL_INTERRUPT_ID_LC4: + case METAL_INTERRUPT_ID_LC5: + case METAL_INTERRUPT_ID_LC6: + case METAL_INTERRUPT_ID_LC7: + case METAL_INTERRUPT_ID_LC8: + case METAL_INTERRUPT_ID_LC9: + case METAL_INTERRUPT_ID_LC10: + case METAL_INTERRUPT_ID_LC11: + case METAL_INTERRUPT_ID_LC12: + case METAL_INTERRUPT_ID_LC13: + case METAL_INTERRUPT_ID_LC14: + case METAL_INTERRUPT_ID_LC15: + if (enable) { + __metal_interrupt_local_enable(id); + } else { + __metal_interrupt_local_disable(id); + } + break; + default: + rc = -1; + } + return rc; +} + +int __metal_exception_register (struct metal_interrupt *controller, + int ecode, metal_exception_handler_t isr) +{ + struct __metal_driver_riscv_cpu_intc *intc = (void *)(controller); + + if ((ecode < METAL_MAX_EXCEPTION_CODE) && isr) { + intc->metal_exception_table[ecode] = isr; + return 0; + } + return -1; +} + +void __metal_driver_riscv_cpu_controller_interrupt_init (struct metal_interrupt *controller) +{ + struct __metal_driver_riscv_cpu_intc *intc = (void *)(controller); + uintptr_t val; + + if ( !intc->init_done ) { + /* Disable and clear all interrupt sources */ + __asm__ volatile ("csrc mie, %0" :: "r"(-1)); + __asm__ volatile ("csrc mip, %0" :: "r"(-1)); + + /* Read the misa CSR to determine if the delegation registers exist */ + uintptr_t misa; + __asm__ volatile ("csrr %0, misa" : "=r" (misa)); + + /* The delegation CSRs exist if user mode interrupts (N extension) or + * supervisor mode (S extension) are supported */ + if((misa & METAL_ISA_N_EXTENSIONS) || (misa & METAL_ISA_S_EXTENSIONS)) { + /* Disable interrupt and exception delegation */ + __asm__ volatile ("csrc mideleg, %0" :: "r"(-1)); + __asm__ volatile ("csrc medeleg, %0" :: "r"(-1)); + } + + /* The satp CSR exists if supervisor mode (S extension) is supported */ + if(misa & METAL_ISA_S_EXTENSIONS) { + /* Clear the entire CSR to make sure that satp.MODE = 0 */ + __asm__ volatile ("csrc satp, %0" :: "r"(-1)); + } + + /* Default to use direct interrupt, setup sw cb table*/ + for (int i = 0; i < METAL_MAX_MI; i++) { + intc->metal_int_table[i].handler = NULL; + intc->metal_int_table[i].sub_int = NULL; + intc->metal_int_table[i].exint_data = NULL; + } + for (int i = 0; i < METAL_MAX_ME; i++) { + intc->metal_exception_table[i] = __metal_default_exception_handler; + } + __metal_controller_interrupt_vector(METAL_DIRECT_MODE, (void *)(uintptr_t)&__metal_exception_handler); + __asm__ volatile ("csrr %0, misa" : "=r"(val)); + if (val & (METAL_ISA_D_EXTENSIONS | METAL_ISA_F_EXTENSIONS | METAL_ISA_Q_EXTENSIONS)) { + /* Floating point architecture, so turn on FP register saving*/ + __asm__ volatile ("csrr %0, mstatus" : "=r"(val)); + __asm__ volatile ("csrw mstatus, %0" :: "r"(val | METAL_MSTATUS_FS_INIT)); + } + intc->init_done = 1; + } +} + +int __metal_driver_riscv_cpu_controller_interrupt_register(struct metal_interrupt *controller, + int id, metal_interrupt_handler_t isr, + void *priv) +{ + int rc = 0; + struct __metal_driver_riscv_cpu_intc *intc = (void *)(controller); + + if ( !__metal_valid_interrupt_id(id) ) { + return -11; + } + + if (isr) { + intc->metal_int_table[id].handler = isr; + intc->metal_int_table[id].exint_data = priv; + } else { + switch (id) { + case METAL_INTERRUPT_ID_SW: + intc->metal_int_table[id].handler = __metal_default_sw_handler; + intc->metal_int_table[id].sub_int = priv; + break; + case METAL_INTERRUPT_ID_TMR: + intc->metal_int_table[id].handler = __metal_default_timer_handler; + intc->metal_int_table[id].sub_int = priv; + break; + case METAL_INTERRUPT_ID_EXT: + case METAL_INTERRUPT_ID_LC0: + case METAL_INTERRUPT_ID_LC1: + case METAL_INTERRUPT_ID_LC2: + case METAL_INTERRUPT_ID_LC3: + case METAL_INTERRUPT_ID_LC4: + case METAL_INTERRUPT_ID_LC5: + case METAL_INTERRUPT_ID_LC6: + case METAL_INTERRUPT_ID_LC7: + case METAL_INTERRUPT_ID_LC8: + case METAL_INTERRUPT_ID_LC9: + case METAL_INTERRUPT_ID_LC10: + case METAL_INTERRUPT_ID_LC11: + case METAL_INTERRUPT_ID_LC12: + case METAL_INTERRUPT_ID_LC13: + case METAL_INTERRUPT_ID_LC14: + case METAL_INTERRUPT_ID_LC15: + intc->metal_int_table[id].handler = __metal_default_interrupt_handler; + intc->metal_int_table[id].sub_int = priv; + break; + default: + rc = -12; + } + } + return rc; +} + +int __metal_driver_riscv_cpu_controller_interrupt_enable (struct metal_interrupt *controller, + int id) +{ + return __metal_local_interrupt_enable(controller, id, METAL_ENABLE); +} + +int __metal_driver_riscv_cpu_controller_interrupt_disable (struct metal_interrupt *controller, + int id) +{ + return __metal_local_interrupt_enable(controller, id, METAL_DISABLE); +} + +int __metal_driver_riscv_cpu_controller_interrupt_enable_vector(struct metal_interrupt *controller, + int id, metal_vector_mode mode) +{ + struct __metal_driver_riscv_cpu_intc *intc = (void *)(controller); + + if (id == METAL_INTERRUPT_ID_BASE) { + if (mode == METAL_DIRECT_MODE) { + __metal_controller_interrupt_vector(mode, (void *)(uintptr_t)&__metal_exception_handler); + return 0; + } + if (mode == METAL_VECTOR_MODE) { + __metal_controller_interrupt_vector(mode, (void *)&intc->metal_mtvec_table); + return 0; + } + } + return -1; +} + +int __metal_driver_riscv_cpu_controller_interrupt_disable_vector(struct metal_interrupt *controller, + int id) +{ + if (id == METAL_INTERRUPT_ID_BASE) { + __metal_controller_interrupt_vector(METAL_DIRECT_MODE, (void *)(uintptr_t)&__metal_exception_handler); + return 0; + } + return -1; +} + +metal_vector_mode __metal_driver_riscv_cpu_controller_get_vector_mode (struct metal_interrupt *controller) +{ + return __metal_controller_interrupt_vector_mode(); +} + +int __metal_driver_riscv_cpu_controller_set_vector_mode (struct metal_interrupt *controller, + metal_vector_mode mode) +{ + struct __metal_driver_riscv_cpu_intc *intc = (void *)(controller); + ( void ) intc; + + if (mode == METAL_DIRECT_MODE) { + __metal_controller_interrupt_vector(mode, (void *)(uintptr_t)&__metal_exception_handler); + return 0; + } + if (mode == METAL_VECTOR_MODE) { + __metal_controller_interrupt_vector(mode, (void *)__metal_vector_table); + return 0; + } + return -1; +} + +int __metal_driver_riscv_cpu_controller_command_request (struct metal_interrupt *controller, + int cmd, void *data) +{ + /* NOP for now, unless local interrupt lines the like of clic, clint, plic */ + return 0; +} + +/* CPU driver !!! */ + +unsigned long long __metal_driver_cpu_mcycle_get(struct metal_cpu *cpu) +{ + unsigned long long val = 0; + +#if __riscv_xlen == 32 + unsigned long hi, hi1, lo; + + __asm__ volatile ("csrr %0, mcycleh" : "=r"(hi)); + __asm__ volatile ("csrr %0, mcycle" : "=r"(lo)); + __asm__ volatile ("csrr %0, mcycleh" : "=r"(hi1)); + if (hi == hi1) { + val = ((unsigned long long)hi << 32) | lo; + } +#else + __asm__ volatile ("csrr %0, mcycle" : "=r"(val)); +#endif + + return val; +} + +unsigned long long __metal_driver_cpu_timebase_get(struct metal_cpu *cpu) +{ + int timebase; + if (!cpu) { + return 0; + } + + timebase = __metal_driver_cpu_timebase((struct metal_cpu *)cpu); + return timebase; +} + +unsigned long long __metal_driver_cpu_mtime_get (struct metal_cpu *cpu) +{ + unsigned long long time = 0; + struct metal_interrupt *tmr_intc; + struct __metal_driver_riscv_cpu_intc *intc = + (struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu); + + if (intc) { + tmr_intc = intc->metal_int_table[METAL_INTERRUPT_ID_TMR].sub_int; + if (tmr_intc) { + tmr_intc->vtable->command_request(tmr_intc, + METAL_TIMER_MTIME_GET, &time); + } + } + return time; +} + +int __metal_driver_cpu_mtimecmp_set (struct metal_cpu *cpu, unsigned long long time) +{ + int rc = -1; + struct metal_interrupt *tmr_intc; + struct __metal_driver_riscv_cpu_intc *intc = + (struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu); + + if (intc) { + tmr_intc = intc->metal_int_table[METAL_INTERRUPT_ID_TMR].sub_int; + if (tmr_intc) { + rc = tmr_intc->vtable->mtimecmp_set(tmr_intc, + __metal_driver_cpu_hartid(cpu), + time); + } + } + return rc; +} + +struct metal_interrupt * +__metal_driver_cpu_timer_controller_interrupt(struct metal_cpu *cpu) +{ +#ifdef __METAL_DT_RISCV_CLINT0_HANDLE + return __METAL_DT_RISCV_CLINT0_HANDLE; +#else +#ifdef __METAL_DT_SIFIVE_CLIC0_HANDLE + return __METAL_DT_SIFIVE_CLIC0_HANDLE; +#else +#pragma message("There is no interrupt controller for Timer interrupt") + return NULL; +#endif +#endif +} + +int __metal_driver_cpu_get_timer_interrupt_id(struct metal_cpu *cpu) +{ + return METAL_INTERRUPT_ID_TMR; +} + +struct metal_interrupt * +__metal_driver_cpu_sw_controller_interrupt(struct metal_cpu *cpu) +{ +#ifdef __METAL_DT_RISCV_CLINT0_HANDLE + return __METAL_DT_RISCV_CLINT0_HANDLE; +#else +#ifdef __METAL_DT_SIFIVE_CLIC0_HANDLE + return __METAL_DT_SIFIVE_CLIC0_HANDLE; +#else +#pragma message("There is no interrupt controller for Software interrupt") + return NULL; +#endif +#endif +} + +int __metal_driver_cpu_get_sw_interrupt_id(struct metal_cpu *cpu) +{ + return METAL_INTERRUPT_ID_SW; +} + +int __metal_driver_cpu_set_sw_ipi (struct metal_cpu *cpu, int hartid) +{ + int rc = -1; + struct metal_interrupt *sw_intc; + struct __metal_driver_riscv_cpu_intc *intc = + (struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu); + + if (intc) { + sw_intc = intc->metal_int_table[METAL_INTERRUPT_ID_SW].sub_int; + if (sw_intc) { + rc = sw_intc->vtable->command_request(sw_intc, + METAL_SOFTWARE_IPI_SET, &hartid); + } + } + return rc; +} + +int __metal_driver_cpu_clear_sw_ipi (struct metal_cpu *cpu, int hartid) +{ + int rc = -1; + struct metal_interrupt *sw_intc; + struct __metal_driver_riscv_cpu_intc *intc = + (struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu); + + if (intc) { + sw_intc = intc->metal_int_table[METAL_INTERRUPT_ID_SW].sub_int; + if (sw_intc) { + rc = sw_intc->vtable->command_request(sw_intc, + METAL_SOFTWARE_IPI_CLEAR, &hartid); + } + } + return rc; +} + +int __metal_driver_cpu_get_msip (struct metal_cpu *cpu, int hartid) +{ + int rc = 0; + struct metal_interrupt *sw_intc; + struct __metal_driver_riscv_cpu_intc *intc = + (struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu); + + if (intc) { + sw_intc = intc->metal_int_table[METAL_INTERRUPT_ID_SW].sub_int; + if (sw_intc) { + rc = sw_intc->vtable->command_request(sw_intc, + METAL_SOFTWARE_MSIP_GET, &hartid); + } + } + return rc; +} + +struct metal_interrupt * +__metal_driver_cpu_controller_interrupt(struct metal_cpu *cpu) +{ + return __metal_driver_cpu_interrupt_controller(cpu); +} + +int __metal_driver_cpu_enable_interrupt(struct metal_cpu *cpu, void *priv) +{ + if ( __metal_driver_cpu_interrupt_controller(cpu) ) { + /* Only support machine mode for now */ + __metal_interrupt_global_enable(); + return 0; + } + return -1; +} + +int __metal_driver_cpu_disable_interrupt(struct metal_cpu *cpu, void *priv) +{ + if ( __metal_driver_cpu_interrupt_controller(cpu) ) { + /* Only support machine mode for now */ + __metal_interrupt_global_disable(); + return 0; + } + return -1; +} + +int __metal_driver_cpu_exception_register(struct metal_cpu *cpu, int ecode, + metal_exception_handler_t isr) +{ + struct __metal_driver_riscv_cpu_intc *intc = + (struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu); + + if (intc) { + return __metal_exception_register((struct metal_interrupt *)intc, ecode, isr); + } + return -1; +} + +int __metal_driver_cpu_get_instruction_length(struct metal_cpu *cpu, uintptr_t epc) +{ + /** + * Per ISA compressed instruction has last two bits of opcode set. + * The encoding '00' '01' '10' are used for compressed instruction. + * Only enconding '11' isn't regarded as compressed instruction (>16b). + */ + return ((*(unsigned short*)epc & METAL_INSN_LENGTH_MASK) + == METAL_INSN_NOT_COMPRESSED) ? 4 : 2; +} + +uintptr_t __metal_driver_cpu_get_exception_pc(struct metal_cpu *cpu) +{ + uintptr_t mepc; + __asm__ volatile ("csrr %0, mepc" : "=r"(mepc)); + return mepc; +} + +int __metal_driver_cpu_set_exception_pc(struct metal_cpu *cpu, uintptr_t mepc) +{ + __asm__ volatile ("csrw mepc, %0" :: "r"(mepc)); + return 0; +} + +__METAL_DEFINE_VTABLE(__metal_driver_vtable_riscv_cpu_intc) = { + .controller_vtable.interrupt_init = __metal_driver_riscv_cpu_controller_interrupt_init, + .controller_vtable.interrupt_register = __metal_driver_riscv_cpu_controller_interrupt_register, + .controller_vtable.interrupt_enable = __metal_driver_riscv_cpu_controller_interrupt_enable, + .controller_vtable.interrupt_disable = __metal_driver_riscv_cpu_controller_interrupt_disable, + .controller_vtable.interrupt_get_vector_mode = __metal_driver_riscv_cpu_controller_get_vector_mode, + .controller_vtable.interrupt_set_vector_mode = __metal_driver_riscv_cpu_controller_set_vector_mode, + .controller_vtable.command_request = __metal_driver_riscv_cpu_controller_command_request, +}; + +__METAL_DEFINE_VTABLE(__metal_driver_vtable_cpu) = { + .cpu_vtable.mcycle_get = __metal_driver_cpu_mcycle_get, + .cpu_vtable.timebase_get = __metal_driver_cpu_timebase_get, + .cpu_vtable.mtime_get = __metal_driver_cpu_mtime_get, + .cpu_vtable.mtimecmp_set = __metal_driver_cpu_mtimecmp_set, + .cpu_vtable.tmr_controller_interrupt = __metal_driver_cpu_timer_controller_interrupt, + .cpu_vtable.get_tmr_interrupt_id = __metal_driver_cpu_get_timer_interrupt_id, + .cpu_vtable.sw_controller_interrupt = __metal_driver_cpu_sw_controller_interrupt, + .cpu_vtable.get_sw_interrupt_id = __metal_driver_cpu_get_sw_interrupt_id, + .cpu_vtable.set_sw_ipi = __metal_driver_cpu_set_sw_ipi, + .cpu_vtable.clear_sw_ipi = __metal_driver_cpu_clear_sw_ipi, + .cpu_vtable.get_msip = __metal_driver_cpu_get_msip, + .cpu_vtable.controller_interrupt = __metal_driver_cpu_controller_interrupt, + .cpu_vtable.exception_register = __metal_driver_cpu_exception_register, + .cpu_vtable.get_ilen = __metal_driver_cpu_get_instruction_length, + .cpu_vtable.get_epc = __metal_driver_cpu_get_exception_pc, + .cpu_vtable.set_epc = __metal_driver_cpu_set_exception_pc, +}; + diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/riscv_plic0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/riscv_plic0.c new file mode 100644 index 000000000..3272f1c66 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/riscv_plic0.c @@ -0,0 +1,195 @@ +/* Copyright 2018 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine/platform.h> + +#ifdef METAL_RISCV_PLIC0 + +#include <metal/io.h> +#include <metal/shutdown.h> +#include <metal/drivers/riscv_plic0.h> +#include <metal/machine.h> + +unsigned int __metal_plic0_claim_interrupt (struct __metal_driver_riscv_plic0 *plic) +{ + unsigned long control_base = __metal_driver_sifive_plic0_control_base((struct metal_interrupt *)plic); + return __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + + METAL_RISCV_PLIC0_CLAIM)); +} + +void __metal_plic0_complete_interrupt(struct __metal_driver_riscv_plic0 *plic, + unsigned int id) +{ + unsigned long control_base = __metal_driver_sifive_plic0_control_base((struct metal_interrupt *)plic); + __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + + METAL_RISCV_PLIC0_CLAIM)) = id; +} + +int __metal_plic0_set_threshold(struct metal_interrupt *controller, unsigned int threshold) +{ + unsigned long control_base = __metal_driver_sifive_plic0_control_base(controller); + __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + + METAL_RISCV_PLIC0_THRESHOLD)) = threshold; + return 0; +} + +unsigned int __metal_plic0_get_threshold(struct metal_interrupt *controller) +{ + unsigned long control_base = __metal_driver_sifive_plic0_control_base(controller); + + return __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + + METAL_RISCV_PLIC0_THRESHOLD)); +} + +int __metal_plic0_set_priority(struct metal_interrupt *controller, int id, unsigned int priority) +{ + unsigned long control_base = __metal_driver_sifive_plic0_control_base((struct metal_interrupt *)controller); + unsigned int max_priority = __metal_driver_sifive_plic0_max_priority((struct metal_interrupt *)controller); + if ( (max_priority) && (priority < max_priority) ) { + __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + + METAL_RISCV_PLIC0_PRIORITY_BASE + + (id << METAL_PLIC_SOURCE_PRIORITY_SHIFT))) = priority; + return 0; + } + return -1; +} + +unsigned int __metal_plic0_get_priority(struct metal_interrupt *controller, int id) +{ + unsigned long control_base = __metal_driver_sifive_plic0_control_base(controller); + + return __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + + METAL_RISCV_PLIC0_PRIORITY_BASE + + (id << METAL_PLIC_SOURCE_PRIORITY_SHIFT))); +} + +void __metal_plic0_enable(struct __metal_driver_riscv_plic0 *plic, int id, int enable) +{ + unsigned int current; + unsigned long control_base = __metal_driver_sifive_plic0_control_base((struct metal_interrupt *)plic); + + current = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + + METAL_RISCV_PLIC0_ENABLE_BASE + + (id >> METAL_PLIC_SOURCE_SHIFT) * 4)); + __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + + METAL_RISCV_PLIC0_ENABLE_BASE + + ((id >> METAL_PLIC_SOURCE_SHIFT) * 4))) = + enable ? (current | (1 << (id & METAL_PLIC_SOURCE_MASK))) + : (current & ~(1 << (id & METAL_PLIC_SOURCE_MASK))); +} + +void __metal_plic0_default_handler (int id, void *priv) { + metal_shutdown(300); +} + +void __metal_plic0_handler (int id, void *priv) +{ + struct __metal_driver_riscv_plic0 *plic = priv; + unsigned int idx = __metal_plic0_claim_interrupt(plic); + unsigned int num_interrupts = __metal_driver_sifive_plic0_num_interrupts((struct metal_interrupt *)plic); + + if ( (idx < num_interrupts) && (plic->metal_exint_table[idx]) ) { + plic->metal_exint_table[idx](idx, + plic->metal_exdata_table[idx].exint_data); + } + + __metal_plic0_complete_interrupt(plic, idx); +} + +void __metal_driver_riscv_plic0_init (struct metal_interrupt *controller) +{ + struct __metal_driver_riscv_plic0 *plic = (void *)(controller); + + if ( !plic->init_done ) { + int num_interrupts, line; + struct metal_interrupt *intc; + + for(int parent = 0; parent < __METAL_PLIC_NUM_PARENTS; parent++) { + num_interrupts = __metal_driver_sifive_plic0_num_interrupts(controller); + intc = __metal_driver_sifive_plic0_interrupt_parents(controller, parent); + line = __metal_driver_sifive_plic0_interrupt_lines(controller, parent); + + /* Initialize ist parent controller, aka cpu_intc. */ + intc->vtable->interrupt_init(intc); + + for (int i = 0; i < num_interrupts; i++) { + __metal_plic0_enable(plic, i, METAL_DISABLE); + __metal_plic0_set_priority(controller, i, 0); + plic->metal_exint_table[i] = NULL; + plic->metal_exdata_table[i].sub_int = NULL; + plic->metal_exdata_table[i].exint_data = NULL; + } + + __metal_plic0_set_threshold(controller, 0); + + /* Register plic (ext) interrupt with with parent controller */ + intc->vtable->interrupt_register(intc, line, NULL, plic); + /* Register plic handler for dispatching its device interrupts */ + intc->vtable->interrupt_register(intc, line, __metal_plic0_handler, plic); + /* Enable plic (ext) interrupt with with parent controller */ + intc->vtable->interrupt_enable(intc, line); + } + plic->init_done = 1; + } +} + +int __metal_driver_riscv_plic0_register (struct metal_interrupt *controller, + int id, metal_interrupt_handler_t isr, + void *priv) +{ + struct __metal_driver_riscv_plic0 *plic = (void *)(controller); + + if (id >= __metal_driver_sifive_plic0_num_interrupts(controller)) { + return -1; + } + + if (isr) { + __metal_plic0_set_priority(controller, id, 2); + plic->metal_exint_table[id] = isr; + plic->metal_exdata_table[id].exint_data = priv; + } else { + __metal_plic0_set_priority(controller, id, 1); + plic->metal_exint_table[id] = __metal_plic0_default_handler; + plic->metal_exdata_table[id].sub_int = priv; + } + + return 0; +} + +int __metal_driver_riscv_plic0_enable (struct metal_interrupt *controller, int id) +{ + struct __metal_driver_riscv_plic0 *plic = (void *)(controller); + + if (id >= __metal_driver_sifive_plic0_num_interrupts(controller)) { + return -1; + } + + __metal_plic0_enable(plic, id, METAL_ENABLE); + return 0; +} + +int __metal_driver_riscv_plic0_disable (struct metal_interrupt *controller, int id) +{ + struct __metal_driver_riscv_plic0 *plic = (void *)(controller); + + if (id >= __metal_driver_sifive_plic0_num_interrupts(controller)) { + return -1; + } + __metal_plic0_enable(plic, id, METAL_DISABLE); + return 0; +} + +__METAL_DEFINE_VTABLE(__metal_driver_vtable_riscv_plic0) = { + .plic_vtable.interrupt_init = __metal_driver_riscv_plic0_init, + .plic_vtable.interrupt_register = __metal_driver_riscv_plic0_register, + .plic_vtable.interrupt_enable = __metal_driver_riscv_plic0_enable, + .plic_vtable.interrupt_disable = __metal_driver_riscv_plic0_disable, + .plic_vtable.interrupt_get_threshold = __metal_plic0_get_threshold, + .plic_vtable.interrupt_set_threshold = __metal_plic0_set_threshold, + .plic_vtable.interrupt_get_priority = __metal_plic0_get_priority, + .plic_vtable.interrupt_set_priority = __metal_plic0_set_priority, +}; + +#endif /* METAL_RISCV_PLIC0 */ + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_ccache0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_ccache0.c new file mode 100644 index 000000000..6f8723735 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_ccache0.c @@ -0,0 +1,84 @@ +/* Copyright 2019 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine/platform.h> + +#ifdef METAL_SIFIVE_CCACHE0 + +#include <stdint.h> +#include <metal/io.h> +#include <metal/drivers/sifive_ccache0.h> +#include <metal/machine.h> + +#define L2_CONFIG_WAYS_SHIFT 8 +#define L2_CONFIG_WAYS_MASK (0xFF << L2_CONFIG_WAYS_SHIFT) + +void __metal_driver_sifive_ccache0_init(struct metal_cache *l2, int ways); + +static void metal_driver_sifive_ccache0_init(void) __attribute__((constructor)); +static void metal_driver_sifive_ccache0_init(void) +{ +#ifdef __METAL_DT_SIFIVE_CCACHE0_HANDLE + /* Get the handle for the L2 cache controller */ + struct metal_cache *l2 = __METAL_DT_SIFIVE_CCACHE0_HANDLE; + if(!l2) { + return; + } + + /* Get the number of available ways per bank */ + unsigned long control_base = __metal_driver_sifive_ccache0_control_base(l2); + uint32_t ways = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_CCACHE0_CONFIG)); + ways = ((ways & L2_CONFIG_WAYS_MASK) >> L2_CONFIG_WAYS_SHIFT); + + /* Enable all the ways */ + __metal_driver_sifive_ccache0_init(l2, ways); +#endif +} + +void __metal_driver_sifive_ccache0_init(struct metal_cache *l2, int ways) +{ + metal_cache_set_enabled_ways(l2, ways); +} + +int __metal_driver_sifive_ccache0_get_enabled_ways(struct metal_cache *cache) +{ + unsigned long control_base = __metal_driver_sifive_ccache0_control_base(cache); + + uint32_t way_enable = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_CCACHE0_WAYENABLE)); + + /* The stored number is the index, so add one */ + return (0xFF & way_enable) + 1; +} + +int __metal_driver_sifive_ccache0_set_enabled_ways(struct metal_cache *cache, int ways) +{ + unsigned long control_base = __metal_driver_sifive_ccache0_control_base(cache); + + /* We can't decrease the number of enabled ways */ + if(metal_cache_get_enabled_ways(cache) > ways) { + return -2; + } + + /* The stored value is the index, so subtract one */ + uint32_t value = 0xFF & (ways - 1); + + /* Set the number of enabled ways */ + __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_CCACHE0_WAYENABLE)) = value; + + /* Make sure the number of ways was set correctly */ + if(metal_cache_get_enabled_ways(cache) != ways) { + return -3; + } + + return 0; +} + +__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_ccache0) = { + .cache.init = __metal_driver_sifive_ccache0_init, + .cache.get_enabled_ways = __metal_driver_sifive_ccache0_get_enabled_ways, + .cache.set_enabled_ways = __metal_driver_sifive_ccache0_set_enabled_ways, +}; + +#endif + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_clic0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_clic0.c new file mode 100644 index 000000000..12c3dac06 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_clic0.c @@ -0,0 +1,736 @@ +/* Copyright 2018 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine/platform.h> + +#ifdef METAL_SIFIVE_CLIC0 + +#include <stdint.h> +#include <metal/io.h> +#include <metal/shutdown.h> +#include <metal/drivers/sifive_clic0.h> +#include <metal/machine.h> + +typedef enum metal_clic_vector_{ + METAL_CLIC_NONVECTOR = 0, + METAL_CLIC_VECTORED = 1 +} metal_clic_vector; + +struct __metal_clic_cfg { + unsigned char : 1, + nmbits : 2, + nlbits : 4, + nvbit : 1; +}; + +const struct __metal_clic_cfg __metal_clic_defaultcfg = { + .nmbits = METAL_INTR_PRIV_M_MODE, + .nlbits = 0, + .nvbit = METAL_CLIC_NONVECTOR + }; + +void __metal_clic0_handler(int id, void *priv) __attribute__((aligned(64))); + +void __metal_clic0_default_vector_handler (void) __attribute__((interrupt, aligned(64))); + +struct __metal_clic_cfg __metal_clic0_configuration (struct __metal_driver_sifive_clic0 *clic, + struct __metal_clic_cfg *cfg) +{ + volatile unsigned char val; + struct __metal_clic_cfg cliccfg; + unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic); + + if ( cfg ) { + val = cfg->nmbits << 5 | cfg->nlbits << 1 | cfg->nvbit; + __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base + + METAL_SIFIVE_CLIC0_MMODE_APERTURE + + METAL_SIFIVE_CLIC0_CLICCFG)) = val; + } + val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base + + METAL_SIFIVE_CLIC0_MMODE_APERTURE + + METAL_SIFIVE_CLIC0_CLICCFG)); + cliccfg.nmbits = (val & METAL_SIFIVE_CLIC0_CLICCFG_NMBITS_MASK) >> 5; + cliccfg.nlbits = (val & METAL_SIFIVE_CLIC0_CLICCFG_NLBITS_MASK) >> 1; + cliccfg.nvbit = val & METAL_SIFIVE_CLIC0_CLICCFG_NVBIT_MASK; + return cliccfg; +} + +int __metal_clic0_interrupt_set_mode (struct __metal_driver_sifive_clic0 *clic, int id, int mode) +{ + uint8_t mask, val; + struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL); + unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic); + + if (mode >= (cfg.nmbits << 1)) { + /* Do nothing, mode request same or exceed what configured in CLIC */ + return 0; + } + + /* Mask out nmbits and retain other values */ + mask = ((uint8_t)(-1)) >> cfg.nmbits; + val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base + + METAL_SIFIVE_CLIC0_MMODE_APERTURE + + METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id)) & mask; + __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base + + METAL_SIFIVE_CLIC0_MMODE_APERTURE + + METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id)) = val | (mode << (8 - cfg.nmbits)); + return 0; +} + +int __metal_clic0_interrupt_set_level (struct __metal_driver_sifive_clic0 *clic, int id, unsigned int level) +{ + uint8_t mask, nmmask, nlmask, val; + struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL); + unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic); + + /* Drop the LSBs that don't fit in nlbits */ + level = level >> (METAL_CLIC_MAX_NLBITS - cfg.nlbits); + + nmmask = ~( ((uint8_t)(-1)) >> (cfg.nmbits) ); + nlmask = ((uint8_t)(-1)) >> (cfg.nmbits + cfg.nlbits); + mask = ~(nlmask | nmmask); + + val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base + + METAL_SIFIVE_CLIC0_MMODE_APERTURE + + METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id)); + __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base + + METAL_SIFIVE_CLIC0_MMODE_APERTURE + + METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id)) = __METAL_SET_FIELD(val, mask, level); + return 0; +} + +unsigned int __metal_clic0_interrupt_get_level (struct __metal_driver_sifive_clic0 *clic, int id) +{ + int level; + uint8_t mask, val, freebits, nlbits; + struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL); + unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic); + int num_intbits = __metal_driver_sifive_clic0_num_intbits((struct metal_interrupt *)clic); + + if ((cfg.nmbits + cfg.nlbits) >= num_intbits) { + nlbits = num_intbits - cfg.nmbits; + } else { + nlbits = cfg.nlbits; + } + + mask = ((1 << nlbits) - 1) << (8 - (cfg.nmbits + nlbits)); + freebits = ((1 << METAL_CLIC_MAX_NLBITS) - 1) >> nlbits; + + if (mask == 0) { + level = (1 << METAL_CLIC_MAX_NLBITS) - 1; + } else { + val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base + + METAL_SIFIVE_CLIC0_MMODE_APERTURE + + METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id)); + val = __METAL_GET_FIELD(val, mask); + level = (val << (METAL_CLIC_MAX_NLBITS - nlbits)) | freebits; + } + + return level; +} + +int __metal_clic0_interrupt_set_priority (struct __metal_driver_sifive_clic0 *clic, int id, int priority) +{ + uint8_t mask, npmask, val, npbits; + struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL); + unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic); + int num_intbits = __metal_driver_sifive_clic0_num_intbits((struct metal_interrupt *)clic); + + if ((cfg.nmbits + cfg.nlbits) < num_intbits) { + npbits = num_intbits - (cfg.nmbits + cfg.nlbits); + priority = priority >> (8 - npbits); + + mask = ((uint8_t)(-1)) >> (cfg.nmbits + cfg.nlbits + npbits); + npmask = ~(((uint8_t)(-1)) >> (cfg.nmbits + cfg.nlbits)); + mask = ~(mask | npmask); + + val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base + + METAL_SIFIVE_CLIC0_MMODE_APERTURE + + METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id)); + __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base + + METAL_SIFIVE_CLIC0_MMODE_APERTURE + + METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id)) = __METAL_SET_FIELD(val, mask, priority); + } + return 0; +} + +int __metal_clic0_interrupt_get_priority (struct __metal_driver_sifive_clic0 *clic, int id) +{ + int priority; + uint8_t mask, val, freebits, nlbits; + struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL); + unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic); + int num_intbits = __metal_driver_sifive_clic0_num_intbits((struct metal_interrupt *)clic); + + if ((cfg.nmbits + cfg.nlbits) >= num_intbits) { + nlbits = num_intbits - cfg.nmbits; + } else { + nlbits = cfg.nlbits; + } + + mask = ((1 << nlbits) - 1) << (8 - (cfg.nmbits + nlbits)); + freebits = ((1 << METAL_CLIC_MAX_NLBITS) - 1) >> nlbits; + + if (mask == 0) { + priority = (1 << METAL_CLIC_MAX_NLBITS) - 1; + } else { + val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base + + METAL_SIFIVE_CLIC0_MMODE_APERTURE + + METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id)); + priority = __METAL_GET_FIELD(val, freebits); + } + return priority; +} + +int __metal_clic0_interrupt_set_vector_mode (struct __metal_driver_sifive_clic0 *clic, int id, int enable) +{ + uint8_t mask, val; + unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic); + int num_intbits = __metal_driver_sifive_clic0_num_intbits((struct metal_interrupt *)clic); + + mask = 1 << (8 - num_intbits); + val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base + + METAL_SIFIVE_CLIC0_MMODE_APERTURE + + METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id)); + /* Ensure its value is 1 bit wide */ + enable &= 0x1; + __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base + + METAL_SIFIVE_CLIC0_MMODE_APERTURE + + METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id)) = __METAL_SET_FIELD(val, mask, enable); + return 0; +} + +int __metal_clic0_interrupt_is_vectored (struct __metal_driver_sifive_clic0 *clic, int id) +{ + uint8_t mask, val; + unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic); + int num_intbits = __metal_driver_sifive_clic0_num_intbits((struct metal_interrupt *)clic); + + mask = 1 << (8 - num_intbits); + val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base + + METAL_SIFIVE_CLIC0_MMODE_APERTURE + + METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id)); + return __METAL_GET_FIELD(val, mask); +} + +int __metal_clic0_interrupt_enable (struct __metal_driver_sifive_clic0 *clic, int id) +{ + unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic); + int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic); + + if (id >= num_subinterrupts) { + return -1; + } + __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base + + METAL_SIFIVE_CLIC0_MMODE_APERTURE + + METAL_SIFIVE_CLIC0_CLICINTIE_BASE + id)) = METAL_ENABLE; + return 0; +} + +int __metal_clic0_interrupt_disable (struct __metal_driver_sifive_clic0 *clic, int id) +{ + unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic); + int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic); + + if (id >= num_subinterrupts) { + return -1; + } + __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base + + METAL_SIFIVE_CLIC0_MMODE_APERTURE + + METAL_SIFIVE_CLIC0_CLICINTIE_BASE + id)) = METAL_DISABLE; + return 0; +} + +int __metal_clic0_interrupt_is_enabled (struct __metal_driver_sifive_clic0 *clic, int id) +{ + unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic); + int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic); + + if (id >= num_subinterrupts) { + return 0; + } + return __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base + + METAL_SIFIVE_CLIC0_MMODE_APERTURE + + METAL_SIFIVE_CLIC0_CLICINTIE_BASE + id)); +} + +int __metal_clic0_interrupt_is_pending (struct __metal_driver_sifive_clic0 *clic, int id) +{ + unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic); + int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic); + + if (id >= num_subinterrupts) { + return 0; + } + return __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base + + METAL_SIFIVE_CLIC0_MMODE_APERTURE + + METAL_SIFIVE_CLIC0_CLICINTIP_BASE + id)); +} + +int __metal_clic0_interrupt_set (struct __metal_driver_sifive_clic0 *clic, int id) +{ + unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic); + int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic); + + if (id < num_subinterrupts) { + __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base + + METAL_SIFIVE_CLIC0_MMODE_APERTURE + + METAL_SIFIVE_CLIC0_CLICINTIP_BASE + id)) = METAL_ENABLE; + return 0; + } + return -1; +} + +int __metal_clic0_interrupt_clear (struct __metal_driver_sifive_clic0 *clic, int id) +{ + unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic); + int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic); + + if (id < num_subinterrupts) { + __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base + + METAL_SIFIVE_CLIC0_MMODE_APERTURE + + METAL_SIFIVE_CLIC0_CLICINTIP_BASE + id)) = METAL_DISABLE; + return 0; + } + return -1; +} + +int __metal_clic0_configure_set_vector_mode (struct __metal_driver_sifive_clic0 *clic, metal_vector_mode mode) +{ + struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL); + + switch (mode) { + case METAL_SELECTIVE_NONVECTOR_MODE: + cfg.nvbit = METAL_CLIC_NONVECTOR; + __metal_controller_interrupt_vector(mode, &clic->metal_mtvt_table); + break; + case METAL_SELECTIVE_VECTOR_MODE: + cfg.nvbit = METAL_CLIC_VECTORED; + __metal_controller_interrupt_vector(mode, &clic->metal_mtvt_table); + break; + case METAL_HARDWARE_VECTOR_MODE: + cfg.nvbit = METAL_CLIC_VECTORED; + __metal_controller_interrupt_vector(mode, &clic->metal_mtvt_table); + break; + default: + return -1; + } + __metal_clic0_configuration(clic, &cfg); + return 0; +} + +metal_vector_mode __metal_clic0_configure_get_vector_mode (struct __metal_driver_sifive_clic0 *clic) +{ + struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL); + metal_vector_mode mode = __metal_controller_interrupt_vector_mode(); + + if (mode == METAL_SELECTIVE_VECTOR_MODE) { + if (cfg.nvbit) { + return METAL_SELECTIVE_VECTOR_MODE; + } else { + return METAL_SELECTIVE_NONVECTOR_MODE; + } + } else { + return mode; + } +} + +int __metal_clic0_configure_set_privilege (struct __metal_driver_sifive_clic0 *clic, metal_intr_priv_mode priv) +{ + struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL); + + cfg.nmbits = priv; + __metal_clic0_configuration(clic, &cfg); + return 0; +} + +metal_intr_priv_mode __metal_clic0_configure_get_privilege (struct __metal_driver_sifive_clic0 *clic) +{ + struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL); + + return cfg.nmbits; +} + +int __metal_clic0_configure_set_level (struct __metal_driver_sifive_clic0 *clic, int level) +{ + struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL); + + cfg.nlbits = level & 0xF; + __metal_clic0_configuration(clic, &cfg); + return 0; +} + +int __metal_clic0_configure_get_level (struct __metal_driver_sifive_clic0 *clic) +{ + struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL); + + return cfg.nlbits; +} + +unsigned long long __metal_clic0_mtime_get (struct __metal_driver_sifive_clic0 *clic) +{ + __metal_io_u32 lo, hi; + unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic); + + /* Guard against rollover when reading */ + do { + hi = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_CLIC0_MTIME + 4)); + lo = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_CLIC0_MTIME)); + } while (__METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_CLIC0_MTIME + 4)) != hi); + + return (((unsigned long long)hi) << 32) | lo; +} + +int __metal_driver_sifive_clic0_mtimecmp_set(struct metal_interrupt *controller, + int hartid, + unsigned long long time) +{ + struct __metal_driver_sifive_clic0 *clic = + (struct __metal_driver_sifive_clic0 *)(controller); + + unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic); + /* Per spec, the RISC-V MTIME/MTIMECMP registers are 64 bit, + * and are NOT internally latched for multiword transfers. + * Need to be careful about sequencing to avoid triggering + * spurious interrupts: For that set the high word to a max + * value first. + */ + __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + (8 * hartid) + METAL_SIFIVE_CLIC0_MTIMECMP_BASE + 4)) = 0xFFFFFFFF; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + (8 * hartid) + METAL_SIFIVE_CLIC0_MTIMECMP_BASE)) = (__metal_io_u32)time; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + (8 * hartid) + METAL_SIFIVE_CLIC0_MTIMECMP_BASE + 4)) = (__metal_io_u32)(time >> 32); + return 0; +} + +void __metal_clic0_handler (int id, void *priv) +{ + struct __metal_driver_sifive_clic0 *clic = priv; + int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic); + + if ( (id < num_subinterrupts) && (clic->metal_exint_table[id].handler) ) { + clic->metal_exint_table[id].handler(id, clic->metal_exint_table[id].exint_data); + } +} + +void __metal_clic0_default_handler (int id, void *priv) { + metal_shutdown(300); +} + +void __metal_clic0_default_vector_handler (void) { + metal_shutdown(400); +} + +void __metal_driver_sifive_clic0_init (struct metal_interrupt *controller) +{ + struct __metal_driver_sifive_clic0 *clic = + (struct __metal_driver_sifive_clic0 *)(controller); + + if ( !clic->init_done ) { + int level, max_levels, line, num_interrupts, num_subinterrupts; + struct __metal_clic_cfg cfg = __metal_clic_defaultcfg; + struct metal_interrupt *intc = + __metal_driver_sifive_clic0_interrupt_parent(controller); + + /* Initialize ist parent controller, aka cpu_intc. */ + intc->vtable->interrupt_init(intc); + __metal_controller_interrupt_vector(METAL_SELECTIVE_NONVECTOR_MODE, + &clic->metal_mtvt_table); + + /* + * Register its interrupts with with parent controller, + * aka sw, timer and ext to its default isr + */ + num_interrupts = __metal_driver_sifive_clic0_num_interrupts(controller); + for (int i = 0; i < num_interrupts; i++) { + line = __metal_driver_sifive_clic0_interrupt_lines(controller, i); + intc->vtable->interrupt_register(intc, line, NULL, clic); + } + + /* Default CLIC mode to per dts */ + max_levels = __metal_driver_sifive_clic0_max_levels(controller); + cfg.nlbits = (max_levels > METAL_CLIC_MAX_NLBITS) ? + METAL_CLIC_MAX_NLBITS : max_levels; + __metal_clic0_configuration(clic, &cfg); + + level = (1 << cfg.nlbits) - 1; + num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller); + clic->metal_mtvt_table[0] = &__metal_clic0_handler; + for (int i = 1; i < num_subinterrupts; i++) { + clic->metal_mtvt_table[i] = NULL; + clic->metal_exint_table[i].handler = NULL; + clic->metal_exint_table[i].sub_int = NULL; + clic->metal_exint_table[i].exint_data = NULL; + __metal_clic0_interrupt_disable(clic, i); + __metal_clic0_interrupt_set_level(clic, i, level); + } + clic->init_done = 1; + } +} + +int __metal_driver_sifive_clic0_register (struct metal_interrupt *controller, + int id, metal_interrupt_handler_t isr, + void *priv) +{ + int rc = -1; + int num_subinterrupts; + struct __metal_driver_sifive_clic0 *clic = + (struct __metal_driver_sifive_clic0 *)(controller); + struct metal_interrupt *intc = + __metal_driver_sifive_clic0_interrupt_parent(controller); + metal_vector_mode mode = __metal_clic0_configure_get_vector_mode(clic); + + if ( ( (mode == METAL_SELECTIVE_VECTOR_MODE) && + (__metal_clic0_interrupt_is_vectored(clic, id)) ) || + (mode == METAL_HARDWARE_VECTOR_MODE) || + (mode == METAL_VECTOR_MODE) || + (mode == METAL_DIRECT_MODE) ) { + return rc; + } + + /* Register its interrupts with parent controller */ + if (id < METAL_INTERRUPT_ID_CSW) { + return intc->vtable->interrupt_register(intc, id, isr, priv); + } + + /* + * CLIC (sub-interrupts) devices interrupts start at 16 but offset from 0 + * Reset the IDs to reflects this. + */ + num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller); + if (id < num_subinterrupts) { + if ( isr) { + clic->metal_exint_table[id].handler = isr; + clic->metal_exint_table[id].exint_data = priv; + } else { + clic->metal_exint_table[id].handler = __metal_clic0_default_handler; + clic->metal_exint_table[id].sub_int = priv; + } + rc = 0; + } + return rc; +} + +int __metal_driver_sifive_clic0_vector_register (struct metal_interrupt *controller, + int id, metal_interrupt_vector_handler_t isr, + void *priv) +{ + int rc = -1; + struct __metal_driver_sifive_clic0 *clic = + (struct __metal_driver_sifive_clic0 *)(controller); + struct metal_interrupt *intc = + __metal_driver_sifive_clic0_interrupt_parent(controller); + int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller); + metal_vector_mode mode = __metal_clic0_configure_get_vector_mode(clic); + + if ((mode != METAL_SELECTIVE_VECTOR_MODE) && (mode != METAL_HARDWARE_VECTOR_MODE)) { + return rc; + } + if ((mode == METAL_SELECTIVE_VECTOR_MODE) && + (__metal_clic0_interrupt_is_vectored(clic, id) == 0) ) { + return rc; + } + if (id < num_subinterrupts) { + if ( isr) { + clic->metal_mtvt_table[id] = isr; + clic->metal_exint_table[id].exint_data = priv; + } else { + clic->metal_mtvt_table[id] = __metal_clic0_default_vector_handler; + clic->metal_exint_table[id].sub_int = priv; + } + rc = 0; + } + return rc; +} + +int __metal_driver_sifive_clic0_enable (struct metal_interrupt *controller, int id) +{ + struct __metal_driver_sifive_clic0 *clic = + (struct __metal_driver_sifive_clic0 *)(controller); + return __metal_clic0_interrupt_enable(clic, id); +} + +int __metal_driver_sifive_clic0_disable (struct metal_interrupt *controller, int id) +{ + struct __metal_driver_sifive_clic0 *clic = + (struct __metal_driver_sifive_clic0 *)(controller); + return __metal_clic0_interrupt_disable(clic, id); +} + +int __metal_driver_sifive_clic0_enable_interrupt_vector(struct metal_interrupt *controller, int id) +{ + int rc = -1; + int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller); + struct __metal_driver_sifive_clic0 *clic = + (struct __metal_driver_sifive_clic0 *)(controller); + metal_vector_mode mode = __metal_clic0_configure_get_vector_mode(clic); + + if ((mode != METAL_SELECTIVE_VECTOR_MODE) && (mode != METAL_HARDWARE_VECTOR_MODE)) { + return rc; + } + if (id < num_subinterrupts) { + __metal_clic0_interrupt_set_vector_mode(clic, id, METAL_ENABLE); + return 0; + } + return -1; +} + +int __metal_driver_sifive_clic0_disable_interrupt_vector(struct metal_interrupt *controller, int id) +{ + int num_subinterrupts; + struct __metal_driver_sifive_clic0 *clic = + (struct __metal_driver_sifive_clic0 *)(controller); + + num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller); + if (id < num_subinterrupts) { + __metal_clic0_interrupt_set_vector_mode(clic, id, METAL_DISABLE); + return 0; + } + return -1; +} + +metal_vector_mode __metal_driver_sifive_clic0_get_vector_mode (struct metal_interrupt *controller) +{ + struct __metal_driver_sifive_clic0 *clic = + (struct __metal_driver_sifive_clic0 *)(controller); + return __metal_clic0_configure_get_vector_mode(clic); +} + +int __metal_driver_sifive_clic0_set_vector_mode (struct metal_interrupt *controller, metal_vector_mode mode) +{ + struct __metal_driver_sifive_clic0 *clic = + (struct __metal_driver_sifive_clic0 *)(controller); + return __metal_clic0_configure_set_vector_mode(clic, mode); +} + +metal_intr_priv_mode __metal_driver_sifive_clic0_get_privilege (struct metal_interrupt *controller) +{ + struct __metal_driver_sifive_clic0 *clic = + (struct __metal_driver_sifive_clic0 *)(controller); + return __metal_clic0_configure_get_privilege(clic); +} + +int __metal_driver_sifive_clic0_set_privilege (struct metal_interrupt *controller, metal_intr_priv_mode priv) +{ + struct __metal_driver_sifive_clic0 *clic = + (struct __metal_driver_sifive_clic0 *)(controller); + return __metal_clic0_configure_set_privilege(clic, priv); +} + +unsigned int __metal_driver_sifive_clic0_get_threshold (struct metal_interrupt *controller) +{ + struct __metal_driver_sifive_clic0 *clic = + (struct __metal_driver_sifive_clic0 *)(controller); + return __metal_clic0_configure_get_level(clic); +} + +int __metal_driver_sifive_clic0_set_threshold (struct metal_interrupt *controller, unsigned int level) +{ + struct __metal_driver_sifive_clic0 *clic = + (struct __metal_driver_sifive_clic0 *)(controller); + return __metal_clic0_configure_set_level(clic, level); +} + +unsigned int __metal_driver_sifive_clic0_get_priority (struct metal_interrupt *controller, int id) +{ + struct __metal_driver_sifive_clic0 *clic = + (struct __metal_driver_sifive_clic0 *)(controller); + return __metal_clic0_interrupt_get_priority(clic, id); +} + +int __metal_driver_sifive_clic0_set_priority (struct metal_interrupt *controller, int id, unsigned int priority) +{ + struct __metal_driver_sifive_clic0 *clic = + (struct __metal_driver_sifive_clic0 *)(controller); + return __metal_clic0_interrupt_set_priority(clic, id, priority); +} + +int __metal_driver_sifive_clic0_clear_interrupt (struct metal_interrupt *controller, int id) +{ + struct __metal_driver_sifive_clic0 *clic = + (struct __metal_driver_sifive_clic0 *)(controller); + return __metal_clic0_interrupt_clear(clic, id); +} + +int __metal_driver_sifive_clic0_set_interrupt (struct metal_interrupt *controller, int id) +{ + struct __metal_driver_sifive_clic0 *clic = + (struct __metal_driver_sifive_clic0 *)(controller); + return __metal_clic0_interrupt_set(clic, id); +} + +int __metal_driver_sifive_clic0_command_request (struct metal_interrupt *controller, + int command, void *data) +{ + int hartid; + int rc = -1; + struct __metal_driver_sifive_clic0 *clic = + (struct __metal_driver_sifive_clic0 *)(controller); + unsigned long control_base = __metal_driver_sifive_clic0_control_base(controller); + + switch (command) { + case METAL_TIMER_MTIME_GET: + if (data) { + *(unsigned long long *)data = __metal_clic0_mtime_get(clic); + rc = 0; + } + break; + case METAL_SOFTWARE_IPI_CLEAR: + if (data) { + hartid = *(int *)data; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + + (hartid * 4))) = METAL_DISABLE; + __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base + + METAL_SIFIVE_CLIC0_MMODE_APERTURE + + METAL_SIFIVE_CLIC0_CLICINTIP_BASE)) = METAL_DISABLE; + rc = 0; + } + break; + case METAL_SOFTWARE_IPI_SET: + if (data) { + hartid = *(int *)data; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + + (hartid * 4))) = METAL_ENABLE; + __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base + + METAL_SIFIVE_CLIC0_MMODE_APERTURE + + METAL_SIFIVE_CLIC0_CLICINTIP_BASE)) = METAL_ENABLE; + rc = 0; + } + break; + case METAL_SOFTWARE_MSIP_GET: + rc = 0; + if (data) { + hartid = *(int *)data; + rc = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + + (hartid * 4))); + } + break; + default: + break; + } + + return rc; +} +__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_clic0) = { + .clic_vtable.interrupt_init = __metal_driver_sifive_clic0_init, + .clic_vtable.interrupt_register = __metal_driver_sifive_clic0_register, + .clic_vtable.interrupt_vector_register = __metal_driver_sifive_clic0_vector_register, + .clic_vtable.interrupt_enable = __metal_driver_sifive_clic0_enable, + .clic_vtable.interrupt_disable = __metal_driver_sifive_clic0_disable, + .clic_vtable.interrupt_vector_enable = __metal_driver_sifive_clic0_enable_interrupt_vector, + .clic_vtable.interrupt_vector_disable = __metal_driver_sifive_clic0_disable_interrupt_vector, + .clic_vtable.interrupt_get_vector_mode = __metal_driver_sifive_clic0_get_vector_mode, + .clic_vtable.interrupt_set_vector_mode = __metal_driver_sifive_clic0_set_vector_mode, + .clic_vtable.interrupt_get_privilege = __metal_driver_sifive_clic0_get_privilege, + .clic_vtable.interrupt_set_privilege = __metal_driver_sifive_clic0_set_privilege, + .clic_vtable.interrupt_get_threshold = __metal_driver_sifive_clic0_get_threshold, + .clic_vtable.interrupt_set_threshold = __metal_driver_sifive_clic0_set_threshold, + .clic_vtable.interrupt_get_priority = __metal_driver_sifive_clic0_get_priority, + .clic_vtable.interrupt_set_priority = __metal_driver_sifive_clic0_set_priority, + .clic_vtable.interrupt_clear = __metal_driver_sifive_clic0_clear_interrupt, + .clic_vtable.interrupt_set = __metal_driver_sifive_clic0_set_interrupt, + .clic_vtable.command_request = __metal_driver_sifive_clic0_command_request, + .clic_vtable.mtimecmp_set = __metal_driver_sifive_clic0_mtimecmp_set, +}; + +#endif /* METAL_SIFIVE_CLIC0 */ + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_hfrosc.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_hfrosc.c new file mode 100644 index 000000000..61af8d314 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_hfrosc.c @@ -0,0 +1,44 @@ +/* Copyright 2018 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine/platform.h> + +#ifdef METAL_SIFIVE_FE310_G000_HFROSC + +#include <metal/drivers/sifive_fe310-g000_hfrosc.h> +#include <metal/machine.h> + +#define CONFIG_DIVIDER 0x0000003FUL +#define CONFIG_TRIM 0x001F0000UL +#define CONFIG_ENABLE 0x40000000UL +#define CONFIG_READY 0x80000000UL + +long __metal_driver_sifive_fe310_g000_hfrosc_get_rate_hz(const struct metal_clock *clock) +{ + struct metal_clock *ref = __metal_driver_sifive_fe310_g000_hfrosc_ref(clock); + long config_offset = __metal_driver_sifive_fe310_g000_hfrosc_config_offset(clock); + struct __metal_driver_sifive_fe310_g000_prci *config_base = + __metal_driver_sifive_fe310_g000_hfrosc_config_base(clock); + const struct __metal_driver_vtable_sifive_fe310_g000_prci *vtable = + __metal_driver_sifive_fe310_g000_prci_vtable(); + long cfg = vtable->get_reg(config_base, config_offset); + + if ((cfg & CONFIG_ENABLE) == 0) + return -1; + if ((cfg & CONFIG_READY) == 0) + return -1; + return metal_clock_get_rate_hz(ref) / ((cfg & CONFIG_DIVIDER) + 1); +} + +long __metal_driver_sifive_fe310_g000_hfrosc_set_rate_hz(struct metal_clock *clock, long rate) +{ + return __metal_driver_sifive_fe310_g000_hfrosc_get_rate_hz(clock); +} + +__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_hfrosc) = { + .clock.get_rate_hz = &__metal_driver_sifive_fe310_g000_hfrosc_get_rate_hz, + .clock.set_rate_hz = &__metal_driver_sifive_fe310_g000_hfrosc_set_rate_hz, +}; +#endif /* METAL_SIFIVE_FE310_G000_HFROSC */ + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_hfxosc.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_hfxosc.c new file mode 100644 index 000000000..9ed7a0bf3 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_hfxosc.c @@ -0,0 +1,43 @@ +/* Copyright 2018 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine/platform.h> + +#ifdef METAL_SIFIVE_FE310_G000_HFXOSC + +#include <metal/drivers/sifive_fe310-g000_hfxosc.h> +#include <metal/machine.h> + +#define CONFIG_ENABLE 0x40000000UL +#define CONFIG_READY 0x80000000UL + +long __metal_driver_sifive_fe310_g000_hfxosc_get_rate_hz(const struct metal_clock *clock) +{ + struct metal_clock *ref = __metal_driver_sifive_fe310_g000_hfxosc_ref(clock); + long config_offset = __metal_driver_sifive_fe310_g000_hfxosc_config_offset(clock); + struct __metal_driver_sifive_fe310_g000_prci *config_base = + __metal_driver_sifive_fe310_g000_hfxosc_config_base(clock); + const struct __metal_driver_vtable_sifive_fe310_g000_prci *vtable = + __metal_driver_sifive_fe310_g000_prci_vtable(); + long cfg = vtable->get_reg(config_base, config_offset); + + if ((cfg & CONFIG_ENABLE) == 0) + return -1; + if ((cfg & CONFIG_READY) == 0) + return -1; + return metal_clock_get_rate_hz(ref); +} + +long __metal_driver_sifive_fe310_g000_hfxosc_set_rate_hz(struct metal_clock *clock, long rate) +{ + return __metal_driver_sifive_fe310_g000_hfxosc_get_rate_hz(clock); +} + +__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_hfxosc) = { + .clock.get_rate_hz = __metal_driver_sifive_fe310_g000_hfxosc_get_rate_hz, + .clock.set_rate_hz = __metal_driver_sifive_fe310_g000_hfxosc_set_rate_hz, +}; + +#endif /* METAL_SIFIVE_FE310_G000_HFXOSC */ + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_lfrosc.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_lfrosc.c new file mode 100644 index 000000000..324382b9d --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_lfrosc.c @@ -0,0 +1,53 @@ +/* Copyright 2019 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine/platform.h> + +#ifdef METAL_SIFIVE_FE310_G000_LFROSC + +#include <metal/drivers/sifive_fe310-g000_lfrosc.h> +#include <metal/machine.h> + +/* LFROSCCFG */ +#define METAL_LFROSCCFG_DIV_MASK 0x3F +#define METAL_LFROSCCFG_TRIM_SHIFT 16 +#define METAL_LFROSCCFG_TRIM_MASK (0x1F << METAL_LFROSCCFG_TRIM_SHIFT) +#define METAL_LFROSCCFG_EN (1 << 30) +#define METAL_LFROSCCFG_RDY (1 << 31) + +/* LFCLKMUX */ +#define METAL_LFCLKMUX_SEL 1 +#define METAL_LFCLKMUX_EXT_MUX_STATUS (1 << 31) + +#define LFROSC_REGW(addr) (__METAL_ACCESS_ONCE((__metal_io_u32 *)addr)) + +long __metal_driver_sifive_fe310_g000_lfrosc_get_rate_hz(const struct metal_clock *clock) +{ + struct metal_clock *internal_ref = __metal_driver_sifive_fe310_g000_lfrosc_lfrosc(clock); + struct metal_clock *external_ref = __metal_driver_sifive_fe310_g000_lfrosc_psdlfaltclk(clock); + + unsigned long int cfg_reg = __metal_driver_sifive_fe310_g000_lfrosc_config_reg(clock); + unsigned long int mux_reg = __metal_driver_sifive_fe310_g000_lfrosc_mux_reg(clock); + + if(LFROSC_REGW(mux_reg) & METAL_LFCLKMUX_EXT_MUX_STATUS) { + return metal_clock_get_rate_hz(external_ref); + } + + const unsigned long int div = (LFROSC_REGW(cfg_reg) & METAL_LFROSCCFG_DIV_MASK) + 1; + + return metal_clock_get_rate_hz(internal_ref) / div; +} + +long __metal_driver_sifive_fe310_g000_lfrosc_set_rate_hz(struct metal_clock *clock, long rate) +{ + return __metal_driver_sifive_fe310_g000_lfrosc_get_rate_hz(clock); +} + +__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_lfrosc) = { + .clock.get_rate_hz = &__metal_driver_sifive_fe310_g000_lfrosc_get_rate_hz, + .clock.set_rate_hz = &__metal_driver_sifive_fe310_g000_lfrosc_set_rate_hz, +}; +#endif /* METAL_SIFIVE_FE310_G000_LFROSC */ + +typedef int no_empty_translation_units; + diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_pll.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_pll.c new file mode 100644 index 000000000..2ca468f43 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_pll.c @@ -0,0 +1,360 @@ +/* Copyright 2018 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine/platform.h> + +#ifdef METAL_SIFIVE_FE310_G000_PLL + +#include <stdio.h> +#include <limits.h> + +#include <metal/machine.h> +#include <metal/drivers/sifive_fe310-g000_pll.h> +#include <stdlib.h> + +#define PLL_R 0x00000007UL +#define PLL_F 0x000003F0UL +#define PLL_Q 0x00000C00UL +#define PLL_SEL 0x00010000UL +#define PLL_REFSEL 0x00020000UL +#define PLL_BYPASS 0x00040000UL +#define PLL_LOCK 0x80000000UL + +#define DIV_DIV 0x0000003FUL +#define DIV_1 0x00000100UL + +#define PLL_R_SHIFT(r) ((r << 0) & PLL_R) +#define PLL_F_SHIFT(f) ((f << 4) & PLL_F) +#define PLL_Q_SHIFT(q) ((q << 10) & PLL_Q) +#define PLL_DIV_SHIFT(d) ((d << 0) & DIV_DIV) + +struct pll_config_t { + unsigned long multiplier; + unsigned long divisor; + unsigned long min_input_rate; + unsigned long max_input_rate; + unsigned long r; + unsigned long f; + unsigned long q; + long d; /* < 0 if disabled */ +}; + +static const struct pll_config_t pll_configs[] = { + /* + * multiplier + * ^ divisor + * | ^ min_input_rate + * | | ^ max_input_rate + * | | | ^ r + * | | | | ^ f + * | | | | | ^ q + * | | | | | | ^ d + * | | | | | | | ^ + * | | | | | | | | */ + { 1, 32, 12000000, 24000000, 1, 31, 3, 63}, + { 1, 32, 24000000, 48000000, 3, 31, 2, 63}, + { 1, 16, 6000000, 12000000, 0, 31, 3, 63}, + { 1, 16, 12000000, 24000000, 1, 31, 2, 63}, + { 1, 16, 24000000, 48000000, 3, 31, 2, 31}, + { 1, 8, 6000000, 12000000, 0, 31, 3, 31}, + { 1, 8, 12000000, 24000000, 1, 31, 2, 31}, + { 1, 8, 24000000, 48000000, 3, 31, 2, 15}, + { 1, 4, 6000000, 12000000, 0, 31, 3, 15}, + { 1, 4, 12000000, 24000000, 1, 31, 2, 15}, + { 1, 4, 24000000, 48000000, 3, 31, 2, 7}, + { 1, 2, 6000000, 12000000, 0, 31, 2, 15}, + { 1, 2, 12000000, 24000000, 1, 31, 1, 15}, + { 1, 2, 24000000, 48000000, 3, 31, 1, 7}, + { 2, 1, 6000000, 12000000, 0, 31, 1, 7}, + { 2, 1, 12000000, 24000000, 1, 31, 1, 3}, + { 2, 1, 24000000, 48000000, 3, 31, 3, -1}, + { 4, 1, 6000000, 12000000, 0, 31, 3, 0}, + { 4, 1, 12000000, 24000000, 1, 31, 3, -1}, + { 4, 1, 24000000, 48000000, 3, 31, 2, -1}, + { 6, 1, 6000000, 10666666, 0, 35, 1, 2}, + { 6, 1, 10666666, 12000000, 0, 23, 3, -1}, + { 6, 1, 12000000, 16000000, 1, 47, 3, -1}, + { 6, 1, 16000000, 18000000, 1, 23, 2, -1}, + { 6, 1, 18000000, 21333333, 2, 35, 2, -1}, + { 8, 1, 6000000, 12000000, 0, 31, 3, -1}, + { 8, 1, 12000000, 24000000, 1, 31, 2, -1}, + { 8, 1, 24000000, 48000000, 3, 31, 1, -1}, + {10, 1, 6000000, 9600000, 0, 39, 3, -1}, + {10, 1, 9600000, 12000000, 0, 19, 2, -1}, + {10, 1, 12000000, 19200000, 1, 39, 2, -1}, + {10, 1, 19200000, 24000000, 1, 19, 1, -1}, + {10, 1, 24000000, 38400000, 3, 39, 1, -1}, + {12, 1, 6000000, 8000000, 0, 47, 3, -1}, + {12, 1, 8000000, 12000000, 0, 23, 2, -1}, + {12, 1, 12000000, 16000000, 1, 47, 2, -1}, + {12, 1, 16000000, 24000000, 1, 23, 1, -1}, + {12, 1, 24000000, 30000000, 3, 47, 1, -1}, + {12, 1, 30000000, 32000000, 3, 47, 1, -1}, + {14, 1, 6000000, 6857142, 0, 55, 3, -1}, + {14, 1, 6857143, 12000000, 0, 27, 2, -1}, + {14, 1, 12000000, 13714285, 1, 55, 2, -1}, + {14, 1, 13714286, 24000000, 1, 27, 1, -1}, + {14, 1, 24000000, 27428571, 3, 55, 1, -1}, + {16, 1, 6000000, 12000000, 0, 31, 2, -1}, + {16, 1, 12000000, 24000000, 1, 31, 1, -1}, + {18, 1, 6000000, 10666666, 0, 35, 2, -1}, + {18, 1, 10666667, 12000000, 0, 17, 1, -1}, + {18, 1, 12000000, 21333333, 1, 35, 1, -1}, + {20, 1, 6000000, 9600000, 0, 39, 2, -1}, + {20, 1, 9600000, 12000000, 0, 19, 1, -1}, + {20, 1, 12000000, 19200000, 1, 39, 1, -1}, + {22, 1, 6000000, 8727272, 0, 43, 2, -1}, + {22, 1, 8727273, 12000000, 0, 21, 1, -1}, + {22, 1, 12000000, 17454545, 1, 43, 1, -1}, + {24, 1, 6000000, 8000000, 0, 47, 2, -1}, + {24, 1, 8000000, 12000000, 0, 23, 1, -1}, + {24, 1, 12000000, 16000000, 1, 47, 1, -1}, + {26, 1, 6000000, 7384615, 0, 51, 2, -1}, + {26, 1, 7384616, 12000000, 0, 25, 1, -1}, + {26, 1, 12000000, 14768230, 1, 51, 1, -1}, + {28, 1, 6000000, 6857142, 0, 55, 2, -1}, + {28, 1, 6857143, 12000000, 0, 27, 1, -1}, + {28, 1, 12000000, 13714285, 1, 55, 1, -1}, + {30, 1, 6000000, 6400000, 0, 59, 2, -1}, + {30, 1, 6400000, 12000000, 0, 29, 1, -1}, + {30, 1, 12000000, 12800000, 1, 59, 1, -1}, + {32, 1, 6000000, 12000000, 0, 31, 1, -1} +}; + +#define PLL_CONFIG_NOT_VALID -1 + +void __metal_driver_sifive_fe310_g000_pll_init(struct __metal_driver_sifive_fe310_g000_pll *pll); + +/* Given the rate of the PLL input frequency and a PLL configuration, what + * will the resulting PLL output frequency be? + * Arguments: + * - pll_input_rate the PLL input frequency in hertz + * - config the PLL configuration + * Returns: + * - PLL_CONFIG_NOT_VALID if the configuration is not valid for the input frequency + * - the output frequency, in hertz */ +static long get_pll_config_freq(unsigned long pll_input_rate, const struct pll_config_t *config) +{ + if(pll_input_rate < config->min_input_rate || pll_input_rate > config->max_input_rate) + return PLL_CONFIG_NOT_VALID; + + return pll_input_rate * config->multiplier / config->divisor; +} + +#ifdef __METAL_DT_SIFIVE_FE310_G000_PLL_HANDLE + +static void metal_sifive_fe310_g000_pll_init(void) __attribute__((constructor)); +static void metal_sifive_fe310_g000_pll_init(void) { + long init_rate = __metal_driver_sifive_fe310_g000_pll_init_rate(); + /* If the PLL init_rate is zero, don't initialize the PLL */ + if(init_rate != 0) + __metal_driver_sifive_fe310_g000_pll_init(__METAL_DT_SIFIVE_FE310_G000_PLL_HANDLE); +} + +#endif /* __METAL_DT_SIFIVE_FE310_G000__PLL_HANDLE */ + +void __metal_driver_sifive_fe310_g000_pll_init(struct __metal_driver_sifive_fe310_g000_pll *pll) { + struct metal_clock *pllref = __metal_driver_sifive_fe310_g000_pll_pllref(&(pll->clock)); + long init_rate = __metal_driver_sifive_fe310_g000_pll_init_rate(); + long config_offset = __metal_driver_sifive_fe310_g000_pll_config_offset(); + long base = __metal_driver_sifive_fe310_g000_prci_base(); + + __metal_io_u32 *pllcfg = (__metal_io_u32 *) (base + config_offset); + + /* If the PLL clock has had a _pre_rate_change_callback configured, call it */ + _metal_clock_call_all_callbacks(pll->clock._pre_rate_change_callback); + + /* If we're running off of the PLL, switch off before we start configuring it*/ + if((__METAL_ACCESS_ONCE(pllcfg) & PLL_SEL) == 0) + __METAL_ACCESS_ONCE(pllcfg) &= ~(PLL_SEL); + + /* Make sure we're running off of the external oscillator for stability */ + if(pllref != NULL) + __METAL_ACCESS_ONCE(pllcfg) |= PLL_REFSEL; + + /* Configure the PLL to run at the requested init frequency. + * Using the vtable instead of the user API because we want to control + * when the callbacks occur. */ + pll->clock.vtable->set_rate_hz(&(pll->clock), init_rate); + + /* If the PLL clock has had a rate_change_callback configured, call it */ + _metal_clock_call_all_callbacks(pll->clock._post_rate_change_callback); +} + +long __metal_driver_sifive_fe310_g000_pll_get_rate_hz(const struct metal_clock *clock) +{ + struct metal_clock *pllref = __metal_driver_sifive_fe310_g000_pll_pllref(clock); + struct metal_clock *pllsel0 = __metal_driver_sifive_fe310_g000_pll_pllsel0(clock); + long config_offset = __metal_driver_sifive_fe310_g000_pll_config_offset(clock); + struct __metal_driver_sifive_fe310_g000_prci *config_base = + __metal_driver_sifive_fe310_g000_pll_config_base(clock); + long divider_offset = __metal_driver_sifive_fe310_g000_pll_divider_offset(clock); + struct __metal_driver_sifive_fe310_g000_prci *divider_base = + __metal_driver_sifive_fe310_g000_pll_divider_base(clock); + const struct __metal_driver_vtable_sifive_fe310_g000_prci *vtable = + __metal_driver_sifive_fe310_g000_prci_vtable(); + + long cfg = vtable->get_reg(config_base, config_offset); + long div = vtable->get_reg(divider_base, divider_offset); + + /* At the end of the PLL there's one big mux: it either selects the HFROSC + * (bypassing the PLL entirely) or uses the PLL. */ + if (__METAL_GET_FIELD(cfg, PLL_SEL) == 0) + return metal_clock_get_rate_hz(pllsel0); + + /* There's a clock mux before the PLL that selects between the HFROSC adn + * the HFXOSC as the PLL's input clock. */ + long ref_hz = metal_clock_get_rate_hz(__METAL_GET_FIELD(cfg, PLL_REFSEL) ? pllref : pllsel0); + + /* It's possible to bypass the PLL, which is an internal bpyass. This + * still obays the PLL's input clock mu. */ + if (__METAL_GET_FIELD(cfg, PLL_BYPASS)) + return ref_hz; + + /* Logically the PLL is a three stage div-mul-div. */ + long div_r = __METAL_GET_FIELD(cfg, PLL_R) + 1; + long mul_f = 2 * (__METAL_GET_FIELD(cfg, PLL_F) + 1); + if (__METAL_GET_FIELD(cfg, PLL_Q) == 0) + return -1; + long div_q = 1 << __METAL_GET_FIELD(cfg, PLL_Q); + + /* In addition to the dividers inherent in the PLL, there's an additional + * clock divider that lives after the PLL and lets us pick a more + * interesting range of frequencies. */ + long pllout = (((ref_hz / div_r) * mul_f) / div_q); + if (__METAL_GET_FIELD(div, DIV_1)) + return pllout; + + return pllout / (2 * (__METAL_GET_FIELD(div, DIV_DIV) + 1)); +} + +/* Find a valid configuration for the PLL which is closest to the desired + * output frequency. + * Arguments: + * - ref_hz PLL input frequency + * - rate desired PLL output frequency + * Returns: + * -1 if no valid configuration is available + * the index into pll_configs of a valid configuration */ +static int find_closest_config(long ref_hz, long rate) +{ + int closest_index = -1; + long closest_diff = LONG_MAX; + + /* We're probably trying for a fast output frequency, so start from + * the high end of the configs. */ + for(int i = (sizeof(pll_configs) / sizeof(pll_configs[0])) - 1; i >= 0; i--) + { + long config_freq = get_pll_config_freq(ref_hz, &(pll_configs[i])); + if(config_freq != PLL_CONFIG_NOT_VALID) + { + long freq_diff = abs(config_freq - rate); + if(freq_diff < closest_diff) + { + closest_index = i; + closest_diff = freq_diff; + } + } + } + + return closest_index; +} + +/* Configure the PLL and wait for it to lock */ +static void configure_pll(__metal_io_u32 *pllcfg, __metal_io_u32 *plloutdiv, const struct pll_config_t *config) +{ + __METAL_ACCESS_ONCE(pllcfg) &= ~(PLL_R); + __METAL_ACCESS_ONCE(pllcfg) |= PLL_R_SHIFT(config->r); + + __METAL_ACCESS_ONCE(pllcfg) &= ~(PLL_F); + __METAL_ACCESS_ONCE(pllcfg) |= PLL_F_SHIFT(config->f); + + __METAL_ACCESS_ONCE(pllcfg) &= ~(PLL_Q); + __METAL_ACCESS_ONCE(pllcfg) |= PLL_Q_SHIFT(config->q); + + if(config->d < 0) + { + /* disable final divider */ + __METAL_ACCESS_ONCE(plloutdiv) |= DIV_1; + + __METAL_ACCESS_ONCE(plloutdiv) &= ~(DIV_DIV); + __METAL_ACCESS_ONCE(plloutdiv) |= PLL_DIV_SHIFT(1); + } + else + { + __METAL_ACCESS_ONCE(plloutdiv) &= ~(DIV_1); + + __METAL_ACCESS_ONCE(plloutdiv) &= ~(DIV_DIV); + __METAL_ACCESS_ONCE(plloutdiv) |= PLL_DIV_SHIFT(config->d); + } + + __METAL_ACCESS_ONCE(pllcfg) &= ~(PLL_BYPASS); + + /* Wait for PLL to lock */ + while((__METAL_ACCESS_ONCE(pllcfg) & PLL_LOCK) == 0) ; +} + +long __metal_driver_sifive_fe310_g000_pll_set_rate_hz(struct metal_clock *clock, long rate) +{ + struct metal_clock *pllref = __metal_driver_sifive_fe310_g000_pll_pllref(clock); + struct metal_clock *pllsel0 = __metal_driver_sifive_fe310_g000_pll_pllsel0(clock); + long config_offset = __metal_driver_sifive_fe310_g000_pll_config_offset(clock); + long divider_offset = __metal_driver_sifive_fe310_g000_pll_divider_offset(clock); + long base = __metal_driver_sifive_fe310_g000_prci_base(); + + __metal_io_u32 *pllcfg = (__metal_io_u32 *) (base + config_offset); + __metal_io_u32 *plloutdiv = (__metal_io_u32 *) (base + divider_offset); + + /* We can't modify the PLL if coreclk is driven by it, so switch it off */ + if (__METAL_ACCESS_ONCE(pllcfg) & PLL_SEL) + __METAL_ACCESS_ONCE(pllcfg) &= ~(PLL_SEL); + + /* There's a clock mux before the PLL that selects between the HFROSC and + * the HFXOSC as the PLL's input clock. */ + long ref_hz = metal_clock_get_rate_hz(__METAL_ACCESS_ONCE(pllcfg) & PLL_REFSEL ? pllref : pllsel0); + + /* if the desired rate is within 75%-125% of the input clock, bypass the PLL */ + if((ref_hz * 3 / 4) <= rate && (ref_hz * 5 / 4) >= rate) + { + __METAL_ACCESS_ONCE(pllcfg) |= PLL_BYPASS; + } + else + { + int config_index = find_closest_config(ref_hz, rate); + if(config_index != -1) + { + configure_pll(pllcfg, plloutdiv, &(pll_configs[config_index])); + } + else + { + /* unable to find a valid configuration */ + __METAL_ACCESS_ONCE(pllcfg) |= PLL_BYPASS; + } + } + + /* Enable the PLL */ + __METAL_ACCESS_ONCE(pllcfg) |= PLL_SEL; + + return __metal_driver_sifive_fe310_g000_pll_get_rate_hz(clock); +} + +#ifdef __METAL_DT_SIFIVE_FE310_G000_PLL_HANDLE +static void use_hfxosc(void) __attribute__((constructor)); +static void use_hfxosc(void) +{ + long init_rate = __metal_driver_sifive_fe310_g000_pll_init_rate(); + metal_clock_set_rate_hz( + &__METAL_DT_SIFIVE_FE310_G000_PLL_HANDLE->clock, init_rate + ); +} +#endif + +__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_pll) = { + .init = __metal_driver_sifive_fe310_g000_pll_init, + .clock.get_rate_hz = __metal_driver_sifive_fe310_g000_pll_get_rate_hz, + .clock.set_rate_hz = __metal_driver_sifive_fe310_g000_pll_set_rate_hz, +}; + +#endif /* METAL_SIFIVE_FE310_G000_PLL */ + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_prci.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_prci.c new file mode 100644 index 000000000..1236eca3b --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_prci.c @@ -0,0 +1,28 @@ +/* Copyright 2018 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine/platform.h> + +#ifdef METAL_SIFIVE_FE310_G000_PRCI + +#include <metal/drivers/sifive_fe310-g000_prci.h> +#include <metal/machine.h> + +long __metal_driver_sifive_fe310_g000_prci_get_reg(const struct __metal_driver_sifive_fe310_g000_prci *prci, long offset) { + unsigned long base = __metal_driver_sifive_fe310_g000_prci_base(); + return __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + offset)); +} + +long __metal_driver_sifive_fe310_g000_prci_set_reg(const struct __metal_driver_sifive_fe310_g000_prci *prci, long offset, long value) { + unsigned long base = __metal_driver_sifive_fe310_g000_prci_base(); + return __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + offset)) = value; +} + +__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_prci) = { + .get_reg = __metal_driver_sifive_fe310_g000_prci_get_reg, + .set_reg = __metal_driver_sifive_fe310_g000_prci_set_reg, +}; + +#endif /* METAL_SIFIVE_FE310_G000_PRCI */ + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_fu540-c000_l2.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_fu540-c000_l2.c new file mode 100644 index 000000000..aafc6e5e3 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_fu540-c000_l2.c @@ -0,0 +1,84 @@ +/* Copyright 2018 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine/platform.h> + +#ifdef METAL_SIFIVE_FU540_C000_L2 + +#include <stdint.h> +#include <metal/io.h> +#include <metal/drivers/sifive_fu540-c000_l2.h> +#include <metal/machine.h> + +#define L2_CONFIG_WAYS_SHIFT 8 +#define L2_CONFIG_WAYS_MASK (0xFF << L2_CONFIG_WAYS_SHIFT) + +void __metal_driver_sifive_fu540_c000_l2_init(struct metal_cache *l2, int ways); + +static void metal_driver_sifive_fu540_c000_l2_init(void) __attribute__((constructor)); +static void metal_driver_sifive_fu540_c000_l2_init(void) +{ +#ifdef __METAL_DT_SIFIVE_FU540_C000_L2_HANDLE + /* Get the handle for the L2 cache controller */ + struct metal_cache *l2 = __METAL_DT_SIFIVE_FU540_C000_L2_HANDLE; + if(!l2) { + return; + } + + /* Get the number of available ways per bank */ + unsigned long control_base = __metal_driver_sifive_fu540_c000_l2_control_base(l2); + uint32_t ways = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_FU540_C000_L2_CONFIG)); + ways = ((ways & L2_CONFIG_WAYS_MASK) >> L2_CONFIG_WAYS_SHIFT); + + /* Enable all the ways */ + __metal_driver_sifive_fu540_c000_l2_init(l2, ways); +#endif +} + +void __metal_driver_sifive_fu540_c000_l2_init(struct metal_cache *l2, int ways) +{ + metal_cache_set_enabled_ways(l2, ways); +} + +int __metal_driver_sifive_fu540_c000_l2_get_enabled_ways(struct metal_cache *cache) +{ + unsigned long control_base = __metal_driver_sifive_fu540_c000_l2_control_base(cache); + + uint32_t way_enable = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_FU540_C000_L2_WAYENABLE)); + + /* The stored number is the index, so add one */ + return (0xFF & way_enable) + 1; +} + +int __metal_driver_sifive_fu540_c000_l2_set_enabled_ways(struct metal_cache *cache, int ways) +{ + unsigned long control_base = __metal_driver_sifive_fu540_c000_l2_control_base(cache); + + /* We can't decrease the number of enabled ways */ + if(metal_cache_get_enabled_ways(cache) > ways) { + return -2; + } + + /* The stored value is the index, so subtract one */ + uint32_t value = 0xFF & (ways - 1); + + /* Set the number of enabled ways */ + __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_FU540_C000_L2_WAYENABLE)) = value; + + /* Make sure the number of ways was set correctly */ + if(metal_cache_get_enabled_ways(cache) != ways) { + return -3; + } + + return 0; +} + +__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fu540_c000_l2) = { + .cache.init = __metal_driver_sifive_fu540_c000_l2_init, + .cache.get_enabled_ways = __metal_driver_sifive_fu540_c000_l2_get_enabled_ways, + .cache.set_enabled_ways = __metal_driver_sifive_fu540_c000_l2_set_enabled_ways, +}; + +#endif + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_global-external-interrupts0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_global-external-interrupts0.c new file mode 100644 index 000000000..0d56bafef --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_global-external-interrupts0.c @@ -0,0 +1,169 @@ +/* Copyright 2018 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine/platform.h> + +#ifdef METAL_SIFIVE_GLOBAL_EXTERNAL_INTERRUPTS0 + +#include <metal/io.h> +#include <metal/shutdown.h> +#include <metal/drivers/sifive_global-external-interrupts0.h> +#include <metal/machine.h> + +void __metal_driver_sifive_global_external_interrupt_init(struct metal_interrupt *controller) +{ + struct __metal_driver_sifive_global_external_interrupts0 *global0; + + global0 = (struct __metal_driver_sifive_global_external_interrupts0 *)(controller); + if ( !global0->init_done ) { + struct metal_interrupt *intc = + __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller); + + if (intc) { + intc->vtable->interrupt_init(intc); + /* Register its interrupts with with parent controller */ + for (int i = 0; + i < __metal_driver_sifive_global_external_interrupts0_num_interrupts(controller); + i++) { + intc->vtable->interrupt_register(intc, + __metal_driver_sifive_global_external_interrupts0_interrupt_lines(controller, i), + NULL, controller); + } + global0->init_done = 1; + } + } +} + +int __metal_driver_sifive_global_external_interrupt_register(struct metal_interrupt *controller, + int id, metal_interrupt_handler_t isr, + void *priv) +{ + int rc = -1; + + if (id != 0) { + struct metal_interrupt *intc = + __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller); + + /* Enable its interrupts with parent controller */ + if (intc) { + rc = intc->vtable->interrupt_register(intc, id, isr, priv); + } + } + return rc; +} + +int __metal_driver_sifive_global_external_interrupt_enable(struct metal_interrupt *controller, int id) +{ + int rc = -1; + + if (id != 0) { + struct metal_interrupt *intc = + __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller); + + /* Enable its interrupts with parent controller */ + if (intc) { + rc = intc->vtable->interrupt_enable(intc, id); + } + } + return rc; +} + +int __metal_driver_sifive_global_external_interrupt_disable(struct metal_interrupt *controller, int id) +{ + int rc = -1; + + if (id != 0) { + struct metal_interrupt *intc = + __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller); + + /* Enable its interrupts with parent controller */ + if (intc) { + rc = intc->vtable->interrupt_disable(intc, id); + } + } + return rc; +} + +int __metal_driver_sifive_global_external_interrupt_set_threshold(struct metal_interrupt *controller, + unsigned int threshold) +{ + struct metal_interrupt *intc = + __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller); + if (intc) { + return intc->vtable->interrupt_set_threshold(intc, threshold); + } + return -1; +} + +unsigned int __metal_driver_sifive_global_external_interrupt_get_threshold(struct metal_interrupt *controller) +{ + struct metal_interrupt *intc = + __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller); + + if (intc) { + return intc->vtable->interrupt_get_threshold(intc); + } + return 0; +} + +int __metal_driver_sifive_global_external_interrupt_set_priority(struct metal_interrupt *controller, + int id, unsigned int priority) +{ + struct metal_interrupt *intc = + __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller); + if (intc) { + return intc->vtable->interrupt_set_priority(intc, id, priority); + } + return -1; +} + +unsigned int __metal_driver_sifive_global_external_interrupt_get_priority(struct metal_interrupt *controller, int id) +{ + struct metal_interrupt *intc = + __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller); + + if (intc) { + return intc->vtable->interrupt_get_priority(intc, id); + } + return 0; +} + +int __metal_driver_sifive_global_external_command_request (struct metal_interrupt *controller, + int command, void *data) +{ + int idx; + int rc = -1; + + switch (command) { + case METAL_MAX_INTERRUPT_GET: + rc = __metal_driver_sifive_global_external_interrupts0_num_interrupts(controller); + break; + case METAL_INDEX_INTERRUPT_GET: + rc = 0; + if (data) { + idx = *(int *)data; + rc = __metal_driver_sifive_global_external_interrupts0_interrupt_lines(controller, idx); + } + break; + default: + break; + } + + return rc; +} + +__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_global_external_interrupts0) = { + .global0_vtable.interrupt_init = __metal_driver_sifive_global_external_interrupt_init, + .global0_vtable.interrupt_register = __metal_driver_sifive_global_external_interrupt_register, + .global0_vtable.interrupt_enable = __metal_driver_sifive_global_external_interrupt_enable, + .global0_vtable.interrupt_disable = __metal_driver_sifive_global_external_interrupt_disable, + .global0_vtable.interrupt_get_threshold = __metal_driver_sifive_global_external_interrupt_get_threshold, + .global0_vtable.interrupt_set_threshold = __metal_driver_sifive_global_external_interrupt_set_threshold, + .global0_vtable.interrupt_get_priority = __metal_driver_sifive_global_external_interrupt_get_priority, + .global0_vtable.interrupt_set_priority = __metal_driver_sifive_global_external_interrupt_set_priority, + .global0_vtable.command_request = __metal_driver_sifive_global_external_command_request, +}; + +#endif + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-buttons.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-buttons.c new file mode 100644 index 000000000..923fe2711 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-buttons.c @@ -0,0 +1,57 @@ +/* Copyright 2018 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine/platform.h> + +#ifdef METAL_SIFIVE_GPIO_BUTTONS + +#include <string.h> +#include <metal/drivers/riscv_cpu.h> +#include <metal/drivers/sifive_gpio-buttons.h> +#include <metal/machine.h> + +int __metal_driver_button_exist (struct metal_button *button, char *label) +{ + if (strcmp(__metal_driver_sifive_gpio_button_label(button), label) == 0) { + return 1; + } + return 0; +} + +struct metal_interrupt * +__metal_driver_button_interrupt_controller(struct metal_button *button) +{ + return __metal_driver_sifive_gpio_button_interrupt_controller(button); +} + +int __metal_driver_button_get_interrupt_id(struct metal_button *button) +{ + int irq, max_irq; + struct metal_interrupt *irc; + + irq = __metal_driver_sifive_gpio_button_interrupt_line(button); + irc = __metal_driver_sifive_gpio_button_interrupt_controller(button); + + if (irc != NULL) { + max_irq = _metal_interrupt_command_request(irc, + METAL_MAX_INTERRUPT_GET, + NULL); + + if (irq < max_irq) { + return _metal_interrupt_command_request(irc, + METAL_INDEX_INTERRUPT_GET, + (void *)&irq); + } + } + return METAL_INTERRUPT_ID_LCMX; +} + +__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_button) = { + .button_vtable.button_exist = __metal_driver_button_exist, + .button_vtable.interrupt_controller = __metal_driver_button_interrupt_controller, + .button_vtable.get_interrupt_id = __metal_driver_button_get_interrupt_id, +}; + +#endif + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-leds.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-leds.c new file mode 100644 index 000000000..a6b627458 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-leds.c @@ -0,0 +1,85 @@ +/* Copyright 2018 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine/platform.h> + +#ifdef METAL_SIFIVE_GPIO_LEDS + +#include <string.h> +#include <metal/gpio.h> +#include <metal/drivers/sifive_gpio-leds.h> +#include <metal/machine.h> + +int __metal_driver_led_exist (struct metal_led *led, char *label) +{ + if (strcmp(__metal_driver_sifive_gpio_led_label(led), label) == 0) { + return 1; + } + return 0; +} + +void __metal_driver_led_enable (struct metal_led *led) +{ + int pin; + struct metal_gpio *gpio; + + pin = __metal_driver_sifive_gpio_led_pin(led); + gpio = __metal_driver_sifive_gpio_led_gpio(led); + + if (gpio != NULL) { + /* Configure LED as output */ + metal_gpio_disable_input((struct metal_gpio *) gpio, pin); + metal_gpio_enable_output((struct metal_gpio *) gpio, pin); + } +} + +void __metal_driver_led_on (struct metal_led *led) +{ + int pin; + struct metal_gpio *gpio; + + pin = __metal_driver_sifive_gpio_led_pin(led); + gpio = __metal_driver_sifive_gpio_led_gpio(led); + + if (gpio != NULL) { + metal_gpio_set_pin((struct metal_gpio *) gpio, pin, 1); + } +} + +void __metal_driver_led_off (struct metal_led *led) +{ + int pin; + struct metal_gpio *gpio; + + pin = __metal_driver_sifive_gpio_led_pin(led); + gpio = __metal_driver_sifive_gpio_led_gpio(led); + + if (gpio != NULL) { + metal_gpio_set_pin((struct metal_gpio *) gpio, pin, 0); + } +} + +void __metal_driver_led_toggle (struct metal_led *led) +{ + int pin; + struct metal_gpio *gpio; + + pin = __metal_driver_sifive_gpio_led_pin(led); + gpio = __metal_driver_sifive_gpio_led_gpio(led); + + if (gpio != NULL) { + metal_gpio_toggle_pin((struct metal_gpio *) gpio, pin); + } +} + +__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_led) = { + .led_vtable.led_exist = __metal_driver_led_exist, + .led_vtable.led_enable = __metal_driver_led_enable, + .led_vtable.led_on = __metal_driver_led_on, + .led_vtable.led_off = __metal_driver_led_off, + .led_vtable.led_toggle = __metal_driver_led_toggle, +}; + +#endif + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-switches.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-switches.c new file mode 100644 index 000000000..fa0a819f1 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-switches.c @@ -0,0 +1,56 @@ +/* Copyright 2018 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine/platform.h> + +#ifdef METAL_SIFIVE_GPIO_SWITCHES + +#include <string.h> +#include <metal/drivers/riscv_cpu.h> +#include <metal/drivers/sifive_gpio-switches.h> +#include <metal/machine.h> + +int __metal_driver_switch_exist (struct metal_switch *flip, char *label) +{ + if (strcmp(__metal_driver_sifive_gpio_switch_label(flip), label) == 0) { + return 1; + } + return 0; +} + +struct metal_interrupt * +__metal_driver_switch_interrupt_controller(struct metal_switch *flip) +{ + return __metal_driver_sifive_gpio_switch_interrupt_controller(flip); +} + +int __metal_driver_switch_get_interrupt_id(struct metal_switch *flip) +{ + int irq, max_irq; + struct metal_interrupt *irc; + + irq = __metal_driver_sifive_gpio_switch_interrupt_line(flip); + irc = __metal_driver_sifive_gpio_switch_interrupt_controller(flip); + if (irc != NULL) { + max_irq = _metal_interrupt_command_request(irc, + METAL_MAX_INTERRUPT_GET, + NULL); + + if (irq < max_irq) { + return _metal_interrupt_command_request(irc, + METAL_INDEX_INTERRUPT_GET, + (void *)&irq); + } + } + return METAL_INTERRUPT_ID_LCMX; +} + +__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_switch) = { + .switch_vtable.switch_exist = __metal_driver_switch_exist, + .switch_vtable.interrupt_controller = __metal_driver_switch_interrupt_controller, + .switch_vtable.get_interrupt_id = __metal_driver_switch_get_interrupt_id, +}; + +#endif + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_gpio0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_gpio0.c new file mode 100644 index 000000000..9ebbea03c --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_gpio0.c @@ -0,0 +1,221 @@ +/* Copyright 2018 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine/platform.h> + +#ifdef METAL_SIFIVE_GPIO0 + +#include <metal/drivers/sifive_gpio0.h> +#include <metal/io.h> +#include <metal/machine.h> + +int __metal_driver_sifive_gpio0_enable_input(struct metal_gpio *ggpio, long source) +{ + long base = __metal_driver_sifive_gpio0_base(ggpio); + + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_INPUT_EN)) |= source; + + return 0; +} + +int __metal_driver_sifive_gpio0_disable_input(struct metal_gpio *ggpio, long source) +{ + long base = __metal_driver_sifive_gpio0_base(ggpio); + + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_INPUT_EN)) &= ~source; + + return 0; +} + +long __metal_driver_sifive_gpio0_input(struct metal_gpio *ggpio) +{ + long base = __metal_driver_sifive_gpio0_base(ggpio); + + return __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_VALUE)); +} + +long __metal_driver_sifive_gpio0_output(struct metal_gpio *ggpio) +{ + long base = __metal_driver_sifive_gpio0_base(ggpio); + + return __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_PORT)); +} + + +int __metal_driver_sifive_gpio0_disable_output(struct metal_gpio *ggpio, long source) +{ + long base = __metal_driver_sifive_gpio0_base(ggpio); + + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_OUTPUT_EN)) &= ~source; + + return 0; +} + +int __metal_driver_sifive_gpio0_enable_output(struct metal_gpio *ggpio, long source) +{ + long base = __metal_driver_sifive_gpio0_base(ggpio); + + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_OUTPUT_EN)) |= source; + + return 0; +} + +int __metal_driver_sifive_gpio0_output_set(struct metal_gpio *ggpio, long value) +{ + long base = __metal_driver_sifive_gpio0_base(ggpio); + + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_PORT)) |= value; + + return 0; +} + +int __metal_driver_sifive_gpio0_output_clear(struct metal_gpio *ggpio, long value) +{ + long base = __metal_driver_sifive_gpio0_base(ggpio); + + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_PORT)) &= ~value; + + return 0; +} + +int __metal_driver_sifive_gpio0_output_toggle(struct metal_gpio *ggpio, long value) +{ + long base = __metal_driver_sifive_gpio0_base(ggpio); + + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_PORT)) = + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_PORT)) ^ value; + + return 0; +} + +int __metal_driver_sifive_gpio0_enable_io(struct metal_gpio *ggpio, long source, long dest) +{ + long base = __metal_driver_sifive_gpio0_base(ggpio); + + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_IOF_SEL)) &= ~source; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_IOF_EN)) |= dest; + + return 0; +} + +int __metal_driver_sifive_gpio0_disable_io(struct metal_gpio *ggpio, long source) +{ + long base = __metal_driver_sifive_gpio0_base(ggpio); + + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_IOF_EN)) &= ~source; + + return 0; +} + +int __metal_driver_sifive_gpio0_config_int(struct metal_gpio *ggpio, long source, int intr_type) +{ + long base = __metal_driver_sifive_gpio0_base(ggpio); + + switch (intr_type) + { + case METAL_GPIO_INT_DISABLE: + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IE)) &= ~source; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IE)) &= ~source; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IE)) &= ~source; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IE)) &= ~source; + break; + case METAL_GPIO_INT_RISING: + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IE)) |= source; + break; + case METAL_GPIO_INT_FALLING: + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IE)) |= source; + break; + case METAL_GPIO_INT_BOTH_EDGE: + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IE)) |= source; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IE)) |= source; + break; + case METAL_GPIO_INT_HIGH: + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IE)) |= source; + break; + case METAL_GPIO_INT_LOW: + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IE)) |= source; + break; + case METAL_GPIO_INT_BOTH_LEVEL: + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IE)) |= source; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IE)) |= source; + break; + case METAL_GPIO_INT_MAX: + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IE)) |= source; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IE)) |= source; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IE)) |= source; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IE)) |= source; + break; + } + return 0; +} + +int __metal_driver_sifive_gpio0_clear_int(struct metal_gpio *ggpio, long source, int intr_type) +{ + long base = __metal_driver_sifive_gpio0_base(ggpio); + + switch (intr_type) + { + case METAL_GPIO_INT_RISING: + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IP)) |= source; + break; + case METAL_GPIO_INT_FALLING: + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IP)) |= source; + break; + case METAL_GPIO_INT_BOTH_EDGE: + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IP)) |= source; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IP)) |= source; + break; + case METAL_GPIO_INT_HIGH: + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IP)) |= source; + break; + case METAL_GPIO_INT_LOW: + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IP)) |= source; + break; + case METAL_GPIO_INT_BOTH_LEVEL: + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IP)) |= source; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IP)) |= source; + break; + case METAL_GPIO_INT_MAX: + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IP)) |= source; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IP)) |= source; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IP)) |= source; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IP)) |= source; + break; + } + return 0; +} + +struct metal_interrupt * +__metal_driver_gpio_interrupt_controller(struct metal_gpio *gpio) +{ + return __metal_driver_sifive_gpio0_interrupt_parent(gpio); +} + +int __metal_driver_gpio_get_interrupt_id(struct metal_gpio *gpio, int pin) +{ + int irq; + irq = __metal_driver_sifive_gpio0_interrupt_lines(gpio, pin); + return irq; +} + +__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_gpio0) = { + .gpio.disable_input = __metal_driver_sifive_gpio0_disable_input, + .gpio.enable_input = __metal_driver_sifive_gpio0_enable_input, + .gpio.input = __metal_driver_sifive_gpio0_input, + .gpio.output = __metal_driver_sifive_gpio0_output, + .gpio.disable_output = __metal_driver_sifive_gpio0_disable_output, + .gpio.enable_output = __metal_driver_sifive_gpio0_enable_output, + .gpio.output_set = __metal_driver_sifive_gpio0_output_set, + .gpio.output_clear = __metal_driver_sifive_gpio0_output_clear, + .gpio.output_toggle = __metal_driver_sifive_gpio0_output_toggle, + .gpio.enable_io = __metal_driver_sifive_gpio0_enable_io, + .gpio.disable_io = __metal_driver_sifive_gpio0_disable_io, + .gpio.config_int = __metal_driver_sifive_gpio0_config_int, + .gpio.clear_int = __metal_driver_sifive_gpio0_clear_int, + .gpio.interrupt_controller = __metal_driver_gpio_interrupt_controller, + .gpio.get_interrupt_id = __metal_driver_gpio_get_interrupt_id, +}; + +#endif /* METAL_SIFIVE_GPIO0 */ + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_local-external-interrupts0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_local-external-interrupts0.c new file mode 100644 index 000000000..1c34ca447 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_local-external-interrupts0.c @@ -0,0 +1,151 @@ +/* Copyright 2018 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine/platform.h> + +#ifdef METAL_SIFIVE_LOCAL_EXTERNAL_INTERRUPTS0 + +#include <metal/io.h> +#include <metal/drivers/sifive_local-external-interrupts0.h> +#include <metal/machine.h> + +void __metal_driver_sifive_local_external_interrupt_init(struct metal_interrupt *controller) +{ + struct __metal_driver_sifive_local_external_interrupts0 *local0; + + local0 = (struct __metal_driver_sifive_local_external_interrupts0 *)(controller); + if ( !local0->init_done ) { + struct metal_interrupt *intc = + __metal_driver_sifive_local_external_interrupts0_interrupt_parent(controller); + + if (intc) { + /* Register its interruptswith with parent controller, aka all external to default isr */ + for (int i = 0; + i < __metal_driver_sifive_local_external_interrupts0_num_interrupts(controller); + i++) { + intc->vtable->interrupt_register(intc, + __metal_driver_sifive_local_external_interrupts0_interrupt_lines(controller, i), + NULL, controller); + } + local0->init_done = 1; + } + } +} + +int __metal_driver_sifive_local_external_interrupt_register(struct metal_interrupt *controller, + int id, metal_interrupt_handler_t isr, + void *priv) +{ + int rc = -1; + + if (id != 0) { + struct metal_interrupt *intc = + __metal_driver_sifive_local_external_interrupts0_interrupt_parent(controller); + + /* Enable its interrupts with parent controller */ + if (intc) { + rc = intc->vtable->interrupt_register(intc, id, isr, priv); + } + } + return rc; +} + +int __metal_driver_sifive_local_external_interrupt_enable(struct metal_interrupt *controller, int id) +{ + int rc = -1; + + if (id != 0) { + struct metal_interrupt *intc = + __metal_driver_sifive_local_external_interrupts0_interrupt_parent(controller); + + /* Enable its interrupts with parent controller */ + if (intc) { + rc = intc->vtable->interrupt_enable(intc, id); + } + } + return rc; +} + +int __metal_driver_sifive_local_external_interrupt_disable(struct metal_interrupt *controller, int id) +{ + int rc = -1; + + if (id != 0) { + struct metal_interrupt *intc = + __metal_driver_sifive_local_external_interrupts0_interrupt_parent(controller); + + /* Enable its interrupts with parent controller */ + if (intc) { + rc = intc->vtable->interrupt_disable(intc, id); + } + } + return rc; +} + +int __metal_driver_sifive_local_external_interrupt_set_threshold(struct metal_interrupt *controller, + unsigned int threshold) +{ + /* Core controller does not support threshold configuration */ + return -1; +} + +unsigned int __metal_driver_sifive_local_external_interrupt_get_threshold(struct metal_interrupt *controller) +{ + /* Core controller does not support threshold configuration */ + return 0; +} + + +int __metal_driver_sifive_local_external_interrupt_set_priority(struct metal_interrupt *controller, + int id, unsigned int priority) +{ + /* Core controller does not support priority configuration */ + return -1; +} + +unsigned int __metal_driver_sifive_local_external_interrupt_get_priority(struct metal_interrupt *controller, int id) +{ + /* Core controller does not support priority configuration */ + return 0; +} + +int __metal_driver_sifive_local_external_command_request (struct metal_interrupt *controller, + int command, void *data) +{ + int idx; + int rc = -1; + + switch (command) { + case METAL_MAX_INTERRUPT_GET: + rc = __metal_driver_sifive_local_external_interrupts0_num_interrupts(controller); + break; + case METAL_INDEX_INTERRUPT_GET: + rc = 0; + if (data) { + idx = *(int *)data; + rc = __metal_driver_sifive_local_external_interrupts0_interrupt_lines(controller, idx); + } + break; + default: + break; + } + + return rc; +} + +__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_local_external_interrupts0) = { + .local0_vtable.interrupt_init = __metal_driver_sifive_local_external_interrupt_init, + .local0_vtable.interrupt_register = __metal_driver_sifive_local_external_interrupt_register, + .local0_vtable.interrupt_enable = __metal_driver_sifive_local_external_interrupt_enable, + .local0_vtable.interrupt_disable = __metal_driver_sifive_local_external_interrupt_disable, + .local0_vtable.interrupt_get_threshold = __metal_driver_sifive_local_external_interrupt_get_threshold, + .local0_vtable.interrupt_set_threshold = __metal_driver_sifive_local_external_interrupt_set_threshold, + .local0_vtable.interrupt_get_priority = __metal_driver_sifive_local_external_interrupt_get_priority, + .local0_vtable.interrupt_set_priority = __metal_driver_sifive_local_external_interrupt_set_priority, + .local0_vtable.command_request = __metal_driver_sifive_local_external_command_request, +}; + +#endif + +typedef int no_empty_translation_units; + diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_rtc0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_rtc0.c new file mode 100644 index 000000000..79b81e7bf --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_rtc0.c @@ -0,0 +1,121 @@ +/* Copyright 2019 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine/platform.h> + +#ifdef METAL_SIFIVE_RTC0 + +#include <metal/drivers/sifive_rtc0.h> +#include <metal/machine.h> + +#include <limits.h> + +/* RTCCFG */ +#define METAL_RTCCFG_RTCSCALE_MASK 0xF +#define METAL_RTCCFG_ENALWAYS (1 << 12) +#define METAL_RTCCFG_IP0 (1 << 28) + +/* RTCCMP0 */ +#define METAL_RTCCMP0_MAX UINT32_MAX + +#define RTC_REG(base, offset) (((unsigned long)base + offset)) +#define RTC_REGW(base, offset) (__METAL_ACCESS_ONCE((__metal_io_u32 *)RTC_REG(base, offset))) + +uint64_t __metal_driver_sifive_rtc0_get_rate(const struct metal_rtc *const rtc) { + const struct metal_clock *const clock = __metal_driver_sifive_rtc0_clock(rtc); + return metal_clock_get_rate_hz(clock); +} + +uint64_t __metal_driver_sifive_rtc0_set_rate(const struct metal_rtc *const rtc, const uint64_t rate) { + const struct metal_clock *const clock = __metal_driver_sifive_rtc0_clock(rtc); + return metal_clock_get_rate_hz(clock); +} + +uint64_t __metal_driver_sifive_rtc0_get_compare(const struct metal_rtc *const rtc) { + const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc); + + const uint32_t shift = RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG) & METAL_RTCCFG_RTCSCALE_MASK; + + return ((uint64_t)RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCMP0) << shift); +} + +uint64_t __metal_driver_sifive_rtc0_set_compare(const struct metal_rtc *const rtc, const uint64_t compare) { + const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc); + + /* Determine the bit shift and shifted value to store in rtccmp0/rtccfg.scale */ + uint32_t shift = 0; + uint64_t comp_shifted = compare; + while (comp_shifted > METAL_RTCCMP0_MAX) { + shift += 1; + comp_shifted = comp_shifted >> shift; + } + + /* Set the value of rtccfg.scale */ + uint32_t cfg = RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG); + cfg &= ~(METAL_RTCCFG_RTCSCALE_MASK); + cfg |= (METAL_RTCCFG_RTCSCALE_MASK & shift); + RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG) = cfg; + + /* Set the value of rtccmp0 */ + RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCMP0) = (uint32_t) comp_shifted; + + return __metal_driver_sifive_rtc0_get_compare(rtc); +} + +uint64_t __metal_driver_sifive_rtc0_get_count(const struct metal_rtc *const rtc) { + const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc); + + uint64_t count = RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCOUNTHI); + count <<= 32; + count |= RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCOUNTLO); + + return count; +} + +uint64_t __metal_driver_sifive_rtc0_set_count(const struct metal_rtc *const rtc, const uint64_t count) { + const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc); + + RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCOUNTHI) = (UINT_MAX & (count >> 32)); + RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCOUNTLO) = (UINT_MAX & count); + + return __metal_driver_sifive_rtc0_get_count(rtc); +} + +int __metal_driver_sifive_rtc0_run(const struct metal_rtc *const rtc, const enum metal_rtc_run_option option) { + const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc); + + switch (option) { + default: + case METAL_RTC_STOP: + RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG) &= ~(METAL_RTCCFG_ENALWAYS); + break; + case METAL_RTC_RUN: + RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG) |= METAL_RTCCFG_ENALWAYS; + break; + } + + return 0; +} + +struct metal_interrupt *__metal_driver_sifive_rtc0_get_interrupt(const struct metal_rtc *const rtc) { + return __metal_driver_sifive_rtc0_interrupt_parent(rtc); +} + +int __metal_driver_sifive_rtc0_get_interrupt_id(const struct metal_rtc *const rtc) { + return __metal_driver_sifive_rtc0_interrupt_line(rtc); +} + +__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_rtc0) = { + .rtc.get_rate = __metal_driver_sifive_rtc0_get_rate, + .rtc.set_rate = __metal_driver_sifive_rtc0_set_rate, + .rtc.get_compare = __metal_driver_sifive_rtc0_get_compare, + .rtc.set_compare = __metal_driver_sifive_rtc0_set_compare, + .rtc.get_count = __metal_driver_sifive_rtc0_get_count, + .rtc.set_count = __metal_driver_sifive_rtc0_set_count, + .rtc.run = __metal_driver_sifive_rtc0_run, + .rtc.get_interrupt = __metal_driver_sifive_rtc0_get_interrupt, + .rtc.get_interrupt_id = __metal_driver_sifive_rtc0_get_interrupt_id, +}; + +#endif + diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_spi0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_spi0.c new file mode 100644 index 000000000..2a346354f --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_spi0.c @@ -0,0 +1,405 @@ +/* Copyright 2018 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine/platform.h> + +#ifdef METAL_SIFIVE_SPI0 +#include <metal/drivers/sifive_spi0.h> +#include <metal/io.h> +#include <metal/machine.h> +#include <metal/time.h> +#include <time.h> + +/* Register fields */ +#define METAL_SPI_SCKDIV_MASK 0xFFF + +#define METAL_SPI_SCKMODE_PHA_SHIFT 0 +#define METAL_SPI_SCKMODE_POL_SHIFT 1 + +#define METAL_SPI_CSMODE_MASK 3 +#define METAL_SPI_CSMODE_AUTO 0 +#define METAL_SPI_CSMODE_HOLD 2 +#define METAL_SPI_CSMODE_OFF 3 + +#define METAL_SPI_PROTO_MASK 3 +#define METAL_SPI_PROTO_SINGLE 0 +#define METAL_SPI_PROTO_DUAL 1 +#define METAL_SPI_PROTO_QUAD 2 + +#define METAL_SPI_ENDIAN_LSB 4 + +#define METAL_SPI_DISABLE_RX 8 + +#define METAL_SPI_FRAME_LEN_SHIFT 16 +#define METAL_SPI_FRAME_LEN_MASK (0xF << METAL_SPI_FRAME_LEN_SHIFT) + +#define METAL_SPI_TXDATA_FULL (1 << 31) +#define METAL_SPI_RXDATA_EMPTY (1 << 31) +#define METAL_SPI_TXMARK_MASK 7 +#define METAL_SPI_TXWM 1 +#define METAL_SPI_TXRXDATA_MASK (0xFF) + +#define METAL_SPI_INTERVAL_SHIFT 16 + +#define METAL_SPI_CONTROL_IO 0 +#define METAL_SPI_CONTROL_MAPPED 1 + +#define METAL_SPI_REG(offset) (((unsigned long)control_base + offset)) +#define METAL_SPI_REGB(offset) (__METAL_ACCESS_ONCE((__metal_io_u8 *)METAL_SPI_REG(offset))) +#define METAL_SPI_REGW(offset) (__METAL_ACCESS_ONCE((__metal_io_u32 *)METAL_SPI_REG(offset))) + +#define METAL_SPI_RXDATA_TIMEOUT 1 + +static int configure_spi(struct __metal_driver_sifive_spi0 *spi, struct metal_spi_config *config) +{ + long control_base = __metal_driver_sifive_spi0_control_base((struct metal_spi *)spi); + /* Set protocol */ + METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) &= ~(METAL_SPI_PROTO_MASK); + switch (config->protocol) { + case METAL_SPI_SINGLE: + METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_SINGLE; + break; + case METAL_SPI_DUAL: + if (config->multi_wire == MULTI_WIRE_ALL) + METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_DUAL; + else + METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_SINGLE; + break; + case METAL_SPI_QUAD: + if (config->multi_wire == MULTI_WIRE_ALL) + METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_QUAD; + else + METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_SINGLE; + break; + default: + /* Unsupported value */ + return -1; + } + + /* Set Polarity */ + if(config->polarity) { + METAL_SPI_REGW(METAL_SIFIVE_SPI0_SCKMODE) |= (1 << METAL_SPI_SCKMODE_PHA_SHIFT); + } else { + METAL_SPI_REGW(METAL_SIFIVE_SPI0_SCKMODE) &= ~(1 << METAL_SPI_SCKMODE_PHA_SHIFT); + } + + /* Set Phase */ + if(config->phase) { + METAL_SPI_REGW(METAL_SIFIVE_SPI0_SCKMODE) |= (1 << METAL_SPI_SCKMODE_POL_SHIFT); + } else { + METAL_SPI_REGW(METAL_SIFIVE_SPI0_SCKMODE) &= ~(1 << METAL_SPI_SCKMODE_POL_SHIFT); + } + + /* Set Endianness */ + if(config->little_endian) { + METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_ENDIAN_LSB; + } else { + METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) &= ~(METAL_SPI_ENDIAN_LSB); + } + + /* Always populate receive FIFO */ + METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) &= ~(METAL_SPI_DISABLE_RX); + + /* Set CS Active */ + if(config->cs_active_high) { + METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSDEF) = 0; + } else { + METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSDEF) = 1; + } + + /* Set frame length */ + if((METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) & METAL_SPI_FRAME_LEN_MASK) != (8 << METAL_SPI_FRAME_LEN_SHIFT)) { + METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) &= ~(METAL_SPI_FRAME_LEN_MASK); + METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= (8 << METAL_SPI_FRAME_LEN_SHIFT); + } + + /* Set CS line */ + METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSID) = 1 << (config->csid); + + /* Toggle off memory-mapped SPI flash mode, toggle on programmable IO mode + * It seems that with this line uncommented, the debugger cannot have access + * to the chip at all because it assumes the chip is in memory-mapped mode. + * I have to compile the code with this line commented and launch gdb, + * reset cores, reset $pc, set *((int *) 0x20004060) = 0, (set the flash + * interface control register to programmable I/O mode) and then continue + * Alternative, comment out the "flash" line in openocd.cfg */ + METAL_SPI_REGW(METAL_SIFIVE_SPI0_FCTRL) = METAL_SPI_CONTROL_IO; + + return 0; +} + +static void spi_mode_switch(struct __metal_driver_sifive_spi0 *spi, + struct metal_spi_config *config, + unsigned int trans_stage) { + long control_base = + __metal_driver_sifive_spi0_control_base((struct metal_spi *)spi); + + if (config->multi_wire == trans_stage) { + METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) &= ~(METAL_SPI_PROTO_MASK); + switch (config->protocol) { + case METAL_SPI_DUAL: + METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_DUAL; + break; + case METAL_SPI_QUAD: + METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_QUAD; + break; + default: + /* Unsupported value */ + return; + } + } +} + +int __metal_driver_sifive_spi0_transfer(struct metal_spi *gspi, + struct metal_spi_config *config, + size_t len, + char *tx_buf, + char *rx_buf) +{ + struct __metal_driver_sifive_spi0 *spi = (void *)gspi; + long control_base = __metal_driver_sifive_spi0_control_base(gspi); + int rc = 0; + size_t i = 0; + + rc = configure_spi(spi, config); + if(rc != 0) { + return rc; + } + + /* Hold the chip select line for all len transferred */ + METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSMODE) &= ~(METAL_SPI_CSMODE_MASK); + METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSMODE) |= METAL_SPI_CSMODE_HOLD; + + unsigned long rxdata; + + /* Declare time_t variables to break out of infinite while loop */ + time_t endwait; + + for (i = 0; i < config->cmd_num; i++) { + + while (METAL_SPI_REGW(METAL_SIFIVE_SPI0_TXDATA) & METAL_SPI_TXDATA_FULL) + ; + + if (tx_buf) { + METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = tx_buf[i]; + } else { + METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = 0; + } + + endwait = metal_time() + METAL_SPI_RXDATA_TIMEOUT; + + while ((rxdata = METAL_SPI_REGW(METAL_SIFIVE_SPI0_RXDATA)) & + METAL_SPI_RXDATA_EMPTY) { + if (metal_time() > endwait) { + METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSMODE) &= + ~(METAL_SPI_CSMODE_MASK); + + return 1; + } + } + + if (rx_buf) { + rx_buf[i] = (char)(rxdata & METAL_SPI_TXRXDATA_MASK); + } + } + + /* switch to Dual/Quad mode */ + spi_mode_switch(spi, config, MULTI_WIRE_ADDR_DATA); + + /* Send Addr data */ + for (; i < (config->cmd_num + config->addr_num); i++) { + + while (METAL_SPI_REGW(METAL_SIFIVE_SPI0_TXDATA) & METAL_SPI_TXDATA_FULL) + ; + + if (tx_buf) { + METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = tx_buf[i]; + } else { + METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = 0; + } + + endwait = metal_time() + METAL_SPI_RXDATA_TIMEOUT; + + while ((rxdata = METAL_SPI_REGW(METAL_SIFIVE_SPI0_RXDATA)) & + METAL_SPI_RXDATA_EMPTY) { + if (metal_time() > endwait) { + METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSMODE) &= + ~(METAL_SPI_CSMODE_MASK); + + return 1; + } + } + + if (rx_buf) { + rx_buf[i] = (char)(rxdata & METAL_SPI_TXRXDATA_MASK); + } + } + + /* Send Dummy data */ + for (; i < (config->cmd_num + config->addr_num + config->dummy_num); i++) { + + while (METAL_SPI_REGW(METAL_SIFIVE_SPI0_TXDATA) & METAL_SPI_TXDATA_FULL) + ; + + if (tx_buf) { + METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = tx_buf[i]; + } else { + METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = 0; + } + + endwait = metal_time() + METAL_SPI_RXDATA_TIMEOUT; + + while ((rxdata = METAL_SPI_REGW(METAL_SIFIVE_SPI0_RXDATA)) & + METAL_SPI_RXDATA_EMPTY) { + if (metal_time() > endwait) { + METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSMODE) &= + ~(METAL_SPI_CSMODE_MASK); + return 1; + } + } + if (rx_buf) { + rx_buf[i] = (char)(rxdata & METAL_SPI_TXRXDATA_MASK); + } + } + + /* switch to Dual/Quad mode */ + spi_mode_switch(spi, config, MULTI_WIRE_DATA_ONLY); + + for (; i < len; i++) { + /* Master send bytes to the slave */ + + /* Wait for TXFIFO to not be full */ + while (METAL_SPI_REGW(METAL_SIFIVE_SPI0_TXDATA) & METAL_SPI_TXDATA_FULL); + + /* Transfer byte by modifying the least significant byte in the TXDATA register */ + if (tx_buf) { + METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = tx_buf[i]; + } else { + /* Transfer a 0 byte if the sending buffer is NULL */ + METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = 0; + } + + /* Master receives bytes from the RX FIFO */ + + /* Wait for RXFIFO to not be empty, but break the nested loops if timeout + * this timeout method needs refining, preferably taking into account + * the device specs */ + endwait = metal_time() + METAL_SPI_RXDATA_TIMEOUT; + + while ((rxdata = METAL_SPI_REGW(METAL_SIFIVE_SPI0_RXDATA)) & METAL_SPI_RXDATA_EMPTY) { + if (metal_time() > endwait) { + /* If timeout, deassert the CS */ + METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSMODE) &= ~(METAL_SPI_CSMODE_MASK); + + /* If timeout, return error code 1 immediately */ + return 1; + } + } + + /* Only store the dequeued byte if the receive_buffer is not NULL */ + if (rx_buf) { + rx_buf[i] = (char) (rxdata & METAL_SPI_TXRXDATA_MASK); + } + } + + /* On the last byte, set CSMODE to auto so that the chip select transitions back to high + * The reason that CS pin is not deasserted after transmitting out the byte buffer is timing. + * The code on the host side likely executes faster than the ability of FIFO to send out bytes. + * After the host iterates through the array, fifo is likely not cleared yet. If host deasserts + * the CS pin immediately, the following bytes in the output FIFO will not be sent consecutively. + * There needs to be a better way to handle this. */ + METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSMODE) &= ~(METAL_SPI_CSMODE_MASK); + + return 0; +} + +int __metal_driver_sifive_spi0_get_baud_rate(struct metal_spi *gspi) +{ + struct __metal_driver_sifive_spi0 *spi = (void *)gspi; + return spi->baud_rate; +} + +int __metal_driver_sifive_spi0_set_baud_rate(struct metal_spi *gspi, int baud_rate) +{ + long control_base = __metal_driver_sifive_spi0_control_base(gspi); + struct metal_clock *clock = __metal_driver_sifive_spi0_clock(gspi); + struct __metal_driver_sifive_spi0 *spi = (void *)gspi; + + spi->baud_rate = baud_rate; + + if (clock != NULL) { + long clock_rate = clock->vtable->get_rate_hz(clock); + + /* Calculate divider */ + long div = (clock_rate / (2 * baud_rate)) - 1; + + if(div > METAL_SPI_SCKDIV_MASK) { + /* The requested baud rate is lower than we can support at + * the current clock rate */ + return -1; + } + + /* Set divider */ + METAL_SPI_REGW(METAL_SIFIVE_SPI0_SCKDIV) &= ~METAL_SPI_SCKDIV_MASK; + METAL_SPI_REGW(METAL_SIFIVE_SPI0_SCKDIV) |= (div & METAL_SPI_SCKDIV_MASK); + } + + return 0; +} + +static void pre_rate_change_callback_func(void *priv) +{ + long control_base = __metal_driver_sifive_spi0_control_base((struct metal_spi *)priv); + + /* Detect when the TXDATA is empty by setting the transmit watermark count + * to one and waiting until an interrupt is pending (indicating an empty TXFIFO) */ + METAL_SPI_REGW(METAL_SIFIVE_SPI0_TXMARK) &= ~(METAL_SPI_TXMARK_MASK); + METAL_SPI_REGW(METAL_SIFIVE_SPI0_TXMARK) |= (METAL_SPI_TXMARK_MASK & 1); + + while((METAL_SPI_REGW(METAL_SIFIVE_SPI0_IP) & METAL_SPI_TXWM) == 0) ; +} + +static void post_rate_change_callback_func(void *priv) +{ + struct __metal_driver_sifive_spi0 *spi = priv; + metal_spi_set_baud_rate(&spi->spi, spi->baud_rate); +} + +void __metal_driver_sifive_spi0_init(struct metal_spi *gspi, int baud_rate) +{ + struct __metal_driver_sifive_spi0 *spi = (void *)(gspi); + struct metal_clock *clock = __metal_driver_sifive_spi0_clock(gspi); + struct __metal_driver_sifive_gpio0 *pinmux = __metal_driver_sifive_spi0_pinmux(gspi); + + if(clock != NULL) { + spi->pre_rate_change_callback.callback = &pre_rate_change_callback_func; + spi->pre_rate_change_callback.priv = spi; + metal_clock_register_pre_rate_change_callback(clock, &(spi->pre_rate_change_callback)); + + spi->post_rate_change_callback.callback = &post_rate_change_callback_func; + spi->post_rate_change_callback.priv = spi; + metal_clock_register_post_rate_change_callback(clock, &(spi->post_rate_change_callback)); + } + + metal_spi_set_baud_rate(&(spi->spi), baud_rate); + + if (pinmux != NULL) { + long pinmux_output_selector = __metal_driver_sifive_spi0_pinmux_output_selector(gspi); + long pinmux_source_selector = __metal_driver_sifive_spi0_pinmux_source_selector(gspi); + pinmux->gpio.vtable->enable_io( + (struct metal_gpio *) pinmux, + pinmux_output_selector, + pinmux_source_selector + ); + } +} + +__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_spi0) = { + .spi.init = __metal_driver_sifive_spi0_init, + .spi.transfer = __metal_driver_sifive_spi0_transfer, + .spi.get_baud_rate = __metal_driver_sifive_spi0_get_baud_rate, + .spi.set_baud_rate = __metal_driver_sifive_spi0_set_baud_rate, +}; +#endif /* METAL_SIFIVE_SPI0 */ + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_test0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_test0.c new file mode 100644 index 000000000..79deebbf5 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_test0.c @@ -0,0 +1,30 @@ +/* Copyright 2018 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine/platform.h> + +#ifdef METAL_SIFIVE_TEST0 + +#include <metal/machine.h> + +#include <stdint.h> + +#include <metal/drivers/sifive_test0.h> +#include <metal/io.h> + +void __metal_driver_sifive_test0_exit(const struct __metal_shutdown *sd, int code) __attribute__((noreturn)); +void __metal_driver_sifive_test0_exit(const struct __metal_shutdown *sd, int code) +{ + long base = __metal_driver_sifive_test0_base(sd); + uint32_t out = (code << 16) + (code == 0 ? 0x5555 : 0x3333); + while (1) { + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_TEST0_FINISHER_OFFSET)) = out; + } +} + +__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_test0) = { + .shutdown.exit = &__metal_driver_sifive_test0_exit, +}; +#endif /* METAL_SIFIVE_TEST0 */ + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_trace.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_trace.c new file mode 100644 index 000000000..8b63fbd28 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_trace.c @@ -0,0 +1,95 @@ +/* Copyright 2019 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine/platform.h> + +#ifdef METAL_SIFIVE_TRACE + +#include <metal/drivers/sifive_trace.h> +#include <metal/machine.h> + +#define TRACE_REG(offset) (((unsigned long)base + (offset))) +#define TRACE_REG8(offset) \ + (__METAL_ACCESS_ONCE((__metal_io_u8 *)TRACE_REG(offset))) +#define TRACE_REG16(offset) \ + (__METAL_ACCESS_ONCE((__metal_io_u16 *)TRACE_REG(offset))) +#define TRACE_REG32(offset) \ + (__METAL_ACCESS_ONCE((__metal_io_u32 *)TRACE_REG(offset))) + +static void write_itc_uint32(struct metal_uart *trace, uint32_t data) { + long base = __metal_driver_sifive_trace_base(trace); + + TRACE_REG32(METAL_SIFIVE_TRACE_ITCSTIMULUS) = data; +} + +static void write_itc_uint16(struct metal_uart *trace, uint16_t data) { + long base = __metal_driver_sifive_trace_base(trace); + + TRACE_REG16(METAL_SIFIVE_TRACE_ITCSTIMULUS + 2) = data; +} + +static void write_itc_uint8(struct metal_uart *trace, uint8_t data) { + long base = __metal_driver_sifive_trace_base(trace); + + TRACE_REG8(METAL_SIFIVE_TRACE_ITCSTIMULUS + 3) = data; +} + +int __metal_driver_sifive_trace_putc(struct metal_uart *trace, + unsigned char c) { + static uint32_t buffer = 0; + static int bytes_in_buffer = 0; + + buffer |= (((uint32_t)c) << (bytes_in_buffer * 8)); + + bytes_in_buffer += 1; + + if (bytes_in_buffer >= 4) { + write_itc_uint32(trace, buffer); + + buffer = 0; + bytes_in_buffer = 0; + } else if ((c == '\n') || (c == '\r')) { // partial write + switch (bytes_in_buffer) { + case 3: // do a full word write + write_itc_uint16(trace, (uint16_t)(buffer)); + write_itc_uint8(trace, (uint8_t)(buffer >> 16)); + break; + case 2: // do a 16 bit write + write_itc_uint16(trace, (uint16_t)buffer); + break; + case 1: // do a 1 byte write + write_itc_uint8(trace, (uint8_t)buffer); + break; + } + + buffer = 0; + bytes_in_buffer = 0; + } + + return (int)c; +} + +void __metal_driver_sifive_trace_init(struct metal_uart *trace, int baud_rate) { + // The only init we do here is to make sure ITC 0 is enabled. It is up to + // Freedom Studio or other mechanisms to make sure tracing is enabled. If we + // try to enable tracing here, it will likely conflict with Freedom Studio, + // and they will just fight with each other. + + long base = __metal_driver_sifive_trace_base(trace); + + TRACE_REG32(METAL_SIFIVE_TRACE_ITCTRACEENABLE) |= 0x00000001; +} + +__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_trace) = { + .uart.init = __metal_driver_sifive_trace_init, + .uart.putc = __metal_driver_sifive_trace_putc, + .uart.getc = NULL, + + .uart.get_baud_rate = NULL, + .uart.set_baud_rate = NULL, + + .uart.controller_interrupt = NULL, + .uart.get_interrupt_id = NULL, +}; + +#endif /* METAL_SIFIVE_TRACE */ diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_uart0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_uart0.c new file mode 100644 index 000000000..2e8098aa7 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_uart0.c @@ -0,0 +1,173 @@ +/* Copyright 2018 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine/platform.h> + +#ifdef METAL_SIFIVE_UART0 + +#include <metal/drivers/sifive_uart0.h> +#include <metal/machine.h> + +/* TXDATA Fields */ +#define UART_TXEN (1 << 0) +#define UART_TXFULL (1 << 31) + +/* RXDATA Fields */ +#define UART_RXEN (1 << 0) +#define UART_RXEMPTY (1 << 31) + +/* TXCTRL Fields */ +#define UART_NSTOP (1 << 1) +#define UART_TXCNT(count) ((0x7 & count) << 16) + +/* IP Fields */ +#define UART_TXWM (1 << 0) + +#define UART_REG(offset) (((unsigned long)control_base + offset)) +#define UART_REGB(offset) (__METAL_ACCESS_ONCE((__metal_io_u8 *)UART_REG(offset))) +#define UART_REGW(offset) (__METAL_ACCESS_ONCE((__metal_io_u32 *)UART_REG(offset))) + +struct metal_interrupt * +__metal_driver_sifive_uart0_interrupt_controller(struct metal_uart *uart) +{ + return __metal_driver_sifive_uart0_interrupt_parent(uart); +} + +int __metal_driver_sifive_uart0_get_interrupt_id(struct metal_uart *uart) +{ + return (__metal_driver_sifive_uart0_interrupt_line(uart) + METAL_INTERRUPT_ID_GL0); +} + + +int __metal_driver_sifive_uart0_txready(struct metal_uart *uart) +{ + long control_base = __metal_driver_sifive_uart0_control_base(uart); + + return !((UART_REGW(METAL_SIFIVE_UART0_TXDATA) & UART_TXFULL)); +} + + +int __metal_driver_sifive_uart0_putc(struct metal_uart *uart, int c) +{ + long control_base = __metal_driver_sifive_uart0_control_base(uart); + + while (!__metal_driver_sifive_uart0_txready(uart)) { + /* wait */ + } + UART_REGW(METAL_SIFIVE_UART0_TXDATA) = c; + return 0; +} + + +int __metal_driver_sifive_uart0_getc(struct metal_uart *uart, int *c) +{ + uint32_t ch; + long control_base = __metal_driver_sifive_uart0_control_base(uart); + /* No seperate status register, we get status and the byte at same time */ + ch = UART_REGW(METAL_SIFIVE_UART0_RXDATA);; + if( ch & UART_RXEMPTY ){ + *c = -1; /* aka: EOF in most of the world */ + } else { + *c = ch & 0x0ff; + } + return 0; +} + + +int __metal_driver_sifive_uart0_get_baud_rate(struct metal_uart *guart) +{ + struct __metal_driver_sifive_uart0 *uart = (void *)guart; + return uart->baud_rate; +} + +int __metal_driver_sifive_uart0_set_baud_rate(struct metal_uart *guart, int baud_rate) +{ + struct __metal_driver_sifive_uart0 *uart = (void *)guart; + long control_base = __metal_driver_sifive_uart0_control_base(guart); + struct metal_clock *clock = __metal_driver_sifive_uart0_clock(guart); + + uart->baud_rate = baud_rate; + + if (clock != NULL) { + long clock_rate = clock->vtable->get_rate_hz(clock); + UART_REGW(METAL_SIFIVE_UART0_DIV) = clock_rate / baud_rate - 1; + UART_REGW(METAL_SIFIVE_UART0_TXCTRL) |= UART_TXEN; + UART_REGW(METAL_SIFIVE_UART0_RXCTRL) |= UART_RXEN; + } + return 0; +} + +static void pre_rate_change_callback_func(void *priv) +{ + struct __metal_driver_sifive_uart0 *uart = priv; + long control_base = __metal_driver_sifive_uart0_control_base((struct metal_uart *)priv); + struct metal_clock *clock = __metal_driver_sifive_uart0_clock((struct metal_uart *)priv); + + /* Detect when the TXDATA is empty by setting the transmit watermark count + * to one and waiting until an interrupt is pending */ + + UART_REGW(METAL_SIFIVE_UART0_TXCTRL) &= ~(UART_TXCNT(0x7)); + UART_REGW(METAL_SIFIVE_UART0_TXCTRL) |= UART_TXCNT(1); + + while((UART_REGW(METAL_SIFIVE_UART0_IP) & UART_TXWM) == 0) ; + + /* When the TXDATA clears, the UART is still shifting out the last byte. + * Calculate the time we must drain to finish transmitting and then wait + * that long. */ + + long bits_per_symbol = (UART_REGW(METAL_SIFIVE_UART0_TXCTRL) & (1 << 1)) ? 9 : 10; + long clk_freq = clock->vtable->get_rate_hz(clock); + long cycles_to_wait = bits_per_symbol * clk_freq / uart->baud_rate; + + for(volatile long x = 0; x < cycles_to_wait; x++) + __asm__("nop"); +} + +static void post_rate_change_callback_func(void *priv) +{ + struct __metal_driver_sifive_uart0 *uart = priv; + metal_uart_set_baud_rate(&uart->uart, uart->baud_rate); +} + +void __metal_driver_sifive_uart0_init(struct metal_uart *guart, int baud_rate) +{ + struct __metal_driver_sifive_uart0 *uart = (void *)(guart); + struct metal_clock *clock = __metal_driver_sifive_uart0_clock(guart); + struct __metal_driver_sifive_gpio0 *pinmux = __metal_driver_sifive_uart0_pinmux(guart); + + if(clock != NULL) { + uart->pre_rate_change_callback.callback = &pre_rate_change_callback_func; + uart->pre_rate_change_callback.priv = guart; + metal_clock_register_pre_rate_change_callback(clock, &(uart->pre_rate_change_callback)); + + uart->post_rate_change_callback.callback = &post_rate_change_callback_func; + uart->post_rate_change_callback.priv = guart; + metal_clock_register_post_rate_change_callback(clock, &(uart->post_rate_change_callback)); + } + + metal_uart_set_baud_rate(&(uart->uart), baud_rate); + + if (pinmux != NULL) { + long pinmux_output_selector = __metal_driver_sifive_uart0_pinmux_output_selector(guart); + long pinmux_source_selector = __metal_driver_sifive_uart0_pinmux_source_selector(guart); + pinmux->gpio.vtable->enable_io( + (struct metal_gpio *) pinmux, + pinmux_output_selector, + pinmux_source_selector + ); + } +} + +__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_uart0) = { + .uart.init = __metal_driver_sifive_uart0_init, + .uart.putc = __metal_driver_sifive_uart0_putc, + .uart.getc = __metal_driver_sifive_uart0_getc, + .uart.get_baud_rate = __metal_driver_sifive_uart0_get_baud_rate, + .uart.set_baud_rate = __metal_driver_sifive_uart0_set_baud_rate, + .uart.controller_interrupt = __metal_driver_sifive_uart0_interrupt_controller, + .uart.get_interrupt_id = __metal_driver_sifive_uart0_get_interrupt_id, +}; + +#endif /* METAL_SIFIVE_UART0 */ + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_wdog0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_wdog0.c new file mode 100644 index 000000000..1a6cf362e --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/drivers/sifive_wdog0.c @@ -0,0 +1,213 @@ +/* Copyright 2019 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine/platform.h> + +#ifdef METAL_SIFIVE_WDOG0 + +#include <metal/drivers/sifive_uart0.h> +#include <metal/machine.h> + +#include <limits.h> + +/* WDOGCFG */ +#define METAL_WDOGCFG_SCALE_MASK 7 +#define METAL_WDOGCFG_RSTEN (1 << 8) +#define METAL_WDOGCFG_ZEROCMP (1 << 9) +#define METAL_WDOGCFG_ENALWAYS (1 << 12) +#define METAL_WDOGCFG_COREAWAKE (1 << 13) +#define METAL_WDOGCFG_IP (1 << 28) + +/* WDOGCMP */ +#define METAL_WDOGCMP_MASK 0xFFFF + +#define WDOG_REG(base, offset) (((unsigned long)base + offset)) +#define WDOG_REGB(base, offset) (__METAL_ACCESS_ONCE((__metal_io_u8 *)WDOG_REG(base, offset))) +#define WDOG_REGW(base, offset) (__METAL_ACCESS_ONCE((__metal_io_u32 *)WDOG_REG(base, offset))) + +/* All writes to watchdog registers must be precedded by a write of + * a magic number to WDOGKEY */ +#define WDOG_UNLOCK(base) (WDOG_REGW(base, METAL_SIFIVE_WDOG0_WDOGKEY) = METAL_SIFIVE_WDOG0_MAGIC_KEY) + +/* Unlock the watchdog and then perform a register access */ +#define WDOG_UNLOCK_REGW(base, offset) \ + WDOG_UNLOCK(base);\ + WDOG_REGW(base, offset) + +int __metal_driver_sifive_wdog0_feed(const struct metal_watchdog *const wdog) +{ + const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog); + + WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGFEED) = METAL_SIFIVE_WDOG0_MAGIC_FOOD; + + return 0; +} + +long int __metal_driver_sifive_wdog0_get_rate(const struct metal_watchdog *const wdog) +{ + const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog); + const struct metal_clock *const clock = __metal_driver_sifive_wdog0_clock(wdog); + + const long int clock_rate = metal_clock_get_rate_hz(clock); + + if (clock_rate == 0) + return -1; + + const unsigned int scale = (WDOG_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) & METAL_WDOGCFG_SCALE_MASK); + + return clock_rate / (1 << scale); +} + +long int __metal_driver_sifive_wdog0_set_rate(const struct metal_watchdog *const wdog, const long int rate) +{ + const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog); + const struct metal_clock *const clock = __metal_driver_sifive_wdog0_clock(wdog); + + const long int clock_rate = metal_clock_get_rate_hz(clock); + + if (rate >= clock_rate) { + /* We can't scale the rate above the driving clock. Clear the scale + * field and return the driving clock rate */ + WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) &= ~(METAL_WDOGCFG_SCALE_MASK); + return clock_rate; + } + + /* Look for the closest scale value */ + long min_diff = LONG_MAX; + unsigned int min_scale = 0; + for (int i = 0; i < METAL_WDOGCFG_SCALE_MASK; i++) { + const long int new_rate = clock_rate / (1 << i); + + long int diff = rate - new_rate; + if (diff < 0) + diff *= -1; + + if (diff < min_diff) { + min_diff = diff; + min_scale = i; + } + } + + WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) &= ~(METAL_WDOGCFG_SCALE_MASK); + WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) |= (METAL_WDOGCFG_SCALE_MASK & min_scale); + + return clock_rate / (1 << min_scale); +} + +long int __metal_driver_sifive_wdog0_get_timeout(const struct metal_watchdog *const wdog) +{ + const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog); + + return (WDOG_REGW(base, METAL_SIFIVE_WDOG0_WDOGCMP) & METAL_WDOGCMP_MASK); +} + +long int __metal_driver_sifive_wdog0_set_timeout(const struct metal_watchdog *const wdog, const long int timeout) +{ + const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog); + + /* Cap the timeout at the max value */ + const long int set_timeout = timeout > METAL_WDOGCMP_MASK ? METAL_WDOGCMP_MASK : timeout; + + /* If we edit the timeout value in-place by masking the compare value to 0 and + * then writing it, we cause a spurious interrupt because the compare value + * is temporarily 0. Instead, read the value into a local variable, modify it + * there, and then write the whole register back */ + uint32_t wdogcmp = WDOG_REGW(base, METAL_SIFIVE_WDOG0_WDOGCMP); + + wdogcmp &= ~(METAL_WDOGCMP_MASK); + wdogcmp |= set_timeout; + + WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCMP) = wdogcmp; + + return set_timeout; +} + +int __metal_driver_sifive_wdog0_set_result(const struct metal_watchdog *const wdog, + const enum metal_watchdog_result result) +{ + const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog); + + /* Turn off reset enable and counter reset */ + WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) &= ~(METAL_WDOGCFG_RSTEN | METAL_WDOGCFG_ZEROCMP); + + switch (result) { + default: + case METAL_WATCHDOG_NO_RESULT: + break; + case METAL_WATCHDOG_INTERRUPT: + /* Reset counter to zero after match */ + WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) |= METAL_WDOGCFG_ZEROCMP; + break; + case METAL_WATCHDOG_FULL_RESET: + WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) |= METAL_WDOGCFG_RSTEN; + break; + } + + return 0; +} + +int __metal_driver_sifive_wdog0_run(const struct metal_watchdog *const wdog, + const enum metal_watchdog_run_option option) +{ + const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog); + + WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) &= ~(METAL_WDOGCFG_ENALWAYS | METAL_WDOGCFG_COREAWAKE); + + switch (option) { + default: + case METAL_WATCHDOG_STOP: + break; + case METAL_WATCHDOG_RUN_ALWAYS: + /* Feed the watchdog before starting to reset counter */ + __metal_driver_sifive_wdog0_feed(wdog); + + WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) |= METAL_WDOGCFG_ENALWAYS; + break; + case METAL_WATCHDOG_RUN_AWAKE: + /* Feed the watchdog before starting to reset counter */ + __metal_driver_sifive_wdog0_feed(wdog); + + WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) |= METAL_WDOGCFG_COREAWAKE; + break; + } + + return 0; +} + +struct metal_interrupt *__metal_driver_sifive_wdog0_get_interrupt(const struct metal_watchdog *const wdog) +{ + return __metal_driver_sifive_wdog0_interrupt_parent(wdog); +} + +int __metal_driver_sifive_wdog0_get_interrupt_id(const struct metal_watchdog *const wdog) +{ + return __metal_driver_sifive_wdog0_interrupt_line(wdog); +} + +int __metal_driver_sifive_wdog0_clear_interrupt(const struct metal_watchdog *const wdog) +{ + const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog); + + /* Clear the interrupt pending bit */ + WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) &= ~(METAL_WDOGCFG_IP); + + return 0; +} + +__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_wdog0) = { + .watchdog.feed = __metal_driver_sifive_wdog0_feed, + .watchdog.get_rate = __metal_driver_sifive_wdog0_get_rate, + .watchdog.set_rate = __metal_driver_sifive_wdog0_set_rate, + .watchdog.get_timeout = __metal_driver_sifive_wdog0_get_timeout, + .watchdog.set_timeout = __metal_driver_sifive_wdog0_set_timeout, + .watchdog.set_result = __metal_driver_sifive_wdog0_set_result, + .watchdog.run = __metal_driver_sifive_wdog0_run, + .watchdog.get_interrupt = __metal_driver_sifive_wdog0_get_interrupt, + .watchdog.get_interrupt_id = __metal_driver_sifive_wdog0_get_interrupt_id, + .watchdog.clear_interrupt = __metal_driver_sifive_wdog0_clear_interrupt, +}; + +#endif /* METAL_SIFIVE_WDOG0 */ + +typedef int no_empty_translation_units; + diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/entry.S b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/entry.S new file mode 100644 index 000000000..97da3fd33 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/entry.S @@ -0,0 +1,106 @@ +/* Copyright 2018 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +/* This code executes before _start, which is contained inside the C library. + * In embedded systems we want to ensure that _enter, which contains the first + * code to be executed, can be loaded at a specific address. To enable this + * feature we provide the '.text.metal.init.enter' section, which is + * defined to have the first address being where execution should start. */ +.section .text.metal.init.enter +.global _enter +_enter: + .cfi_startproc + + /* Inform the debugger that there is nowhere to backtrace past _enter. */ + .cfi_undefined ra + + /* The absolute first thing that must happen is configuring the global + * pointer register, which must be done with relaxation disabled because + * it's not valid to obtain the address of any symbol without GP + * configured. The C environment might go ahead and do this again, but + * that's safe as it's a fixed register. */ +.option push +.option norelax + la gp, __global_pointer$ +.option pop + + /* Set up a simple trap vector to catch anything that goes wrong early in + * the boot process. */ + la t0, early_trap_vector + csrw mtvec, t0 + /* enable chicken bit if core is bullet series*/ + la t0, __metal_chicken_bit + beqz t0, 1f + csrwi 0x7C1, 0 +1: + + /* There may be pre-initialization routines inside the MBI code that run in + * C, so here we set up a C environment. First we set up a stack pointer, + * which is left as a weak reference in order to allow initialization + * routines that do not need a stack to be set up to transparently be + * called. */ + .weak __metal_stack_pointer + la sp, __metal_stack_pointer + + /* Check for an initialization routine and call it if one exists, otherwise + * just skip over the call entirely. Note that __metal_initialize isn't + * actually a full C function, as it doesn't end up with the .bss or .data + * segments having been initialized. This is done to avoid putting a + * burden on systems that can be initialized without having a C environment + * set up. */ + .weak __metal_before_start + la ra, __metal_before_start + beqz ra, 1f + jalr ra +1: + + /* At this point we can enter the C runtime's startup file. The arguments + * to this function are designed to match those provided to the SEE, just + * so we don't have to write another ABI. */ + csrr a0, mhartid + li a1, 0 + li a2, 0 + call _start + + /* If we've made it back here then there's probably something wrong. We + * allow the METAL to register a handler here. */ + .weak __metal_after_main + la ra, __metal_after_main + beqz ra, 1f + jalr ra +1: + + /* If that handler returns then there's not a whole lot we can do. Just + * try to make some noise. */ + la t0, 1f + csrw mtvec, t0 +1: + lw t1, 0(x0) + j 1b + + .cfi_endproc + +/* For sanity's sake we set up an early trap vector that just does nothing. If + * you end up here then there's a bug in the early boot code somewhere. */ +.section .text.metal.init.trapvec +.align 2 +early_trap_vector: + .cfi_startproc + csrr t0, mcause + csrr t1, mepc + csrr t2, mtval + j early_trap_vector + .cfi_endproc + +/* The GCC port might not emit a __register_frame_info symbol, which eventually + * results in a weak undefined reference that eventually causes crash when it + * is dereference early in boot. We really shouldn't need to put this here, + * but to deal with what I think is probably a bug in the linker script I'm + * going to leave this in for now. At least it's fairly cheap :) */ +.weak __register_frame_info +.global __register_frame_info +.section .text.metal.init.__register_frame_info +__register_frame_info: + .cfi_startproc + ret + .cfi_endproc diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/gpio.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/gpio.c new file mode 100644 index 000000000..504526eb3 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/gpio.c @@ -0,0 +1,30 @@ +/* Copyright 2019 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine.h> +#include <metal/gpio.h> + +extern __inline__ int metal_gpio_disable_input(struct metal_gpio *gpio, int pin); +extern __inline__ int metal_gpio_enable_input(struct metal_gpio *gpio, int pin); +extern __inline__ int metal_gpio_enable_output(struct metal_gpio *gpio, int pin); +extern __inline__ int metal_gpio_disable_output(struct metal_gpio *gpio, int pin); +extern __inline__ int metal_gpio_get_output_pin(struct metal_gpio *gpio, int pin); +extern __inline__ int metal_gpio_get_input_pin(struct metal_gpio *gpio, int pin); +extern __inline__ int metal_gpio_set_pin(struct metal_gpio *, int pin, int value); +extern __inline__ int metal_gpio_clear_pin(struct metal_gpio *, int pin); +extern __inline__ int metal_gpio_toggle_pin(struct metal_gpio *, int pin); +extern __inline__ int metal_gpio_enable_pinmux(struct metal_gpio *, int pin, int io_function); +extern __inline__ int metal_gpio_disable_pinmux(struct metal_gpio *, int pin); +extern __inline__ struct metal_interrupt* metal_gpio_interrupt_controller(struct metal_gpio *gpio); +extern __inline__ int metal_gpio_get_interrupt_id(struct metal_gpio *gpio, int pin); +extern __inline__ int metal_gpio_config_interrupt(struct metal_gpio *gpio, int pin, int intr_type); +extern __inline__ int metal_gpio_clear_interrupt(struct metal_gpio *gpio, int pin, int intr_type); + +struct metal_gpio *metal_gpio_get_device(unsigned int device_num) +{ + if(device_num > __MEE_DT_MAX_GPIOS) { + return NULL; + } + + return (struct metal_gpio *) __metal_gpio_table[device_num]; +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/interrupt.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/interrupt.c new file mode 100644 index 000000000..eeb88b26f --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/interrupt.c @@ -0,0 +1,82 @@ +/* Copyright 2018 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <string.h> +#include <metal/interrupt.h> +#include <metal/machine.h> + +struct metal_interrupt* metal_interrupt_get_controller (metal_intr_cntrl_type cntrl, + int id) +{ + switch (cntrl) { + case METAL_CPU_CONTROLLER: + break; + case METAL_CLINT_CONTROLLER: +#ifdef __METAL_DT_RISCV_CLINT0_HANDLE + return __METAL_DT_RISCV_CLINT0_HANDLE; +#endif + break; + case METAL_CLIC_CONTROLLER: +#ifdef __METAL_DT_SIFIVE_CLIC0_HANDLE + return __METAL_DT_SIFIVE_CLIC0_HANDLE; +#endif + break; + case METAL_PLIC_CONTROLLER: +#ifdef __METAL_DT_RISCV_PLIC0_HANDLE + return __METAL_DT_RISCV_PLIC0_HANDLE; +#endif + break; + } + return NULL; +} + +extern __inline__ void metal_interrupt_init(struct metal_interrupt *controller); + +extern __inline__ int metal_interrupt_set_vector_mode(struct metal_interrupt *controller, + metal_vector_mode mode); +extern __inline__ metal_vector_mode metal_interrupt_get_vector_mode(struct metal_interrupt *controller); + +extern __inline__ int metal_interrupt_set_privilege(struct metal_interrupt *controller, + metal_intr_priv_mode mode); +extern __inline__ metal_intr_priv_mode metal_interrupt_get_privilege(struct metal_interrupt *controller); + +extern __inline__ int metal_interrupt_set_threshold(struct metal_interrupt *controller, + unsigned int level); +extern __inline__ unsigned int metal_interrupt_get_threshold(struct metal_interrupt *controller); + +extern __inline__ unsigned int metal_interrupt_get_priority(struct metal_interrupt *controller, int id); + +extern __inline__ int metal_interrupt_set_priority(struct metal_interrupt *controller, int id, unsigned int priority); + +extern __inline__ int metal_interrupt_clear(struct metal_interrupt *controller, int id); + +extern __inline__ int metal_interrupt_set(struct metal_interrupt *controller, int id); + +extern __inline__ int metal_interrupt_register_handler(struct metal_interrupt *controller, + int id, + metal_interrupt_handler_t handler, + void *priv); + +extern __inline__ int metal_interrupt_register_vector_handler(struct metal_interrupt *controller, + int id, + metal_interrupt_vector_handler_t handler, + void *priv_data); + +extern __inline__ int metal_interrupt_enable(struct metal_interrupt *controller, int id); + +extern __inline__ int metal_interrupt_disable(struct metal_interrupt *controller, int id); + +extern __inline__ unsigned int metal_interrupt_get_threshold(struct metal_interrupt *controller); + +extern __inline__ int metal_interrupt_set_threshold(struct metal_interrupt *controller, unsigned int threshold); + +extern __inline__ unsigned int metal_interrupt_get_priority(struct metal_interrupt *controller, int id); + +extern __inline__ int metal_interrupt_set_priority(struct metal_interrupt *controller, int id, unsigned int priority); + +extern __inline__ int metal_interrupt_vector_enable(struct metal_interrupt *controller, int id); + +extern __inline__ int metal_interrupt_vector_disable(struct metal_interrupt *controller, int id); + +extern __inline__ int _metal_interrupt_command_request(struct metal_interrupt *controller, + int cmd, void *data); diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/led.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/led.c new file mode 100644 index 000000000..91b74dbde --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/led.c @@ -0,0 +1,38 @@ +/* Copyright 2018 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <string.h> +#include <metal/led.h> +#include <metal/machine.h> + +struct metal_led* metal_led_get_rgb (char *label, char *color) +{ + int i; + struct metal_led *led; + char led_label[100]; + + if ((__METAL_DT_MAX_LEDS == 0) || + (label == NULL) || (color == NULL)) { + return NULL; + } + + strcpy(led_label, label); + strcat(led_label, color); + for (i = 0; i < __METAL_DT_MAX_LEDS; i++) { + led = (struct metal_led*)__metal_led_table[i]; + if (led->vtable->led_exist(led, led_label)) { + return led; + } + } + return NULL; +} + +struct metal_led* metal_led_get (char *label) +{ + return metal_led_get_rgb(label, ""); +} + +extern __inline__ void metal_led_enable(struct metal_led *led); +extern __inline__ void metal_led_on(struct metal_led *led); +extern __inline__ void metal_led_off(struct metal_led *led); +extern __inline__ void metal_led_toggle(struct metal_led *led); diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/lock.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/lock.c new file mode 100644 index 000000000..9e04230a3 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/lock.c @@ -0,0 +1,8 @@ +/* Copyright 2019 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/lock.h> + +extern __inline__ int metal_lock_init(struct metal_lock *lock); +extern __inline__ int metal_lock_take(struct metal_lock *lock); +extern __inline__ int metal_lock_give(struct metal_lock *lock); diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/memory.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/memory.c new file mode 100644 index 000000000..05ab7ead2 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/memory.c @@ -0,0 +1,26 @@ +/* Copyright 2019 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine.h> +#include <metal/memory.h> + +struct metal_memory *metal_get_memory_from_address(const uintptr_t address) { + for(int i = 0; i < __METAL_DT_MAX_MEMORIES; i++) { + struct metal_memory *mem = __metal_memory_table[i]; + + uintptr_t lower_bound = metal_memory_get_base_address(mem); + uintptr_t upper_bound = lower_bound + metal_memory_get_size(mem); + + if((address >= lower_bound) && (address < upper_bound)) { + return mem; + } + } + + return NULL; +} + +extern __inline__ uintptr_t metal_memory_get_base_address(const struct metal_memory *memory); +extern __inline__ size_t metal_memory_get_size(const struct metal_memory *memory); +extern __inline__ int metal_memory_supports_atomics(const struct metal_memory *memory); +extern __inline__ int metal_memory_is_cachable(const struct metal_memory *memory); + diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/pmp.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/pmp.c new file mode 100644 index 000000000..5c2f68ada --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/pmp.c @@ -0,0 +1,586 @@ +/* Copyright 2018 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine.h> +#include <metal/pmp.h> +#include <metal/cpu.h> + +#define CONFIG_TO_INT(_config) (*((char *) &(_config))) +#define INT_TO_CONFIG(_int) (*((struct metal_pmp_config *)(char *) &(_int))) + +struct metal_pmp *metal_pmp_get_device(void) +{ +#ifdef __METAL_DT_PMP_HANDLE + return __METAL_DT_PMP_HANDLE; +#else + return NULL; +#endif +} + +/* This function calculates the minimum granularity from the address + * that pmpaddr takes on after writing all ones to pmpaddr when pmpcfg = 0. + * + * Detect the address granularity based on the position of the + * least-significant 1 set in the address. + * + * For example, if the value read from pmpaddr is 0x3ffffc00, the + * least-significant set bit is in bit 10 (counting from 0), resulting + * in a detected granularity of 2^(10 + 2) = 4096. + */ +static uintptr_t _get_detected_granularity(uintptr_t address) { + if(address == 0) { + return (uintptr_t) -1; + } + + /* Get the index of the least significant set bit */ + int index = 0; + while(((address >> index) & 0x1) == 0) { + index += 1; + } + + /* The granularity is equal to 2^(index + 2) bytes */ + return (1 << (index + 2)); +} + +/* This function calculates the granularity requested by the user's provided + * value for pmpaddr. + * + * Calculate the requested granularity based on the position of the + * least-significant unset bit. + * + * For example, if the requested address is 0x20009ff, the least-significant + * unset bit is at index 9 (counting from 0), resulting in a requested + * granularity of 2^(9 + 3) = 4096. + */ +static uintptr_t _get_pmpaddr_granularity(uintptr_t address) { + /* Get the index of the least significant unset bit */ + int index = 0; + while(((address >> index) & 0x1) == 1) { + index += 1; + } + + /* The granularity is equal to 2^(index + 3) bytes */ + return (1 << (index + 3)); +} + +/* Get the number of pmp regions for the given hart */ +int metal_pmp_num_regions(int hartid) +{ + struct metal_cpu *cpu = metal_cpu_get(hartid); + + return __metal_driver_cpu_num_pmp_regions(cpu); +} + +/* Get the number of pmp regions for the current hart */ +static unsigned int _pmp_regions() { + return metal_pmp_num_regions(metal_cpu_get_current_hartid()); +} + +void metal_pmp_init(struct metal_pmp *pmp) { + if(!pmp) { + return; + } + + struct metal_pmp_config init_config = { + .L = METAL_PMP_UNLOCKED, + .A = METAL_PMP_OFF, + .X = 0, + .W = 0, + .R = 0, + }; + + for(unsigned int i = 0; i < _pmp_regions(); i++) { + metal_pmp_set_region(pmp, i, init_config, 0); + } + + /* Detect the region granularity by writing all 1s to pmpaddr0 while + * pmpcfg0 = 0. */ + if(metal_pmp_set_address(pmp, 0, -1) != 0) { + /* Failed to detect granularity */ + return; + } + + /* Calculate the granularity based on the value that pmpaddr0 takes on */ + pmp->_granularity[metal_cpu_get_current_hartid()] = _get_detected_granularity(metal_pmp_get_address(pmp, 0)); + + /* Clear pmpaddr0 */ + metal_pmp_set_address(pmp, 0, 0); +} + +int metal_pmp_set_region(struct metal_pmp *pmp, + unsigned int region, + struct metal_pmp_config config, + size_t address) +{ + struct metal_pmp_config old_config; + size_t old_address; + size_t cfgmask; + size_t pmpcfg; + int rc = 0; + + if(!pmp) { + /* Device handle cannot be NULL */ + return 1; + } + + if(region > _pmp_regions()) { + /* Region outside of supported range */ + return 2; + } + + if(config.A == METAL_PMP_NA4 && pmp->_granularity[metal_cpu_get_current_hartid()] > 4) { + /* The requested granularity is too small */ + return 3; + } + + if(config.A == METAL_PMP_NAPOT && + pmp->_granularity[metal_cpu_get_current_hartid()] > _get_pmpaddr_granularity(address)) + { + /* The requested granularity is too small */ + return 3; + } + + rc = metal_pmp_get_region(pmp, region, &old_config, &old_address); + if(rc) { + /* Error reading region */ + return rc; + } + + if(old_config.L == METAL_PMP_LOCKED) { + /* Cannot modify locked region */ + return 4; + } + + /* Update the address first, because if the region is being locked we won't + * be able to modify it after we set the config */ + if(old_address != address) { + switch(region) { + case 0: + __asm__("csrw pmpaddr0, %[addr]" + :: [addr] "r" (address) :); + break; + case 1: + __asm__("csrw pmpaddr1, %[addr]" + :: [addr] "r" (address) :); + break; + case 2: + __asm__("csrw pmpaddr2, %[addr]" + :: [addr] "r" (address) :); + break; + case 3: + __asm__("csrw pmpaddr3, %[addr]" + :: [addr] "r" (address) :); + break; + case 4: + __asm__("csrw pmpaddr4, %[addr]" + :: [addr] "r" (address) :); + break; + case 5: + __asm__("csrw pmpaddr5, %[addr]" + :: [addr] "r" (address) :); + break; + case 6: + __asm__("csrw pmpaddr6, %[addr]" + :: [addr] "r" (address) :); + break; + case 7: + __asm__("csrw pmpaddr7, %[addr]" + :: [addr] "r" (address) :); + break; + case 8: + __asm__("csrw pmpaddr8, %[addr]" + :: [addr] "r" (address) :); + break; + case 9: + __asm__("csrw pmpaddr9, %[addr]" + :: [addr] "r" (address) :); + break; + case 10: + __asm__("csrw pmpaddr10, %[addr]" + :: [addr] "r" (address) :); + break; + case 11: + __asm__("csrw pmpaddr11, %[addr]" + :: [addr] "r" (address) :); + break; + case 12: + __asm__("csrw pmpaddr12, %[addr]" + :: [addr] "r" (address) :); + break; + case 13: + __asm__("csrw pmpaddr13, %[addr]" + :: [addr] "r" (address) :); + break; + case 14: + __asm__("csrw pmpaddr14, %[addr]" + :: [addr] "r" (address) :); + break; + case 15: + __asm__("csrw pmpaddr15, %[addr]" + :: [addr] "r" (address) :); + break; + } + } + +#if __riscv_xlen==32 + if(CONFIG_TO_INT(old_config) != CONFIG_TO_INT(config)) { + /* Mask to clear old pmpcfg */ + cfgmask = (0xFF << (8 * (region % 4)) ); + pmpcfg = (CONFIG_TO_INT(config) << (8 * (region % 4)) ); + + switch(region / 4) { + case 0: + __asm__("csrc pmpcfg0, %[mask]" + :: [mask] "r" (cfgmask) :); + + __asm__("csrs pmpcfg0, %[cfg]" + :: [cfg] "r" (pmpcfg) :); + break; + case 1: + __asm__("csrc pmpcfg1, %[mask]" + :: [mask] "r" (cfgmask) :); + + __asm__("csrs pmpcfg1, %[cfg]" + :: [cfg] "r" (pmpcfg) :); + break; + case 2: + __asm__("csrc pmpcfg2, %[mask]" + :: [mask] "r" (cfgmask) :); + + __asm__("csrs pmpcfg2, %[cfg]" + :: [cfg] "r" (pmpcfg) :); + break; + case 3: + __asm__("csrc pmpcfg3, %[mask]" + :: [mask] "r" (cfgmask) :); + + __asm__("csrs pmpcfg3, %[cfg]" + :: [cfg] "r" (pmpcfg) :); + break; + } + } +#elif __riscv_xlen==64 + if(CONFIG_TO_INT(old_config) != CONFIG_TO_INT(config)) { + /* Mask to clear old pmpcfg */ + cfgmask = (0xFF << (8 * (region % 8)) ); + pmpcfg = (CONFIG_TO_INT(config) << (8 * (region % 8)) ); + + switch(region / 8) { + case 0: + __asm__("csrc pmpcfg0, %[mask]" + :: [mask] "r" (cfgmask) :); + + __asm__("csrs pmpcfg0, %[cfg]" + :: [cfg] "r" (pmpcfg) :); + break; + case 1: + __asm__("csrc pmpcfg2, %[mask]" + :: [mask] "r" (cfgmask) :); + + __asm__("csrs pmpcfg2, %[cfg]" + :: [cfg] "r" (pmpcfg) :); + break; + } + } +#else +#error XLEN is not set to supported value for PMP driver +#endif + + return 0; +} + +int metal_pmp_get_region(struct metal_pmp *pmp, + unsigned int region, + struct metal_pmp_config *config, + size_t *address) +{ + size_t pmpcfg = 0; + char *pmpcfg_convert = (char *)&pmpcfg; + + if(!pmp || !config || !address) { + /* NULL pointers are invalid arguments */ + return 1; + } + + if(region > _pmp_regions()) { + /* Region outside of supported range */ + return 2; + } + +#if __riscv_xlen==32 + switch(region / 4) { + case 0: + __asm__("csrr %[cfg], pmpcfg0" + : [cfg] "=r" (pmpcfg) ::); + break; + case 1: + __asm__("csrr %[cfg], pmpcfg1" + : [cfg] "=r" (pmpcfg) ::); + break; + case 2: + __asm__("csrr %[cfg], pmpcfg2" + : [cfg] "=r" (pmpcfg) ::); + break; + case 3: + __asm__("csrr %[cfg], pmpcfg3" + : [cfg] "=r" (pmpcfg) ::); + break; + } + + pmpcfg = (0xFF & (pmpcfg >> (8 * (region % 4)) ) ); + +#elif __riscv_xlen==64 + switch(region / 8) { + case 0: + __asm__("csrr %[cfg], pmpcfg0" + : [cfg] "=r" (pmpcfg) ::); + break; + case 1: + __asm__("csrr %[cfg], pmpcfg2" + : [cfg] "=r" (pmpcfg) ::); + break; + } + + pmpcfg = (0xFF & (pmpcfg >> (8 * (region % 8)) ) ); + +#else +#error XLEN is not set to supported value for PMP driver +#endif + + *config = INT_TO_CONFIG(*pmpcfg_convert); + + switch(region) { + case 0: + __asm__("csrr %[addr], pmpaddr0" + : [addr] "=r" (*address) ::); + break; + case 1: + __asm__("csrr %[addr], pmpaddr1" + : [addr] "=r" (*address) ::); + break; + case 2: + __asm__("csrr %[addr], pmpaddr2" + : [addr] "=r" (*address) ::); + break; + case 3: + __asm__("csrr %[addr], pmpaddr3" + : [addr] "=r" (*address) ::); + break; + case 4: + __asm__("csrr %[addr], pmpaddr4" + : [addr] "=r" (*address) ::); + break; + case 5: + __asm__("csrr %[addr], pmpaddr5" + : [addr] "=r" (*address) ::); + break; + case 6: + __asm__("csrr %[addr], pmpaddr6" + : [addr] "=r" (*address) ::); + break; + case 7: + __asm__("csrr %[addr], pmpaddr7" + : [addr] "=r" (*address) ::); + break; + case 8: + __asm__("csrr %[addr], pmpaddr8" + : [addr] "=r" (*address) ::); + break; + case 9: + __asm__("csrr %[addr], pmpaddr9" + : [addr] "=r" (*address) ::); + break; + case 10: + __asm__("csrr %[addr], pmpaddr10" + : [addr] "=r" (*address) ::); + break; + case 11: + __asm__("csrr %[addr], pmpaddr11" + : [addr] "=r" (*address) ::); + break; + case 12: + __asm__("csrr %[addr], pmpaddr12" + : [addr] "=r" (*address) ::); + break; + case 13: + __asm__("csrr %[addr], pmpaddr13" + : [addr] "=r" (*address) ::); + break; + case 14: + __asm__("csrr %[addr], pmpaddr14" + : [addr] "=r" (*address) ::); + break; + case 15: + __asm__("csrr %[addr], pmpaddr15" + : [addr] "=r" (*address) ::); + break; + } + + return 0; +} + +int metal_pmp_lock(struct metal_pmp *pmp, unsigned int region) +{ + struct metal_pmp_config config; + size_t address; + int rc = 0; + + rc = metal_pmp_get_region(pmp, region, &config, &address); + if(rc) { + return rc; + } + + if(config.L == METAL_PMP_LOCKED) { + return 0; + } + + config.L = METAL_PMP_LOCKED; + + rc = metal_pmp_set_region(pmp, region, config, address); + + return rc; +} + + +int metal_pmp_set_address(struct metal_pmp *pmp, unsigned int region, size_t address) +{ + struct metal_pmp_config config; + size_t old_address; + int rc = 0; + + rc = metal_pmp_get_region(pmp, region, &config, &old_address); + if(rc) { + return rc; + } + + rc = metal_pmp_set_region(pmp, region, config, address); + + return rc; +} + +size_t metal_pmp_get_address(struct metal_pmp *pmp, unsigned int region) +{ + struct metal_pmp_config config; + size_t address = 0; + + metal_pmp_get_region(pmp, region, &config, &address); + + return address; +} + + +int metal_pmp_set_address_mode(struct metal_pmp *pmp, unsigned int region, enum metal_pmp_address_mode mode) +{ + struct metal_pmp_config config; + size_t address; + int rc = 0; + + rc = metal_pmp_get_region(pmp, region, &config, &address); + if(rc) { + return rc; + } + + config.A = mode; + + rc = metal_pmp_set_region(pmp, region, config, address); + + return rc; +} + +enum metal_pmp_address_mode metal_pmp_get_address_mode(struct metal_pmp *pmp, unsigned int region) +{ + struct metal_pmp_config config; + size_t address = 0; + + metal_pmp_get_region(pmp, region, &config, &address); + + return config.A; +} + + +int metal_pmp_set_executable(struct metal_pmp *pmp, unsigned int region, int X) +{ + struct metal_pmp_config config; + size_t address; + int rc = 0; + + rc = metal_pmp_get_region(pmp, region, &config, &address); + if(rc) { + return rc; + } + + config.X = X; + + rc = metal_pmp_set_region(pmp, region, config, address); + + return rc; +} + +int metal_pmp_get_executable(struct metal_pmp *pmp, unsigned int region) +{ + struct metal_pmp_config config; + size_t address = 0; + + metal_pmp_get_region(pmp, region, &config, &address); + + return config.X; +} + + +int metal_pmp_set_writeable(struct metal_pmp *pmp, unsigned int region, int W) +{ + struct metal_pmp_config config; + size_t address; + int rc = 0; + + rc = metal_pmp_get_region(pmp, region, &config, &address); + if(rc) { + return rc; + } + + config.W = W; + + rc = metal_pmp_set_region(pmp, region, config, address); + + return rc; +} + +int metal_pmp_get_writeable(struct metal_pmp *pmp, unsigned int region) +{ + struct metal_pmp_config config; + size_t address = 0; + + metal_pmp_get_region(pmp, region, &config, &address); + + return config.W; +} + + +int metal_pmp_set_readable(struct metal_pmp *pmp, unsigned int region, int R) +{ + struct metal_pmp_config config; + size_t address; + int rc = 0; + + rc = metal_pmp_get_region(pmp, region, &config, &address); + if(rc) { + return rc; + } + + config.R = R; + + rc = metal_pmp_set_region(pmp, region, config, address); + + return rc; +} + +int metal_pmp_get_readable(struct metal_pmp *pmp, unsigned int region) +{ + struct metal_pmp_config config; + size_t address = 0; + + metal_pmp_get_region(pmp, region, &config, &address); + + return config.R; +} + diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/privilege.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/privilege.c new file mode 100644 index 000000000..54bfcfc2c --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/privilege.c @@ -0,0 +1,57 @@ +/* Copyright 2019 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <stddef.h> + +#include <metal/privilege.h> + +#define METAL_MSTATUS_MIE_OFFSET 3 +#define METAL_MSTATUS_MPIE_OFFSET 7 +#define METAL_MSTATUS_SIE_OFFSET 1 +#define METAL_MSTATUS_SPIE_OFFSET 5 +#define METAL_MSTATUS_UIE_OFFSET 0 +#define METAL_MSTATUS_UPIE_OFFSET 4 + +#define METAL_MSTATUS_MPP_OFFSET 11 +#define METAL_MSTATUS_MPP_MASK 3 + +void metal_privilege_drop_to_mode(enum metal_privilege_mode mode, + struct metal_register_file regfile, + metal_privilege_entry_point_t entry_point) +{ + uintptr_t mstatus; + __asm__ volatile("csrr %0, mstatus" : "=r" (mstatus)); + + /* Set xPIE bits based on current xIE bits */ + if(mstatus && (1 << METAL_MSTATUS_MIE_OFFSET)) { + mstatus |= (1 << METAL_MSTATUS_MPIE_OFFSET); + } else { + mstatus &= ~(1 << METAL_MSTATUS_MPIE_OFFSET); + } + if(mstatus && (1 << METAL_MSTATUS_SIE_OFFSET)) { + mstatus |= (1 << METAL_MSTATUS_SPIE_OFFSET); + } else { + mstatus &= ~(1 << METAL_MSTATUS_SPIE_OFFSET); + } + if(mstatus && (1 << METAL_MSTATUS_UIE_OFFSET)) { + mstatus |= (1 << METAL_MSTATUS_UPIE_OFFSET); + } else { + mstatus &= ~(1 << METAL_MSTATUS_UPIE_OFFSET); + } + + /* Set MPP to the requested privilege mode */ + mstatus &= ~(METAL_MSTATUS_MPP_MASK << METAL_MSTATUS_MPP_OFFSET); + mstatus |= (mode << METAL_MSTATUS_MPP_OFFSET); + + __asm__ volatile("csrw mstatus, %0" :: "r" (mstatus)); + + /* Set the entry point in MEPC */ + __asm__ volatile("csrw mepc, %0" :: "r" (entry_point)); + + /* Set the register file */ + __asm__ volatile("mv ra, %0" :: "r" (regfile.ra)); + __asm__ volatile("mv sp, %0" :: "r" (regfile.sp)); + + __asm__ volatile("mret"); +} + diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/rtc.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/rtc.c new file mode 100644 index 000000000..8b79892df --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/rtc.c @@ -0,0 +1,27 @@ +/* Copyright 2019 SiFive, Inc. */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine.h> +#include <metal/rtc.h> + +#include <stddef.h> + +extern inline uint64_t metal_rtc_get_rate(const struct metal_rtc *const rtc); +extern inline uint64_t metal_rtc_set_rate(const struct metal_rtc *const rtc, const uint64_t rate); +extern inline uint64_t metal_rtc_get_compare(const struct metal_rtc *const rtc); +extern inline uint64_t metal_rtc_set_compare(const struct metal_rtc *const rtc, const uint64_t compare); +extern inline uint64_t metal_rtc_get_count(const struct metal_rtc *const rtc); +extern inline uint64_t metal_rtc_set_count(const struct metal_rtc *const rtc, const uint64_t count); +extern inline int metal_rtc_run(const struct metal_rtc *const rtc, const enum metal_rtc_run_option option); +extern inline struct metal_interrupt *metal_rtc_get_interrupt(const struct metal_rtc *const rtc); +extern inline int metal_rtc_get_interrupt_id(const struct metal_rtc *const rtc); + +struct metal_rtc *metal_rtc_get_device(int index) { +#ifdef __METAL_DT_MAX_RTCS + if (index < __METAL_DT_MAX_RTCS) { + return (struct metal_rtc *) __metal_rtc_table[index]; + } +#endif + return NULL; +} + diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/shutdown.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/shutdown.c new file mode 100644 index 000000000..c3b5255a7 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/shutdown.c @@ -0,0 +1,22 @@ +/* Copyright 2018 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine.h> +#include <metal/shutdown.h> + +extern __inline__ void __metal_shutdown_exit(const struct __metal_shutdown *sd, int code); + +#if defined(__METAL_DT_SHUTDOWN_HANDLE) +void metal_shutdown(int code) +{ + __metal_shutdown_exit(__METAL_DT_SHUTDOWN_HANDLE, code); +} +#else +#pragma message("There is no defined shutdown mechanism, metal_shutdown() will spin.") +void metal_shutdown(int code) +{ + while (1) { + __asm__ volatile ("nop"); + } +} +#endif diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/spi.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/spi.c new file mode 100644 index 000000000..de8cda737 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/spi.c @@ -0,0 +1,21 @@ +/* Copyright 2018 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine.h> +#include <metal/spi.h> + +extern __inline__ void metal_spi_init(struct metal_spi *spi, int baud_rate); +extern __inline__ int metal_spi_transfer(struct metal_spi *spi, struct metal_spi_config *config, size_t len, char *tx_buf, char *rx_buf); +extern __inline__ int metal_spi_get_baud_rate(struct metal_spi *spi); +extern __inline__ int metal_spi_set_baud_rate(struct metal_spi *spi, int baud_rate); + +struct metal_spi *metal_spi_get_device(unsigned int device_num) +{ +#if __METAL_DT_MAX_SPIS > 0 + if (device_num < __METAL_DT_MAX_SPIS) { + return (struct metal_spi *) __metal_spi_table[device_num]; + } +#endif + + return NULL; +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/switch.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/switch.c new file mode 100644 index 000000000..4f17229c7 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/switch.c @@ -0,0 +1,27 @@ +/* Copyright 2018 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/switch.h> +#include <metal/machine.h> + +struct metal_switch* metal_switch_get (char *label) +{ + int i; + struct metal_switch *flip; + + if ((__METAL_DT_MAX_BUTTONS == 0) || (label == NULL)) { + return NULL; + } + + for (i = 0; i < __METAL_DT_MAX_BUTTONS; i++) { + flip = (struct metal_switch*)__metal_switch_table[i]; + if (flip->vtable->switch_exist(flip, label)) { + return flip; + } + } + return NULL; +} + +extern __inline__ struct metal_interrupt* + metal_switch_interrupt_controller(struct metal_switch *flip); +extern __inline__ int metal_switch_get_interrupt_id(struct metal_switch *flip); diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/synchronize_harts.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/synchronize_harts.c new file mode 100644 index 000000000..a5338e942 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/synchronize_harts.c @@ -0,0 +1,62 @@ +/* Copyright 2019 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine.h> +#include <metal/machine/platform.h> +#include <metal/io.h> +#include <metal/cpu.h> + +#define METAL_REG(base, offset) (((unsigned long)(base) + (offset))) +#define METAL_REGW(base, offset) (__METAL_ACCESS_ONCE((__metal_io_u32 *)METAL_REG((base), (offset)))) +#define METAL_MSIP(base, hart) (METAL_REGW((base),4*(hart))) + +/* + * _synchronize_harts() is called by crt0.S to cause harts > 0 to wait for + * hart 0 to finish copying the datat section, zeroing the BSS, and running + * the libc contstructors. + */ +__attribute__((section(".init"))) +void __metal_synchronize_harts() { +#if __METAL_DT_MAX_HARTS > 1 + + int hart; + __asm__ volatile("csrr %0, mhartid" : "=r" (hart) ::); + + uintptr_t msip_base = 0; + + /* Get the base address of the MSIP registers */ +#ifdef __METAL_DT_RISCV_CLINT0_HANDLE + msip_base = __metal_driver_sifive_clint0_control_base(__METAL_DT_RISCV_CLINT0_HANDLE); + msip_base += METAL_RISCV_CLINT0_MSIP_BASE; +#elif __METAL_DT_RISCV_CLIC0_HANDLE + msip_base = __metal_driver_sifive_clic0_control_base(__METAL_DT_RISCV_CLIC0_HANDLE); + msip_base += METAL_RISCV_CLIC0_MSIP_BASE; +#else +#pragma message(No handle for CLINT or CLIC found, harts may be unsynchronized after init!) +#endif + + /* Disable machine interrupts as a precaution */ + __asm__ volatile("csrc mstatus, %0" :: "r" (METAL_MSTATUS_MIE)); + + if (hart == 0) { + /* Hart 0 waits for all harts to set their MSIP bit */ + for (int i = 1 ; i < __METAL_DT_MAX_HARTS; i++) { + while (METAL_MSIP(msip_base, i) == 0) ; + } + + /* Hart 0 clears everyone's MSIP bit */ + for (int i = 1 ; i < __METAL_DT_MAX_HARTS; i++) { + METAL_MSIP(msip_base, i) = 0; + } + } else { + /* Other harts set their MSIP bit to indicate they're ready */ + METAL_MSIP(msip_base, hart) = 1; + __asm__ volatile ("fence w,rw"); + + /* Wait for hart 0 to clear the MSIP bit */ + while (METAL_MSIP(msip_base, hart) == 1) ; + } + +#endif /* __METAL_DT_MAX_HARTS > 1 */ +} + diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/time.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/time.c new file mode 100644 index 000000000..529f8bd56 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/time.c @@ -0,0 +1,30 @@ +/* Copyright 2019 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/time.h> +#include <metal/timer.h> + +int metal_gettimeofday(struct timeval *tp, void *tzp) +{ + int rv; + unsigned long long mcc, timebase; + if ((rv = metal_timer_get_cyclecount(0, &mcc))) { + return -1; + } + if ((rv = metal_timer_get_timebase_frequency(0, &timebase))) { + return -1; + } + tp->tv_sec = mcc / timebase; + tp->tv_usec = mcc % timebase * 1000000 / timebase; + return 0; +} + +time_t metal_time (void) +{ + struct timeval now; + + if (metal_gettimeofday(&now, NULL) < 0) + now.tv_sec = (time_t) -1; + + return now.tv_sec; +} diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/timer.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/timer.c new file mode 100644 index 000000000..f58413321 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/timer.c @@ -0,0 +1,80 @@ +/* Copyright 2018 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <sys/time.h> +#include <sys/times.h> +#include <metal/cpu.h> +#include <metal/timer.h> +#include <metal/machine.h> + +#if defined(__METAL_DT_MAX_HARTS) +/* This implementation serves as a small shim that interfaces with the first + * timer on a system. */ +int metal_timer_get_cyclecount(int hartid, unsigned long long *mcc) +{ + struct metal_cpu *cpu = metal_cpu_get(hartid); + + if ( cpu ) { + *mcc = metal_cpu_get_timer(cpu); + return 0; + } + return -1; +} + +int metal_timer_get_timebase_frequency(int hartid, unsigned long long *timebase) +{ + struct metal_cpu *cpu = metal_cpu_get(hartid); + + if ( cpu ) { + *timebase = metal_cpu_get_timebase(cpu); + return 0; + } + return -1; +} + +int metal_timer_get_machine_time(int hartid) +{ + struct metal_cpu *cpu = metal_cpu_get(hartid); + + if ( cpu ) { + return metal_cpu_get_mtime(cpu); + } + return 0; +} + +int metal_timer_set_machine_time(int hartid, unsigned long long time) +{ + struct metal_cpu *cpu = metal_cpu_get(hartid); + + if ( cpu ) { + return metal_cpu_set_mtimecmp(cpu, time); + } + return -1; +} + +#else + +/* This implementation of gettimeofday doesn't actually do anything, it's just there to + * provide a shim and return 0 so we can ensure that everything can link to _gettimeofday. + */ +int nop_cyclecount(int id, unsigned long long *c) __attribute__((section(".text.metal.nop.cyclecount"))); +int nop_cyclecount(int id, unsigned long long *c) { return -1; } +int nop_timebase(unsigned long long *t) __attribute__((section(".text.metal.nop.timebase"))); +int nop_timebase(unsigned long long *t) { return -1; } +int nop_tick(int second) __attribute__((section(".text.metal.nop.tick"))); +int nop_tick(int second) { return -1; } +int metal_timer_get_cyclecount(int hartid, unsigned long long *c) __attribute__((weak, alias("nop_cyclecount"))) +{ +#pragma message("There is no default timer device, metal_timer_get_cyclecount() will always return cyclecount -1.") +} +int metal_timer_get_timebase_frequency(unsigned long long *t) __attribute__((weak, alias("nop_timebase"))) +{ +#pragma message("There is no default timer device, metal_timer_get_timebase_frequency() will always return timebase -1.") +} +int metal_timer_set_tick(int second) __attribute__((weak, alias("nop_tick"))) +{ +#pragma message("There is no default timer device, metal_timer_set_tick) will always return -1.") +} + +#endif + diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/trap.S b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/trap.S new file mode 100644 index 000000000..b55b6656a --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/trap.S @@ -0,0 +1,53 @@ +/* Copyright 2019 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#define METAL_MSTATUS_MIE_SHIFT 8 +#define METAL_MSTATUS_MPP_M 3 +#define METAL_MSTATUS_MPP_SHIFT 11 + +#define METAL_MTVEC_MODE_MASK 3 + +/* void _metal_trap(int ecode) + * + * Trigger a machine-mode trap with exception code ecode + */ +.global _metal_trap +.type _metal_trap, @function + +_metal_trap: + + /* Store the instruction which called _metal_trap in mepc */ + addi t0, ra, -1 + csrw mepc, t0 + + /* Set mcause to the desired exception code */ + csrw mcause, a0 + + /* Read mstatus */ + csrr t0, mstatus + + /* Set MIE=0 */ + li t1, -1 + xori t1, t1, METAL_MSTATUS_MIE_SHIFT + and t0, t0, t1 + + /* Set MPP=M */ + li t1, METAL_MSTATUS_MPP_M + slli t1, t1, METAL_MSTATUS_MPP_SHIFT + or t0, t0, t1 + + /* Write mstatus */ + csrw mstatus, t0 + + /* Read mtvec */ + csrr t0, mtvec + + /* + * Mask the mtvec MODE bits + * Exceptions always jump to mtvec.BASE regradless of the vectoring mode. + */ + andi t0, t0, METAL_MTVEC_MODE_MASK + + /* Jump to mtvec */ + jr t0 + diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/tty.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/tty.c new file mode 100644 index 000000000..306192451 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/tty.c @@ -0,0 +1,51 @@ +/* Copyright 2018 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/uart.h> +#include <metal/tty.h> +#include <metal/machine.h> + +#if defined(__METAL_DT_STDOUT_UART_HANDLE) +/* This implementation serves as a small shim that interfaces with the first + * UART on a system. */ +int metal_tty_putc(int c) +{ + if (c == '\n') { + metal_tty_putc_raw( '\r' ); + } + return metal_tty_putc_raw( c ); +} + +int metal_tty_putc_raw(int c) +{ + return metal_uart_putc(__METAL_DT_STDOUT_UART_HANDLE, c); +} + +int metal_tty_getc(int *c) +{ + do { + metal_uart_getc( __METAL_DT_STDOUT_UART_HANDLE, c ); + /* -1 means no key pressed, getc waits */ + } while( -1 == *c ) + ; + return 0; +} + +#ifndef __METAL_DT_STDOUT_UART_BAUD +#define __METAL_DT_STDOUT_UART_BAUD 115200 +#endif + +static void metal_tty_init(void) __attribute__((constructor)); +static void metal_tty_init(void) +{ + metal_uart_init(__METAL_DT_STDOUT_UART_HANDLE, __METAL_DT_STDOUT_UART_BAUD); +} +#else +/* This implementation of putc doesn't actually do anything, it's just there to + * provide a shim that eats all the characters so we can ensure that everything + * can link to metal_tty_putc. */ +int nop_putc(int c) __attribute__((section(".text.metal.nop.putc"))); +int nop_putc(int c) { return -1; } +int metal_tty_putc(int c) __attribute__((weak, alias("nop_putc"))); +#pragma message("There is no default output device, metal_tty_putc() will throw away all input.") +#endif diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/uart.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/uart.c new file mode 100644 index 000000000..8981eb8d3 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/uart.c @@ -0,0 +1,11 @@ +/* Copyright 2018 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/uart.h> + +extern __inline__ void metal_uart_init(struct metal_uart *uart, int baud_rate); +extern __inline__ int metal_uart_putc(struct metal_uart *uart, int c); +extern __inline__ int metal_uart_txready(struct metal_uart *uart); +extern __inline__ int metal_uart_getc(struct metal_uart *uart, int *c); +extern __inline__ int metal_uart_get_baud_rate(struct metal_uart *uart); +extern __inline__ int metal_uart_set_baud_rate(struct metal_uart *uart, int baud_rate); diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/vector.S b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/vector.S new file mode 100644 index 000000000..1da52d2df --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1-RevB_FreedomStudio/freedom-metal/src/vector.S @@ -0,0 +1,160 @@ +/* Copyright 2019 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +/* + * Jump table for CLINT vectored mode + */ +.weak metal_interrupt_vector_handler +.balign 4, 0 +.global metal_interrupt_vector_handler + +.weak metal_software_interrupt_vector_handler +.balign 4, 0 +.global metal_software_interrupt_vector_handler + +.weak metal_timer_interrupt_vector_handler +.balign 4, 0 +.global metal_timer_interrupt_vector_handler + +.weak metal_external_interrupt_vector_handler +.balign 4, 0 +.global metal_external_interrupt_vector_handler + +.weak metal_lc0_interrupt_vector_handler +.balign 4, 0 +.global metal_lc0_interrupt_vector_handler + +.weak metal_lc1_interrupt_vector_handler +.balign 4, 0 +.global metal_lc1_interrupt_vector_handler + +.weak metal_lc2_interrupt_vector_handler +.balign 4, 0 +.global metal_lc2_interrupt_vector_handler + +.weak metal_lc3_interrupt_vector_handler +.balign 4, 0 +.global metal_lc3_interrupt_vector_handler + +.weak metal_lc4_interrupt_vector_handler +.balign 4, 0 +.global metal_lc4_interrupt_vector_handler + +.weak metal_lc5_interrupt_vector_handler +.balign 4, 0 +.global metal_lc5_interrupt_vector_handler + +.weak metal_lc6_interrupt_vector_handler +.balign 4, 0 +.global metal_lc6_interrupt_vector_handler + +.weak metal_lc7_interrupt_vector_handler +.balign 4, 0 +.global metal_lc7_interrupt_vector_handler + +.weak metal_lc8_interrupt_vector_handler +.balign 4, 0 +.global metal_lc8_interrupt_vector_handler + +.weak metal_lc9_interrupt_vector_handler +.balign 4, 0 +.global metal_lc9_interrupt_vector_handler + +.weak metal_lc10_interrupt_vector_handler +.balign 4, 0 +.global metal_lc10_interrupt_vector_handler + +.weak metal_lc11_interrupt_vector_handler +.balign 4, 0 +.global metal_lc11_interrupt_vector_handler + +.weak metal_lc12_interrupt_vector_handler +.balign 4, 0 +.global metal_lc12_interrupt_vector_handler + +.weak metal_lc13_interrupt_vector_handler +.balign 4, 0 +.global metal_lc13_interrupt_vector_handler + +.weak metal_lc14_interrupt_vector_handler +.balign 4, 0 +.global metal_lc14_interrupt_vector_handler + +.weak metal_lc15_interrupt_vector_handler +.balign 4, 0 +.global metal_lc15_interrupt_vector_handler + +#if __riscv_xlen == 32 +.balign 128, 0 +#else +.balign 256, 0 +#endif +.option norvc +.global __metal_vector_table +__metal_vector_table: +IRQ_0: + j metal_interrupt_vector_handler +IRQ_1: + j metal_interrupt_vector_handler +IRQ_2: + j metal_interrupt_vector_handler +IRQ_3: + j metal_software_interrupt_vector_handler +IRQ_4: + j metal_interrupt_vector_handler +IRQ_5: + j metal_interrupt_vector_handler +IRQ_6: + j metal_interrupt_vector_handler +IRQ_7: + j metal_timer_interrupt_vector_handler +IRQ_8: + j metal_interrupt_vector_handler +IRQ_9: + j metal_interrupt_vector_handler +IRQ_10: + j metal_interrupt_vector_handler +IRQ_11: + j metal_interrupt_vector_handler +IRQ_12: + j metal_interrupt_vector_handler +IRQ_13: + j metal_interrupt_vector_handler +IRQ_14: + j metal_interrupt_vector_handler +IRQ_15: + j metal_interrupt_vector_handler +IRQ_LC0: + j metal_lc0_interrupt_vector_handler +IRQ_LC1: + j metal_lc1_interrupt_vector_handler +IRQ_LC2: + j metal_lc2_interrupt_vector_handler +IRQ_LC3: + j metal_lc3_interrupt_vector_handler +IRQ_LC4: + j metal_lc4_interrupt_vector_handler +IRQ_LC5: + j metal_lc5_interrupt_vector_handler +IRQ_LC6: + j metal_lc6_interrupt_vector_handler +IRQ_LC7: + j metal_lc7_interrupt_vector_handler +IRQ_LC8: + j metal_lc8_interrupt_vector_handler +IRQ_LC9: + j metal_lc9_interrupt_vector_handler +IRQ_LC10: + j metal_lc10_interrupt_vector_handler +IRQ_LC11: + j metal_lc11_interrupt_vector_handler +IRQ_LC12: + j metal_lc12_interrupt_vector_handler +IRQ_LC13: + j metal_lc13_interrupt_vector_handler +IRQ_LC14: + j metal_lc14_interrupt_vector_handler +IRQ_LC15: + j metal_lc15_interrupt_vector_handler + + |