URL
https://opencores.org/ocsvn/neorv32/neorv32/trunk
Subversion Repositories neorv32
Compare Revisions
- This comparison shows the changes necessary to convert path
/neorv32/trunk/sw/lib/source
- from Rev 45 to Rev 47
- ↔ Reverse comparison
Rev 45 → Rev 47
/neorv32_cfu.c
File deleted
/neorv32_cfs.c
0,0 → 1,65
// ################################################################################################# |
// # << NEORV32: neorv32_cfs.c - Custom Functions Subsystem (CFS) HW Driver (stub) >> # |
// # ********************************************************************************************* # |
// # BSD 3-Clause License # |
// # # |
// # Copyright (c) 2021, Stephan Nolting. All rights reserved. # |
// # # |
// # Redistribution and use in source and binary forms, with or without modification, are # |
// # permitted provided that the following conditions are met: # |
// # # |
// # 1. Redistributions of source code must retain the above copyright notice, this list of # |
// # conditions and the following disclaimer. # |
// # # |
// # 2. Redistributions in binary form must reproduce the above copyright notice, this list of # |
// # conditions and the following disclaimer in the documentation and/or other materials # |
// # provided with the distribution. # |
// # # |
// # 3. Neither the name of the copyright holder nor the names of its contributors may be used to # |
// # endorse or promote products derived from this software without specific prior written # |
// # permission. # |
// # # |
// # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS # |
// # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # |
// # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # |
// # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # |
// # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # |
// # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED # |
// # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # |
// # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # |
// # OF THE POSSIBILITY OF SUCH DAMAGE. # |
// # ********************************************************************************************* # |
// # The NEORV32 Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting # |
// ################################################################################################# |
|
|
/**********************************************************************//** |
* @file neorv32_cfs.c |
* @author Stephan Nolting |
* @brief Custom Functions Subsystem (CFS) HW driver source file. |
* |
* @warning There are no "real" CFS driver functions available here, because these functions are defined by the actual hardware. |
* @warning Hence, the CFS designer has to provide the actual driver functions. |
* |
* @note These functions should only be used if the CFS was synthesized (IO_CFS_EN = true). |
**************************************************************************/ |
|
#include "neorv32.h" |
#include "neorv32_cfs.h" |
|
|
/**********************************************************************//** |
* Check if custom functions unit 0 was synthesized. |
* |
* @return 0 if CFS was not synthesized, 1 if CFS is available. |
**************************************************************************/ |
int neorv32_cfs_available(void) { |
|
if (SYSINFO_FEATURES & (1 << SYSINFO_FEATURES_IO_CFS)) { |
return 1; |
} |
else { |
return 0; |
} |
} |
|
/neorv32_cpu.c
47,11 → 47,31
/**********************************************************************//** |
* >Private< helper functions. |
**************************************************************************/ |
static int __neorv32_cpu_irq_id_check(uint8_t irq_sel); |
static uint32_t __neorv32_cpu_pmp_cfg_read(uint32_t index); |
static void __neorv32_cpu_pmp_cfg_write(uint32_t index, uint32_t data); |
|
|
/**********************************************************************//** |
* Private function: Check IRQ id. |
* |
* @param[in] irq_sel CPU interrupt select. See #NEORV32_CSR_MIE_enum. |
* @return 0 if success, 1 if error (invalid irq_sel). |
**************************************************************************/ |
static int __neorv32_cpu_irq_id_check(uint8_t irq_sel) { |
|
if ((irq_sel == CSR_MIE_MSIE) || (irq_sel == CSR_MIE_MTIE) || (irq_sel == CSR_MIE_MEIE) || |
(irq_sel == CSR_MIE_FIRQ0E) || (irq_sel == CSR_MIE_FIRQ1E) || (irq_sel == CSR_MIE_FIRQ2E) || (irq_sel == CSR_MIE_FIRQ3E) || |
(irq_sel == CSR_MIE_FIRQ4E) || (irq_sel == CSR_MIE_FIRQ5E) || (irq_sel == CSR_MIE_FIRQ6E) || (irq_sel == CSR_MIE_FIRQ7E)) { |
return 0; |
} |
else { |
return 1; |
} |
} |
|
|
/**********************************************************************//** |
* Enable specific CPU interrupt. |
* |
* @note Interrupts have to be globally enabled via neorv32_cpu_eint(void), too. |
61,8 → 81,8
**************************************************************************/ |
int neorv32_cpu_irq_enable(uint8_t irq_sel) { |
|
if ((irq_sel != CSR_MIE_MSIE) && (irq_sel != CSR_MIE_MTIE) && (irq_sel != CSR_MIE_MEIE) && |
(irq_sel != CSR_MIE_FIRQ0E) && (irq_sel != CSR_MIE_FIRQ1E) && (irq_sel != CSR_MIE_FIRQ2E) && (irq_sel != CSR_MIE_FIRQ3E)) { |
// check IRQ id |
if (__neorv32_cpu_irq_id_check(irq_sel)) { |
return 1; |
} |
|
80,8 → 100,8
**************************************************************************/ |
int neorv32_cpu_irq_disable(uint8_t irq_sel) { |
|
if ((irq_sel != CSR_MIE_MSIE) && (irq_sel != CSR_MIE_MTIE) && (irq_sel != CSR_MIE_MEIE) && |
(irq_sel != CSR_MIE_FIRQ0E) && (irq_sel != CSR_MIE_FIRQ1E) && (irq_sel != CSR_MIE_FIRQ2E) && (irq_sel != CSR_MIE_FIRQ3E)) { |
// check IRQ id |
if (__neorv32_cpu_irq_id_check(irq_sel)) { |
return 1; |
} |
|
/neorv32_rte.c
45,7 → 45,7
/**********************************************************************//** |
* The >private< trap vector look-up table of the NEORV32 RTE. |
**************************************************************************/ |
static uint32_t __neorv32_rte_vector_lut[17] __attribute__((unused)); // trap handler vector table |
static uint32_t __neorv32_rte_vector_lut[21] __attribute__((unused)); // trap handler vector table |
|
// private functions |
static void __attribute__((__interrupt__)) __neorv32_rte_core(void) __attribute__((aligned(16))) __attribute__((unused)); |
52,6 → 52,7
static void __neorv32_rte_debug_exc_handler(void) __attribute__((unused)); |
static void __neorv32_rte_print_true_false(int state) __attribute__((unused)); |
static void __neorv32_rte_print_hex_word(uint32_t num); |
static int __neorv32_rte_check_exc_id(uint32_t id); |
|
|
/**********************************************************************//** |
93,14 → 94,8
int neorv32_rte_exception_install(uint8_t id, void (*handler)(void)) { |
|
// id valid? |
if ((id == RTE_TRAP_I_MISALIGNED) || (id == RTE_TRAP_I_ACCESS) || (id == RTE_TRAP_I_ILLEGAL) || |
(id == RTE_TRAP_BREAKPOINT) || (id == RTE_TRAP_L_MISALIGNED) || (id == RTE_TRAP_L_ACCESS) || |
(id == RTE_TRAP_S_MISALIGNED) || (id == RTE_TRAP_S_ACCESS) || (id == RTE_TRAP_MENV_CALL) || (id == RTE_TRAP_UENV_CALL) || |
(id == RTE_TRAP_MSI) || (id == RTE_TRAP_MTI) || (id == RTE_TRAP_MEI) || |
(id == RTE_TRAP_FIRQ_0) || (id == RTE_TRAP_FIRQ_1) || (id == RTE_TRAP_FIRQ_2) || (id == RTE_TRAP_FIRQ_3)) { |
|
if (__neorv32_rte_check_exc_id(id) == 0) { |
__neorv32_rte_vector_lut[id] = (uint32_t)handler; // install handler |
|
return 0; |
} |
return 1; |
120,14 → 115,8
int neorv32_rte_exception_uninstall(uint8_t id) { |
|
// id valid? |
if ((id == RTE_TRAP_I_MISALIGNED) || (id == RTE_TRAP_I_ACCESS) || (id == RTE_TRAP_I_ILLEGAL) || |
(id == RTE_TRAP_BREAKPOINT) || (id == RTE_TRAP_L_MISALIGNED) || (id == RTE_TRAP_L_ACCESS) || |
(id == RTE_TRAP_S_MISALIGNED) || (id == RTE_TRAP_S_ACCESS) || (id == RTE_TRAP_MENV_CALL) || (id == RTE_TRAP_UENV_CALL) || |
(id == RTE_TRAP_MSI) || (id == RTE_TRAP_MTI) || (id == RTE_TRAP_MEI) || |
(id == RTE_TRAP_FIRQ_0) || (id == RTE_TRAP_FIRQ_1) || (id == RTE_TRAP_FIRQ_2) || (id == RTE_TRAP_FIRQ_3)) { |
|
if (__neorv32_rte_check_exc_id(id) == 0) { |
__neorv32_rte_vector_lut[id] = (uint32_t)(&__neorv32_rte_debug_exc_handler); // use dummy handler in case the exception is accidently triggered |
|
return 0; |
} |
return 1; |
186,6 → 175,10
case TRAP_CODE_FIRQ_1: rte_handler = __neorv32_rte_vector_lut[RTE_TRAP_FIRQ_1]; break; |
case TRAP_CODE_FIRQ_2: rte_handler = __neorv32_rte_vector_lut[RTE_TRAP_FIRQ_2]; break; |
case TRAP_CODE_FIRQ_3: rte_handler = __neorv32_rte_vector_lut[RTE_TRAP_FIRQ_3]; break; |
case TRAP_CODE_FIRQ_4: rte_handler = __neorv32_rte_vector_lut[RTE_TRAP_FIRQ_4]; break; |
case TRAP_CODE_FIRQ_5: rte_handler = __neorv32_rte_vector_lut[RTE_TRAP_FIRQ_5]; break; |
case TRAP_CODE_FIRQ_6: rte_handler = __neorv32_rte_vector_lut[RTE_TRAP_FIRQ_6]; break; |
case TRAP_CODE_FIRQ_7: rte_handler = __neorv32_rte_vector_lut[RTE_TRAP_FIRQ_7]; break; |
default: break; |
} |
|
221,10 → 214,14
case TRAP_CODE_MSI: neorv32_uart_print("Machine software interrupt"); break; |
case TRAP_CODE_MTI: neorv32_uart_print("Machine timer interrupt"); break; |
case TRAP_CODE_MEI: neorv32_uart_print("Machine external interrupt"); break; |
case TRAP_CODE_FIRQ_0: neorv32_uart_print("Fast interrupt 0"); break; |
case TRAP_CODE_FIRQ_1: neorv32_uart_print("Fast interrupt 1"); break; |
case TRAP_CODE_FIRQ_2: neorv32_uart_print("Fast interrupt 2"); break; |
case TRAP_CODE_FIRQ_3: neorv32_uart_print("Fast interrupt 3"); break; |
case TRAP_CODE_FIRQ_0: |
case TRAP_CODE_FIRQ_1: |
case TRAP_CODE_FIRQ_2: |
case TRAP_CODE_FIRQ_3: |
case TRAP_CODE_FIRQ_4: |
case TRAP_CODE_FIRQ_5: |
case TRAP_CODE_FIRQ_6: |
case TRAP_CODE_FIRQ_7: neorv32_uart_print("Fast interrupt "); neorv32_uart_putc((char)('0' + (trap_cause & 0x7))); break; |
default: neorv32_uart_print("Unknown trap cause: "); __neorv32_rte_print_hex_word(trap_cause); break; |
} |
|
431,11 → 428,8
neorv32_uart_printf("TRNG - "); |
__neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_TRNG)); |
|
neorv32_uart_printf("CFU0 - "); |
__neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_CFU0)); |
|
neorv32_uart_printf("CFU1 - "); |
__neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_CFU1)); |
neorv32_uart_printf("CFS - "); |
__neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_CFS)); |
} |
|
|
476,7 → 470,31
} |
|
|
/**********************************************************************//** |
* NEORV32 runtime environment: Private function to check exception id |
* as 8-digit hexadecimal value (with "0x" suffix). |
* |
* @param[in] id Exception id (#NEORV32_RTE_TRAP_enum). |
* @return Return 0 if id is valid |
**************************************************************************/ |
static int __neorv32_rte_check_exc_id(uint32_t id) { |
|
// id valid? |
if ((id == RTE_TRAP_I_MISALIGNED) || (id == RTE_TRAP_I_ACCESS) || (id == RTE_TRAP_I_ILLEGAL) || |
(id == RTE_TRAP_BREAKPOINT) || (id == RTE_TRAP_L_MISALIGNED) || (id == RTE_TRAP_L_ACCESS) || |
(id == RTE_TRAP_S_MISALIGNED) || (id == RTE_TRAP_S_ACCESS) || (id == RTE_TRAP_MENV_CALL) || (id == RTE_TRAP_UENV_CALL) || |
(id == RTE_TRAP_MSI) || (id == RTE_TRAP_MTI) || (id == RTE_TRAP_MEI) || |
(id == RTE_TRAP_FIRQ_0) || (id == RTE_TRAP_FIRQ_1) || (id == RTE_TRAP_FIRQ_2) || (id == RTE_TRAP_FIRQ_3) || |
(id == RTE_TRAP_FIRQ_4) || (id == RTE_TRAP_FIRQ_5) || (id == RTE_TRAP_FIRQ_6) || (id == RTE_TRAP_FIRQ_7)) { |
return 0; |
} |
else { |
return 1; |
} |
} |
|
|
|
/**********************************************************************//** |
* NEORV32 runtime environment: Print the processor version in human-readable format. |
**************************************************************************/ |
547,12 → 565,13
for (v=0; v<4; v++) { |
tmp = logo_data_c[u][v]; |
for (w=0; w<32; w++){ |
if (tmp & (1 << (31-w))) { |
if (tmp & 0x80000000UL) { // check MSB |
neorv32_uart_putc('#'); |
} |
else { |
neorv32_uart_putc(' '); |
} |
tmp <<= 1; |
} |
} |
} |
/neorv32_trng.c
70,13 → 70,13
|
TRNG_CT = 0; // reset |
|
for (i=0; i<1000; i++) { |
for (i=0; i<256; i++) { |
asm volatile ("nop"); |
} |
|
TRNG_CT = 1 << TRNG_CT_EN; // activate |
|
for (i=0; i<1000; i++) { |
for (i=0; i<256; i++) { |
asm volatile ("nop"); |
} |
} |
87,37 → 87,32
**************************************************************************/ |
void neorv32_trng_disable(void) { |
|
TRNG_CT &= ~((uint32_t)(1 << TRNG_CT_EN)); |
TRNG_CT = 0; |
} |
|
|
/**********************************************************************//** |
* Get random data from TRNG. |
* Get random data byte from TRNG. |
* |
* @note The TRNG is automatically reset if a stuck-at-one/stuck-at-zero error is detected. |
* |
* @param[in,out] data uint8_t pointer for storing random data word |
* @return Data is valid when 0, stuck-at-zero error when 1, stuck-at-one error when 2, data not (yet) valid when 3 |
* @param[in,out] data uint8_t pointer for storing random data byte. |
* @return Data is valid when 0 and invalid otherwise. |
**************************************************************************/ |
int neorv32_trng_get(uint8_t *data) { |
|
uint32_t trng_ct_reg = TRNG_CT; |
const int retries = 3; |
int i; |
uint32_t ct_reg; |
|
if (trng_ct_reg & (1<<TRNG_CT_ERROR_0)) { // stuck at zero error |
neorv32_trng_enable(); // reset TRNG |
return 1; |
} |
for (i=0; i<retries; i++) { |
ct_reg = TRNG_CT; |
|
if (trng_ct_reg & (1<<TRNG_CT_ERROR_1)) { // stuck at one error |
neorv32_trng_enable(); // reset TRNG |
return 2; |
} |
if ((ct_reg & (1<<TRNG_CT_VALID)) == 0) { // output data valid? |
continue; |
} |
|
if ((trng_ct_reg & (1<<TRNG_CT_VALID)) == 0) { // output data valid (yet)? |
return 3; |
*data = (uint8_t)(ct_reg >> TRNG_CT_DATA_LSB); |
return 0; // valid data |
} |
|
*data = (uint8_t)(trng_ct_reg >> TRNG_CT_DATA_LSB); |
return 0; // valid data |
return -1; // no valid data available |
} |
|
/neorv32_uart.c
71,9 → 71,11
/**********************************************************************//** |
* Enable and configure UART. |
* |
* @warning The 'UART_SIM_MODE' compiler flag will configure UART for simulation mode: all UART TX data will be redirected to simulation output. Use this for simulations only! |
* @warning To enable simulation mode add <USER_FLAGS+=-DUART_SIM_MODE> when compiling. |
* @note The 'UART_SIM_MODE' compiler flag will configure UART for simulation mode: all UART TX data will be redirected to simulation output. Use this for simulations only! |
* @note To enable simulation mode add <USER_FLAGS+=-DUART_SIM_MODE> when compiling. |
* |
* @warning The baud rate is computed using INTEGER operations (truncation errors might occur). |
* |
* @param[in] baudrate Targeted BAUD rate (e.g. 9600). |
* @param[in] parity PArity configuration (00=off, 10=even, 11=odd). |
* @param[in] rx_irq Enable RX interrupt (data received) when 1. |
99,7 → 101,7
} |
#endif |
|
// find clock prsc |
// find baud prescaler (12-bit wide)) |
while (i >= 0x0fff) { |
if ((p == 2) || (p == 4)) |
i >>= 3; |
108,11 → 110,12
p++; |
} |
|
uint32_t prsc = (uint32_t)p; |
prsc = prsc << UART_CT_PRSC0; |
uint32_t clk_prsc = (uint32_t)p; |
clk_prsc = clk_prsc << UART_CT_PRSC0; |
|
uint32_t baud = (uint32_t)i; |
baud = baud << UART_CT_BAUD00; |
uint32_t baud_prsc = (uint32_t)i; |
baud_prsc = baud_prsc - 1; |
baud_prsc = baud_prsc << UART_CT_BAUD00; |
|
uint32_t uart_en = 1; |
uart_en = uart_en << UART_CT_EN; |
135,7 → 138,7
uint32_t sim_mode = 0; |
#endif |
|
UART_CT = prsc | baud | uart_en | parity_config | rx_irq_en | tx_irq_en | sim_mode; |
UART_CT = clk_prsc | baud_prsc | uart_en | parity_config | rx_irq_en | tx_irq_en | sim_mode; |
} |
|
|
/neorv32_wdt.c
62,34 → 62,48
|
|
/**********************************************************************//** |
* Enable and configure watchdog timer. The WDT control register bits are listed in #NEORV32_WDT_CT_enum. |
* Configure and enable watchdog timer. The WDT control register bits are listed in #NEORV32_WDT_CT_enum. |
* |
* @param[in] clk_prsc Clock prescaler to selet timeout interval. See #NEORV32_CLOCK_PRSC_enum. |
* @param[in] timeout_mode Trigger system reset on timeout when 1, trigger interrupt on timeout when 0. |
* @param[in] prsc Clock prescaler to selet timeout interval. See #NEORV32_CLOCK_PRSC_enum. |
* @param[in] mode Trigger system reset on timeout when 1, trigger interrupt on timeout when 0. |
* @param[in] lock Control register will be locked when 1 (unitl next reset). |
**************************************************************************/ |
void neorv32_wdt_setup(uint8_t clk_prsc, uint8_t timeout_mode) { |
void neorv32_wdt_setup(uint8_t prsc, uint8_t mode, uint8_t lock) { |
|
uint32_t prsc = (uint32_t)(clk_prsc & 0x07); |
prsc = prsc << WDT_CT_CLK_SEL0; |
WDT_CT = (1 << WDT_CT_RESET); // reset WDT counter |
|
uint32_t mode = (uint32_t)(timeout_mode & 0x01); |
mode = mode << WDT_CT_MODE; |
uint32_t prsc_int = (uint32_t)(prsc & 0x07); |
prsc_int = prsc_int << WDT_CT_CLK_SEL0; |
|
uint32_t password = (uint32_t)(WDT_PASSWORD); |
password = password << WDT_CT_PASSWORD_LSB; |
uint32_t mode_int = (uint32_t)(mode & 0x01); |
mode_int = mode_int << WDT_CT_MODE; |
|
uint32_t enable = (uint32_t)(1 << WDT_CT_EN); |
uint32_t lock_int = (uint32_t)(lock & 0x01); |
lock_int = lock_int << WDT_CT_LOCK; |
|
WDT_CT = password | enable | mode | prsc; |
const uint32_t enable = (uint32_t)(1 << WDT_CT_EN); |
|
// update WDT control register |
WDT_CT = enable | mode_int | prsc_int | lock_int; |
} |
|
|
/**********************************************************************//** |
* Disable watchdog timer. |
* |
* @return Returns 0 if WDT is really deativated, -1 otherwise. |
**************************************************************************/ |
void neorv32_wdt_disable(void) { |
int neorv32_wdt_disable(void) { |
|
WDT_CT = 0; |
|
WDT_CT = ((uint32_t)(WDT_PASSWORD << WDT_CT_PASSWORD_LSB)) | ((uint32_t)(0 << WDT_CT_EN)); |
// check if wdt is really off |
if (WDT_CT & (1 << WDT_CT_EN)) { |
return -1; // WDT still active |
} |
else { |
return 0; |
} |
} |
|
|
98,38 → 112,30
**************************************************************************/ |
void neorv32_wdt_reset(void) { |
|
WDT_CT = WDT_CT | ((uint32_t)(WDT_PASSWORD << WDT_CT_PASSWORD_LSB)); |
WDT_CT = (1 << WDT_CT_RESET); |
} |
|
|
/**********************************************************************//** |
* Get cause of last watchdog action. |
* Get cause of last system reset. |
* |
* @return Cause of last reset/IRQ (0: undefined, 1: external reset, 2: watchdog timeout, 3: watchdog access error (wrong password)). |
* @return Cause of last reset/IRQ (0: external reset, 1: watchdog timeout). |
**************************************************************************/ |
uint8_t neorv32_wdt_get_cause(void) { |
int neorv32_wdt_get_cause(void) { |
|
uint8_t cause = 0; |
uint32_t ctrl = WDT_CT; |
if (ctrl & (1 << WDT_CT_CAUSE)) { // reset/IRQ casued by watchdog |
if (ctrl & (1 << WDT_CT_PWFAIL)) { // reset/IRQ due to wrong password |
cause = 3; |
} |
else { // reset/IRQ due to timeout |
cause = 2; |
} |
if (WDT_CT & (1 << WDT_CT_RCAUSE)) { // reset caused by watchdog |
return 1; |
} |
else { // external reset |
cause = 1; |
return 0; |
} |
return cause; |
} |
|
|
/**********************************************************************//** |
* Force watchdog action (reset/IRQ) via wrong-password access. |
* Force immediate watchdog action (reset/IRQ). |
**************************************************************************/ |
void neorv32_wdt_force(void) { |
|
WDT_CT = 0; // invalid access |
WDT_CT = WDT_CT | (1 << WDT_CT_FORCE); |
} |