diff --git a/bootloaders/miv-rv32-bootloader/src/application/bootloader/bootloader.c b/bootloaders/miv-rv32-bootloader/src/application/bootloader/bootloader.c index 30de29a..3f208a7 100644 --- a/bootloaders/miv-rv32-bootloader/src/application/bootloader/bootloader.c +++ b/bootloaders/miv-rv32-bootloader/src/application/bootloader/bootloader.c @@ -25,13 +25,6 @@ #define FLASH_BYTE_SIZE (FLASH_SECTOR_SIZE * FLASH_SECTORS) #define LAST_BLOCK_ADDR (FLASH_BYTE_SIZE - FLASH_BLOCK_SIZE) -#ifdef __UNUSED_CODE -static int test_flash(void); -static void mem_test(uint8_t *address); -static int read_program_from_flash(uint8_t *read_buf, uint32_t read_byte_length); -static void Bootloader_JumpToApplication(uint32_t stack_location, uint32_t reset_vector); -#endif - static int write_program_to_i2ceeprom(uint8_t *write_buf, uint32_t file_size); static int write_program_to_flash(uint8_t *write_buf, uint32_t file_size); static void copy_hex_to_i2ceeprom(void); @@ -590,340 +583,3 @@ static int write_program_to_flash(uint8_t *write_buf, uint32_t file_size) return(0); } - -#ifdef __UNUSED_CODE -/*-------------------------------------------------------------------------*//** - * Test flash on RTG4 - */ -static int test_flash(void) -{ - uint8_t write_buffer[FLASH_SEGMENT_SIZE]; - uint8_t read_buffer[FLASH_SEGMENT_SIZE]; - uint16_t status; - int flash_address = 0; - int count = 0; - spi_flash_status_t result; - struct device_Info DevInfo; - - spi_flash_control_hw( SPI_FLASH_RESET, 0, &status ); - - result = spi_flash_control_hw( SPI_FLASH_READ_DEVICE_ID, - count * FLASH_SECTOR_SIZE, - &DevInfo ); - - result = spi_flash_control_hw( SPI_FLASH_READ_DEVICE_ID, - count * FLASH_SECTOR_SIZE, - &DevInfo ); - - /*-------------------------------------------------------------------------- - * First fetch status register. First byte in low 8 bits, second byte in - * upper 8 bits. - */ - result = spi_flash_control_hw( SPI_FLASH_GET_STATUS, 0, &status ); - - result = spi_flash_control_hw( SPI_FLASH_READ_DEVICE_ID, - count * FLASH_SECTOR_SIZE, - &DevInfo ); - - /*-------------------------------------------------------------------------- - * Fetch protection register value for each of the 128 sectors. - * After power up these should all read as 0xFF - */ - for( count = 0; count != 128; ++count ) - { - result = spi_flash_control_hw( SPI_FLASH_GET_PROTECT, - count * FLASH_SECTOR_SIZE, - &read_buffer[count] ); - } - - //device D - result = spi_flash_control_hw( SPI_FLASH_READ_DEVICE_ID, - count * FLASH_SECTOR_SIZE, - &DevInfo ); - - /*-------------------------------------------------------------------------- - * Show sector protection in action by: - * - unprotecting the first sector - * - erasing the sector - * - writing some data to the first 256 bytes - * - protecting the first sector - * - erasing the first sector - * - reading back the first 256 bytes of the first sector - * - unprotecting the first sector - * - erasing the sector - * - reading back the first 256 bytes of the first sector - * - * The first read should still show the written data in place as the erase - * will fail. the second read should show all 0xFFs. Step through the code - * in debug mode and examine the read buffer after the read operations to - * see this. - */ - result = spi_flash_control_hw( SPI_FLASH_SECTOR_UNPROTECT, flash_address, NULL ); - //device D works - result = spi_flash_control_hw( SPI_FLASH_READ_DEVICE_ID, - count * FLASH_SECTOR_SIZE, - &DevInfo ); - result = spi_flash_control_hw( SPI_FLASH_4KBLOCK_ERASE, flash_address , NULL ); - //device D-- now working - result = spi_flash_control_hw( SPI_FLASH_READ_DEVICE_ID, - count * FLASH_SECTOR_SIZE, - &DevInfo ); - memset( write_buffer, count, FLASH_SEGMENT_SIZE ); - strcpy( (char *)write_buffer, "Microsemi FLASH test" ); - - spi_flash_write( flash_address, write_buffer, FLASH_SEGMENT_SIZE ); - //device D -- - result = spi_flash_control_hw( SPI_FLASH_READ_DEVICE_ID, - count * FLASH_SECTOR_SIZE, - &DevInfo ); - - result = spi_flash_control_hw( SPI_FLASH_SECTOR_PROTECT, flash_address, NULL ); - //device D - result = spi_flash_control_hw( SPI_FLASH_READ_DEVICE_ID, - count * FLASH_SECTOR_SIZE, - &DevInfo ); - result = spi_flash_control_hw( SPI_FLASH_4KBLOCK_ERASE, flash_address , NULL ); - //device D - result = spi_flash_control_hw( SPI_FLASH_READ_DEVICE_ID, - count * FLASH_SECTOR_SIZE, - &DevInfo ); - result = spi_flash_control_hw( SPI_FLASH_GET_STATUS, 0, &status ); - //device D - result = spi_flash_control_hw( SPI_FLASH_READ_DEVICE_ID, - count * FLASH_SECTOR_SIZE, - &DevInfo ); - - spi_flash_read ( flash_address, read_buffer, FLASH_SEGMENT_SIZE); - //device D - result = spi_flash_control_hw( SPI_FLASH_READ_DEVICE_ID, - count * FLASH_SECTOR_SIZE, - &DevInfo ); - - result = spi_flash_control_hw( SPI_FLASH_SECTOR_UNPROTECT, flash_address, NULL ); - //device D - result = spi_flash_control_hw( SPI_FLASH_READ_DEVICE_ID, - count * FLASH_SECTOR_SIZE, - &DevInfo ); - result = spi_flash_control_hw( SPI_FLASH_4KBLOCK_ERASE, flash_address , NULL ); - //device D - result = spi_flash_control_hw( SPI_FLASH_READ_DEVICE_ID, - count * FLASH_SECTOR_SIZE, - &DevInfo ); - result = spi_flash_control_hw( SPI_FLASH_GET_STATUS, 0, &status ); - //device D - result = spi_flash_control_hw( SPI_FLASH_READ_DEVICE_ID, - count * FLASH_SECTOR_SIZE, - &DevInfo ); - - result = spi_flash_control_hw( SPI_FLASH_SECTOR_UNPROTECT, flash_address, NULL ); - //device D - result = spi_flash_control_hw( SPI_FLASH_READ_DEVICE_ID, - count * FLASH_SECTOR_SIZE, - &DevInfo ); - result = spi_flash_control_hw( SPI_FLASH_4KBLOCK_ERASE, flash_address , NULL ); - //device D - result = spi_flash_control_hw( SPI_FLASH_READ_DEVICE_ID, - count * FLASH_SECTOR_SIZE, - &DevInfo ); - - spi_flash_read ( flash_address, read_buffer, FLASH_SEGMENT_SIZE ); - //device D - result = spi_flash_control_hw( SPI_FLASH_READ_DEVICE_ID, - count * FLASH_SECTOR_SIZE, - &DevInfo ); - /*-------------------------------------------------------------------------- - * Read the protection registers again so you can see that the first sector - * is unprotected now. - */ - for( count = 0; count != 128; ++count ) - { - spi_flash_control_hw( SPI_FLASH_GET_PROTECT, count * FLASH_SECTOR_SIZE, - &write_buffer[count] ); - } - //device D - result = spi_flash_control_hw( SPI_FLASH_READ_DEVICE_ID, - count * FLASH_SECTOR_SIZE, - &DevInfo ); - /*-------------------------------------------------------------------------- - * Write something to all 32768 blocks of 256 bytes in the 8MB FLASH. - */ - for( count = 0; count != 1000 /*32768*/; ++count ) - { - /*---------------------------------------------------------------------- - * Vary the fill for each chunk of 256 bytes - */ - memset( write_buffer, count, FLASH_SEGMENT_SIZE ); - strcpy( (char *)write_buffer, "Microsemi FLASH test" ); - /*---------------------------------------------------------------------- - * at the start of each sector we need to make sure it is unprotected - * so we can erase blocks within it. The spi_flash_write() function - * unprotects the sector as well but we need to start erasing before the - * first write takes place. - */ - if(0 == (flash_address % FLASH_SECTOR_SIZE)) - { - result = spi_flash_control_hw( SPI_FLASH_SECTOR_UNPROTECT, flash_address, NULL ); - } - /*---------------------------------------------------------------------- - * At the start of each 4K block we issue an erase so that we are then - * free to write anything we want to the block. If we don't do this the - * write may fail as we can only effectively turn 1s to 0s when we - * write. For example if we have an erased location with 0xFF in it and - * we write 0xAA to it first and then later on write 0x55, the resulting - * value is 0x00... - */ - if(0 == (flash_address % FLASH_BLOCK_SIZE)) - { - result = spi_flash_control_hw( SPI_FLASH_4KBLOCK_ERASE, flash_address , NULL ); - } - /*---------------------------------------------------------------------- - * Write our values to the FLASH, read them back and compare. - * Placing a breakpoint on the while statement below will allow - * you break on any failures. - */ - spi_flash_write( flash_address, write_buffer, FLASH_SEGMENT_SIZE ); - spi_flash_read ( flash_address, read_buffer, FLASH_SEGMENT_SIZE ); - if( memcmp( write_buffer, read_buffer, FLASH_SEGMENT_SIZE ) ) - { - while(1) // Breakpoint here will trap write faults - { - result = spi_flash_control_hw( SPI_FLASH_READ_DEVICE_ID, - count * FLASH_SECTOR_SIZE, - &DevInfo ); - spi_flash_control_hw( SPI_FLASH_RESET, 0, &status ); - - } - - } - - flash_address += FLASH_SEGMENT_SIZE; /* Step to the next 256 byte chunk */ - } - - /*-------------------------------------------------------------------------- - * One last look at the protection registers which should all be 0 now - */ - for( count = 0; count != 128; ++count ) - { - spi_flash_control_hw(SPI_FLASH_GET_PROTECT, - count * FLASH_SECTOR_SIZE, - &write_buffer[count]); - } - - UART_polled_tx_string( &g_uart, " Flash test success\r\n" ); - - return(0); -} - -/** - * Read from flash - */ -static int read_program_from_flash(uint8_t *read_buf, uint32_t read_byte_length) -{ - uint16_t status; - int flash_address = 0; - int count = 0; - uint32_t nb_segments_to_read; - spi_flash_status_t result; - struct device_Info DevInfo; - flash_content_t flash_content; - - UART_polled_tx_string( &g_uart, "\r\n------------------- Reading from SPI flash into DDR memory --------------------\r\n" ); - UART_polled_tx_string( &g_uart, "This will take several minutes to complete in order to read the full SPI flash \r\ncontent.\r\n" ); - - spi_flash_control_hw( SPI_FLASH_RESET, 0, &status ); - - result = spi_flash_control_hw(SPI_FLASH_READ_DEVICE_ID, - count * FLASH_SECTOR_SIZE, - &DevInfo); - - result = spi_flash_control_hw(SPI_FLASH_READ_DEVICE_ID, - count * FLASH_SECTOR_SIZE, - &DevInfo); - - /*-------------------------------------------------------------------------- - * First fetch status register. First byte in low 8 bits, second byte in - * upper 8 bits. - */ - result = spi_flash_control_hw(SPI_FLASH_GET_STATUS, 0, &status); - - result = spi_flash_control_hw(SPI_FLASH_READ_DEVICE_ID, - count * FLASH_SECTOR_SIZE, - &DevInfo); - - /*-------------------------------------------------------------------------- - * Retrieve the size of the data previously written to SPI flash. - */ - spi_flash_read ( LAST_BLOCK_ADDR, (uint8_t *)&flash_content, FLASH_SEGMENT_SIZE ); - - if(SPI_FLASH_VALID_CONTENT_KEY == flash_content.validity_key) - { - read_byte_length = flash_content.spi_content_byte_size; - } - else - { - read_byte_length = 0; - } - - /*-------------------------------------------------------------------------- - * Read from flash 256 bytes increments (FLASH_SEGMENT_SIZE). - */ - nb_segments_to_read = read_byte_length / FLASH_SEGMENT_SIZE; - if((read_byte_length % FLASH_SEGMENT_SIZE) > 0) - { - ++nb_segments_to_read; - } - - for( count = 0; count != nb_segments_to_read; ++count ) - { - /*---------------------------------------------------------------------- - * Write our values to the FLASH, read them back and compare. - * Placing a breakpoint on the while statement below will allow - * you break on any failures. - */ - - spi_flash_read ( flash_address, read_buf, FLASH_SEGMENT_SIZE ); - read_buf += FLASH_SEGMENT_SIZE; - - flash_address += FLASH_SEGMENT_SIZE; /* Step to the next 256 byte chunk */ - } - - UART_polled_tx_string( &g_uart, " Flash read success\r\n" ); - - return(0); -} - -/* - * Simple sanity check - */ -static void mem_test(uint8_t *address) -{ - volatile uint8_t value=2; - volatile uint32_t value32=3; - *address = 1; - value = *address; - value32 = (uint32_t)*address; - - if((value32 == value) &&(value == 1)) - UART_polled_tx_string( &g_uart, " Read/Write success\r\n" ); - else - UART_polled_tx_string( &g_uart, " Read/Write fail\r\n" ); -} - -/*------------------------------------------------------------------------------ - * Call this function if you want to switch to another program - * de-init any loaded drivers before calling this function - */ -//volatile uint32_t cj_debug; -static void Bootloader_JumpToApplication(uint32_t stack_location, uint32_t reset_vector) -{ - /* - * The bootstrap is going to copy the program from NV memory to the TCM. - * The TCM start address is 0x40000000. Jump to that address. - */ - __asm__ volatile ("fence.i"); - __asm__ volatile("lui ra,0x40000"); - __asm__ volatile("ret"); - /*User application execution should now start and never return here.... */ -} - -#endif /*__UNUSED_CODE*/ diff --git a/bootloaders/miv-rv32-bootloader/src/platform/hal/hal_assert.h b/bootloaders/miv-rv32-bootloader/src/platform/hal/hal_assert.h index 8e0c747..2b4c3fb 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/hal/hal_assert.h +++ b/bootloaders/miv-rv32-bootloader/src/platform/hal/hal_assert.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright 2019-2021 Microchip FPGA Embedded Systems Solutions. + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * diff --git a/bootloaders/miv-rv32-bootloader/src/platform/hal/hal_irq.c b/bootloaders/miv-rv32-bootloader/src/platform/hal/hal_irq.c index 6fe7fce..a799ca8 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/hal/hal_irq.c +++ b/bootloaders/miv-rv32-bootloader/src/platform/hal/hal_irq.c @@ -1,5 +1,5 @@ /***************************************************************************//** - * Copyright 2019-2021 Microchip FPGA Embedded Systems Solutions. + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * diff --git a/bootloaders/miv-rv32-bootloader/src/platform/hal/hw_macros.h b/bootloaders/miv-rv32-bootloader/src/platform/hal/hw_macros.h index ed2c681..95396ee 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/hal/hw_macros.h +++ b/bootloaders/miv-rv32-bootloader/src/platform/hal/hw_macros.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright 2019-2021 Microchip FPGA Embedded Systems Solutions. + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * diff --git a/bootloaders/miv-rv32-bootloader/src/platform/hal/hw_reg_access.S b/bootloaders/miv-rv32-bootloader/src/platform/hal/hw_reg_access.S index f4aa0a0..6d99e80 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/hal/hw_reg_access.S +++ b/bootloaders/miv-rv32-bootloader/src/platform/hal/hw_reg_access.S @@ -1,5 +1,5 @@ /***************************************************************************//** - * Copyright 2019-2021 Microchip FPGA Embedded Systems Solutions. + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * diff --git a/bootloaders/miv-rv32-bootloader/src/platform/hal/hw_reg_access.h b/bootloaders/miv-rv32-bootloader/src/platform/hal/hw_reg_access.h index 1f6a551..010e698 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/hal/hw_reg_access.h +++ b/bootloaders/miv-rv32-bootloader/src/platform/hal/hw_reg_access.h @@ -1,5 +1,5 @@ /***************************************************************************//** - * Copyright 2019-2021 Microchip FPGA Embedded Systems Solutions. + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * diff --git a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld index 19df5fb..bfb4698 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld +++ b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld @@ -36,7 +36,7 @@ MEMORY } STACK_SIZE = 1k; /* needs to be calculated for your application */ -HEAP_SIZE = 0; /* needs to be calculated for your application */ +HEAP_SIZE = 1k; /* needs to be calculated for your application */ SECTIONS { diff --git a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv-rv32-ram.ld b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv-rv32-ram.ld index e0707df..1aa2a82 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv-rv32-ram.ld +++ b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv-rv32-ram.ld @@ -34,7 +34,7 @@ MEMORY } STACK_SIZE = 2k; /* needs to be calculated for your application */ -HEAP_SIZE = 0k; /* needs to be calculated for your application */ +HEAP_SIZE = 1k; /* needs to be calculated for your application */ SECTIONS { diff --git a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_assert.h b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_assert.h new file mode 100644 index 0000000..b3912ed --- /dev/null +++ b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_assert.h @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * MIV_RV32 HAL Embedded Software + * + */ +#ifndef MIV_RV32_ASSERT_HEADER +#define MIV_RV32_ASSERT_HEADER + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + * ASSERT() implementation. + ******************************************************************************/ +/* Disable assertions if we do not recognize the compiler. */ +#if defined ( __GNUC__ ) +#if defined(NDEBUG) +#define ASSERT(CHECK) +#else +#define ASSERT(CHECK)\ + do { \ + if (!(CHECK)) \ + { \ + __asm__ volatile ("ebreak"); \ + }\ + } while(0); + +#endif /* NDEBUG check */ +#endif /* compiler check */ + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_RV32_ASSERT_HEADER */ + diff --git a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_entry.S b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_entry.S index a19a813..b16a86e 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_entry.S +++ b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_entry.S @@ -15,6 +15,8 @@ #define MTVEC_MODE_BIT_MASK 0x00000003u #define MTVEC_VECTORED_MODE_VAL 0x00000001u +#define MTIMEH_ADDR 0x200BFFCu + #if __riscv_xlen == 64 # define LREG ld # define SREG sd @@ -685,6 +687,12 @@ handle_reset: csrwi mie, 0 la ra, _start +/* Clearnig this to be on safer side as RTL doesnt seem to clear it on reset. */ +#ifndef MIV_LEGACY_RV32 + li t0, MTIMEH_ADDR + sw x0, 0(t0) +#endif + csrr t0, misa andi t0, t0, A_EXTENSION_MASK bnez t0, ima_cores_setup /* Jump to IMA core handling */ diff --git a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_hal.c b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_hal.c index 8fa82b1..2f73a63 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_hal.c +++ b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_hal.c @@ -29,12 +29,20 @@ extern "C" { sw a1, mtimecmp+4 # No smaller than new value. sw a0, mtimecmp # New value. */ +#ifndef MIV_RV32_EXT_TIMECMP #define WRITE_MTIMECMP(value) MTIMECMPH = MASK_32BIT; \ MTIMECMP = value & MASK_32BIT;\ MTIMECMPH = (value >> 32u) & MASK_32BIT; +#else +#define WRITE_MTIMECMP(value) +#endif +#ifndef MIV_RV32_EXT_TIMER #define WRITE_MTIME(value) MTIME = value & MASK_32BIT;\ MTIMEH = (value >> 32u) & MASK_32BIT; +#else +#define WRITE_MTIME(value) +#endif extern void Software_IRQHandler(void); @@ -132,13 +140,14 @@ extern void MSYS_EI4_IRQHandler(void); extern void MSYS_EI5_IRQHandler(void); extern void OPSRV_IRQHandler(void); -#endif +#endif /* MIV_LEGACY_RV32 */ /*------------------------------------------------------------------------------ * Increment value for the mtimecmp register in order to achieve a system tick * interrupt as specified through the MRV_systick_config() function. */ static uint64_t g_systick_increment = 0U; +static uint64_t g_systick_cmp_value = 0U; /*------------------------------------------------------------------------------ * Configure the machine timer to generate an interrupt. @@ -146,15 +155,19 @@ static uint64_t g_systick_increment = 0U; uint32_t MRV_systick_config(uint64_t ticks) { uint32_t ret_val = ERROR; + uint64_t remainder = ticks; + + while (remainder >= MTIME_PRESCALER) + { + remainder -= MTIME_PRESCALER; + g_systick_increment++; + } - g_systick_increment = (uint64_t)(ticks) / MTIME_PRESCALER; + g_systick_cmp_value = g_systick_increment + MTIME; if (g_systick_increment > 0U) { - -#ifndef MIV_RV32_EXT_TIMECMP - WRITE_MTIMECMP(MRV_read_mtime() + g_systick_increment) -#endif + WRITE_MTIMECMP(g_systick_cmp_value); set_csr(mie, MIP_MTIP); MRV_enable_interrupts(); @@ -169,10 +182,42 @@ uint32_t MRV_systick_config(uint64_t ticks) */ void handle_m_timer_interrupt(void) { -#ifndef MIV_RV32_EXT_TIMECMP - WRITE_MTIMECMP(MRV_read_mtime() + g_systick_increment) + clear_csr(mie, MIP_MTIP); + + uint64_t mtime_at_irq = MTIME; + +#ifndef NDEBUG + static volatile uint32_t d_tick = 0u; #endif + + while(g_systick_cmp_value < (mtime_at_irq + MTIME_DELTA)) { + g_systick_cmp_value = g_systick_cmp_value + g_systick_increment; + +#ifndef NDEBUG + d_tick += 1; +#endif + } + + /* + * Note: If d_tick > 1 it means, that a system timer interrupt has been missed. + * + * Please ensure that interrupt handlers are as short as possible to prevent + * them stopping other interrupts from being handled. For example, if a + * system timer interrupt occurs during a software interrupt, the system + * timer interrupt will not be handled until the software interrupt handling + * is complete. If the software interrupt handling time is more than one systick + * interval, it will result in d_tick > 1. + * + * If you are running the program using the debugger and halt the CPU at a breakpoint, + * MTIME will continue to increment and interrupts will be missed; resulting + * in d_tick > 1. + */ + + WRITE_MTIMECMP(g_systick_cmp_value); + SysTick_Handler(); + + set_csr(mie, MIP_MTIP); } /*------------------------------------------------------------------------------ @@ -197,7 +242,7 @@ void handle_m_ext_interrupt(void) } } } -#endif +#endif /* MIV_LEGACY_RV32 */ void handle_m_soft_interrupt(void) { @@ -263,7 +308,7 @@ void handle_trap(uintptr_t mcause, uintptr_t mepc) { MGECI_IRQHandler(); } -#endif +#endif /* MIV_LEGACY_RV32 */ else { @@ -318,7 +363,7 @@ void handle_trap(uintptr_t mcause, uintptr_t mepc) __asm__("ebreak"); #else _exit(1 + mcause); -#endif +#endif /* NDEBUG */ } } diff --git a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_hal.h b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_hal.h index 7231610..c4e071d 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_hal.h +++ b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_hal.h @@ -32,12 +32,13 @@ #include "miv_rv32_regs.h" #include "miv_rv32_plic.h" +#include "miv_rv32_assert.h" #ifndef LEGACY_DIR_STRUCTURE #include "fpga_design_config/fpga_design_config.h" #else #include "hw_platform.h" -#endif +#endif /*LEGACY_DIR_STRUCTURE*/ #ifdef __cplusplus extern "C" { @@ -66,21 +67,28 @@ void SysTick_Handler(void); * intervals. * Takes the number of system clock ticks between interrupts. * + * Though this function can take any valid ticks value as parameter, we expect + * that, for all practical purposes, a small tick value (to generate periodic + * interrupts every few miliseconds) will be passed. If you need to generate + * periodic events in the range of seconds or more, you may use the SysTick_Handler() + * to further count the number of interrupts and hence the larger time intervals. + * * Returns 0 if successful. * Returns 1 if the interrupt interval cannot be achieved. */ uint32_t MRV_systick_config(uint64_t ticks); +#define MTIME_DELTA 5 #ifdef MIV_LEGACY_RV32 -#define MSIP (*(uint32_t*)0x44000000UL) -#define MTIMECMP (*(uint32_t*)0x44004000UL) -#define MTIMECMPH (*(uint32_t*)0x44004004UL) -#define MTIME (*(uint32_t*)0x4400BFF8UL) -#define MTIMEH (*(uint32_t*)0x4400BFFCUL) +#define MSIP (*(uint32_t*)0x44000000UL) +#define MTIMECMP (*(uint32_t*)0x44004000UL) +#define MTIMECMPH (*(uint32_t*)0x44004004UL) +#define MTIME (*(uint32_t*)0x4400BFF8UL) +#define MTIMEH (*(uint32_t*)0x4400BFFCUL) /* To maintain backward compatibility with FreeRTOS config code */ -#define PRCI_BASE 0x44000000UL +#define PRCI_BASE 0x44000000UL #else @@ -113,10 +121,13 @@ typedef struct #define OPSRV ((OPSRV_Type *)OPSRV_BASE_ADDR) -#define EXT_INTR_SOURCES 1 - +#ifndef MIV_RV32_EXT_TIMECMP #define MTIMECMP (*(volatile uint32_t*)0x02004000UL) #define MTIMECMPH (*(volatile uint32_t*)0x02004004UL) +#else +#define MTIMECMP (0u) +#define MTIMECMPH (0u) +#endif /* On MIV_RV32IMC v2.0 and v2.1 MTIME_PRESCALER is not defined and using this * definition will result in crash. For those core use the definition as below @@ -128,8 +139,9 @@ typedef struct #define MTIME (*(volatile uint32_t*)0x0200BFF8UL) #define MTIMEH (*(volatile uint32_t*)0x0200BFFCUL) #else -#define MTIME HAL_ASSERT(0); -#endif +#define MTIME (0u) +#define MTIMEH (0u) +#endif /*MIV_RV32_EXT_TIMER*/ /* These definitions are provided for convenient identification of the interrupts * in the MIE/MIP registers. @@ -181,7 +193,7 @@ enum } MRV_LOCAL_IRQn_Type; -#ifndef MIV_LEGACY_RV32 + #define MRV32_MGEUIE_IRQn MIE_16_IRQn #define MRV32_MGECIE_IRQn MIE_17_IRQn #define MRV32_MSYS_EIE0_IRQn MIE_24_IRQn @@ -243,52 +255,7 @@ static inline uint32_t MRV32_is_gpr_ded(void) static inline void MRV32_clear_gpr_ded(void) { OPSRV->soft_reg &= ~0x04u; -} - -/***************************************************************************//** - * The function MRV32_enable_parity_check() is used to enable parity check on - * the TCM and it's interface transactions. This feature is not available on - * MIV_RV32 v3.0.100 soft processor core. - */ -static inline void MRV32_enable_parity_check(void) -{ - OPSRV->cfg |= 0x01u; -} -/***************************************************************************//** - * The function MRV32_disable_parity_check() is used to disable parity check on - * the TCM and it's interface transactions. - */ -static inline void MRV32_disable_parity_check(void) -{ - OPSRV->cfg &= ~0x01u; -} - -/***************************************************************************//** - * The function MRV32_cpu_soft_reset() is used to cause a soft cpu reset on - * the MIV_RV32 soft processor core. - */ -static inline void MRV32_cpu_soft_reset(void) -{ - OPSRV->soft_reg &= ~0x01u; -} - -/***************************************************************************//** - Clear GPR ECC Uncorrectable interrupt. MGEUI interrupt is available only when - ECC is enabled in MIV_RV32 IP configurator. - */ -static inline void MRV32_mgeui_clear_irq(uint32_t irq_mask) -{ - clear_csr(mip, MRV32_MGEUIE_IRQn); -} - -/***************************************************************************//** - Clear GPR ECC correctable interrupt. MGECI interrupt is available only when - ECC is enabled in MIV_RV32 IP configurator. - */ -static inline void MRV32_mgeci_clear_irq(uint32_t irq_mask) -{ - clear_csr(mip, MRV32_MGECIE_IRQn); } /***************************************************************************//** @@ -408,7 +375,51 @@ static inline void MRV32_clear_gpr_ecc_errors(void) :"m" (temp)); } -#endif +/***************************************************************************//** + * The function MRV32_enable_parity_check() is used to enable parity check on + * the TCM and it's interface transactions. This feature is not available on + * MIV_RV32 v3.0.100 soft processor core. + */ +static inline void MRV32_enable_parity_check(void) +{ + OPSRV->cfg |= 0x01u; +} + +/***************************************************************************//** + * The function MRV32_disable_parity_check() is used to disable parity check on + * the TCM and it's interface transactions. + */ +static inline void MRV32_disable_parity_check(void) +{ + OPSRV->cfg &= ~0x01u; +} + +/***************************************************************************//** + * The function MRV32_cpu_soft_reset() is used to cause a soft cpu reset on + * the MIV_RV32 soft processor core. + */ +static inline void MRV32_cpu_soft_reset(void) +{ + OPSRV->soft_reg &= ~0x01u; +} + +/***************************************************************************//** + Clear GPR ECC Uncorrectable interrupt. MGEUI interrupt is available only when + ECC is enabled in MIV_RV32 IP configurator. + */ +static inline void MRV32_mgeui_clear_irq(uint32_t irq_mask) +{ + clear_csr(mip, MRV32_MGEUIE_IRQn); +} + +/***************************************************************************//** + Clear GPR ECC correctable interrupt. MGECI interrupt is available only when + ECC is enabled in MIV_RV32 IP configurator. + */ +static inline void MRV32_mgeci_clear_irq(uint32_t irq_mask) +{ + clear_csr(mip, MRV32_MGECIE_IRQn); +} /***************************************************************************//** * Enable interrupts. @@ -441,7 +452,8 @@ static inline void MRV_disable_local_irq(uint32_t mask) { clear_csr(mie, mask); } -#endif + +#endif /* MIV_LEGACY_RV32 */ /***************************************************************************//** * The function MRV_raise_soft_irq() raises a synchronous software interrupt @@ -501,7 +513,6 @@ static inline uint64_t MRV_read_mtime(void) volatile uint32_t hi = 0u; volatile uint32_t lo = 0u; -#ifndef MIV_RV32_EXT_TIMER /* when mtime lower word is 0xFFFFFFFF, there will be rollover and * returned value could be wrong. */ do { @@ -510,7 +521,6 @@ static inline uint64_t MRV_read_mtime(void) } while(hi != MTIMEH); return((((uint64_t)MTIMEH) << 32u) | lo); -#endif } #ifdef __cplusplus diff --git a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_plic.h b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_plic.h index 19050cf..e3b1401 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_plic.h +++ b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_plic.h @@ -15,6 +15,7 @@ #define RISCV_PLIC_H #include +#include "miv_rv32_regs.h" #ifdef __cplusplus extern "C" { @@ -204,7 +205,7 @@ static inline void MRV_PLIC_clear_pending_irq(void) } } -#endif +#endif /* MIV_LEGACY_RV32 */ #ifdef __cplusplus } diff --git a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_regs.h b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_regs.h index 1837f42..9e21bd7 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_regs.h +++ b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_regs.h @@ -74,7 +74,8 @@ extern "C" { #define MSYS_EI5IP (1u << MSYS_EI5) #define MSYS_EXTERNAL_INT (0x3Fu << MSYS_EI0) #define MIP_OPSRV_REG (1u << OPSRV_REG) -#endif + +#endif /* MIV_LEGACY_RV32 */ #define PRV_M 3U diff --git a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_stubs.c b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_stubs.c index 7f5042b..a7a02d0 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_stubs.c +++ b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_stubs.c @@ -232,7 +232,7 @@ __attribute__((weak)) void MSYS_EI0_IRQHandler(void) { } -#endif +#endif /* MIV_LEGACY_RV32 */ #ifdef __cplusplus } diff --git a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_syscall.c b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_syscall.c index b24e729..98e0036 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_syscall.c +++ b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_syscall.c @@ -15,6 +15,7 @@ #include "miv_rv32_hal.h" #ifdef MSCC_STDIO_THRU_CORE_UART_APB +#include #ifndef LEGACY_DIR_STRUCTURE #include "drivers/fabric_ip/CoreUARTapb/core_uart_apb.h" @@ -119,17 +120,14 @@ char **environ = __env; void write_hex(int fd, uint32_t hex) { - uint8_t ii; - uint8_t jj; char towrite; - uint8_t digit; write( fd , "0x", 2U ); - for (ii = 8U ; ii > 0U; ii--) + for (uint32_t ii = 8U ; ii > 0U; ii--) { - jj = ii-1U; - digit = ((hex & (0xFU << (jj*4U))) >> (jj*4U)); + uint32_t jj = ii-1U; + uint8_t digit = ((hex & (0xFU << (jj*4U))) >> (jj*4U)); towrite = digit < 0xAU ? (0x48U + digit) : (0x65U + (digit - 0xAU)); write( fd, &towrite, 1U); } @@ -154,13 +152,23 @@ void _exit(int code) void *_sbrk(ptrdiff_t incr) { - extern char _end[]; - extern char _heap_end[]; - static char *curbrk = _end; + extern char _end; + extern char _heap_end; + extern char __heap_start; + extern char __heap_end; + static char *curbrk = &_end; void * ret = NULL; - if (((curbrk + incr) < _end) || ((curbrk + incr) > _heap_end)) + /* + * Did we allocated memory for the heap in the linker script? + * You need to set HEAP_SIZE to a non-zero value in your linker script if + * the following assertion fires. + */ + ASSERT(&__heap_end > &__heap_start); + + if (((curbrk + incr) < &_end) || ((curbrk + incr) > &_heap_end)) { + errno = ENOMEM; ret = ((char *) - 1); } else @@ -169,6 +177,13 @@ void *_sbrk(ptrdiff_t incr) ret = curbrk - incr; } + /* + * Did we run out of heap? + * You need to increase the heap size in the linker script if the following + * assertion fires. + * */ + ASSERT(curbrk <= &__heap_end); + return(ret); }