summaryrefslogtreecommitdiff
path: root/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers')
-rw-r--r--FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/fixed-clock.c2
-rw-r--r--FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/fixed-factor-clock.c2
-rw-r--r--FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/riscv_clint0.c67
-rw-r--r--FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/riscv_cpu.c437
-rw-r--r--FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/riscv_plic0.c49
-rw-r--r--FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_ccache0.c84
-rw-r--r--FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_clic0.c294
-rw-r--r--FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_hfrosc.c6
-rw-r--r--FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_hfxosc.c6
-rw-r--r--FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_lfrosc.c53
-rw-r--r--FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_pll.c10
-rw-r--r--FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_prci.c2
-rw-r--r--FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fu540-c000_l2.c29
-rw-r--r--FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_global-external-interrupts0.c49
-rw-r--r--FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-buttons.c2
-rw-r--r--FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-leds.c2
-rw-r--r--FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-switches.c2
-rw-r--r--FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio0.c150
-rw-r--r--FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_local-external-interrupts0.c34
-rw-r--r--FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_rtc0.c121
-rw-r--r--FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_spi0.c168
-rw-r--r--FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_test0.c10
-rw-r--r--FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_trace.c95
-rw-r--r--FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_uart0.c48
-rw-r--r--FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_wdog0.c213
25 files changed, 1731 insertions, 204 deletions
diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/fixed-clock.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/fixed-clock.c
index a1219e01e..92c61d023 100644
--- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/fixed-clock.c
+++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/fixed-clock.c
@@ -25,3 +25,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_fixed_clock) = {
};
#endif /* METAL_FIXED_CLOCK */
+
+typedef int no_empty_translation_units;
diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/fixed-factor-clock.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/fixed-factor-clock.c
index 2e0624652..57d83af87 100644
--- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/fixed-factor-clock.c
+++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/fixed-factor-clock.c
@@ -30,3 +30,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_fixed_factor_clock) = {
.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_FreedomStudio/freedom-metal/src/drivers/riscv_clint0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/riscv_clint0.c
index f1814d365..d0488b317 100644
--- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/riscv_clint0.c
+++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/riscv_clint0.c
@@ -76,11 +76,15 @@ int __metal_driver_riscv_clint0_register (struct metal_interrupt *controller,
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);
@@ -97,6 +101,41 @@ int __metal_driver_riscv_clint0_register (struct metal_interrupt *controller,
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;
@@ -120,6 +159,8 @@ int __metal_driver_riscv_clint0_enable (struct metal_interrupt *controller, int
rc = intc->vtable->interrupt_enable(intc, id);
}
}
+
+ return rc;
}
int __metal_driver_riscv_clint0_disable (struct metal_interrupt *controller, int id)
@@ -145,6 +186,8 @@ int __metal_driver_riscv_clint0_disable (struct metal_interrupt *controller, int
rc = intc->vtable->interrupt_disable(intc, id);
}
}
+
+ return rc;
}
int __metal_driver_riscv_clint0_command_request (struct metal_interrupt *controller,
@@ -206,13 +249,35 @@ int __metal_driver_riscv_clint0_command_request (struct metal_interrupt *control
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_FreedomStudio/freedom-metal/src/drivers/riscv_cpu.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/riscv_cpu.c
index 88175eb18..b693f312a 100644
--- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/riscv_cpu.c
+++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/riscv_cpu.c
@@ -6,6 +6,7 @@
#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);
@@ -20,7 +21,7 @@ struct metal_cpu *__metal_driver_cpu_get(int hartid)
uintptr_t __metal_myhart_id (void)
{
uintptr_t myhart;
- asm volatile ("csrr %0, mhartid" : "=r"(myhart));
+ __asm__ volatile ("csrr %0, mhartid" : "=r"(myhart));
return myhart;
}
@@ -34,54 +35,54 @@ void __metal_zero_memory (unsigned char *base, unsigned int size)
void __metal_interrupt_global_enable (void) {
uintptr_t m;
- asm volatile ("csrrs %0, mstatus, %1" : "=r"(m) : "r"(METAL_MIE_INTERRUPT));
+ __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));
+ __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));
+ __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));
+ __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));
+ __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));
+ __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));
+ __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));
+ __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));
+ __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));
+ __asm__ volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(b));
}
void __metal_default_exception_handler (struct metal_cpu *cpu, int ecode) {
@@ -92,12 +93,31 @@ 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));
+ __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);
@@ -105,6 +125,20 @@ void __metal_default_sw_handler (int id, void *priv) {
}
}
+/* 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);
@@ -113,6 +147,20 @@ void __metal_default_timer_handler (int id, void *priv) {
__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;
@@ -121,17 +169,17 @@ void __metal_exception_handler (void) {
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));
+ __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_LC0) ||
+ 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);
@@ -141,9 +189,9 @@ void __metal_exception_handler (void) {
uintptr_t mtvt;
metal_interrupt_handler_t mtvt_handler;
- asm volatile ("csrr %0, mtvt" : "=r"(mtvt));
+ __asm__ volatile ("csrr %0, 0x307" : "=r"(mtvt));
priv = intc->metal_int_table[METAL_INTERRUPT_ID_SW].sub_int;
- mtvt_handler = (metal_interrupt_handler_t)mtvt;
+ mtvt_handler = (metal_interrupt_handler_t)*(uintptr_t *)mtvt;
mtvt_handler(id, priv);
return;
}
@@ -153,28 +201,271 @@ void __metal_exception_handler (void) {
}
}
+/* 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));
+ __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 mtvt, %0" :: "r"(trap_entry | METAL_MTVEC_CLIC));
- asm volatile ("csrw mtvec, %0" :: "r"(val | METAL_MTVEC_CLIC));
+ __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 mtvt, %0" :: "r"(trap_entry | METAL_MTVEC_CLIC_VECTORED));
- asm volatile ("csrw mtvec, %0" :: "r"(val | METAL_MTVEC_CLIC_VECTORED));
+ __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));
+ __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));
+ __asm__ volatile ("csrw mtvec, %0" :: "r"(trap_entry & ~METAL_MTVEC_CLIC_VECTORED));
break;
}
}
@@ -270,7 +561,7 @@ int __metal_local_interrupt_enable (struct metal_interrupt *controller,
__metal_interrupt_local_disable(id);
}
break;
- defaut:
+ default:
rc = -1;
}
return rc;
@@ -295,25 +586,25 @@ void __metal_driver_riscv_cpu_controller_interrupt_init (struct metal_interrupt
if ( !intc->init_done ) {
/* Disable and clear all interrupt sources */
- asm volatile ("csrc mie, %0" :: "r"(-1));
- asm volatile ("csrc mip, %0" :: "r"(-1));
+ __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));
+ __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));
+ __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));
+ __asm__ volatile ("csrc satp, %0" :: "r"(-1));
}
/* Default to use direct interrupt, setup sw cb table*/
@@ -325,12 +616,12 @@ void __metal_driver_riscv_cpu_controller_interrupt_init (struct metal_interrupt
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, &__metal_exception_handler);
- asm volatile ("csrr %0, misa" : "=r"(val));
+ __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));
+ __asm__ volatile ("csrr %0, mstatus" : "=r"(val));
+ __asm__ volatile ("csrw mstatus, %0" :: "r"(val | METAL_MSTATUS_FS_INIT));
}
intc->init_done = 1;
}
@@ -380,7 +671,7 @@ int __metal_driver_riscv_cpu_controller_interrupt_register(struct metal_interrup
intc->metal_int_table[id].handler = __metal_default_interrupt_handler;
intc->metal_int_table[id].sub_int = priv;
break;
- defaut:
+ default:
rc = -12;
}
}
@@ -406,11 +697,11 @@ int __metal_driver_riscv_cpu_controller_interrupt_enable_vector(struct metal_int
if (id == METAL_INTERRUPT_ID_BASE) {
if (mode == METAL_DIRECT_MODE) {
- __metal_controller_interrupt_vector(mode, &__metal_exception_handler);
+ __metal_controller_interrupt_vector(mode, (void *)(uintptr_t)&__metal_exception_handler);
return 0;
}
if (mode == METAL_VECTOR_MODE) {
- __metal_controller_interrupt_vector(mode, &intc->metal_mtvec_table);
+ __metal_controller_interrupt_vector(mode, (void *)&intc->metal_mtvec_table);
return 0;
}
}
@@ -420,10 +711,30 @@ int __metal_driver_riscv_cpu_controller_interrupt_enable_vector(struct metal_int
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 (id == METAL_INTERRUPT_ID_BASE) {
- __metal_controller_interrupt_vector(METAL_DIRECT_MODE, &__metal_exception_handler);
+ 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;
@@ -436,25 +747,23 @@ int __metal_driver_riscv_cpu_controller_command_request (struct metal_interrupt
return 0;
}
-extern inline int __metal_controller_interrupt_is_selective_vectored(void);
-
/* CPU driver !!! */
-unsigned long long __metal_driver_cpu_timer_get(struct metal_cpu *cpu)
+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));
+ __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));
+ __asm__ volatile ("csrr %0, mcycle" : "=r"(val));
#endif
return val;
@@ -477,7 +786,6 @@ unsigned long long __metal_driver_cpu_mtime_get (struct metal_cpu *cpu)
struct metal_interrupt *tmr_intc;
struct __metal_driver_riscv_cpu_intc *intc =
(struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu);
- struct __metal_driver_cpu *_cpu = (void *)cpu;
if (intc) {
tmr_intc = intc->metal_int_table[METAL_INTERRUPT_ID_TMR].sub_int;
@@ -495,7 +803,6 @@ int __metal_driver_cpu_mtimecmp_set (struct metal_cpu *cpu, unsigned long long t
struct metal_interrupt *tmr_intc;
struct __metal_driver_riscv_cpu_intc *intc =
(struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu);
- struct __metal_driver_cpu *_cpu = (void *)cpu;
if (intc) {
tmr_intc = intc->metal_int_table[METAL_INTERRUPT_ID_TMR].sub_int;
@@ -517,7 +824,7 @@ __metal_driver_cpu_timer_controller_interrupt(struct metal_cpu *cpu)
#ifdef __METAL_DT_SIFIVE_CLIC0_HANDLE
return __METAL_DT_SIFIVE_CLIC0_HANDLE;
#else
-#warning "There is no interrupt controller for Timer interrupt"
+#pragma message("There is no interrupt controller for Timer interrupt")
return NULL;
#endif
#endif
@@ -537,7 +844,7 @@ __metal_driver_cpu_sw_controller_interrupt(struct metal_cpu *cpu)
#ifdef __METAL_DT_SIFIVE_CLIC0_HANDLE
return __METAL_DT_SIFIVE_CLIC0_HANDLE;
#else
-#warning "There is no interrupt controller for Software interrupt"
+#pragma message("There is no interrupt controller for Software interrupt")
return NULL;
#endif
#endif
@@ -554,7 +861,6 @@ int __metal_driver_cpu_set_sw_ipi (struct metal_cpu *cpu, int hartid)
struct metal_interrupt *sw_intc;
struct __metal_driver_riscv_cpu_intc *intc =
(struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu);
- struct __metal_driver_cpu *_cpu = (void *)cpu;
if (intc) {
sw_intc = intc->metal_int_table[METAL_INTERRUPT_ID_SW].sub_int;
@@ -572,7 +878,6 @@ int __metal_driver_cpu_clear_sw_ipi (struct metal_cpu *cpu, int hartid)
struct metal_interrupt *sw_intc;
struct __metal_driver_riscv_cpu_intc *intc =
(struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu);
- struct __metal_driver_cpu *_cpu = (void *)cpu;
if (intc) {
sw_intc = intc->metal_int_table[METAL_INTERRUPT_ID_SW].sub_int;
@@ -590,7 +895,6 @@ int __metal_driver_cpu_get_msip (struct metal_cpu *cpu, int hartid)
struct metal_interrupt *sw_intc;
struct __metal_driver_riscv_cpu_intc *intc =
(struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu);
- struct __metal_driver_cpu *_cpu = (void *)cpu;
if (intc) {
sw_intc = intc->metal_int_table[METAL_INTERRUPT_ID_SW].sub_int;
@@ -642,35 +946,40 @@ int __metal_driver_cpu_exception_register(struct metal_cpu *cpu, int ecode,
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 */
- return (*(unsigned short*)epc & 3) ? 4 : 2;
+ /**
+ * 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));
+ __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));
+ __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_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_vector_enable = __metal_driver_riscv_cpu_controller_interrupt_enable_vector,
- .controller_vtable.interrupt_vector_disable = __metal_driver_riscv_cpu_controller_interrupt_disable_vector,
+ .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.timer_get = __metal_driver_cpu_timer_get,
+ .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,
diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/riscv_plic0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/riscv_plic0.c
index ed9782450..3272f1c66 100644
--- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/riscv_plic0.c
+++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/riscv_plic0.c
@@ -25,30 +25,47 @@ void __metal_plic0_complete_interrupt(struct __metal_driver_riscv_plic0 *plic,
METAL_RISCV_PLIC0_CLAIM)) = id;
}
-void __metal_plic0_set_threshold(struct __metal_driver_riscv_plic0 *plic,
- unsigned int threshold)
+int __metal_plic0_set_threshold(struct metal_interrupt *controller, unsigned int threshold)
{
- unsigned long control_base = __metal_driver_sifive_plic0_control_base((struct metal_interrupt *)plic);
+ 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;
}
-void __metal_plic0_set_priority(struct __metal_driver_riscv_plic0 *plic,
- int id, unsigned int priority)
+unsigned int __metal_plic0_get_threshold(struct metal_interrupt *controller)
{
- unsigned long control_base = __metal_driver_sifive_plic0_control_base((struct metal_interrupt *)plic);
- int max_priority = __metal_driver_sifive_plic0_max_priority((struct metal_interrupt *)plic);
+ 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 hartid = __metal_myhart_id();
unsigned long control_base = __metal_driver_sifive_plic0_control_base((struct metal_interrupt *)plic);
current = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
@@ -69,7 +86,7 @@ void __metal_plic0_handler (int id, void *priv)
{
struct __metal_driver_riscv_plic0 *plic = priv;
unsigned int idx = __metal_plic0_claim_interrupt(plic);
- int num_interrupts = __metal_driver_sifive_plic0_num_interrupts((struct metal_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,
@@ -97,13 +114,13 @@ void __metal_driver_riscv_plic0_init (struct metal_interrupt *controller)
for (int i = 0; i < num_interrupts; i++) {
__metal_plic0_enable(plic, i, METAL_DISABLE);
- __metal_plic0_set_priority(plic, i, 0);
+ __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(plic, 0);
+ __metal_plic0_set_threshold(controller, 0);
/* Register plic (ext) interrupt with with parent controller */
intc->vtable->interrupt_register(intc, line, NULL, plic);
@@ -127,11 +144,11 @@ int __metal_driver_riscv_plic0_register (struct metal_interrupt *controller,
}
if (isr) {
- __metal_plic0_set_priority(plic ,id, 2);
+ __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(plic, id, 1);
+ __metal_plic0_set_priority(controller, id, 1);
plic->metal_exint_table[id] = __metal_plic0_default_handler;
plic->metal_exdata_table[id].sub_int = priv;
}
@@ -167,6 +184,12 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_riscv_plic0) = {
.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_FreedomStudio/freedom-metal/src/drivers/sifive_ccache0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_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_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_FreedomStudio/freedom-metal/src/drivers/sifive_clic0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_clic0.c
index 3f213847d..12c3dac06 100644
--- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_clic0.c
+++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_clic0.c
@@ -11,12 +11,6 @@
#include <metal/drivers/sifive_clic0.h>
#include <metal/machine.h>
-typedef enum metal_priv_mode_ {
- METAL_PRIV_M_MODE = 0,
- METAL_PRIV_MU_MODE = 1,
- METAL_PRIV_MSU_MODE = 2
-} metal_priv_mode;
-
typedef enum metal_clic_vector_{
METAL_CLIC_NONVECTOR = 0,
METAL_CLIC_VECTORED = 1
@@ -30,17 +24,20 @@ struct __metal_clic_cfg {
};
const struct __metal_clic_cfg __metal_clic_defaultcfg = {
- .nmbits = METAL_PRIV_M_MODE,
+ .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;
- uintptr_t hartid = __metal_myhart_id();
unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
if ( cfg ) {
@@ -80,7 +77,7 @@ int __metal_clic0_interrupt_set_mode (struct __metal_driver_sifive_clic0 *clic,
return 0;
}
-int __metal_clic0_interrupt_set_level (struct __metal_driver_sifive_clic0 *clic, int id, int level)
+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);
@@ -102,7 +99,7 @@ int __metal_clic0_interrupt_set_level (struct __metal_driver_sifive_clic0 *clic,
return 0;
}
-int __metal_clic0_interrupt_get_level (struct __metal_driver_sifive_clic0 *clic, int id)
+unsigned int __metal_clic0_interrupt_get_level (struct __metal_driver_sifive_clic0 *clic, int id)
{
int level;
uint8_t mask, val, freebits, nlbits;
@@ -185,7 +182,7 @@ int __metal_clic0_interrupt_get_priority (struct __metal_driver_sifive_clic0 *cl
return priority;
}
-int __metal_clic0_interrupt_set_vector (struct __metal_driver_sifive_clic0 *clic, int id, int enable)
+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);
@@ -272,36 +269,102 @@ int __metal_clic0_interrupt_is_pending (struct __metal_driver_sifive_clic0 *clic
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 >= METAL_INTERRUPT_ID_LC0) && (id < num_subinterrupts)) {
+ 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 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 >= METAL_INTERRUPT_ID_LC0) && (id < num_subinterrupts)) {
+ 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;
}
-void __metal_clic0_configure_privilege (struct __metal_driver_sifive_clic0 *clic, metal_priv_mode priv)
+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;
}
-void __metal_clic0_configure_level (struct __metal_driver_sifive_clic0 *clic, int level)
+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);
- cfg.nlbits = level;
+ 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)
@@ -338,16 +401,13 @@ int __metal_driver_sifive_clic0_mtimecmp_set(struct metal_interrupt *controller,
return 0;
}
-void __metal_clic0_handler(int id, void *priv) __attribute__((aligned(64)));
void __metal_clic0_handler (int id, void *priv)
{
- int idx;
struct __metal_driver_sifive_clic0 *clic = priv;
int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic);
- idx = id - METAL_INTERRUPT_ID_LC0;
- if ( (idx < num_subinterrupts) && (clic->metal_mtvt_table[idx]) ) {
- clic->metal_mtvt_table[idx](id, clic->metal_exint_table[idx].exint_data);
+ if ( (id < num_subinterrupts) && (clic->metal_exint_table[id].handler) ) {
+ clic->metal_exint_table[id].handler(id, clic->metal_exint_table[id].exint_data);
}
}
@@ -355,6 +415,10 @@ 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 =
@@ -368,8 +432,8 @@ void __metal_driver_sifive_clic0_init (struct metal_interrupt *controller)
/* Initialize ist parent controller, aka cpu_intc. */
intc->vtable->interrupt_init(intc);
- __metal_controller_interrupt_vector(METAL_SELECTIVE_VECTOR_MODE,
- &__metal_clic0_handler);
+ __metal_controller_interrupt_vector(METAL_SELECTIVE_NONVECTOR_MODE,
+ &clic->metal_mtvt_table);
/*
* Register its interrupts with with parent controller,
@@ -389,8 +453,10 @@ void __metal_driver_sifive_clic0_init (struct metal_interrupt *controller)
level = (1 << cfg.nlbits) - 1;
num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller);
- for (int i = 0; i < num_subinterrupts; i++) {
+ 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);
@@ -403,31 +469,71 @@ void __metal_driver_sifive_clic0_init (struct metal_interrupt *controller)
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_LC0) {
+ 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.
+ * Reset the IDs to reflects this.
*/
- id -= METAL_INTERRUPT_ID_LC0;
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_handler;
+ clic->metal_mtvt_table[id] = __metal_clic0_default_vector_handler;
clic->metal_exint_table[id].sub_int = priv;
}
rc = 0;
@@ -449,31 +555,20 @@ int __metal_driver_sifive_clic0_disable (struct metal_interrupt *controller, int
return __metal_clic0_interrupt_disable(clic, id);
}
-int __metal_driver_sifive_clic0_enable_interrupt_vector(struct metal_interrupt *controller,
- int id, metal_vector_mode mode)
+int __metal_driver_sifive_clic0_enable_interrupt_vector(struct metal_interrupt *controller, int id)
{
- int num_subinterrupts;
+ 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 (id == METAL_INTERRUPT_ID_BASE) {
- if (mode == METAL_SELECTIVE_VECTOR_MODE) {
- __metal_controller_interrupt_vector(mode, &__metal_clic0_handler);
- return 0;
- }
- if (mode == METAL_HARDWARE_VECTOR_MODE) {
- __metal_controller_interrupt_vector(mode, &clic->metal_mtvt_table);
- return 0;
- }
+ if ((mode != METAL_SELECTIVE_VECTOR_MODE) && (mode != METAL_HARDWARE_VECTOR_MODE)) {
+ return rc;
}
- num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller);
- if ((id >= METAL_INTERRUPT_ID_LC0) && (id < num_subinterrupts)) {
- if ((mode == METAL_SELECTIVE_VECTOR_MODE) &&
- __metal_controller_interrupt_is_selective_vectored()) {
- __metal_clic0_interrupt_set_vector(clic, id, METAL_ENABLE);
- return 0;
- }
-
+ if (id < num_subinterrupts) {
+ __metal_clic0_interrupt_set_vector_mode(clic, id, METAL_ENABLE);
+ return 0;
}
return -1;
}
@@ -484,20 +579,84 @@ int __metal_driver_sifive_clic0_disable_interrupt_vector(struct metal_interrupt
struct __metal_driver_sifive_clic0 *clic =
(struct __metal_driver_sifive_clic0 *)(controller);
- if (id == METAL_INTERRUPT_ID_BASE) {
- __metal_controller_interrupt_vector(METAL_SELECTIVE_VECTOR_MODE, &__metal_clic0_handler);
- return 0;
- }
num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller);
- if ((id >= METAL_INTERRUPT_ID_LC0) && (id < num_subinterrupts)) {
- if (__metal_controller_interrupt_is_selective_vectored()) {
- __metal_clic0_interrupt_set_vector(clic, id, METAL_DISABLE);
- return 0;
- }
+ 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)
{
@@ -553,12 +712,25 @@ int __metal_driver_sifive_clic0_command_request (struct metal_interrupt *control
__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_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_hfrosc.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_hfrosc.c
index 14ce2fae6..61af8d314 100644
--- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_hfrosc.c
+++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_hfrosc.c
@@ -23,9 +23,9 @@ long __metal_driver_sifive_fe310_g000_hfrosc_get_rate_hz(const struct metal_cloc
__metal_driver_sifive_fe310_g000_prci_vtable();
long cfg = vtable->get_reg(config_base, config_offset);
- if (cfg & CONFIG_ENABLE == 0)
+ if ((cfg & CONFIG_ENABLE) == 0)
return -1;
- if (cfg & CONFIG_READY == 0)
+ if ((cfg & CONFIG_READY) == 0)
return -1;
return metal_clock_get_rate_hz(ref) / ((cfg & CONFIG_DIVIDER) + 1);
}
@@ -40,3 +40,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_hfrosc) = {
.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_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_hfxosc.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_hfxosc.c
index dbe467487..9ed7a0bf3 100644
--- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_hfxosc.c
+++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_hfxosc.c
@@ -21,9 +21,9 @@ long __metal_driver_sifive_fe310_g000_hfxosc_get_rate_hz(const struct metal_cloc
__metal_driver_sifive_fe310_g000_prci_vtable();
long cfg = vtable->get_reg(config_base, config_offset);
- if (cfg & CONFIG_ENABLE == 0)
+ if ((cfg & CONFIG_ENABLE) == 0)
return -1;
- if (cfg & CONFIG_READY == 0)
+ if ((cfg & CONFIG_READY) == 0)
return -1;
return metal_clock_get_rate_hz(ref);
}
@@ -39,3 +39,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_hfxosc) = {
};
#endif /* METAL_SIFIVE_FE310_G000_HFXOSC */
+
+typedef int no_empty_translation_units;
diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_lfrosc.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_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_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_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_pll.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_pll.c
index c91328565..2ca468f43 100644
--- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_pll.c
+++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_pll.c
@@ -133,7 +133,7 @@ void __metal_driver_sifive_fe310_g000_pll_init(struct __metal_driver_sifive_fe31
* 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(long pll_input_rate, const struct pll_config_t *config)
+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;
@@ -162,8 +162,7 @@ void __metal_driver_sifive_fe310_g000_pll_init(struct __metal_driver_sifive_fe31
__metal_io_u32 *pllcfg = (__metal_io_u32 *) (base + config_offset);
/* If the PLL clock has had a _pre_rate_change_callback configured, call it */
- if(pll->clock._pre_rate_change_callback != NULL)
- pll->clock._pre_rate_change_callback(pll->clock._pre_rate_change_callback_priv);
+ _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)
@@ -179,8 +178,7 @@ void __metal_driver_sifive_fe310_g000_pll_init(struct __metal_driver_sifive_fe31
pll->clock.vtable->set_rate_hz(&(pll->clock), init_rate);
/* If the PLL clock has had a rate_change_callback configured, call it */
- if(pll->clock._post_rate_change_callback != NULL)
- pll->clock._post_rate_change_callback(pll->clock._post_rate_change_callback_priv);
+ _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)
@@ -358,3 +356,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_pll) = {
};
#endif /* METAL_SIFIVE_FE310_G000_PLL */
+
+typedef int no_empty_translation_units;
diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_prci.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_prci.c
index 4b402a27a..1236eca3b 100644
--- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_prci.c
+++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_prci.c
@@ -24,3 +24,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_prci) = {
};
#endif /* METAL_SIFIVE_FE310_G000_PRCI */
+
+typedef int no_empty_translation_units;
diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fu540-c000_l2.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fu540-c000_l2.c
index 5e66b6cda..aafc6e5e3 100644
--- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fu540-c000_l2.c
+++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fu540-c000_l2.c
@@ -2,25 +2,32 @@
/* 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)
-#ifdef CONFIG_SIFIVE_FU540_C000_L2
+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_driver_sifive_fu540_c000_l2 *l2 = __METAL_DT_SIFIVE_FU540_C000_L2_HANDLE;
+ struct metal_cache *l2 = __METAL_DT_SIFIVE_FU540_C000_L2_HANDLE;
if(!l2) {
return;
}
/* Get the number of available ways per bank */
- uint32_t ways = __METAL_ACCESS_ONCE((__metal_io_u32 *)(l2->control_base + SIFIVE_FU540_C000_L2_CONFIG));
+ 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 */
@@ -35,12 +42,9 @@ void __metal_driver_sifive_fu540_c000_l2_init(struct metal_cache *l2, int ways)
int __metal_driver_sifive_fu540_c000_l2_get_enabled_ways(struct metal_cache *cache)
{
- struct __metal_driver_sifive_fu540_c000_l2 *l2 = (struct __metal_driver_sifive_fu540_c000_l2 *) cache;
- if(!l2) {
- return -1;
- }
+ unsigned long control_base = __metal_driver_sifive_fu540_c000_l2_control_base(cache);
- uint32_t way_enable = __METAL_ACCESS_ONCE((__metal_io_u32 *)(l2->control_base + SIFIVE_FU540_C000_L2_WAYENABLE));
+ 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;
@@ -48,10 +52,7 @@ int __metal_driver_sifive_fu540_c000_l2_get_enabled_ways(struct metal_cache *cac
int __metal_driver_sifive_fu540_c000_l2_set_enabled_ways(struct metal_cache *cache, int ways)
{
- struct __metal_driver_sifive_fu540_c000_l2 *l2 = (struct __metal_driver_sifive_fu540_c000_l2 *) cache;
- if(!l2) {
- return -1;
- }
+ 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) {
@@ -62,7 +63,7 @@ int __metal_driver_sifive_fu540_c000_l2_set_enabled_ways(struct metal_cache *cac
uint32_t value = 0xFF & (ways - 1);
/* Set the number of enabled ways */
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(l2->control_base + SIFIVE_FU540_C000_L2_WAYENABLE)) = value;
+ __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) {
@@ -79,3 +80,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fu540_c000_l2) = {
};
#endif
+
+typedef int no_empty_translation_units;
diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_global-external-interrupts0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_global-external-interrupts0.c
index 59f6fbe48..0d56bafef 100644
--- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_global-external-interrupts0.c
+++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_global-external-interrupts0.c
@@ -84,6 +84,50 @@ int __metal_driver_sifive_global_external_interrupt_disable(struct metal_interru
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)
{
@@ -113,8 +157,13 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_global_external_interrupts0)
.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_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-buttons.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-buttons.c
index fbb6c92a7..923fe2711 100644
--- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-buttons.c
+++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-buttons.c
@@ -53,3 +53,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_button) = {
};
#endif
+
+typedef int no_empty_translation_units;
diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-leds.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-leds.c
index 68f72d5bd..a6b627458 100644
--- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-leds.c
+++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-leds.c
@@ -81,3 +81,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_led) = {
};
#endif
+
+typedef int no_empty_translation_units;
diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-switches.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-switches.c
index b9302529d..fa0a819f1 100644
--- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-switches.c
+++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-switches.c
@@ -52,3 +52,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_switch) = {
};
#endif
+
+typedef int no_empty_translation_units;
diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio0.c
index 55ff458bf..9ebbea03c 100644
--- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio0.c
+++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio0.c
@@ -9,6 +9,15 @@
#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);
@@ -18,6 +27,13 @@ int __metal_driver_sifive_gpio0_disable_input(struct metal_gpio *ggpio, long sou
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);
@@ -25,6 +41,16 @@ long __metal_driver_sifive_gpio0_output(struct metal_gpio *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);
@@ -72,14 +98,124 @@ int __metal_driver_sifive_gpio0_enable_io(struct metal_gpio *ggpio, long source,
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.output = __metal_driver_sifive_gpio0_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_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_FreedomStudio/freedom-metal/src/drivers/sifive_local-external-interrupts0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_local-external-interrupts0.c
index d205957ad..1c34ca447 100644
--- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_local-external-interrupts0.c
+++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_local-external-interrupts0.c
@@ -82,6 +82,33 @@ int __metal_driver_sifive_local_external_interrupt_disable(struct metal_interrup
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)
{
@@ -111,7 +138,14 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_local_external_interrupts0) =
.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_FreedomStudio/freedom-metal/src/drivers/sifive_rtc0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_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_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_FreedomStudio/freedom-metal/src/drivers/sifive_spi0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_spi0.c
index fd9bc5e91..2a346354f 100644
--- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_spi0.c
+++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_spi0.c
@@ -7,6 +7,7 @@
#include <metal/drivers/sifive_spi0.h>
#include <metal/io.h>
#include <metal/machine.h>
+#include <metal/time.h>
#include <time.h>
/* Register fields */
@@ -54,19 +55,25 @@ static int configure_spi(struct __metal_driver_sifive_spi0 *spi, struct metal_sp
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:
+ 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;
- break;
- case METAL_SPI_QUAD:
+ 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;
- break;
- default:
- /* Unsupported value */
- return -1;
+ else
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_SINGLE;
+ break;
+ default:
+ /* Unsupported value */
+ return -1;
}
/* Set Polarity */
@@ -107,7 +114,7 @@ static int configure_spi(struct __metal_driver_sifive_spi0 *spi, struct metal_sp
}
/* Set CS line */
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSID) = config->csid;
+ 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
@@ -121,6 +128,28 @@ static int configure_spi(struct __metal_driver_sifive_spi0 *spi, struct metal_sp
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,
@@ -130,6 +159,7 @@ int __metal_driver_sifive_spi0_transfer(struct metal_spi *gspi,
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) {
@@ -145,7 +175,97 @@ int __metal_driver_sifive_spi0_transfer(struct metal_spi *gspi,
/* Declare time_t variables to break out of infinite while loop */
time_t endwait;
- for(int i = 0; i < len; i++) {
+ 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 */
@@ -164,10 +284,10 @@ int __metal_driver_sifive_spi0_transfer(struct metal_spi *gspi,
/* 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 = time(NULL) + METAL_SPI_RXDATA_TIMEOUT;
+ endwait = metal_time() + METAL_SPI_RXDATA_TIMEOUT;
while ((rxdata = METAL_SPI_REGW(METAL_SIFIVE_SPI0_RXDATA)) & METAL_SPI_RXDATA_EMPTY) {
- if (time(NULL) > endwait) {
+ if (metal_time() > endwait) {
/* If timeout, deassert the CS */
METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSMODE) &= ~(METAL_SPI_CSMODE_MASK);
@@ -227,18 +347,19 @@ int __metal_driver_sifive_spi0_set_baud_rate(struct metal_spi *gspi, int baud_ra
return 0;
}
-static void pre_rate_change_callback(void *priv)
+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 zero and waiting until an interrupt is pending */
+ * 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(void *priv)
+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);
@@ -251,8 +372,13 @@ void __metal_driver_sifive_spi0_init(struct metal_spi *gspi, int baud_rate)
struct __metal_driver_sifive_gpio0 *pinmux = __metal_driver_sifive_spi0_pinmux(gspi);
if(clock != NULL) {
- metal_clock_register_pre_rate_change_callback(clock, &pre_rate_change_callback, spi);
- metal_clock_register_post_rate_change_callback(clock, &post_rate_change_callback, spi);
+ 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);
@@ -275,3 +401,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_spi0) = {
.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_FreedomStudio/freedom-metal/src/drivers/sifive_test0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_test0.c
index 4ef0aa861..79deebbf5 100644
--- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_test0.c
+++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_test0.c
@@ -5,15 +5,17 @@
#ifdef METAL_SIFIVE_TEST0
+#include <metal/machine.h>
+
+#include <stdint.h>
+
#include <metal/drivers/sifive_test0.h>
#include <metal/io.h>
-#include <stdint.h>
-#include <metal/machine.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();
+ 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;
@@ -24,3 +26,5 @@ __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_FreedomStudio/freedom-metal/src/drivers/sifive_trace.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_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_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_FreedomStudio/freedom-metal/src/drivers/sifive_uart0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_uart0.c
index 46971ec79..2e8098aa7 100644
--- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_uart0.c
+++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_uart0.c
@@ -38,27 +38,42 @@ 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_putc(struct metal_uart *uart, unsigned char c)
+
+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 ((UART_REGW(METAL_SIFIVE_UART0_TXDATA) & UART_TXFULL) != 0) { }
+ 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, unsigned char *c)
+
+int __metal_driver_sifive_uart0_getc(struct metal_uart *uart, int *c)
{
- uint32_t ch = UART_RXEMPTY;
+ uint32_t ch;
long control_base = __metal_driver_sifive_uart0_control_base(uart);
-
- while (ch & UART_RXEMPTY) {
- ch = UART_REGW(METAL_SIFIVE_UART0_RXDATA);
+ /* 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;
}
- *c = ch & 0xff;
return 0;
}
+
int __metal_driver_sifive_uart0_get_baud_rate(struct metal_uart *guart)
{
struct __metal_driver_sifive_uart0 *uart = (void *)guart;
@@ -82,7 +97,7 @@ int __metal_driver_sifive_uart0_set_baud_rate(struct metal_uart *guart, int baud
return 0;
}
-static void pre_rate_change_callback(void *priv)
+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);
@@ -105,10 +120,10 @@ static void pre_rate_change_callback(void *priv)
long cycles_to_wait = bits_per_symbol * clk_freq / uart->baud_rate;
for(volatile long x = 0; x < cycles_to_wait; x++)
- asm("nop");
+ __asm__("nop");
}
-static void post_rate_change_callback(void *priv)
+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);
@@ -121,8 +136,13 @@ void __metal_driver_sifive_uart0_init(struct metal_uart *guart, int baud_rate)
struct __metal_driver_sifive_gpio0 *pinmux = __metal_driver_sifive_uart0_pinmux(guart);
if(clock != NULL) {
- metal_clock_register_pre_rate_change_callback(clock, &pre_rate_change_callback, guart);
- metal_clock_register_post_rate_change_callback(clock, &post_rate_change_callback, guart);
+ 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);
@@ -149,3 +169,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_uart0) = {
};
#endif /* METAL_SIFIVE_UART0 */
+
+typedef int no_empty_translation_units;
diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_wdog0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_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_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;
+