From c1f9fa0d98d57716a3f9c24b71461bf46355ad61 Mon Sep 17 00:00:00 2001 From: Conor Paxton Date: Tue, 18 Oct 2022 17:31:52 +0100 Subject: [PATCH] Squashed 'driver-examples/miv-udma/' content from commit 40555a8 git-subtree-dir: driver-examples/miv-udma git-subtree-split: 40555a80dd53f26fe83014cfad42ab3e6f5f694d --- Jenkinsfile | 2 + miv-rv32-udma/.cproject | 622 +++++++++++++ miv-rv32-udma/.gitignore | 7 + miv-rv32-udma/.project | 26 + miv-rv32-udma/README.md | 58 ++ miv-rv32-udma/miv-rv32-udma hw attach.launch | 59 ++ miv-rv32-udma/miv-rv32-udma hw debug.launch | 61 ++ miv-rv32-udma/src/application/main.c | 163 ++++ .../fpga_design/design_description/README.md | 2 + .../fpga_design_config/fpga_design_config.h | 151 ++++ .../linker/miv-rv32-execute-in-place.ld | 154 ++++ .../platform_config/linker/miv-rv32-ram.ld | 150 ++++ .../miv_rv32_hal_config/readme.md | 2 + miv-rv32-udma/src/middleware/README.md | 1 + .../drivers/fpga_ip/CoreGPIO/core_gpio.c | 531 +++++++++++ .../drivers/fpga_ip/CoreGPIO/core_gpio.h | 654 ++++++++++++++ .../drivers/fpga_ip/CoreGPIO/coregpio_regs.h | 43 + .../fpga_ip/CoreUARTapb/core_uart_apb.c | 295 +++++++ .../fpga_ip/CoreUARTapb/core_uart_apb.h | 432 +++++++++ .../fpga_ip/CoreUARTapb/coreuartapb_regs.h | 131 +++ .../drivers/fpga_ip/miv_udma/miv_udma.c | 107 +++ .../drivers/fpga_ip/miv_udma/miv_udma.h | 289 ++++++ .../drivers/fpga_ip/miv_udma/miv_udma_regs.h | 94 ++ miv-rv32-udma/src/platform/hal/cpu_types.h | 41 + miv-rv32-udma/src/platform/hal/hal.h | 235 +++++ miv-rv32-udma/src/platform/hal/hal_assert.h | 48 + miv-rv32-udma/src/platform/hal/hal_irq.c | 45 + miv-rv32-udma/src/platform/hal/hw_macros.h | 106 +++ .../src/platform/hal/hw_reg_access.S | 215 +++++ .../src/platform/hal/hw_reg_access.h | 239 +++++ miv-rv32-udma/src/platform/hal/readme.md | 38 + .../miv_rv32_hal/miv-rv32-execute-in-place.ld | 154 ++++ .../src/platform/miv_rv32_hal/miv-rv32-ram.ld | 150 ++++ .../platform/miv_rv32_hal/miv_rv32_entry.S | 821 ++++++++++++++++++ .../src/platform/miv_rv32_hal/miv_rv32_hal.c | 327 +++++++ .../src/platform/miv_rv32_hal/miv_rv32_hal.h | 521 +++++++++++ .../src/platform/miv_rv32_hal/miv_rv32_init.c | 39 + .../src/platform/miv_rv32_hal/miv_rv32_plic.h | 213 +++++ .../src/platform/miv_rv32_hal/miv_rv32_regs.h | 543 ++++++++++++ .../platform/miv_rv32_hal/miv_rv32_stubs.c | 239 +++++ .../platform/miv_rv32_hal/miv_rv32_syscall.c | 349 ++++++++ .../miv_rv32_hal/sample_fpga_design_config.h | 167 ++++ .../linker/miv-rv32-execute-in-place.ld | 154 ++++ .../linker/miv-rv32-ram.ld | 150 ++++ .../linker/readme.md | 2 + .../miv_rv32_hal_config/readme.md | 2 + 46 files changed, 8832 insertions(+) create mode 100644 Jenkinsfile create mode 100644 miv-rv32-udma/.cproject create mode 100644 miv-rv32-udma/.gitignore create mode 100644 miv-rv32-udma/.project create mode 100644 miv-rv32-udma/README.md create mode 100644 miv-rv32-udma/miv-rv32-udma hw attach.launch create mode 100644 miv-rv32-udma/miv-rv32-udma hw debug.launch create mode 100644 miv-rv32-udma/src/application/main.c create mode 100644 miv-rv32-udma/src/boards/polarfire-eval-kit/fpga_design/design_description/README.md create mode 100644 miv-rv32-udma/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h create mode 100644 miv-rv32-udma/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-execute-in-place.ld create mode 100644 miv-rv32-udma/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld create mode 100644 miv-rv32-udma/src/boards/polarfire-eval-kit/platform_config/miv_rv32_hal_config/readme.md create mode 100644 miv-rv32-udma/src/middleware/README.md create mode 100644 miv-rv32-udma/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c create mode 100644 miv-rv32-udma/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h create mode 100644 miv-rv32-udma/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h create mode 100644 miv-rv32-udma/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c create mode 100644 miv-rv32-udma/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h create mode 100644 miv-rv32-udma/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h create mode 100644 miv-rv32-udma/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c create mode 100644 miv-rv32-udma/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h create mode 100644 miv-rv32-udma/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h create mode 100644 miv-rv32-udma/src/platform/hal/cpu_types.h create mode 100644 miv-rv32-udma/src/platform/hal/hal.h create mode 100644 miv-rv32-udma/src/platform/hal/hal_assert.h create mode 100644 miv-rv32-udma/src/platform/hal/hal_irq.c create mode 100644 miv-rv32-udma/src/platform/hal/hw_macros.h create mode 100644 miv-rv32-udma/src/platform/hal/hw_reg_access.S create mode 100644 miv-rv32-udma/src/platform/hal/hw_reg_access.h create mode 100644 miv-rv32-udma/src/platform/hal/readme.md create mode 100644 miv-rv32-udma/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld create mode 100644 miv-rv32-udma/src/platform/miv_rv32_hal/miv-rv32-ram.ld create mode 100644 miv-rv32-udma/src/platform/miv_rv32_hal/miv_rv32_entry.S create mode 100644 miv-rv32-udma/src/platform/miv_rv32_hal/miv_rv32_hal.c create mode 100644 miv-rv32-udma/src/platform/miv_rv32_hal/miv_rv32_hal.h create mode 100644 miv-rv32-udma/src/platform/miv_rv32_hal/miv_rv32_init.c create mode 100644 miv-rv32-udma/src/platform/miv_rv32_hal/miv_rv32_plic.h create mode 100644 miv-rv32-udma/src/platform/miv_rv32_hal/miv_rv32_regs.h create mode 100644 miv-rv32-udma/src/platform/miv_rv32_hal/miv_rv32_stubs.c create mode 100644 miv-rv32-udma/src/platform/miv_rv32_hal/miv_rv32_syscall.c create mode 100644 miv-rv32-udma/src/platform/miv_rv32_hal/sample_fpga_design_config.h create mode 100644 miv-rv32-udma/src/platform/platform_config_reference/linker/miv-rv32-execute-in-place.ld create mode 100644 miv-rv32-udma/src/platform/platform_config_reference/linker/miv-rv32-ram.ld create mode 100644 miv-rv32-udma/src/platform/platform_config_reference/linker/readme.md create mode 100644 miv-rv32-udma/src/platform/platform_config_reference/miv_rv32_hal_config/readme.md diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..a078858 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,2 @@ +@Library('automated-testing-library') _ +pipelineSoftIPExamples() diff --git a/miv-rv32-udma/.cproject b/miv-rv32-udma/.cproject new file mode 100644 index 0000000..015c247 --- /dev/null +++ b/miv-rv32-udma/.cproject @@ -0,0 +1,622 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/miv-rv32-udma/.gitignore b/miv-rv32-udma/.gitignore new file mode 100644 index 0000000..f8ed8bd --- /dev/null +++ b/miv-rv32-udma/.gitignore @@ -0,0 +1,7 @@ +/*Debug*/ +/*Release*/ +/.settings*/ +/miv-rv32i-debug/ +/miv-rv32-imc-debug/ +/miv-rv32-imc-release/ +/miv-rv32i-release/ diff --git a/miv-rv32-udma/.project b/miv-rv32-udma/.project new file mode 100644 index 0000000..0a46e7c --- /dev/null +++ b/miv-rv32-udma/.project @@ -0,0 +1,26 @@ + + + miv-rv32-udma + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/miv-rv32-udma/README.md b/miv-rv32-udma/README.md new file mode 100644 index 0000000..e4351d3 --- /dev/null +++ b/miv-rv32-udma/README.md @@ -0,0 +1,58 @@ +# MIV uDMA Example + +This project demonstrates the Mi-V Soft IP uDMA module functionality, which is delivered as a +part of MIV Extended Sub System(MIV_ESS). +This project sets up the data transfer between two memory blocks, based on the +configuration the uDMA controller will generate the interrupt for error or +success of the transfer. +The uDMA IRQ from the MIV_ESS can be connected to +any of the external interrupt pins on the MIV_RV32, so the application +developer should perform the interrupt handling in respective interrupt handler. + + +There are 2 different build configurations provided with this project which configure +this SoftConsole project for RISC-V IMC instruction extension. +The Following configurations are provided with the example. + - miv32imc-Debug + - miv32imc-Release + + To use this project, configure the COM port interface as below: + - 115200 baud + - 8 data bits + - 1 stop bit + - no parity + - no flow control + +## fpga_design_config (formerly known as hw_config.h) +The SoftConsole project targeted for Mi-V processors now use an improved +directory structure. Detailed description of the folder structure is available +at https://github.com/Mi-V-Soft-RISC-V/miv-rv32-documentation. +The fpga_design_config.h must be stored as shown below + +` + /boards//fpga_design_config/fpga_design_config.h +` + +Currently, this file must be hand crafted when using the Mi-V Soft Processor. +In future, all the design and soft IP configurations will be automatically +generated from the Libero design description data. + +You can use the sample file provided with MIV_RV32 HAL as an example. +Rename it from sample_fpga_design_config.h to fpga_design_config.h and then +customize it per your hardware design such as SYS_CLK_FREQ, peripheral +BASE addresses, interrupt numbers, definition of MSCC_STDIO_UART_BASE_ADDR if +you want a CoreUARTapb mapped to STDIO, etc. + +## Linker script changes + +You must make sure that in addition to the reset vector, all other memory address +configurations in the Mi-V soft processor match with the memory layout defined +in the linker script. + +## Target hardware +This project is tested on PolarFire Eval Kit MIV_RV32 IMC Core. +Libero example/job URL here: +https://mi-v-soft-risc-v.github.io/PolarFire-Eval-Kit/ + +## Mi-V soft processor revision dependencies +This project is tested with MIV_RV32 v3.0 diff --git a/miv-rv32-udma/miv-rv32-udma hw attach.launch b/miv-rv32-udma/miv-rv32-udma hw attach.launch new file mode 100644 index 0000000..e0f8c6c --- /dev/null +++ b/miv-rv32-udma/miv-rv32-udma hw attach.launch @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/miv-rv32-udma/miv-rv32-udma hw debug.launch b/miv-rv32-udma/miv-rv32-udma hw debug.launch new file mode 100644 index 0000000..52e8bb3 --- /dev/null +++ b/miv-rv32-udma/miv-rv32-udma hw debug.launch @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/miv-rv32-udma/src/application/main.c b/miv-rv32-udma/src/application/main.c new file mode 100644 index 0000000..2797825 --- /dev/null +++ b/miv-rv32-udma/src/application/main.c @@ -0,0 +1,163 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * MIV uDMA Example project + * + * This project will demonstrate the use of MIV uDMA Bare-metal software driver. + * A 32-bit data is written into the source address and the uDMA controller + * will copy the data from src_addr to dest_addr. + * A verify function will check if the correct data is read or not, and based + * on the response, UART messages will be printed. + * + * Please refer README.md in the root folder of this project for more details. + */ + +#include +#include "miv_rv32_hal/miv_rv32_hal.h" +#include "fpga_design_config/fpga_design_config.h" +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" +#include "drivers/fpga_ip/miv_udma/miv_udma.h" + +/****************************************************************************** + * Peripheral instance data. + *****************************************************************************/ +UART_instance_t g_uart; + +miv_udma_instance_t g_miv_ess_udma; + +/* Local function to verify the uDMA transaction */ +static uint8_t +verify_write +( + uint32_t* write_buff, + uint32_t* read_buff, + uint16_t size +); + +/* + * Local Constants to hold the source and destination address + * Application developer should update these values as per requirements. + */ +#define MIV_UDMA_TRANSFER_SRC_ADDR 0x89000000u +#define MIV_UDMA_TRANSFER_DEST_ADDR 0x8A000000u + +/*============================================================================== + * Messages displayed over the UART. + */ +const uint8_t g_greeting_msg[] = +"\r\n\r\n\t\t **** PolarFire MiV uDMA Example ****\n\n\n\r\ +This application will demonstrate the use of MIV uDMA bare-metal driver.\r\n\n\ +It will copy the data from MIV_UDMA_TRANSFER_SRC_ADDR to MIV_UDMA_TRANSFER_DEST_ADDR.\r\n\n\ +"; + +static void display_greeting(void); + +uint32_t g_udma_status = 0u; + +/*============================================================================== + * Display greeting message when application is started. + */ +static void display_greeting(void) +{ + UART_polled_tx_string(&g_uart, g_greeting_msg); +} + +/* MIV RV32 External interrupt handlers for MIV_ESS uDMA */ +void MSYS_EI1_IRQHandler() +{ + g_udma_status = MIV_uDMA_read_status(&g_miv_ess_udma); + + MIV_uDMA_reset(&g_miv_ess_udma); +} + +/****************************************************************************** + * main function. + *****************************************************************************/ +void main(void) +{ + size_t rx_size; + uint8_t rx_buff[1] = {0x00}; + uint32_t counter = 0u; + + /* Initialize CoreUARTapb with its base address, baud value, and line + * configuration. + */ + UART_init(&g_uart, COREUARTAPB0_BASE_ADDR, BAUD_VALUE_115200, (DATA_8_BITS | NO_PARITY)); + + display_greeting(); + + MRV_enable_local_irq(MRV32_MSYS_EIE1_IRQn); + + HAL_enable_interrupts(); + + uint32_t *src_addr = (uint32_t*)MIV_UDMA_TRANSFER_SRC_ADDR; + uint32_t *dest_addr = (uint32_t*)MIV_UDMA_TRANSFER_DEST_ADDR; + + /* Write some data in the source memory */ + *src_addr = 0xAFAFAFAF; + + MIV_uDMA_init(&g_miv_ess_udma, MIV_ESS_uDMA_BASE_ADDR); + + MIV_uDMA_config(&g_miv_ess_udma, MIV_UDMA_TRANSFER_SRC_ADDR , + MIV_UDMA_TRANSFER_DEST_ADDR, 0x8, MIV_uDMA_CTRL_IRQ_CONFIG); + + MIV_uDMA_start(&g_miv_ess_udma); + + while(1) + { + if (g_udma_status == MIV_uDMA_STATUS_BUSY) + { + UART_polled_tx_string(&g_uart, + (const uint8_t *)"\r\n uDMA busy"); + + g_udma_status = 0xff; + } + else if (g_udma_status == MIV_uDMA_STATUS_ERROR) + { + UART_polled_tx_string(&g_uart, + (const uint8_t *)"\r\n uDMA error"); + g_udma_status = 0xff; + } + else if (g_udma_status == 0u) + { + counter = verify_write(src_addr, dest_addr, 8u); + if (counter == 0u) + { + UART_polled_tx_string(&g_uart, + (const uint8_t *)"\r\n uDMA Success"); + g_udma_status = 0xff; + } + else + { + UART_polled_tx_string(&g_uart, + (const uint8_t *)"\r\n uDMA wrong data"); + g_udma_status = 0xff; + } + } + } +} + +/**************************************************************************//** + * Read the data from destination memory and compare the same with source + * address contents. + */ +static uint8_t verify_write(uint32_t* write_buff, uint32_t* read_buff, uint16_t size) +{ + uint8_t error = 0U; + uint16_t index = 0U; + + while(size != 0U) + { + if(write_buff[index] != read_buff[index]) + { + error = 1U; + break; + } + index++; + size--; + } + + return error; +} diff --git a/miv-rv32-udma/src/boards/polarfire-eval-kit/fpga_design/design_description/README.md b/miv-rv32-udma/src/boards/polarfire-eval-kit/fpga_design/design_description/README.md new file mode 100644 index 0000000..4f7aa4b --- /dev/null +++ b/miv-rv32-udma/src/boards/polarfire-eval-kit/fpga_design/design_description/README.md @@ -0,0 +1,2 @@ +# Desgin desctription +The Libero generated design desctription will be stored here. diff --git a/miv-rv32-udma/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h b/miv-rv32-udma/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h new file mode 100644 index 0000000..524ef50 --- /dev/null +++ b/miv-rv32-udma/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h @@ -0,0 +1,151 @@ +/******************************************************************************* + * Copyright 2021 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file sample_fpga_design_config.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Sample design configuration settings + * + */ + /*========================================================================*//** + @mainpage + Example file detailing how the fpga_design_config.h should be constructed + for the SoftConsole project targeted for Mi-V processors. + + @section intro_sec Introduction + The SoftConsole project targeted for Mi-V processors now have an improved + folder structure. Detailed description of the folder structure is available + at https://github.com/Mi-V-Soft-RISC-V/miv-rv32-documentation. + + The fpga_design_config.h must be stored as shown below + /boards//fpga_design_config.h + + Currently this file must be hand crafted when using the Mi-V Soft Processor. + In future, all the design and soft IP configurations will be automatically + generated from the Libero design description data. + + You can use this sample file as an example. + Rename this file from sample_fpga_design_config.h to fpga_design_config.h + and then customize it per your hardware design. + + @section driver_configuration Project configuration Instructions + 1. Change SYS_CLK_FREQ define to frequency of Mi-V Soft processor clock + 2 Add all the soft IP core BASE addresses + 3. Add the peripheral Core Interrupts to Mi-V Soft processor IRQ number + mappings + 4. Define MSCC_STDIO_UART_BASE_ADDR if you want a CoreUARTapb mapped to + STDIO + + **NOTE** + In the legacy folder structures, the file hw_config.h as was used at the + root of the project folder. This file is now deprecated. + +*//*=========================================================================*/ + +#ifndef FPGA_DESIGN_CONFIG_H_ +#define FPGA_DESIGN_CONFIG_H_ + +/***************************************************************************//** + * Soft-processor clock definition + * This is the only clock brought over from the Mi-V Soft processor Libero design. + */ +#define SYS_CLK_FREQ 50000000UL + +/***************************************************************************//** + * Non-memory Peripheral base addresses + * Format of define is: + * __BASE_ADDR + */ +#define MIV_ESS_BASE_ADDR 0x70000000UL +#define COREUARTAPB0_BASE_ADDR 0x71000000UL +#define COREGPIO_BASE_ADDR 0x75000000UL +#define MIV_ESS_uDMA_BASE_ADDR 0x78000000UL + + +/***************************************************************************//** + * Peripheral Interrupts are mapped to the corresponding Mi-V Soft processor + * interrupt from the Libero design. + * + * On the legacy RV32 cores, there can be up to 31 external interrupts (IRQ[30:0] + * pins). The legacy RV32 Soft processor external interrupts are defined in the + riscv_plic.h + * + * These are of the form + * typedef enum +{ + NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + . + . + . + External_31_IRQn = 31 +} IRQn_Type; + + On the legacy RV32 processors, the PLIC identifies the interrupt and passes it + on to the processor core. The interrupt 0 is not used. The pin IRQ[0] should + map to External_1_IRQn likewise IRQ[30] should map to External_31_IRQn + +e.g + +#define TIMER0_IRQn External_30_IRQn +#define TIMER1_IRQn External_31_IRQn + + The MIV_RV32 have up to six optional system interrupts, MSYS_EI[n] in addition + to one EXT_IRQ. + On the MIV_RV32 does not have an inbuilt PLIC and all the interrupts are directly + delivered to the processor core, hence unlike legacy RV32 core no interrupt + number mapping is necessary on MIV_RV32 core. + */ + +/**************************************************************************** + * Baud value to achieve a 115200 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ +#define BAUD_VALUE_115200 ((SYS_CLK_FREQ / (16 * 115200)) - 1) + +/****************************************************************************** + * Baud value to achieve a 57600 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + #define BAUD_VALUE_57600 ((SYS_CLK_FREQ / (16 * 57600)) - 1) + +/***************************************************************************//** + * Define MSCC_STDIO_THRU_CORE_UART_APB in the project settings if you want the + * standard IOs to be redirected to a terminal via UART. + */ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +/* + * A base address mapping for the STDIO printf/scanf mapping to CortUARTapb + * must be provided if it is being used + * + * e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR + */ +#define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB0_BASE_ADDR + +#ifndef MSCC_STDIO_UART_BASE_ADDR +#error MSCC_STDIO_UART_BASE_ADDR not defined- e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR +#endif + +#ifndef MSCC_STDIO_BAUD_VALUE +/* + * The MSCC_STDIO_BAUD_VALUE define should be set in your project's settings to + * specify the baud value used by the standard output CoreUARTapb instance for + * generating the UART's baud rate if you want a different baud rate from the + * default of 115200 baud + */ +#define MSCC_STDIO_BAUD_VALUE 115200 +#endif /*MSCC_STDIO_BAUD_VALUE*/ + +#endif /* end of MSCC_STDIO_THRU_CORE_UART_APB */ +/******************************************************************************* + * End of user edit section + */ +#endif /* FPGA_DESIGN_CONFIG_H_ */ + + diff --git a/miv-rv32-udma/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-execute-in-place.ld b/miv-rv32-udma/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-execute-in-place.ld new file mode 100644 index 0000000..19df5fb --- /dev/null +++ b/miv-rv32-udma/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-execute-in-place.ld @@ -0,0 +1,154 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-execute-in-place.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * image executing from a one address space whereas the data, sdata and stack + * sections are placed in another address space. This could be used in cases such + * as: + * 1) When using MIV_RV32, the reset vector points to the LSRAM at address + * 0x80000000 and the data, sdata, bss and stack sections are placed in the + * TCM region. + * + * 2) Executing from a Non Volatile memory. The actual memory will depend on + * the FPGA platform. For exameple, it could be the eNVM on SmartFusion2, + * Igloo2 or on-board non-volatile memory which supports code execution. + * + * NOTE: Modify the memory section addresses and the sizes according to your + * Libero design. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + + +MEMORY +{ + rom (rx) : ORIGIN = 0x80000000, LENGTH = 16k + ram (rwx) : ORIGIN = 0x80004000, LENGTH = 16k +} + +STACK_SIZE = 1k; /* needs to be calculated for your application */ +HEAP_SIZE = 0; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > rom + + .text : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.text.entry))) + . = ALIGN(0x10); + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } >rom + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } >ram AT>rom + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } >ram AT>rom + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram +} + diff --git a/miv-rv32-udma/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld b/miv-rv32-udma/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld new file mode 100644 index 0000000..e0707df --- /dev/null +++ b/miv-rv32-udma/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld @@ -0,0 +1,150 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-ram.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * debug image executing in SRAM. + * + * This linker script assumes that a RAM is connected at on Mi-V soft processor + * memory space pointed by the reset vector address. + * + * NOTE : Modify the memory section address and the size according to your + * Libero design. + * For example: + * 1) If you want to download and step debug at a different RAM memory address in + * your design (For example TCM base address) than the one provided in this file. + * 2) The MIV_RV32, when used with MIV_ESS IP, provides ways to copy the executable + * HEX file from external Non-Volatile memory into the TCM at reset. In this + * case your executable must be linked to the TCM address. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +MEMORY +{ + ram (rwx) : ORIGIN = 0x80000000, LENGTH = 32k +} + +STACK_SIZE = 2k; /* needs to be calculated for your application */ +HEAP_SIZE = 0k; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > ram + + .text : ALIGN(0x10) + { + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } > ram + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } > ram + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } > ram + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram +} + diff --git a/miv-rv32-udma/src/boards/polarfire-eval-kit/platform_config/miv_rv32_hal_config/readme.md b/miv-rv32-udma/src/boards/polarfire-eval-kit/platform_config/miv_rv32_hal_config/readme.md new file mode 100644 index 0000000..46ee0bd --- /dev/null +++ b/miv-rv32-udma/src/boards/polarfire-eval-kit/platform_config/miv_rv32_hal_config/readme.md @@ -0,0 +1,2 @@ +# readme +Software configurations that may be required for MIV_RV32 HAL in future will be stored here. diff --git a/miv-rv32-udma/src/middleware/README.md b/miv-rv32-udma/src/middleware/README.md new file mode 100644 index 0000000..dafa1d2 --- /dev/null +++ b/miv-rv32-udma/src/middleware/README.md @@ -0,0 +1 @@ +Place holder readme file in the middleware directory. diff --git a/miv-rv32-udma/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c b/miv-rv32-udma/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c new file mode 100644 index 0000000..63cd377 --- /dev/null +++ b/miv-rv32-udma/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c @@ -0,0 +1,531 @@ +/******************************************************************************* + * (c) Copyright 2008-2021 Microchip FPGA Embedded Systems Solutions. + * + * @file core_gpio.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreGPIO bare metal driver implementation. + * + */ +#include "coregpio_regs.h" +#include "core_gpio.h" + +/*-------------------------------------------------------------------------*//** + * + */ +#define GPIO_INT_ENABLE_MASK (uint32_t)0x00000008UL +#define OUTPUT_BUFFER_ENABLE_MASK 0x00000004UL + + +#define NB_OF_GPIO 32 + +#define CLEAR_ALL_IRQ32 (uint32_t)0xFFFFFFFF +#define CLEAR_ALL_IRQ16 (uint16_t)0xFFFF +#define CLEAR_ALL_IRQ8 (uint8_t)0xFF + +/*-------------------------------------------------------------------------*//** + * GPIO_init() + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_init +( + gpio_instance_t * this_gpio, + addr_t base_addr, + gpio_apb_width_t bus_width +) +{ + uint8_t i = 0; + addr_t cfg_reg_addr = base_addr; + + this_gpio->base_addr = base_addr; + this_gpio->apb_bus_width = bus_width; + + /* Clear configuration. */ + for( i = 0, cfg_reg_addr = base_addr; i < NB_OF_GPIO; ++i ) + { + HW_set_8bit_reg( cfg_reg_addr, 0 ); + cfg_reg_addr += 4; + } + /* Clear any pending interrupts */ + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, CLEAR_ALL_IRQ32 ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, (uint16_t)CLEAR_ALL_IRQ16 ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, (uint16_t)CLEAR_ALL_IRQ16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, (uint8_t)CLEAR_ALL_IRQ8 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_config + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_config +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint32_t config +) +{ + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + uint32_t cfg_reg_addr = this_gpio->base_addr; + cfg_reg_addr += (port_id * 4); + HW_set_32bit_reg( cfg_reg_addr, config ); + + /* + * Verify that the configuration was correctly written. Failure to read + * back the expected value may indicate that the GPIO port was configured + * as part of the hardware flow and cannot be modified through software. + * It may also indicate that the base address passed as parameter to + * GPIO_init() was incorrect. + */ + HAL_ASSERT( HW_get_32bit_reg( cfg_reg_addr ) == config ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_set_outputs + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_set_outputs +( + gpio_instance_t * this_gpio, + uint32_t value +) +{ + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, GPIO_OUT, value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, GPIO_OUT0, (uint16_t)value ); + HAL_set_16bit_reg( this_gpio->base_addr, GPIO_OUT1, (uint16_t)(value >> 16) ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT0, (uint8_t)value ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT1, (uint8_t)(value >> 8) ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT2, (uint8_t)(value >> 16) ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT3, (uint8_t)(value >> 24) ); + break; + + default: + HAL_ASSERT(0); + break; + } + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( GPIO_get_outputs( this_gpio ) == value ); +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_inputs + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_inputs +( + gpio_instance_t * this_gpio +) +{ + uint32_t gpio_in = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + gpio_in = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_IN ); + break; + + case GPIO_APB_16_BITS_BUS: + gpio_in |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_IN0 ); + gpio_in |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_IN1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + gpio_in |= HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN0 ); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN1 ) << 8); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN2 ) << 16); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return gpio_in; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_outputs + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_outputs +( + gpio_instance_t * this_gpio +) +{ + uint32_t gpio_out = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + gpio_out = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ); + break; + + case GPIO_APB_16_BITS_BUS: + gpio_out |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT0 ); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + gpio_out |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT0 ); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT1 ) << 8); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT2 ) << 16); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return gpio_out; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_set_output + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_set_output +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint8_t value +) +{ + HAL_ASSERT( port_id < NB_OF_GPIO ); + + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + { + uint32_t outputs_state; + + outputs_state = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ); + if ( 0 == value ) + { + outputs_state &= ~(1 << port_id); + } + else + { + outputs_state |= 1 << port_id; + } + HAL_set_32bit_reg( this_gpio->base_addr, GPIO_OUT, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ) == outputs_state ); + } + break; + + case GPIO_APB_16_BITS_BUS: + { + uint16_t outputs_state; + uint32_t gpio_out_reg_addr = this_gpio->base_addr + GPIO_OUT_REG_OFFSET + ((port_id >> 4) * 4); + + outputs_state = HW_get_16bit_reg( gpio_out_reg_addr ); + if ( 0 == value ) + { + outputs_state &= ~(1 << (port_id & 0x0F)); + } + else + { + outputs_state |= 1 << (port_id & 0x0F); + } + HW_set_16bit_reg( gpio_out_reg_addr, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HW_get_16bit_reg( gpio_out_reg_addr ) == outputs_state ); + } + break; + + case GPIO_APB_8_BITS_BUS: + { + uint8_t outputs_state; + uint32_t gpio_out_reg_addr = this_gpio->base_addr + GPIO_OUT_REG_OFFSET + ((port_id >> 3) * 4); + + outputs_state = HW_get_8bit_reg( gpio_out_reg_addr ); + if ( 0 == value ) + { + outputs_state &= ~(1 << (port_id & 0x07)); + } + else + { + outputs_state |= 1 << (port_id & 0x07); + } + HW_set_8bit_reg( gpio_out_reg_addr, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HW_get_8bit_reg( gpio_out_reg_addr ) == outputs_state ); + } + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_drive_inout + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_drive_inout +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + gpio_inout_state_t inout_state +) +{ + uint32_t config; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + switch( inout_state ) + { + case GPIO_DRIVE_HIGH: + /* Set output high */ + GPIO_set_output( this_gpio, port_id, 1 ); + + /* Enable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config |= OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + case GPIO_DRIVE_LOW: + /* Set output low */ + GPIO_set_output( this_gpio, port_id, 0 ); + + /* Enable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config |= OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + case GPIO_HIGH_Z: + /* Disable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config &= ~OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_enable_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_enable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t cfg_value; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + cfg_reg_addr += (port_id * 4); + cfg_value = HW_get_8bit_reg( cfg_reg_addr ); + cfg_value |= GPIO_INT_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, cfg_value ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_disable_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_disable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t cfg_value; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + cfg_reg_addr += (port_id * 4); + cfg_value = HW_get_8bit_reg( cfg_reg_addr ); + cfg_value &= ~GPIO_INT_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, cfg_value ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_clear_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_clear_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t irq_clr_value = ((uint32_t)1) << ((uint32_t)port_id); + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, irq_clr_value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, irq_clr_value >> 16 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, irq_clr_value >> 24 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_irq_sources + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_irq_sources +( + gpio_instance_t * this_gpio +) +{ + uint32_t intr_src = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + intr_src = HAL_get_32bit_reg( this_gpio->base_addr, IRQ ); + break; + + case GPIO_APB_16_BITS_BUS: + intr_src |= HAL_get_16bit_reg( this_gpio->base_addr, IRQ0 ); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + intr_src |= HAL_get_16bit_reg( this_gpio->base_addr, IRQ0 ); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ1 ) << 8); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ2 ) << 16); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return intr_src; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_clear_all_irq_sources + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_clear_all_irq_sources +( + gpio_instance_t * this_gpio, + uint32_t bitmask +) +{ + uint32_t irq_clr_value = bitmask; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, irq_clr_value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, irq_clr_value >> 16 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, irq_clr_value >> 24 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} diff --git a/miv-rv32-udma/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h b/miv-rv32-udma/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h new file mode 100644 index 0000000..3491d68 --- /dev/null +++ b/miv-rv32-udma/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h @@ -0,0 +1,654 @@ +/******************************************************************************* + * (c) Copyright 2008-2021 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file core_gpio.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreGPIO bare metal driver public API. + * + */ + +/*=========================================================================*//** + @mainpage CoreGPIO Bare Metal Driver. + + @section intro_sec Introduction + The CoreGPIO hardware IP includes up to 32 general purpose input output GPIOs. + This driver provides a set of functions for controlling the GPIOs as part of a + bare metal system where no operating system is available. These drivers + can be adapted for use as part of an operating system but the implementation + of the adaptation layer between this driver and the operating system's driver + model is outside the scope of this driver. + + @section driver_configuration Driver Configuration + The CoreGPIO individual IOs can be configured either in the hardware flow or + as part of the software application through calls to the GPIO_config() function. + GPIOs configured as as part of the hardware is fixed and cannot be modified + using a call to the GPI_config() function. + + @section theory_op Theory of Operation + The CoreGPIO driver uses the Actel Hardware Abstraction Layer (HAL) to access + hardware registers. You must ensure that the Actel HAL is included as part of + your software project. The Actel HAL is available through the Actel Firmware + Catalog. + + The CoreGPIO driver functions are logically grouped into the following groups: + - Initialization + - Configuration + - Reading and writing GPIO state + - Interrupt control + + The CoreGPIO driver is initialized through a call to the GPIO_init() function. + The GPIO_init() function must be called before any other GPIO driver functions + can be called. + + Each GPIO port is individually configured through a call to the + GPIO_config() function. Configuration includes deciding if a GPIO port + will be used as input, output or both. GPIO ports configured as inputs can be + further configured to generate interrupts based on the input's state. + Interrupts can be level or edge sensitive. + Please note that a CoreGPIO hardware instance can be generated, as part of the + hardware flow, with a fixed configuration for some or all of its IOs. Attempting + to modify the configuration of such a hardware configured IO using the + GPIO_config() function has no effect. + + The state of the GPIO ports can be read and written using the following + functions: + - GPIO_get_inputs() + - GPIO_get_outputs() + - GPIO_set_outputs() + - GPIO_drive_inout() + + Interrupts generated by GPIO ports configured as inputs are controlled using + the following functions: + - GPIO_enable_irq() + - GPIO_disable_irq() + - GPIO_clear_irq() + - GPIO_get_irq_sources() + - GPIO_clear_all_irq_sources() + + *//*=========================================================================*/ +#ifndef CORE_GPIO_H_ +#define CORE_GPIO_H_ + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#endif + +/*-------------------------------------------------------------------------*//** + The gpio_id_t enumeration is used to identify GPIOs as part of the + parameter to functions: + - GPIO_config(), + - GPIO_drive_inout(), + - GPIO_enable_int(), + - GPIO_disable_int(), + - GPIO_clear_int() + */ +typedef enum __gpio_id_t +{ + GPIO_0 = 0, + GPIO_1 = 1, + GPIO_2 = 2, + GPIO_3 = 3, + GPIO_4 = 4, + GPIO_5 = 5, + GPIO_6 = 6, + GPIO_7 = 7, + GPIO_8 = 8, + GPIO_9 = 9, + GPIO_10 = 10, + GPIO_11 = 11, + GPIO_12 = 12, + GPIO_13 = 13, + GPIO_14 = 14, + GPIO_15 = 15, + GPIO_16 = 16, + GPIO_17 = 17, + GPIO_18 = 18, + GPIO_19 = 19, + GPIO_20 = 20, + GPIO_21 = 21, + GPIO_22 = 22, + GPIO_23 = 23, + GPIO_24 = 24, + GPIO_25 = 25, + GPIO_26 = 26, + GPIO_27 = 27, + GPIO_28 = 28, + GPIO_29 = 29, + GPIO_30 = 30, + GPIO_31 = 31 +} gpio_id_t; + +typedef enum __gpio_apb_width_t +{ + GPIO_APB_8_BITS_BUS = 0, + GPIO_APB_16_BITS_BUS = 1, + GPIO_APB_32_BITS_BUS = 2, + GPIO_APB_UNKNOWN_BUS_WIDTH = 3 +} gpio_apb_width_t; + +/*-------------------------------------------------------------------------*//** + */ +typedef struct __gpio_instance_t +{ + addr_t base_addr; + gpio_apb_width_t apb_bus_width; +} gpio_instance_t; + +/*-------------------------------------------------------------------------*//** + GPIO ports definitions used to identify GPIOs as part of the parameter to + function GPIO_set_outputs(). + These definitions can also be used to identity GPIO through logical + operations on the return value of function GPIO_get_inputs(). + */ +#define GPIO_0_MASK 0x00000001UL +#define GPIO_1_MASK 0x00000002UL +#define GPIO_2_MASK 0x00000004UL +#define GPIO_3_MASK 0x00000008UL +#define GPIO_4_MASK 0x00000010UL +#define GPIO_5_MASK 0x00000020UL +#define GPIO_6_MASK 0x00000040UL +#define GPIO_7_MASK 0x00000080UL +#define GPIO_8_MASK 0x00000100UL +#define GPIO_9_MASK 0x00000200UL +#define GPIO_10_MASK 0x00000400UL +#define GPIO_11_MASK 0x00000800UL +#define GPIO_12_MASK 0x00001000UL +#define GPIO_13_MASK 0x00002000UL +#define GPIO_14_MASK 0x00004000UL +#define GPIO_15_MASK 0x00008000UL +#define GPIO_16_MASK 0x00010000UL +#define GPIO_17_MASK 0x00020000UL +#define GPIO_18_MASK 0x00040000UL +#define GPIO_19_MASK 0x00080000UL +#define GPIO_20_MASK 0x00100000UL +#define GPIO_21_MASK 0x00200000UL +#define GPIO_22_MASK 0x00400000UL +#define GPIO_23_MASK 0x00800000UL +#define GPIO_24_MASK 0x01000000UL +#define GPIO_25_MASK 0x02000000UL +#define GPIO_26_MASK 0x04000000UL +#define GPIO_27_MASK 0x08000000UL +#define GPIO_28_MASK 0x10000000UL +#define GPIO_29_MASK 0x20000000UL +#define GPIO_30_MASK 0x40000000UL +#define GPIO_31_MASK 0x80000000UL + +/*-------------------------------------------------------------------------*//** + * GPIO modes + */ +#define GPIO_INPUT_MODE 0x0000000002UL +#define GPIO_OUTPUT_MODE 0x0000000005UL +#define GPIO_INOUT_MODE 0x0000000003UL + +/*-------------------------------------------------------------------------*//** + * Possible GPIO inputs interrupt configurations. + */ +#define GPIO_IRQ_LEVEL_HIGH 0x0000000000UL +#define GPIO_IRQ_LEVEL_LOW 0x0000000020UL +#define GPIO_IRQ_EDGE_POSITIVE 0x0000000040UL +#define GPIO_IRQ_EDGE_NEGATIVE 0x0000000060UL +#define GPIO_IRQ_EDGE_BOTH 0x0000000080UL + +/*-------------------------------------------------------------------------*//** + * Possible states for GPIO configured as INOUT. + */ +typedef enum gpio_inout_state +{ + GPIO_DRIVE_LOW = 0, + GPIO_DRIVE_HIGH, + GPIO_HIGH_Z +} gpio_inout_state_t; + +/*-------------------------------------------------------------------------*//** + The GPIO_init() function initialises a CoreGPIO hardware instance and the data + structure associated with the CoreGPIO hardware instance. + Please note that a CoreGPIO hardware instance can be generated with a fixed + configuration for some or all of its IOs as part of the hardware flow. Attempting + to modify the configuration of such a hardware configured IO using the + GPIO_config() function has no effect. + + @param this_gpio + Pointer to the gpio_instance_t data structure instance holding all data + regarding the CoreGPIO hardware instance being initialized. A pointer to the + same data structure will be used in subsequent calls to the CoreGPIO driver + functions in order to identify the CoreGPIO instance that should perform the + operation implemented by the called driver function. + + @param base_addr + The base_addr parameter is the base address in the processor's memory map for + the registers of the GPIO instance being initialized. + + @param bus_width + The bus_width parameter informs the driver of the APB bus width selected during + the hardware flow configuration of the CoreGPIO hardware instance. It indicates + to the driver whether the CoreGPIO hardware registers will be visible as 8, 16 + or 32 bits registers. Allowed value are: + - GPIO_APB_8_BITS_BUS + - GPIO_APB_16_BITS_BUS + - GPIO_APB_32_BITS_BUS + + @return + none. + + Example: + @code + #define COREGPIO_BASE_ADDR 0xC2000000 + + gpio_instance_t g_gpio; + + void system_init( void ) + { + GPIO_init( &g_gpio, COREGPIO_BASE_ADDR, GPIO_APB_32_BITS_BUS ); + } + @endcode + */ +void GPIO_init +( + gpio_instance_t * this_gpio, + addr_t base_addr, + gpio_apb_width_t bus_width +); + +/*-------------------------------------------------------------------------*//** + The GPIO_config() function is used to configure an individual GPIO port. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure holding + all data regarding the CoreGPIO instance controlled through this function call. + + @param port_id + The port_id parameter identifies the GPIO port to be configured. + An enumeration item of the form GPIO_n where n is the number of the GPIO + port is used to identify the GPIO port. For example GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @param config + The config parameter specifies the configuration to be applied to the GPIO + port identified by the first parameter. It is a logical OR of GPIO mode and + the interrupt mode. The interrupt mode is only relevant if the GPIO is + configured as input. + Possible modes are: + - GPIO_INPUT_MODE, + - GPIO_OUTPUT_MODE, + - GPIO_INOUT_MODE. + Possible interrupt modes are: + - GPIO_IRQ_LEVEL_HIGH, + - GPIO_IRQ_LEVEL_LOW, + - GPIO_IRQ_EDGE_POSITIVE, + - GPIO_IRQ_EDGE_NEGATIVE, + - GPIO_IRQ_EDGE_BOTH + + @return + none. + + For example the following call will configure GPIO 4 as an input generating + interrupts on a low to high transition of the input: + @code + GPIO_config( &g_gpio, GPIO_4, GPIO_INPUT_MODE | GPIO_IRQ_EDGE_POSITIVE ); + @endcode + */ +void GPIO_config +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint32_t config +); + +/*-------------------------------------------------------------------------*//** + The GPIO_set_outputs() function is used to set the state of the GPIO ports + configured as outputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure holding + all data regarding the CoreGPIO instance controlled through this function call. + + @param value + The value parameter specifies the state of the GPIO ports configured as + outputs. It is a bit mask of the form (GPIO_n_MASK | GPIO_m_MASK) where n + and m are numbers identifying GPIOs. + For example (GPIO_0_MASK | GPIO_1_MASK | GPIO_2_MASK ) specifies that the + first, second and third GPIOs' must be set high and all other outputs set + low. + + @return + none. + + Example 1: + Set GPIOs outputs 0 and 8 high and all other GPIO outputs low. + @code + GPIO_set_outputs( &g_gpio, GPIO_0_MASK | GPIO_8_MASK ); + @endcode + + Example 2: + Set GPIOs outputs 2 and 4 low without affecting other GPIO outputs. + @code + uint32_t gpio_outputs; + gpio_outputs = GPIO_get_outputs( &g_gpio ); + gpio_outputs &= ~( GPIO_2_MASK | GPIO_4_MASK ); + GPIO_set_outputs( &g_gpio, gpio_outputs ); + @endcode + + @see GPIO_get_outputs() + */ +void GPIO_set_outputs +( + gpio_instance_t * this_gpio, + uint32_t value +); + +/*-------------------------------------------------------------------------*//** + The GPIO_set_output() function is used to set the state of a single GPIO + port configured as output. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure holding + all data regarding the CoreGPIO instance controlled through this function call. + + @param port_id + The port_id parameter specifies the GPIO port that will have its output set + by a call to this function. + + @param value + The value parameter specifies the desired state for the GPIO output. A value + of 0 will set the output low and a value of 1 will set the port high. + + @return + none. + */ +void GPIO_set_output +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint8_t value +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_inputs() function is used to read the state of all GPIOs + configured as inputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure holding + all data regarding the CoreGPIO instance controlled through this function call. + + @return + This function returns a 32 bit unsigned integer where each bit represents + the state of an input. The least significant bit representing the state of + GPIO 0 and the most significant bit the state of GPIO 31. + */ +uint32_t GPIO_get_inputs +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_outputs() function is used to read the current state of all + GPIO outputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure holding + all data regarding the CoreGPIO instance controlled through this function call. + + @return + This function returns a 32 bit unsigned integer where each bit represents + the state of an output. The least significant bit representing the state + of GPIO 0 and the most significant bit the state of GPIO 31. + */ +uint32_t GPIO_get_outputs +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_drive_inout() function is used to set the output state of a + GPIO configured as INOUT. An INOUT GPIO can be in one of three states: + - high + - low + - high impedance + An INOUT output would typically be used where several devices can drive the + state of a signal. The high and low states are equivalent to the high and low + states of a GPIO configured as output. The high impedance state is used to + prevent the GPIO from driving the state of the output and therefore allow + reading the state of the GPIO as an input. + Please note that the GPIO port you wish to use as INOUT through this function + must be configurable through software. Therefore the GPIO ports used as INOUT + must not have a fixed configuration selected as part of the hardware flow. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure holding + all data regarding the CoreGPIO instance controlled through this function call. + + @param port_id + The port_id parameter identifies the GPIO for which this function will + change the output state. + An enumeration item of the form GPIO_n where n is the number of the GPIO + port is used to identify the GPIO port. For example GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @param inout_state + The inout_state parameter specifies the state of the I/O identified by the + first parameter. Possible states are: + - GPIO_DRIVE_HIGH, + - GPIO_DRIVE_LOW, + - GPIO_HIGH_Z (high impedance) + + @return + none. + + Example: + The call to GPIO_drive_inout() below will set the GPIO 7 output to + high impedance state. + @code + GPIO_drive_inout( &g_gpio, GPIO_7, GPIO_HIGH_Z ); + @endcode + */ +void GPIO_drive_inout +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + gpio_inout_state_t inout_state +); + +/*-------------------------------------------------------------------------*//** + The GPIO_enable_irq() function is used to enable an interrupt to be + generated based on the state of the input identified as parameter. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure holding + all data regarding the CoreGPIO instance controlled through this function call. + + @param port_id + The port_id parameter identifies the GPIO input the call to + GPIO_enable_irq() will enable to generate interrupts. + An enumeration item of the form GPIO_n where n is the number of the GPIO + port is used to identify the GPIO port. For example GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + Example: + The call to GPIO_enable_irq() below will allow GPIO 8 to generate + interrupts. + @code + GPIO_enable_irq( &g_gpio, GPIO_8 ); + @endcode + */ +void GPIO_enable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_disable_irq() function is used to disable interrupt from being + generated based on the state of the input specified as parameter. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure holding + all data regarding the CoreGPIO instance controlled through this function call. + + @param port_id + The port_id parameter identifies the GPIO input the call to + GPIO_disable_irq() will disable from generating interrupts. + An enumeration item of the form GPIO_n where n is the number of the GPIO + port is used to identify the GPIO port. For example GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + Example: + The call to GPIO_disable_irq() below will prevent GPIO 8 from generating + interrupts. + @code + GPIO_disable_irq( &g_gpio, GPIO_8 ); + @endcode + */ +void GPIO_disable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_clear_irq() function is used to clear the interrupt generated by + the GPIO specified as parameter. The GPIO_clear_irq() function must be + called as part of a GPIO interrupt service routine (ISR) in order to prevent + the same interrupt event re-triggering a call to the GPIO ISR. + Please note that interrupts may also need to be cleared in the processor's + interrupt controller. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure holding + all data regarding the CoreGPIO instance controlled through this function call. + + @param port_id + The port_id parameter identifies the GPIO input for which to clear the + interrupt. + An enumeration item of the form GPIO_n where n is the number of the GPIO + port is used to identify the GPIO port. For example GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + Example: + The example below demonstrates the use of the GPIO_clear_irq() function as + part of the GPIO 9 interrupt service routine. + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + GPIO_clear_irq( &g_gpio, GPIO_9 ); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +void GPIO_clear_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_irq_sources() function is used to identify the source of + interrupt. i.e. the GPIO input line whose state change triggered the interrupt. + The GPIO_get_irq_sources() function must be called as part of a GPIO + interrupt service routine (ISR) in order to determine the interrupt source. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure holding + all data regarding the CoreGPIO instance controlled through this function call. + + @return + This function returns a 32 bit unsigned integer where each bit represents + the pin number of GPIO. + + Example: + The example below demonstrates the use of the GPIO_get_irq_sources() function + as part of the GPIO 9 interrupt service routine. + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + GPIO_clear_all_irq_sources(g_p_mygpio, GPIO_get_irq_sources(g_p_mygpio)); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +uint32_t GPIO_get_irq_sources +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_clear_all_irq_sources() function is used to clear the all the active + interrupt generated by the GPIO specified as parameter. The + GPIO_clear_all_irq_sources() function must be called as part of a GPIO interrupt + service routine (ISR) in order to prevent the same interrupt event + re-triggering a call to the GPIO ISR. + Please note that interrupts may also need to be cleared in the processor's + interrupt controller. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure holding + all data regarding the CoreGPIO instance controlled through this function call. + + @param bitmask + This bitmask parameter is a 32 bit unsigned integer where each bit represents + the GPIO pin used to clears the interrupt bit register of the corresponding + GPIO bit. The least significant bit representing the status of GPIO 0 and + the most significant bit the status of GPIO 31. + + @return + none. + + Example: + The example below demonstrates the use of the GPIO_clear_all_irq_sources() function as + part of the GPIO 9 interrupt service routine. + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + do_interrupt_processing(); + + GPIO_clear_all_irq_sources(g_p_mygpio, GPIO_get_irq_sources(g_p_mygpio)); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +void GPIO_clear_all_irq_sources +( + gpio_instance_t * this_gpio, + uint32_t bitmask +); +#endif /* CORE_GPIO_H_ */ diff --git a/miv-rv32-udma/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h b/miv-rv32-udma/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h new file mode 100644 index 0000000..0c13e28 --- /dev/null +++ b/miv-rv32-udma/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h @@ -0,0 +1,43 @@ +/******************************************************************************* + * (c) Copyright 2008-2021 Microchip FPGA Embedded Systems Solutions. + * + * @file coregpio_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreGPIO register definitions + * + */ + +#ifndef __CORE_GPIO_REGISTERS_H +#define __CORE_GPIO_REGISTERS_H 1 + +/*------------------------------------------------------------------------------ + * + */ +#define IRQ_REG_OFFSET 0x80 + +#define IRQ0_REG_OFFSET 0x80 +#define IRQ1_REG_OFFSET 0x84 +#define IRQ2_REG_OFFSET 0x88 +#define IRQ3_REG_OFFSET 0x8C + +/*------------------------------------------------------------------------------ + * + */ +#define GPIO_IN_REG_OFFSET 0x90 + +#define GPIO_IN0_REG_OFFSET 0x90 +#define GPIO_IN1_REG_OFFSET 0x94 +#define GPIO_IN2_REG_OFFSET 0x98 +#define GPIO_IN3_REG_OFFSET 0x9C + +/*------------------------------------------------------------------------------ + * + */ +#define GPIO_OUT_REG_OFFSET 0xA0 + +#define GPIO_OUT0_REG_OFFSET 0xA0 +#define GPIO_OUT1_REG_OFFSET 0xA4 +#define GPIO_OUT2_REG_OFFSET 0xA8 +#define GPIO_OUT3_REG_OFFSET 0xAC + +#endif /* __CORE_GPIO_REGISTERS_H */ diff --git a/miv-rv32-udma/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c b/miv-rv32-udma/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c new file mode 100644 index 0000000..2b2087a --- /dev/null +++ b/miv-rv32-udma/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c @@ -0,0 +1,295 @@ +/******************************************************************************* + * (c) Copyright 2007-2021 Microchip FPGA Embedded Systems Solutions. + * + * @file core_uart_apb.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreUARTapb driver implementation. See file "core_uart_apb.h" for + * description of the functions implemented in this file. + * + */ + +#include "coreuartapb_regs.h" +#include "core_uart_apb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define NULL_INSTANCE ( ( UART_instance_t* ) 0 ) +#define NULL_BUFFER ( ( uint8_t* ) 0 ) + +#define MAX_LINE_CONFIG ( ( uint8_t )( DATA_8_BITS | ODD_PARITY ) ) +#define MAX_BAUD_VALUE ( ( uint16_t )( 0x1FFF ) ) +#define STATUS_ERROR_MASK ( ( uint8_t )( STATUS_PARITYERR_MASK | \ + STATUS_OVERFLOW_MASK | \ + STATUS_FRAMERR_MASK ) ) +#define BAUDVALUE_LSB ( (uint16_t) (0x00FF) ) +#define BAUDVALUE_MSB ( (uint16_t) (0xFF00) ) +#define BAUDVALUE_SHIFT ( (uint8_t) (5) ) + +#define STATUS_ERROR_OFFSET STATUS_PARITYERR_SHIFT + +/***************************************************************************//** + * UART_init() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_init +( + UART_instance_t * this_uart, + addr_t base_addr, + uint16_t baud_value, + uint8_t line_config +) +{ + uint8_t rx_full; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( line_config <= MAX_LINE_CONFIG ) + HAL_ASSERT( baud_value <= MAX_BAUD_VALUE ) + + if( ( this_uart != NULL_INSTANCE ) && + ( line_config <= MAX_LINE_CONFIG ) && + ( baud_value <= MAX_BAUD_VALUE ) ) + { + /* + * Store lower 8-bits of baud value in CTRL1. + */ + HAL_set_8bit_reg( base_addr, CTRL1, (uint_fast8_t)(baud_value & + BAUDVALUE_LSB ) ); + + /* + * Extract higher 5-bits of baud value and store in higher 5-bits + * of CTRL2, along with line configuration in lower 3 three bits. + */ + HAL_set_8bit_reg( base_addr, CTRL2, (uint_fast8_t)line_config | + (uint_fast8_t)((baud_value & + BAUDVALUE_MSB) >> BAUDVALUE_SHIFT ) ); + + this_uart->base_address = base_addr; +#ifndef NDEBUG + { + uint8_t config; + uint8_t temp; + uint16_t baud_val; + baud_val = HAL_get_8bit_reg( this_uart->base_address, CTRL1 ); + config = HAL_get_8bit_reg( this_uart->base_address, CTRL2 ); + /* + * To resolve operator precedence between & and << + */ + temp = ( config & (uint8_t)(CTRL2_BAUDVALUE_MASK ) ); + baud_val |= (uint16_t)( (uint16_t)(temp) << BAUDVALUE_SHIFT ); + config &= (uint8_t)(~CTRL2_BAUDVALUE_MASK); + HAL_ASSERT( baud_val == baud_value ); + HAL_ASSERT( config == line_config ); + } +#endif + + /* + * Flush the receive FIFO of data that may have been received before the + * driver was initialized. + */ + rx_full = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_RXFULL_MASK; + while ( rx_full ) + { + HAL_get_8bit_reg( this_uart->base_address, RXDATA ); + rx_full = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_RXFULL_MASK; + } + + /* + * Clear status of the UART instance. + */ + this_uart->status = (uint8_t)0; + } +} + +/***************************************************************************//** + * UART_send() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_send +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +) +{ + size_t char_idx; + uint8_t tx_ready; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( tx_buffer != NULL_BUFFER ) + HAL_ASSERT( tx_size > 0 ) + + if( (this_uart != NULL_INSTANCE) && + (tx_buffer != NULL_BUFFER) && + (tx_size > (size_t)0) ) + { + for ( char_idx = (size_t)0; char_idx < tx_size; char_idx++ ) + { + /* Wait for UART to become ready to transmit. */ + do { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( !tx_ready ); + /* Send next character in the buffer. */ + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)tx_buffer[char_idx] ); + } + } +} + +/***************************************************************************//** + * UART_fill_tx_fifo() + * See "core_uart_apb.h" for details of how to use this function. + */ +size_t +UART_fill_tx_fifo +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +) +{ + uint8_t tx_ready; + size_t size_sent = 0u; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( tx_buffer != NULL_BUFFER ) + HAL_ASSERT( tx_size > 0 ) + + /* Fill the UART's Tx FIFO until the FIFO is full or the complete input + * buffer has been written. */ + if( (this_uart != NULL_INSTANCE) && + (tx_buffer != NULL_BUFFER) && + (tx_size > 0u) ) + { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + if ( tx_ready ) + { + do { + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)tx_buffer[size_sent] ); + size_sent++; + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( (tx_ready) && ( size_sent < tx_size ) ); + } + } + return size_sent; +} + +/***************************************************************************//** + * UART_get_rx() + * See "core_uart_apb.h" for details of how to use this function. + */ +size_t +UART_get_rx +( + UART_instance_t * this_uart, + uint8_t * rx_buffer, + size_t buff_size +) +{ + uint8_t new_status; + uint8_t rx_full; + size_t rx_idx = 0u; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( rx_buffer != NULL_BUFFER ) + HAL_ASSERT( buff_size > 0 ) + + if( (this_uart != NULL_INSTANCE) && + (rx_buffer != NULL_BUFFER) && + (buff_size > 0u) ) + { + rx_idx = 0u; + new_status = HAL_get_8bit_reg( this_uart->base_address, STATUS ); + this_uart->status |= new_status; + rx_full = new_status & STATUS_RXFULL_MASK; + while ( ( rx_full ) && ( rx_idx < buff_size ) ) + { + rx_buffer[rx_idx] = HAL_get_8bit_reg( this_uart->base_address, + RXDATA ); + rx_idx++; + new_status = HAL_get_8bit_reg( this_uart->base_address, STATUS ); + this_uart->status |= new_status; + rx_full = new_status & STATUS_RXFULL_MASK; + } + } + return rx_idx; +} + +/***************************************************************************//** + * UART_polled_tx_string() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_polled_tx_string +( + UART_instance_t * this_uart, + const uint8_t * p_sz_string +) +{ + uint32_t char_idx; + uint8_t tx_ready; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( p_sz_string != NULL_BUFFER ) + + if( ( this_uart != NULL_INSTANCE ) && ( p_sz_string != NULL_BUFFER ) ) + { + char_idx = 0U; + while( 0U != p_sz_string[char_idx] ) + { + /* Wait for UART to become ready to transmit. */ + do { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( !tx_ready ); + /* Send next character in the buffer. */ + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)p_sz_string[char_idx] ); + char_idx++; + } + } +} + +/***************************************************************************//** + * UART_get_rx_status() + * See "core_uart_apb.h" for details of how to use this function. + */ +uint8_t +UART_get_rx_status +( + UART_instance_t * this_uart +) +{ + uint8_t status = UART_APB_INVALID_PARAM; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + /* + * Extract UART error status and place in lower bits of "status". + * Bit 0 - Parity error status + * Bit 1 - Overflow error status + * Bit 2 - Frame error status + */ + if( this_uart != NULL_INSTANCE ) + { + status = ( ( this_uart->status & STATUS_ERROR_MASK ) >> + STATUS_ERROR_OFFSET ); + /* + * Clear the sticky status for this instance. + */ + this_uart->status = (uint8_t)0; + } + return status; +} + +#ifdef __cplusplus +} +#endif diff --git a/miv-rv32-udma/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h b/miv-rv32-udma/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h new file mode 100644 index 0000000..2ce0b88 --- /dev/null +++ b/miv-rv32-udma/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h @@ -0,0 +1,432 @@ +/******************************************************************************* + * (c) Copyright 2007-2021 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file core_uart_apb.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief This file contains the application programming interface for the + * CoreUARTapb bare metal driver. + * + */ +/*=========================================================================*//** + @mainpage CoreUARTapb Bare Metal Driver. + + @section intro_sec Introduction + CoreUARTapb is an implementation of the Universal Asynchronous + Receiver/Transmitter aimed at a minimal FPGA tile usage within an Microsemi + FPGA. The CoreUARTapb bare metal software driver is designed for use in + systems with no operating system. + + The CoreUARTapb driver provides functions for basic polled transmitting and + receiving operations. It also provides functions allowing use of the + CoreUARTapb in interrupt-driven mode, but leaves the management of interrupts + to the calling application, as interrupt enabling and disabling cannot be + controlled through the CoreUARTapb registers. The CoreUARTapb driver is + provided as C source code. + + @section driver_configuration Driver Configuration + Your application software should configure the CoreUARTapb driver, through + calls to the UART_init() function for each CoreUARTapb instance in the + hardware design. The configuration parameters include the CoreUARTapb + hardware instance base address and other runtime parameters, such as baud + rate, bit width, and parity. No CoreUARTapb hardware configuration parameters + are needed by the driver, apart from the CoreUARTapb hardware instance base + address. Hence, no additional configuration files are required to use the driver. + + A CoreUARTapb hardware instance can be generated with fixed baud value, + character size and parity configuration settings as part of the hardware flow. + The baud_value and line_config parameter values passed to the UART_init() + function will not have any effect if fixed values were selected for the + baud value, character size and parity in the hardware configuration of + CoreUARTapb. When fixed values are selected for these hardware configuration + parameters, the driver cannot overwrite the fixed values in the CoreUARTapb + control registers, CTRL1 and CTRL2. + + @section theory_op Theory of Operation + The CoreUARTapb software driver is designed to allow the control of multiple + instances of CoreUARTapb. Each instance of CoreUARTapb in the hardware design + is associated with a single instance of the UART_instance_t structure in the + software. You need to allocate memory for one unique UART_instance_t + structure instance for each CoreUARTapb hardware instance. The contents of + these data structures are initialized during calls to function UART_init(). + A pointer to the structure is passed to subsequent driver functions in order + to identify the CoreUARTapb hardware instance you wish to perform the + requested operation on. + + Note: Do not attempt to directly manipulate the content of UART_instance_t + structures. This structure is only intended to be modified by the driver + function. + + The driver can be used to transmit and receive data once initialized. + Transmit can be performed using the UART_send() function. This function + is blocking, meaning that it will only return once the data passed to + the function has been sent to the CoreUARTapb hardware. Data received + by the CoreUARTapb hardware can be read by the user application using + the UART_get_rx() function. + + The function UART_fill_tx_fifo() is also provided to be used as part of + interrupt-driven transmit. This function fills the CoreUARTapb hardware + transmit FIFO with the content of a data buffer passed as a parameter before + returning. The control of the interrupts must be implemented outside the + driver as the CoreUARTapb hardware does not provide the ability to enable + or disable its interrupt sources. + + The function UART_polled_tx_string() is provided to transmit a NULL + terminated string in polled mode. This function is blocking, meaning that it + will only return once the data passed to the function has been sent to the + CoreUARTapb hardware. + + The function UART_get_rx_status() returns the error status of the CoreUARTapb + receiver. This can be used by applications to take appropriate action in case + of receiver errors. +*//*=========================================================================*/ +#ifndef __CORE_UART_APB_H +#define __CORE_UART_APB_H 1 + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + * Data bits length defines: + */ +#define DATA_7_BITS 0x00u +#define DATA_8_BITS 0x01u + +/***************************************************************************//** + * Parity defines: + */ +#define NO_PARITY 0x00u +#define EVEN_PARITY 0x02u +#define ODD_PARITY 0x06u + +/***************************************************************************//** + * Error Status definitions: + */ +#define UART_APB_PARITY_ERROR 0x01u +#define UART_APB_OVERFLOW_ERROR 0x02u +#define UART_APB_FRAMING_ERROR 0x04u +#define UART_APB_NO_ERROR 0x00u +#define UART_APB_INVALID_PARAM 0xFFu + +/***************************************************************************//** + * UART_instance_t + * + * There should be one instance of this structure for each instance of CoreUARTapb + * in your system. This structure instance is used to identify the various UARTs + * in a system and should be passed as first parameter to UART functions to + * identify which UART should perform the requested operation. The 'status' + * element in the structure is used to provide sticky status information. + */ +typedef struct +{ + addr_t base_address; + uint8_t status; +} UART_instance_t; + +/***************************************************************************//** + * The function UART_init() initializes the UART with the configuration passed + * as parameters. The configuration parameters are the baud_value used to + * generate the baud rate and the line configuration (bit length and parity). + * + * @param this_uart The this_uart parameter is a pointer to a UART_instance_t + * structure which holds all data regarding this instance of + * the CoreUARTapb. This pointer will be used to identify + * the target CoreUARTapb hardware instance in subsequent + * calls to the CoreUARTapb functions. + * @param base_addr The base_address parameter is the base address in the + * processor's memory map for the registers of the + * CoreUARTapb instance being initialized. + * @param baud_value The baud_value parameter is used to select the baud rate + * for the UART. The baud value is calculated from the + * frequency of the system clock in hertz and the desired + * baud rate using the following equation: + * + * baud_value = (clock /(baud_rate * 16)) - 1. + * + * The baud_value parameter must be a value in the range 0 + * to 8191 (or 0x0000 to 0x1FFF). + * @param line_config This parameter is the line configuration specifying the + * bit length and parity settings. This is a logical OR of: + * - DATA_7_BITS + * - DATA_8_BITS + * - NO_PARITY + * - EVEN_PARITY + * - ODD_PARITY + * For example, 8 bits even parity would be specified as + * (DATA_8_BITS | EVEN_PARITY). + * @return This function does not return a value. + * Example: + * @code + * #define BAUD_VALUE_57600 25 + * + * #define COREUARTAPB0_BASE_ADDR 0xC3000000UL + * + * UART_instance_t g_uart; + * int main() + * { + * UART_init(&g_uart, COREUARTAPB0_BASE_ADDR, + BAUD_VALUE_57600, (DATA_8_BITS | EVEN_PARITY)); + * } + * @endcode + */ +void +UART_init +( + UART_instance_t * this_uart, + addr_t base_addr, + uint16_t baud_value, + uint8_t line_config +); + +/***************************************************************************//** + * The function UART_send() is used to transmit data. It transfers the contents + * of the transmitter data buffer, passed as a function parameter, into the + * UART's hardware transmitter FIFO. It returns when the full content of the + * transmitter data buffer has been transferred to the UART's transmitter FIFO. + * + * Note: you cannot assume that the data you are sending using this function has + * been received at the other end by the time this function returns. The actual + * transmit over the serial connection will still be taking place at the time of + * the function return. It is safe to release or reuse the memory used as the + * transmit buffer once this function returns. + * + * @param this_uart The this_uart parameter is a pointer to a + * UART_instance_t structure which holds all data regarding + * this instance of the CoreUARTapbUART. + * @param tx_buffer The tx_buffer parameter is a pointer to a buffer + * containing the data to be transmitted. + * @param tx_size The tx_size parameter is the size, in bytes, of + * the data to be transmitted. + * + * @return This function does not return a value. + * + * Example: + * @code + * uint8_t testmsg1[] = {"\n\r\n\r\n\rUART_send() test message 1"}; + * UART_send(&g_uart,(const uint8_t *)&testmsg1,sizeof(testmsg1)); + * @endcode + */ +void +UART_send +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +); + +/***************************************************************************//** + * The function UART_fill_tx_fifo() fills the UART's transmitter hardware FIFO + * with the data found in the transmitter buffer that is passed in as a + * function parameter. The function returns either when the FIFO is full or + * when the complete contents of the transmitter buffer have been copied into + * the FIFO. It returns the number of bytes copied into the UART's transmitter + * hardware FIFO. This function is intended to be used as part of + * interrupt-driven transmission. + * + * Note: You cannot assume that the data you transmit using this function has + * been received at the other end by the time this function returns. + * The actual transmission over the serial connection will still be + * taking place at the time of the function return. + * + * @param this_uart The this_uart parameter is a pointer to a UART_instance_t + * structure which holds all data regarding this instance of + * the UART. + * @param tx_buffer The tx_buffer parameter is a pointer to a buffer + * containing the data to be transmitted. + * @param tx_size The tx_size parameter is the size in bytes, of the data + * to be transmitted. + * @return This function returns the number of bytes copied + * into the UART's transmitter hardware FIFO. + * + * Example: + * @code + * void send_using_interrupt + * ( + * uint8_t * pbuff, + * size_t tx_size + * ) + * { + * size_t size_in_fifo; + * size_in_fifo = UART_fill_tx_fifo( &g_uart, pbuff, tx_size ); + * } + * @endcode + */ +size_t +UART_fill_tx_fifo +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +); + +/***************************************************************************//** + * The function UART_get_rx() reads the content of the UART's receiver hardware + * FIFO and stores it in the receiver buffer that is passed in as a function + * parameter. It copies either the full contents of the FIFO into the receiver + * buffer, or just enough data from the FIFO to fill the receiver buffer, + * dependent upon the size of the receiver buffer. The size of the receiver + * buffer is passed in as a function parameter. UART_get_rx() returns the number + * of bytes copied into the receiver buffer. If no data was received at the time + * the function is called, the function returns 0. + * + * Note: This function reads and accumulates the receiver status of the + * CoreUARTapb instance before reading each byte from the receiver's + * data register/FIFO. This allows the driver to maintain a sticky + * record of any receiver errors that occur as the UART receives each + * data byte; receiver errors would otherwise be lost after each read + * from the receiver's data register. A call to the UART_get_rx_status() + * function returns any receiver errors accumulated during the execution + * of the UART_get_rx() function. + * Note: When FIFO mode is disabled in the CoreUARTapb hardware configuration, + * the driver accumulates a sticky record of any parity errors, framing + * errors or overflow errors. When FIFO mode is enabled, the driver + * accumulates a sticky record of overflow errors only; in this case + * interrupts must be used to handle parity errors or framing errors. + * + * @param this_uart The this_uart parameter is a pointer to a UART_instance_t + * structure which holds all data regarding this instance of + * the UART. + * @param rx_buffer The rx_buffer parameter is a pointer to a buffer where the + * received data will be copied. + * @param buff_size The buff_size parameter is the size of the receive buffer + * in bytes. + * @return This function returns the number of bytes copied into the + * receive buffer. + * + * Example: + * @code + * #define MAX_RX_DATA_SIZE 256 + * + * uint8_t rx_data[MAX_RX_DATA_SIZE]; + * uint8_t rx_size = 0; + * + * rx_size = UART_get_rx( &g_uart, rx_data, sizeof(rx_data) ); + * @endcode + */ +size_t +UART_get_rx +( + UART_instance_t * this_uart, + uint8_t * rx_buffer, + size_t buff_size +); + +/***************************************************************************//** + * The function UART_polled_tx_string() is used to transmit a NULL ('\0') + * terminated string. Internally, it polls for the transmit ready status and + * transfers the text starting at the address pointed to by p_sz_string into + * the UART's hardware transmitter FIFO. It is a blocking function and returns + * only when the complete string has been transferred to the UART's transmit + * FIFO. + * + * Note: You cannot assume that the data you transmit using this function + * has been received at the other end by the time this function + * returns. The actual transmission over the serial connection will + * still be taking place at the time of the function return. + * + * @param this_uart The this_uart parameter is a pointer to a + * UART_instance_t structure which holds + * all data regarding this instance of the UART. + * @param p_sz_string The p_sz_string parameter is a pointer to a buffer + * containing the NULL ('\0') terminated string to be + * transmitted. + * @return This function does not return a value. + * + * Example: + * @code + * uint8_t testmsg1[] = {"\r\n\r\nUART_polled_tx_string() test message 1\0"}; + * UART_polled_tx_string(&g_uart,(const uint8_t *)&testmsg1); + * @endcode + */ +void +UART_polled_tx_string +( + UART_instance_t * this_uart, + const uint8_t * p_sz_string +); + +/***************************************************************************//** + * The UART_get_rx_status() function returns the receiver error status of the + * CoreUARTapb instance. It reads both the current error status of the receiver + * and the accumulated error status from preceding calls to the UART_get_rx() + * function and combines them using a bitwise OR. It returns the cumulative + * parity, framing and overflow error status of the receiver, since the + * previous call to UART_get_rx_status(), as an 8-bit encoded value. + * + * Note: The UART_get_rx() function reads and accumulates the receiver status + * of the CoreUARTapb instance before reading each byte from the + * receiver's data register/FIFO. The driver maintains a sticky record + * of the cumulative error status, which persists after the + * UART_get_rx() function returns. The UART_get_rx_status() function + * clears this accumulated record of receiver errors before returning. + * + * @param this_uart The this_uart parameter is a pointer to a UART_instance_t + * structure which holds all data regarding this instance + * of the UART. + * @return This function returns the UART receiver error status as + * an 8-bit encoded value. The returned value is 0 if no + * receiver errors occurred. The driver provides a set of + * bit mask constants which should be compared with and/or + * used to mask the returned value to determine the + * receiver error status. + * When the return value is compared to the following bit + * masks, a non-zero result indicates that the + * corresponding error occurred: + * UART_APB_PARITY_ERROR (bit mask = 0x01) + * UART_APB_OVERFLOW_ERROR (bit mask = 0x02) + * UART_APB_FRAMING_ERROR (bit mask = 0x04) + * When the return value is compared to the following bit + * mask, a non-zero result indicates that no error occurred: + * UART_APB_NO_ERROR (0x00) + * + * Example: + * @code + * UART_instance_t g_uart; + * uint8_t rx_data[MAX_RX_DATA_SIZE]; + * uint8_t err_status; + * err_status = UART_get_err_status(&g_uart); + * + * if(UART_APB_NO_ERROR == err_status ) + * { + * rx_size = UART_get_rx( &g_uart, rx_data, MAX_RX_DATA_SIZE ); + * } + * @endcode + */ +uint8_t +UART_get_rx_status +( + UART_instance_t * this_uart +); + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_UART_APB_H */ diff --git a/miv-rv32-udma/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h b/miv-rv32-udma/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h new file mode 100644 index 0000000..8651f0c --- /dev/null +++ b/miv-rv32-udma/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h @@ -0,0 +1,131 @@ +/******************************************************************************* + * (c) Copyright 2007-2021 Microchip FPGA Embedded Systems Solutions. + * + * @file coreuartapb_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreUARTapb register definitions + */ + +#ifndef __CORE_UART_APB_REGISTERS +#define __CORE_UART_APB_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * TxData register details + */ +#define TXDATA_REG_OFFSET 0x0u + +/* + * TxData bits. + */ +#define TXDATA_OFFSET 0x0u +#define TXDATA_MASK 0xFFu +#define TXDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * RxData register details + */ +#define RXDATA_REG_OFFSET 0x4u + +/* + * RxData bits. + */ +#define RXDATA_OFFSET 0x4u +#define RXDATA_MASK 0xFFu +#define RXDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * ControReg1 register details + */ +#define CTRL1_REG_OFFSET 0x8u + +/* + * Baud value (Lower 8-bits) + */ +#define CTRL1_BAUDVALUE_OFFSET 0x8u +#define CTRL1_BAUDVALUE_MASK 0xFFu +#define CTRL1_BAUDVALUE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * ControReg2 register details + */ +#define CTRL2_REG_OFFSET 0xCu + +/* + * Bit length + */ +#define CTRL2_BIT_LENGTH_OFFSET 0xCu +#define CTRL2_BIT_LENGTH_MASK 0x01u +#define CTRL2_BIT_LENGTH_SHIFT 0u + +/* + * Parity enable. + */ +#define CTRL2_PARITY_EN_OFFSET 0xCu +#define CTRL2_PARITY_EN_MASK 0x02u +#define CTRL2_PARITY_EN_SHIFT 1u + +/* + * Odd/even parity selection. + */ +#define CTRL2_ODD_EVEN_OFFSET 0xCu +#define CTRL2_ODD_EVEN_MASK 0x04u +#define CTRL2_ODD_EVEN_SHIFT 2u + +/* + * Baud value (Higher 5-bits) + */ +#define CTRL2_BAUDVALUE_OFFSET 0xCu +#define CTRL2_BAUDVALUE_MASK 0xF8u +#define CTRL2_BAUDVALUE_SHIFT 3u + +/*------------------------------------------------------------------------------ + * StatusReg register details + */ +#define StatusReg_REG_OFFSET 0x10u + +#define STATUS_REG_OFFSET 0x10u + +/* + * Transmit ready. + */ +#define STATUS_TXRDY_OFFSET 0x10u +#define STATUS_TXRDY_MASK 0x01u +#define STATUS_TXRDY_SHIFT 0u + +/* + * Receive full. + */ +#define STATUS_RXFULL_OFFSET 0x10u +#define STATUS_RXFULL_MASK 0x02u +#define STATUS_RXFULL_SHIFT 1u + +/* + * Parity error. + */ +#define STATUS_PARITYERR_OFFSET 0x10u +#define STATUS_PARITYERR_MASK 0x04u +#define STATUS_PARITYERR_SHIFT 2u + +/* + * Overflow. + */ +#define STATUS_OVERFLOW_OFFSET 0x10u +#define STATUS_OVERFLOW_MASK 0x08u +#define STATUS_OVERFLOW_SHIFT 3u + +/* + * Frame Error. + */ +#define STATUS_FRAMERR_OFFSET 0x10u +#define STATUS_FRAMERR_MASK 0x10u +#define STATUS_FRAMERR_SHIFT 4u + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_UART_APB_REGISTERS */ diff --git a/miv-rv32-udma/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c b/miv-rv32-udma/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c new file mode 100644 index 0000000..d57f2ae --- /dev/null +++ b/miv-rv32-udma/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c @@ -0,0 +1,107 @@ +/******************************************************************************* + * (c) Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * Mi-V uDMA Soft IP bare-metal driver. This module is delivered as part of + * Mi-V Extended Sub System(MIV_ESS) + */ + +#include "miv_udma_regs.h" +#include "miv_udma.h" + +/***************************************************************************//** + * MIV_uDMA_init() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_init +( + miv_udma_instance_t* this_udma, + addr_t base_addr +) +{ + /* Assign the Mi-V uDMA base address to the uDMA instance structure */ + this_udma->base_address = base_addr; +} + +/***************************************************************************//** + * MIV_uDMA_config() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_config +( + miv_udma_instance_t* this_udma, + addr_t src_addr, + addr_t dest_addr, + uint32_t transfer_size, + uint32_t irq_config +) +{ + /* Source memory start address */ + HAL_set_32bit_reg(this_udma->base_address, SRC_START_ADDR, src_addr); + + /* Destination memory start address */ + HAL_set_32bit_reg(this_udma->base_address, DEST_START_ADDR, dest_addr); + + /* Data transfer size */ + HAL_set_32bit_reg(this_udma->base_address, BLK_SIZE, transfer_size); + + /* Configure the uDMA IRQ */ + HAL_set_32bit_reg(this_udma->base_address, IRQ_CFG, irq_config); +} + +/***************************************************************************//** + * MIV_uDMA_start() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_start +( + miv_udma_instance_t* this_udma +) +{ + /* Start the uDMA transfer */ + HAL_set_32bit_reg(this_udma->base_address, CONTROL_SR, CTRL_START_TX_MASK); +} + +/***************************************************************************//** + * MIV_uDMA_reset() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_reset +( + miv_udma_instance_t* this_udma +) +{ + /* Toggle the uDMA_reset bit to reset the uDMA. + * Resetting the uDMA will clear all the configuration made by + * MIV_uDMA_config(). + * + * This function should be called from the interrupt handler to clear the + * IRQ. + */ + HAL_set_32bit_reg_field(this_udma->base_address, CTRL_RESET_TX, 0x1u); + HAL_set_32bit_reg_field(this_udma->base_address, CTRL_RESET_TX, 0x0u); +} + +/***************************************************************************//** + * MIV_uDMA_read_status() + * See "miv_udma.h" for details of how to use this function. + */ +uint32_t +MIV_uDMA_read_status +( + miv_udma_instance_t* this_udma +) +{ + uint32_t status = 0u; + + /* Read the status of the uDMA transfer. + * The transfer status register can be Error or Busy depending on the + * current uDMA transfer. + */ + status = HAL_get_32bit_reg(this_udma->base_address, TX_STATUS); + + return status; +} diff --git a/miv-rv32-udma/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h b/miv-rv32-udma/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h new file mode 100644 index 0000000..c4e7f3c --- /dev/null +++ b/miv-rv32-udma/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h @@ -0,0 +1,289 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * uDMA module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(MIV_ESS). + */ + +/*=========================================================================*//** + @mainpage Mi-V uDMA Bare Metal Driver. + The Mi-V uDMA bare metal software driver. + + @section intro_sec Introduction + The Mi-V uDMA driver provides a set of functions to control the Mi-V uDMA + module in the Mi-V Extended Sub System(MIV_ESS) soft-IP. The Mi-V uDMA module + allows peripherals with AHB interfaces to transfer data independently of the + MIV_RV32 RISC-V processor. + + The major features provided by the Mi-V uDMA driver are: + - Initialization and configuration + - Start and reset the transaction + + This driver can be used as part of a bare metal system where no operating + system is available. The driver can be adapted for use as part of an + operating system, but the implementation of the adaptation layer between the + driver and the operating system's driver model is outside the scope of this + driver. + + @section hw_dependencies Hardware Flow Dependency + The application software should initialize and configure the Mi-V uDMA through + the call to MIV_uDMA_init(), MIV_uDMA_config() function for Mi-V uDMA + instance in the design. + The μDMA can operate in two possible transfer configurations: + + AHBL Read –> AHBL Write: + In this configuration, the μDMA reads data from the source memory over an + AHBL (Mirrored Main/Initiator) read interface and writes data to the + destination memory over an AHBL (Mirrored Main/Initiator) write interface. + + AHBL Read –> TAS Write: + In this configuration, the μDMA reads data from the source memory over an + AHBL (Mirrored Main/Initiator) read interface and writes data to the + destination memory over the TAS (Mirrored Main/Initiator) write interface. + + The AHBL Read -> TAS Write configuration is out of scope for this driver. + + @section theory_op Theory of Operation + The uDMA module in the Mi-V Extended Sub System(MIV_ESS) is a single channel + uDMA module that allows peripherals to perform read write operations between + source and destination memory. The Mi-V uDMA driver is generally used in + interrupt driven mode and uses the Mi-V uDMA IRQ signal to drive the + interrupt service routine(ISR) which signifies a transfer has completed. + The status is checked in the ISR to ensure the transfer is completed + successfully. + The reset operation in the ISR will reset the Mi-V uDMA controller. + Once the Mi-V uDMA transfer completes, Mi-V uDMA retires. To + initiate another transaction, Mi-V uDMA will have to be configured again. + + The operation of the Mi-V uDMA driver can be divided into following + categories: + - Initialization + - Configuration + - Start and reset transfer + + ### Initialization and configuration + Mi-V uDMA is first initialized by a call to MIV_uDMA_init(). This function + initializes the instance of Mi-V uDMA with base address. The MIV_uDMA_init() + function must be called before calling any other Mi-V uDMA driver functions. + + The Mi-V uDMA is configured by a call to MIV_uDMA_config(). This function + will configure the source_addr and dest_addr registers of the Mi-V uDMA with + source and destination addresses for Mi-V uDMA transfers. + This function also configures the transfer size and interrupt preference for + successful transfer of Mi-V uDMA. + + ### Start and Reset transfer + Once the Mi-V uDMA is configured, the transfers can be started with a call to + MIV_uDMA_start(). Once the Mi-V uDMA transfer is started, it can not be + aborted and the status of the transfer should be read from the ISR by a call + to MIV_uDMA_read_status(). + + The Mi-V uDMA can be reset to the default state by calling MIV_uDMA_reset() + function. After performing reset operation, the Mi-V uDMA should be + re-configured to perform transfer since MIV_uDMA_reset() resets the Mi-V uDMA + controller. + */ + +#ifndef MIV_uDMA_H_ +#define MIV_uDMA_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#include "hal/cpu_types.h" + +#else +#include "hal.h" +#include "cpu_types.h" +#endif + +/*-------------------------------------------------------------------------*//** + MIV_uDMA_CTRL_IRQ_CONFIG + ===================== + + The MIV_uDMA_CTRL_IRQ_CONFIG macro is used to assert the uDMA IRQ when an error + occurs during a uDMA transfer or on the completion of a uDMA transfer. + */ +#define MIV_uDMA_CTRL_IRQ_CONFIG 1u + +/*-------------------------------------------------------------------------*//** + MIV_uDMA_STATUS_BUSY + ===================== + + The MIV_uDMA_STATUS_BUSY macro is used to indicate that the uDMA transfer is + in progress. + */ +#define MIV_uDMA_STATUS_BUSY 1u + +/*-------------------------------------------------------------------------*//** + MIV_uDMA_STATUS_ERROR + ===================== + + The MIV_uDMA_STATUS_ERROR macro is used to indicate that the last uDMA + transfer has caused an error. + */ +#define MIV_uDMA_STATUS_ERROR 2u + +/***************************************************************************//** + * Mi-V uDMA instant structure. + * This structure will hold the base of Mi-V uDMA module which is used in the + * other functions in the driver to access the uDMA registers. + */ +typedef struct miv_udma_instance +{ + addr_t base_address; +} miv_udma_instance_t; + +/***************************************************************************//** + * The MIV_uDMA_init() assigns the base address of Mi-V uDMA module to the + * uDMA instance structure. + * This address is used in later part of the driver to access the uDMA registers. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure. + * + * @param base_addr + * Base address of the Mi-V uDMA module. + * + * @return + * This function does not return a value. + */ +void +MIV_uDMA_init +( + miv_udma_instance_t* this_udma, + addr_t base_addr +); + +/***************************************************************************//** + * The MIV_uDMA_config() is used to configure the Mi-V uDMA controller. + * This function will set the source address, destination address, block size + * and IRQ config register. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure which + * holds the base address of Mi-V uDMA module. + * + * @param base_addr + * Base address of the Mi-V uDMA + * + * @param src_addr + * Source address of memory from which the uDMA will read the data. + * + * @param dest_addr + * Destination address where the data will be written from src_addr. + * + * @param transfer_size + * Number of 32-bit words to transfer + * + * @param irq_config + * uDMA IRQ Configuration. + * + * When set, the IRQ is asserted when and error occurs during a uDMA + * transfer or on the completion of the uDMA transfer. + * + * When clear, the IRQ is only asserted when an error occurs during a uDMA + * transfer. + * + * @return + * This function does not return any value. + */ +void +MIV_uDMA_config +( + miv_udma_instance_t* this_udma, + addr_t src_addr, + addr_t dest_addr, + uint32_t transfer_size, + uint32_t irq_config +); + +/***************************************************************************//** + * The MIV_uDMA_start() is used to start the uDMA transfer. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure which + * holds the base address of Mi-V uDMA module. + * + * @return + * This function does not return any value. + */ +void +MIV_uDMA_start +( + miv_udma_instance_t* this_udma +); + +/***************************************************************************//** + * The MIV_uDMA_reset() is used to clear the uDMA interrupt and reset the uDMA + * transfer. + * + * This function should be called from interrupt handler and it will reset the + * values set during MIV_uDMA_config(). + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure which + * holds the base address of Mi-V uDMA module. + * + * @return + * This function does not return any value. + */ +void +MIV_uDMA_reset +( + miv_udma_instance_t* this_udma +); + +/***************************************************************************//** + * The MIV_uDMA_read_status() will be used to status of the uDMA transfer. When + * Interrupt is enabled this function can be called from the interrupt handler + * to know the reason of uDMA interrupt. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure which + * holds the base address of Mi-V uDMA module. + * + * @return + * Return value will indicate error of busy status of the uDMA channel. + * + * |Bit Number| Name | Description | + * |----------|---------|------------------------------------------------------| + * | 0 | Busy | When set indicates that uDMA transfer is in progress| + * | 1 | Error | When set indicates that last uDMA transfer caused an| + * | | | error. | + */ +uint32_t +MIV_uDMA_read_status +( + miv_udma_instance_t* this_pdma +); + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_uDMA_H_ */ diff --git a/miv-rv32-udma/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h b/miv-rv32-udma/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h new file mode 100644 index 0000000..14d0759 --- /dev/null +++ b/miv-rv32-udma/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h @@ -0,0 +1,94 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP uDMA module driver. This module is delivered as a part of Mi-V + * extended Sub-System(ESS) MIV_ESS. + */ + +#ifndef MIV_UDMA_APB_REGISTERS +#define MIV_UDMA_APB_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/**************************************************************************//** + * Control start/Reset register details + */ + +#define CONTROL_SR_REG_OFFSET 0x0u + +/* Control start/Reset register bits */ +#define CONTROL_SR_OFFSET 0x00u +#define CONTROL_SR_MASK 0x03u +#define CONTROL_SR_SHIFT 0u + +/* uDMA Control Start Transfer */ + +#define CTRL_START_TX_OFFSET 0x00u +#define CTRL_START_TX_MASK 0x01u +#define CTRL_START_TX_SHIFT 0u + +/* uDMA Control Reset Transfer */ +#define CTRL_RESET_TX_OFFSET 0x00u +#define CTRL_RESET_TX_MASK 0x02u +#define CTRL_RESET_TX_SHIFT 1u + +/**************************************************************************//** + * IRQ Configuration register details + */ +#define IRQ_CFG_REG_OFFSET 0x4u + +/* Control start/Reset register bits */ +#define IRQ_CFG_OFFSET 0x04u +#define IRQ_CFG_MASK 0x01u +#define IRQ_CFG_SHIFT 0u + +/***************************************************************************//** + * Transfer Status register details + */ +#define TX_STATUS_REG_OFFSET 0x08u + +/* Transfer status register bits */ +#define TX_STATUS_OFFSET 0x08u +#define TX_STATUS_MASK 0x03u +#define TX_STATUS_SHIFT 0u + +/***************************************************************************//** + * Source Memory Start Address Register + */ +#define SRC_START_ADDR_REG_OFFSET 0x0cu + +/* Source Memory Start Address Register bits */ +#define SRC_START_ADDR_OFFSET 0x0cu +#define SRC_START_ADDR_MASK 0xFFFFFFFFu +#define SRC_START_ADDR_SHIFT 0u + +/***************************************************************************//** + * Destination Memory Start Address register details + */ +#define DEST_START_ADDR_REG_OFFSET 0x10u + +/* Destination Memory Start Address register bits */ +#define DEST_START_ADDR_OFFSET 0x10u +#define DEST_START_ADDR_MASK 0xFFFFFFFFu +#define DEST_START_ADDR_SHIFT 0x0u + +/***************************************************************************//** + * Block Size register details + */ +#define BLK_SIZE_REG_OFFSET 0x14u + +/* Destination Memory Start Address register bits */ +#define BLK_SIZE_OFFSET 0x14u +#define BLK_SIZE_MASK 0xFFFFFFFFu +#define BLK_SIZE_SHIFT 0x0u + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_UDMA_APB_REGISTERS */ diff --git a/miv-rv32-udma/src/platform/hal/cpu_types.h b/miv-rv32-udma/src/platform/hal/cpu_types.h new file mode 100644 index 0000000..ef8ab20 --- /dev/null +++ b/miv-rv32-udma/src/platform/hal/cpu_types.h @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file cpu_types.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Type definitions which can be commonly used by the fabric-ip drivers. + * + */ +#ifndef __CPU_TYPES_H +#define __CPU_TYPES_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned int size_t; + +/*------------------------------------------------------------------------------ + * addr_t: address type. + * Used to specify the address of peripherals present in the processor's memory + * map. + */ +typedef unsigned int addr_t; + +/*------------------------------------------------------------------------------ + * psr_t: processor state register. + * Used by HAL_disable_interrupts() and HAL_restore_interrupts() to store the + * processor's state between disabling and restoring interrupts. + */ +typedef unsigned int psr_t; + +#ifdef __cplusplus +} +#endif + +#endif /* CPU_TYPES_H */ + diff --git a/miv-rv32-udma/src/platform/hal/hal.h b/miv-rv32-udma/src/platform/hal/hal.h new file mode 100644 index 0000000..7eec17a --- /dev/null +++ b/miv-rv32-udma/src/platform/hal/hal.h @@ -0,0 +1,235 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file hal.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware abstraction layer functions for peripheral register accesses. + * + */ +#ifndef __HAL_H +#define __HAL_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include "cpu_types.h" +#include "hw_reg_access.h" +#include "hal_assert.h" +/***************************************************************************//** + * Enable all interrupts at the processor level. + */ +void HAL_enable_interrupts( void ); + +/***************************************************************************//** + * Disable all interrupts at the processor core level. + * Return the interrupts enable state before disabling occurred so that it can + * later be restored. + */ +psr_t HAL_disable_interrupts( void ); + +/***************************************************************************//** + * Restore the interrupts enable state at the processor core level. + * This function is normally passed the value returned from a previous call to + * HAL_disable_interrupts(). + */ +void HAL_restore_interrupts( psr_t saved_psr ); + +/***************************************************************************//** + */ +#define FIELD_OFFSET(FIELD_NAME) (FIELD_NAME##_OFFSET) +#define FIELD_SHIFT(FIELD_NAME) (FIELD_NAME##_SHIFT) +#define FIELD_MASK(FIELD_NAME) (FIELD_NAME##_MASK) + +/***************************************************************************//** + * The macro HAL_set_32bit_reg() allows writing a 32 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint32_t containing the value to write. + */ +#define HAL_set_32bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_32bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_32bit_reg() is used to read the value of a 32 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint32_t value. + */ +#define HAL_get_32bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_32bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)) )) + +/***************************************************************************//** + * The macro HAL_set_32bit_reg_field() is used to write a field within a + * 32 bits wide register. The field written can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * VALUE: A variable of type uint32_t containing the field value to write. + */ +#define HAL_set_32bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_32bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_32bit_reg_field() is used to read a register field from + * within a 32 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint32_t value. + */ +#define HAL_get_32bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_32bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +/***************************************************************************//** + * The macro HAL_set_16bit_reg() allows writing a 16 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint_fast16_t containing the value to write. + */ +#define HAL_set_16bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_16bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_16bit_reg() is used to read the value of a 16 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint16_t value. + */ +#define HAL_get_16bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_16bit_reg( (BASE_ADDR) + (REG_NAME##_REG_OFFSET) )) + +/***************************************************************************//** + * The macro HAL_set_16bit_reg_field() is used to write a field within a + * 16 bits wide register. The field written can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * VALUE: A variable of type uint16_t containing the field value to write. + */ +#define HAL_set_16bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_16bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_16bit_reg_field() is used to read a register field from + * within a 8 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint16_t value. + */ +#define HAL_get_16bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_16bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +/***************************************************************************//** + * The macro HAL_set_8bit_reg() allows writing a 8 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint_fast8_t containing the value to write. + */ +#define HAL_set_8bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_8bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_8bit_reg() is used to read the value of a 8 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint8_t value. + */ +#define HAL_get_8bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_8bit_reg( (BASE_ADDR) + (REG_NAME##_REG_OFFSET) )) + +/***************************************************************************//** + */ +#define HAL_set_8bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_8bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_8bit_reg_field() is used to read a register field from + * within a 8 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint8_t value. + */ +#define HAL_get_8bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_8bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +#ifdef __cplusplus +} +#endif + +#endif /*HAL_H*/ + diff --git a/miv-rv32-udma/src/platform/hal/hal_assert.h b/miv-rv32-udma/src/platform/hal/hal_assert.h new file mode 100644 index 0000000..8e0c747 --- /dev/null +++ b/miv-rv32-udma/src/platform/hal/hal_assert.h @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright 2019-2021 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hal_assert.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief HAL assert functions + */ +#ifndef __HAL_ASSERT_HEADER +#define __HAL_ASSERT_HEADER 1 +#define NDEBUG 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Disable assertions if we do not recognize the compiler. */ +#if defined ( __GNUC__ ) +#if defined(NDEBUG) +/***************************************************************************//** + * HAL_ASSERT() is defined out when the NDEBUG symbol is used. + ******************************************************************************/ +#define HAL_ASSERT(CHECK) + +#else + +/***************************************************************************//** + * Default behavior for HAL_ASSERT() macro: + *------------------------------------------------------------------------------ + The behavior is toolchain specific and project setting specific. + ******************************************************************************/ +#define HAL_ASSERT(CHECK)\ + do { \ + if (!(CHECK)) \ + { \ + __asm__ volatile ("ebreak"); \ + }\ + } while(0); + +#endif /* NDEBUG */ +#endif /*__GNUC__*/ + +#ifdef __cplusplus +} +#endif +#endif /* __HAL_ASSERT_HEADER */ + diff --git a/miv-rv32-udma/src/platform/hal/hal_irq.c b/miv-rv32-udma/src/platform/hal/hal_irq.c new file mode 100644 index 0000000..6fe7fce --- /dev/null +++ b/miv-rv32-udma/src/platform/hal/hal_irq.c @@ -0,0 +1,45 @@ +/***************************************************************************//** + * Copyright 2019-2021 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hal_irq.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Legacy interrupt control functions for the Microchip driver library + * hardware abstraction layer. + * + */ +#include "hal.h" +#include "miv_rv32_hal/miv_rv32_hal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * + */ +void HAL_enable_interrupts(void) { + MRV_enable_interrupts(); +} + +/*------------------------------------------------------------------------------ + * + */ +psr_t HAL_disable_interrupts(void) { + psr_t psr; + psr = read_csr(mstatus); + MRV_disable_interrupts(); + return(psr); +} + +/*------------------------------------------------------------------------------ + * + */ +void HAL_restore_interrupts(psr_t saved_psr) { + write_csr(mstatus, saved_psr); +} + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/miv-rv32-udma/src/platform/hal/hw_macros.h b/miv-rv32-udma/src/platform/hal/hw_macros.h new file mode 100644 index 0000000..ed2c681 --- /dev/null +++ b/miv-rv32-udma/src/platform/hal/hw_macros.h @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright 2019-2021 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hw_macros.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware registers access macros. + * + * THE MACROS DEFINED IN THIS FILE ARE DEPRECATED. DO NOT USE FOR NEW + * DEVELOPMENT. + * + * These macros are used to access peripheral registers. They allow access to + * 8, 16 and 32 bit wide registers. All accesses to peripheral registers should + * be done through these macros in order to ease porting across different + * processors/bus architectures. + * + * Some of these macros also allow access to a specific register field. + * + */ +#ifndef __HW_REGISTER_MACROS_H +#define __HW_REGISTER_MACROS_H 1 +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * 32 bits registers access: + */ +#define HW_get_uint32_reg(BASE_ADDR, REG_OFFSET) (*((uint32_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint32_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint32_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint32_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint32_t) \ + ( \ + (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint32_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint32_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 32 bits memory access: + */ +#define HW_get_uint32(BASE_ADDR) (*((uint32_t volatile *)(BASE_ADDR))) + +#define HW_set_uint32(BASE_ADDR, VALUE) (*((uint32_t volatile *)(BASE_ADDR)) = (VALUE)) + +/*------------------------------------------------------------------------------ + * 16 bits registers access: + */ +#define HW_get_uint16_reg(BASE_ADDR, REG_OFFSET) (*((uint16_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint16_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint16_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint16_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint16_t) \ + ( \ + (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint16_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint16_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 8 bits registers access: + */ +#define HW_get_uint8_reg(BASE_ADDR, REG_OFFSET) (*((uint8_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint8_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint8_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint8_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint8_t) \ + ( \ + (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint8_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint8_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 8 bits memory access: + */ +#define HW_get_uint8(BASE_ADDR) (*((uint8_t volatile *)(BASE_ADDR))) + +#define HW_set_uint8(BASE_ADDR, VALUE) (*((uint8_t volatile *)(BASE_ADDR)) = (VALUE)) + +#ifdef __cplusplus +extern "C" { +#endif + +#endif /* __HW_REGISTER_MACROS_H */ + diff --git a/miv-rv32-udma/src/platform/hal/hw_reg_access.S b/miv-rv32-udma/src/platform/hal/hw_reg_access.S new file mode 100644 index 0000000..f4aa0a0 --- /dev/null +++ b/miv-rv32-udma/src/platform/hal/hw_reg_access.S @@ -0,0 +1,215 @@ +/***************************************************************************//** + * Copyright 2019-2021 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hw_reg_access.S + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware registers access functions. + * The implementation of these function is platform and toolchain specific. + * The functions declared here are implemented using assembler as part of the + * processor/toolchain specific HAL. This implementation is for the combination + * of the 32 bit RISC-V processors and GNU tool chain. + * + */ + +.section .text + .globl HW_set_32bit_reg + .globl HW_get_32bit_reg + .globl HW_set_32bit_reg_field + .globl HW_get_32bit_reg_field + .globl HW_set_16bit_reg + .globl HW_get_16bit_reg + .globl HW_set_16bit_reg_field + .globl HW_get_16bit_reg_field + .globl HW_set_8bit_reg + .globl HW_get_8bit_reg + .globl HW_set_8bit_reg_field + .globl HW_get_8bit_reg_field + + +/***************************************************************************//** + * HW_set_32bit_reg is used to write the content of a 32 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint32_t value + */ +HW_set_32bit_reg: + sw a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_32bit_reg is used to read the content of a 32 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + + * @return 32 bits value read from the peripheral register. + */ +HW_get_32bit_reg: + lw a0, 0(a0) + ret + +/***************************************************************************//** + * HW_set_32bit_reg_field is used to set the content of a field in a 32 bits + * wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint32_t mask + * a3: uint32_t value + */ +HW_set_32bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lw t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sw t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_32bit_reg_field is used to read the content of a field out of a + * 32 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint32_t mask + * + * @return 32 bits value containing the register field value specified + * as parameter. + */ +HW_get_32bit_reg_field: + lw a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +/***************************************************************************//** + * HW_set_16bit_reg is used to write the content of a 16 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint_fast16_t value + */ +HW_set_16bit_reg: + sh a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_16bit_reg is used to read the content of a 16 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + + * @return 16 bits value read from the peripheral register. + */ +HW_get_16bit_reg: + lh a0, (a0) + ret + +/***************************************************************************//** + * HW_set_16bit_reg_field is used to set the content of a field in a 16 bits + * wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast16_t mask + * a3: uint_fast16_t value + * @param value Value to be written in the specified field. + */ +HW_set_16bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lh t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sh t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_16bit_reg_field is used to read the content of a field from a + * 16 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast16_t mask + * + * @return 16 bits value containing the register field value specified + * as parameter. + */ +HW_get_16bit_reg_field: + lh a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +/***************************************************************************//** + * HW_set_8bit_reg is used to write the content of a 8 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint_fast8_t value + */ +HW_set_8bit_reg: + sb a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_8bit_reg is used to read the content of a 8 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + + * @return 8 bits value read from the peripheral register. + */ +HW_get_8bit_reg: + lb a0, 0(a0) + ret + +/***************************************************************************//** + * HW_set_8bit_reg_field is used to set the content of a field in a 8 bits + * wide peripheral register. + * + * a0: addr_t reg_addr, + * a1: int_fast8_t shift + * a2: uint_fast8_t mask + * a3: uint_fast8_t value + */ +HW_set_8bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lb t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sb t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_8bit_reg_field is used to read the content of a field from a + * 8 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast8_t mask + * + * @return 8 bits value containing the register field value specified + * as parameter. + */ +HW_get_8bit_reg_field: + lb a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +.end diff --git a/miv-rv32-udma/src/platform/hal/hw_reg_access.h b/miv-rv32-udma/src/platform/hal/hw_reg_access.h new file mode 100644 index 0000000..1f6a551 --- /dev/null +++ b/miv-rv32-udma/src/platform/hal/hw_reg_access.h @@ -0,0 +1,239 @@ +/***************************************************************************//** + * Copyright 2019-2021 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hw_reg_access.S + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware registers access functions. + * The implementation of these function is platform and tool-chain specific. + * The functions declared here are implemented using assembler as part of the + * processor/tool-chain specific HAL. This implementation is for the combination + * of the 32 bit RISC-V processors and GNU tool chain. + * + */ +#ifndef __HW_REG_ACCESS +#define __HW_REG_ACCESS +#ifdef __cplusplus +extern "C" { +#endif + +#include "cpu_types.h" +/***************************************************************************//** + * HW_set_32bit_reg is used to write the content of a 32 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_32bit_reg +( + addr_t reg_addr, + uint32_t value +); + +/***************************************************************************//** + * HW_get_32bit_reg is used to read the content of a 32 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 32 bits value read from the peripheral register. + */ +uint32_t +HW_get_32bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_32bit_reg_field is used to set the content of a field in a 32 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void +HW_set_32bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint32_t mask, + uint32_t value +); + +/***************************************************************************//** + * HW_get_32bit_reg_field is used to read the content of a field out of a + * 32 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 32 bits value containing the register field value specified + * as parameter. + */ +uint32_t +HW_get_32bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint32_t mask +); + +/***************************************************************************//** + * HW_set_16bit_reg is used to write the content of a 16 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_16bit_reg +( + addr_t reg_addr, + uint_fast16_t value +); + +/***************************************************************************//** + * HW_get_16bit_reg is used to read the content of a 16 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 16 bits value read from the peripheral register. + */ +uint16_t +HW_get_16bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_16bit_reg_field is used to set the content of a field in a 16 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void HW_set_16bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast16_t mask, + uint_fast16_t value +); + +/***************************************************************************//** + * HW_get_16bit_reg_field is used to read the content of a field from a + * 16 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 16 bits value containing the register field value specified + * as parameter. + */ +uint16_t HW_get_16bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast16_t mask +); + +/***************************************************************************//** + * HW_set_8bit_reg is used to write the content of a 8 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_8bit_reg +( + addr_t reg_addr, + uint_fast8_t value +); + +/***************************************************************************//** + * HW_get_8bit_reg is used to read the content of a 8 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 8 bits value read from the peripheral register. + */ +uint8_t +HW_get_8bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_8bit_reg_field is used to set the content of a field in a 8 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void HW_set_8bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast8_t mask, + uint_fast8_t value +); + +/***************************************************************************//** + * HW_get_8bit_reg_field is used to read the content of a field from a + * 8 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 8 bits value containing the register field value specified + * as parameter. + */ +uint8_t HW_get_8bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast8_t mask +); + +#ifdef __cplusplus +} +#endif + +#endif /* __HW_REG_ACCESS */ + diff --git a/miv-rv32-udma/src/platform/hal/readme.md b/miv-rv32-udma/src/platform/hal/readme.md new file mode 100644 index 0000000..c756b34 --- /dev/null +++ b/miv-rv32-udma/src/platform/hal/readme.md @@ -0,0 +1,38 @@ +# hal folder + + +The HAL folder hardware abstraction for the bare metal drivers for the fabric +IP cores. The HAL folder contains files using a combination of C and assembly +source code. This layer allows the fabric ip drivers to be used with any of the +soft processors or the MSS hardened processors. + +The hal folder should be included in a your project under the platform directory. +See location in the drawing below. + +The hal folder contains: + +* register access functions +* assert macros + +### Project directory strucutre, showing where hal folder sits. + + +---------+ +-----------+ + | src +----->|application| + +---------+ | +-----------+ + | + | +-----------+ + +-->|middleware | + | +-----------+ + | + | +-----------+ +---------+ + +-->|platform +---->|drivers | + +-----------+ | +---------+ + | + | +---------+ + +->|hal | + | +---------+ + | + | +---------+ + +->|mpfs_hal | + +---------+ + \ No newline at end of file diff --git a/miv-rv32-udma/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld b/miv-rv32-udma/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld new file mode 100644 index 0000000..19df5fb --- /dev/null +++ b/miv-rv32-udma/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld @@ -0,0 +1,154 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-execute-in-place.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * image executing from a one address space whereas the data, sdata and stack + * sections are placed in another address space. This could be used in cases such + * as: + * 1) When using MIV_RV32, the reset vector points to the LSRAM at address + * 0x80000000 and the data, sdata, bss and stack sections are placed in the + * TCM region. + * + * 2) Executing from a Non Volatile memory. The actual memory will depend on + * the FPGA platform. For exameple, it could be the eNVM on SmartFusion2, + * Igloo2 or on-board non-volatile memory which supports code execution. + * + * NOTE: Modify the memory section addresses and the sizes according to your + * Libero design. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + + +MEMORY +{ + rom (rx) : ORIGIN = 0x80000000, LENGTH = 16k + ram (rwx) : ORIGIN = 0x80004000, LENGTH = 16k +} + +STACK_SIZE = 1k; /* needs to be calculated for your application */ +HEAP_SIZE = 0; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > rom + + .text : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.text.entry))) + . = ALIGN(0x10); + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } >rom + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } >ram AT>rom + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } >ram AT>rom + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram +} + diff --git a/miv-rv32-udma/src/platform/miv_rv32_hal/miv-rv32-ram.ld b/miv-rv32-udma/src/platform/miv_rv32_hal/miv-rv32-ram.ld new file mode 100644 index 0000000..e0707df --- /dev/null +++ b/miv-rv32-udma/src/platform/miv_rv32_hal/miv-rv32-ram.ld @@ -0,0 +1,150 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-ram.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * debug image executing in SRAM. + * + * This linker script assumes that a RAM is connected at on Mi-V soft processor + * memory space pointed by the reset vector address. + * + * NOTE : Modify the memory section address and the size according to your + * Libero design. + * For example: + * 1) If you want to download and step debug at a different RAM memory address in + * your design (For example TCM base address) than the one provided in this file. + * 2) The MIV_RV32, when used with MIV_ESS IP, provides ways to copy the executable + * HEX file from external Non-Volatile memory into the TCM at reset. In this + * case your executable must be linked to the TCM address. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +MEMORY +{ + ram (rwx) : ORIGIN = 0x80000000, LENGTH = 32k +} + +STACK_SIZE = 2k; /* needs to be calculated for your application */ +HEAP_SIZE = 0k; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > ram + + .text : ALIGN(0x10) + { + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } > ram + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } > ram + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } > ram + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram +} + diff --git a/miv-rv32-udma/src/platform/miv_rv32_hal/miv_rv32_entry.S b/miv-rv32-udma/src/platform/miv_rv32_hal/miv_rv32_entry.S new file mode 100644 index 0000000..a19a813 --- /dev/null +++ b/miv-rv32-udma/src/platform/miv_rv32_hal/miv_rv32_entry.S @@ -0,0 +1,821 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_entry.S + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor vectors, trap handling and startup code. + * + */ +#ifndef ENTRY_S +#define ENTRY_S + +#define A_EXTENSION_MASK 0x00000001u +#define MTVEC_MODE_BIT_MASK 0x00000003u +#define MTVEC_VECTORED_MODE_VAL 0x00000001u + +#if __riscv_xlen == 64 +# define LREG ld +# define SREG sd +# define REGBYTES 8 +#else +# define LREG lw +# define SREG sw +# define REGBYTES 4 +#endif + + .section .entry, "ax" + .globl _start + +_start: + j handle_reset + +/* Some of the Mi-V soft IP cores support compressed 'C' extension. If the Mi-V + core in your design doesn't support 'C' extension and you enable 'C' extension + in firmware project compiler options, then it would result in a trap. For this + case, we are avoiding compressed instruction here so you can put a breakpoint + at the jump and you can at least look at mcause, mepc and get some hints + about the crash. */ +trap_entry: +.option push +.option norvc +j generic_trap_handler +.option pop + .word 0 + .word 0 + +sw_trap_entry: + j vector_sw_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + +tmr_trap_entry: + j vector_tmr_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + +ext_trap_entry: + j vector_ext_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + .word 0 + +#ifndef MIV_LEGACY_RV32 +MGEUI_trap_entry: + j vector_MGEUI_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MGECI_trap_entry: + j vector_MGECI_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + +MSYS_EI0_trap_entry: + j vector_MSYS_EI0_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_EI1_trap_entry: + j vector_MSYS_EI1_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_EI2_trap_entry: + j vector_MSYS_EI2_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_EI3_trap_entry: + j vector_MSYS_EI3_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_EI4_trap_entry: + j vector_MSYS_EI4_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_EI5_trap_entry: + j vector_MSYS_EI5_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +#ifdef __riscv_compressed + .2byte 0 +#endif + +OPSRV_trap_entry: + j vector_OPSRV_IRQHandler +#endif /* MIV_LEGACY_RV32 */ + +.align 4 +generic_trap_handler: + addi sp, sp, -32*REGBYTES +.align 4 + SREG x1, 0 * REGBYTES(sp) + SREG x2, 1 * REGBYTES(sp) + SREG x3, 2 * REGBYTES(sp) + SREG x4, 3 * REGBYTES(sp) + SREG x5, 4 * REGBYTES(sp) + SREG x6, 5 * REGBYTES(sp) + SREG x7, 6 * REGBYTES(sp) + SREG x8, 7 * REGBYTES(sp) + SREG x9, 8 * REGBYTES(sp) + SREG x10, 9 * REGBYTES(sp) + SREG x11, 10 * REGBYTES(sp) + SREG x12, 11 * REGBYTES(sp) + SREG x13, 12 * REGBYTES(sp) + SREG x14, 13 * REGBYTES(sp) + SREG x15, 14 * REGBYTES(sp) + SREG x16, 15 * REGBYTES(sp) + SREG x17, 16 * REGBYTES(sp) + SREG x18, 17 * REGBYTES(sp) + SREG x19, 18 * REGBYTES(sp) + SREG x20, 19 * REGBYTES(sp) + SREG x21, 20 * REGBYTES(sp) + SREG x22, 21 * REGBYTES(sp) + SREG x23, 22 * REGBYTES(sp) + SREG x24, 23 * REGBYTES(sp) + SREG x25, 24 * REGBYTES(sp) + SREG x26, 25 * REGBYTES(sp) + SREG x27, 26 * REGBYTES(sp) + SREG x28, 27 * REGBYTES(sp) + SREG x29, 28 * REGBYTES(sp) + SREG x30, 29 * REGBYTES(sp) + SREG x31, 30 * REGBYTES(sp) + + csrr a0, mcause + csrr a1, mepc + jal handle_trap + j generic_restore + +vector_sw_trap_handler: + addi sp, sp, -32*REGBYTES + + SREG x1, 0 * REGBYTES(sp) + SREG x2, 1 * REGBYTES(sp) + SREG x3, 2 * REGBYTES(sp) + SREG x4, 3 * REGBYTES(sp) + SREG x5, 4 * REGBYTES(sp) + SREG x6, 5 * REGBYTES(sp) + SREG x7, 6 * REGBYTES(sp) + SREG x8, 7 * REGBYTES(sp) + SREG x9, 8 * REGBYTES(sp) + SREG x10, 9 * REGBYTES(sp) + SREG x11, 10 * REGBYTES(sp) + SREG x12, 11 * REGBYTES(sp) + SREG x13, 12 * REGBYTES(sp) + SREG x14, 13 * REGBYTES(sp) + SREG x15, 14 * REGBYTES(sp) + SREG x16, 15 * REGBYTES(sp) + SREG x17, 16 * REGBYTES(sp) + SREG x18, 17 * REGBYTES(sp) + SREG x19, 18 * REGBYTES(sp) + SREG x20, 19 * REGBYTES(sp) + SREG x21, 20 * REGBYTES(sp) + SREG x22, 21 * REGBYTES(sp) + SREG x23, 22 * REGBYTES(sp) + SREG x24, 23 * REGBYTES(sp) + SREG x25, 24 * REGBYTES(sp) + SREG x26, 25 * REGBYTES(sp) + SREG x27, 26 * REGBYTES(sp) + SREG x28, 27 * REGBYTES(sp) + SREG x29, 28 * REGBYTES(sp) + SREG x30, 29 * REGBYTES(sp) + SREG x31, 30 * REGBYTES(sp) + + jal handle_m_soft_interrupt + j generic_restore + +vector_tmr_trap_handler: + addi sp, sp, -32*REGBYTES + + SREG x1, 0 * REGBYTES(sp) + SREG x2, 1 * REGBYTES(sp) + SREG x3, 2 * REGBYTES(sp) + SREG x4, 3 * REGBYTES(sp) + SREG x5, 4 * REGBYTES(sp) + SREG x6, 5 * REGBYTES(sp) + SREG x7, 6 * REGBYTES(sp) + SREG x8, 7 * REGBYTES(sp) + SREG x9, 8 * REGBYTES(sp) + SREG x10, 9 * REGBYTES(sp) + SREG x11, 10 * REGBYTES(sp) + SREG x12, 11 * REGBYTES(sp) + SREG x13, 12 * REGBYTES(sp) + SREG x14, 13 * REGBYTES(sp) + SREG x15, 14 * REGBYTES(sp) + SREG x16, 15 * REGBYTES(sp) + SREG x17, 16 * REGBYTES(sp) + SREG x18, 17 * REGBYTES(sp) + SREG x19, 18 * REGBYTES(sp) + SREG x20, 19 * REGBYTES(sp) + SREG x21, 20 * REGBYTES(sp) + SREG x22, 21 * REGBYTES(sp) + SREG x23, 22 * REGBYTES(sp) + SREG x24, 23 * REGBYTES(sp) + SREG x25, 24 * REGBYTES(sp) + SREG x26, 25 * REGBYTES(sp) + SREG x27, 26 * REGBYTES(sp) + SREG x28, 27 * REGBYTES(sp) + SREG x29, 28 * REGBYTES(sp) + SREG x30, 29 * REGBYTES(sp) + SREG x31, 30 * REGBYTES(sp) + + jal handle_m_timer_interrupt + j generic_restore + +vector_ext_trap_handler: + addi sp, sp, -32*REGBYTES + + SREG x1, 0 * REGBYTES(sp) + SREG x2, 1 * REGBYTES(sp) + SREG x3, 2 * REGBYTES(sp) + SREG x4, 3 * REGBYTES(sp) + SREG x5, 4 * REGBYTES(sp) + SREG x6, 5 * REGBYTES(sp) + SREG x7, 6 * REGBYTES(sp) + SREG x8, 7 * REGBYTES(sp) + SREG x9, 8 * REGBYTES(sp) + SREG x10, 9 * REGBYTES(sp) + SREG x11, 10 * REGBYTES(sp) + SREG x12, 11 * REGBYTES(sp) + SREG x13, 12 * REGBYTES(sp) + SREG x14, 13 * REGBYTES(sp) + SREG x15, 14 * REGBYTES(sp) + SREG x16, 15 * REGBYTES(sp) + SREG x17, 16 * REGBYTES(sp) + SREG x18, 17 * REGBYTES(sp) + SREG x19, 18 * REGBYTES(sp) + SREG x20, 19 * REGBYTES(sp) + SREG x21, 20 * REGBYTES(sp) + SREG x22, 21 * REGBYTES(sp) + SREG x23, 22 * REGBYTES(sp) + SREG x24, 23 * REGBYTES(sp) + SREG x25, 24 * REGBYTES(sp) + SREG x26, 25 * REGBYTES(sp) + SREG x27, 26 * REGBYTES(sp) + SREG x28, 27 * REGBYTES(sp) + SREG x29, 28 * REGBYTES(sp) + SREG x30, 29 * REGBYTES(sp) + SREG x31, 30 * REGBYTES(sp) + +#ifdef MIV_LEGACY_RV32 + jal handle_m_ext_interrupt +#else + jal External_IRQHandler +#endif /* MIV_LEGACY_RV32 */ + j generic_restore + +#ifndef MIV_LEGACY_RV32 +vector_MGEUI_trap_handler: + addi sp, sp, -32*REGBYTES + + SREG x1, 0 * REGBYTES(sp) + SREG x2, 1 * REGBYTES(sp) + SREG x3, 2 * REGBYTES(sp) + SREG x4, 3 * REGBYTES(sp) + SREG x5, 4 * REGBYTES(sp) + SREG x6, 5 * REGBYTES(sp) + SREG x7, 6 * REGBYTES(sp) + SREG x8, 7 * REGBYTES(sp) + SREG x9, 8 * REGBYTES(sp) + SREG x10, 9 * REGBYTES(sp) + SREG x11, 10 * REGBYTES(sp) + SREG x12, 11 * REGBYTES(sp) + SREG x13, 12 * REGBYTES(sp) + SREG x14, 13 * REGBYTES(sp) + SREG x15, 14 * REGBYTES(sp) + SREG x16, 15 * REGBYTES(sp) + SREG x17, 16 * REGBYTES(sp) + SREG x18, 17 * REGBYTES(sp) + SREG x19, 18 * REGBYTES(sp) + SREG x20, 19 * REGBYTES(sp) + SREG x21, 20 * REGBYTES(sp) + SREG x22, 21 * REGBYTES(sp) + SREG x23, 22 * REGBYTES(sp) + SREG x24, 23 * REGBYTES(sp) + SREG x25, 24 * REGBYTES(sp) + SREG x26, 25 * REGBYTES(sp) + SREG x27, 26 * REGBYTES(sp) + SREG x28, 27 * REGBYTES(sp) + SREG x29, 28 * REGBYTES(sp) + SREG x30, 29 * REGBYTES(sp) + SREG x31, 30 * REGBYTES(sp) + + jal MGEUI_IRQHandler + j generic_restore + +vector_MGECI_trap_handler: + addi sp, sp, -32*REGBYTES + + SREG x1, 0 * REGBYTES(sp) + SREG x2, 1 * REGBYTES(sp) + SREG x3, 2 * REGBYTES(sp) + SREG x4, 3 * REGBYTES(sp) + SREG x5, 4 * REGBYTES(sp) + SREG x6, 5 * REGBYTES(sp) + SREG x7, 6 * REGBYTES(sp) + SREG x8, 7 * REGBYTES(sp) + SREG x9, 8 * REGBYTES(sp) + SREG x10, 9 * REGBYTES(sp) + SREG x11, 10 * REGBYTES(sp) + SREG x12, 11 * REGBYTES(sp) + SREG x13, 12 * REGBYTES(sp) + SREG x14, 13 * REGBYTES(sp) + SREG x15, 14 * REGBYTES(sp) + SREG x16, 15 * REGBYTES(sp) + SREG x17, 16 * REGBYTES(sp) + SREG x18, 17 * REGBYTES(sp) + SREG x19, 18 * REGBYTES(sp) + SREG x20, 19 * REGBYTES(sp) + SREG x21, 20 * REGBYTES(sp) + SREG x22, 21 * REGBYTES(sp) + SREG x23, 22 * REGBYTES(sp) + SREG x24, 23 * REGBYTES(sp) + SREG x25, 24 * REGBYTES(sp) + SREG x26, 25 * REGBYTES(sp) + SREG x27, 26 * REGBYTES(sp) + SREG x28, 27 * REGBYTES(sp) + SREG x29, 28 * REGBYTES(sp) + SREG x30, 29 * REGBYTES(sp) + SREG x31, 30 * REGBYTES(sp) + + jal MGECI_IRQHandler + j generic_restore + +vector_MSYS_EI0_trap_handler: + addi sp, sp, -32*REGBYTES + + SREG x1, 0 * REGBYTES(sp) + SREG x2, 1 * REGBYTES(sp) + SREG x3, 2 * REGBYTES(sp) + SREG x4, 3 * REGBYTES(sp) + SREG x5, 4 * REGBYTES(sp) + SREG x6, 5 * REGBYTES(sp) + SREG x7, 6 * REGBYTES(sp) + SREG x8, 7 * REGBYTES(sp) + SREG x9, 8 * REGBYTES(sp) + SREG x10, 9 * REGBYTES(sp) + SREG x11, 10 * REGBYTES(sp) + SREG x12, 11 * REGBYTES(sp) + SREG x13, 12 * REGBYTES(sp) + SREG x14, 13 * REGBYTES(sp) + SREG x15, 14 * REGBYTES(sp) + SREG x16, 15 * REGBYTES(sp) + SREG x17, 16 * REGBYTES(sp) + SREG x18, 17 * REGBYTES(sp) + SREG x19, 18 * REGBYTES(sp) + SREG x20, 19 * REGBYTES(sp) + SREG x21, 20 * REGBYTES(sp) + SREG x22, 21 * REGBYTES(sp) + SREG x23, 22 * REGBYTES(sp) + SREG x24, 23 * REGBYTES(sp) + SREG x25, 24 * REGBYTES(sp) + SREG x26, 25 * REGBYTES(sp) + SREG x27, 26 * REGBYTES(sp) + SREG x28, 27 * REGBYTES(sp) + SREG x29, 28 * REGBYTES(sp) + SREG x30, 29 * REGBYTES(sp) + SREG x31, 30 * REGBYTES(sp) + + jal MSYS_EI0_IRQHandler + j generic_restore + +vector_MSYS_EI1_trap_handler: + addi sp, sp, -32*REGBYTES + + SREG x1, 0 * REGBYTES(sp) + SREG x2, 1 * REGBYTES(sp) + SREG x3, 2 * REGBYTES(sp) + SREG x4, 3 * REGBYTES(sp) + SREG x5, 4 * REGBYTES(sp) + SREG x6, 5 * REGBYTES(sp) + SREG x7, 6 * REGBYTES(sp) + SREG x8, 7 * REGBYTES(sp) + SREG x9, 8 * REGBYTES(sp) + SREG x10, 9 * REGBYTES(sp) + SREG x11, 10 * REGBYTES(sp) + SREG x12, 11 * REGBYTES(sp) + SREG x13, 12 * REGBYTES(sp) + SREG x14, 13 * REGBYTES(sp) + SREG x15, 14 * REGBYTES(sp) + SREG x16, 15 * REGBYTES(sp) + SREG x17, 16 * REGBYTES(sp) + SREG x18, 17 * REGBYTES(sp) + SREG x19, 18 * REGBYTES(sp) + SREG x20, 19 * REGBYTES(sp) + SREG x21, 20 * REGBYTES(sp) + SREG x22, 21 * REGBYTES(sp) + SREG x23, 22 * REGBYTES(sp) + SREG x24, 23 * REGBYTES(sp) + SREG x25, 24 * REGBYTES(sp) + SREG x26, 25 * REGBYTES(sp) + SREG x27, 26 * REGBYTES(sp) + SREG x28, 27 * REGBYTES(sp) + SREG x29, 28 * REGBYTES(sp) + SREG x30, 29 * REGBYTES(sp) + SREG x31, 30 * REGBYTES(sp) + + jal MSYS_EI1_IRQHandler + j generic_restore + +vector_MSYS_EI2_trap_handler: + addi sp, sp, -32*REGBYTES + + SREG x1, 0 * REGBYTES(sp) + SREG x2, 1 * REGBYTES(sp) + SREG x3, 2 * REGBYTES(sp) + SREG x4, 3 * REGBYTES(sp) + SREG x5, 4 * REGBYTES(sp) + SREG x6, 5 * REGBYTES(sp) + SREG x7, 6 * REGBYTES(sp) + SREG x8, 7 * REGBYTES(sp) + SREG x9, 8 * REGBYTES(sp) + SREG x10, 9 * REGBYTES(sp) + SREG x11, 10 * REGBYTES(sp) + SREG x12, 11 * REGBYTES(sp) + SREG x13, 12 * REGBYTES(sp) + SREG x14, 13 * REGBYTES(sp) + SREG x15, 14 * REGBYTES(sp) + SREG x16, 15 * REGBYTES(sp) + SREG x17, 16 * REGBYTES(sp) + SREG x18, 17 * REGBYTES(sp) + SREG x19, 18 * REGBYTES(sp) + SREG x20, 19 * REGBYTES(sp) + SREG x21, 20 * REGBYTES(sp) + SREG x22, 21 * REGBYTES(sp) + SREG x23, 22 * REGBYTES(sp) + SREG x24, 23 * REGBYTES(sp) + SREG x25, 24 * REGBYTES(sp) + SREG x26, 25 * REGBYTES(sp) + SREG x27, 26 * REGBYTES(sp) + SREG x28, 27 * REGBYTES(sp) + SREG x29, 28 * REGBYTES(sp) + SREG x30, 29 * REGBYTES(sp) + SREG x31, 30 * REGBYTES(sp) + + jal MSYS_EI2_IRQHandler + j generic_restore + +vector_MSYS_EI3_trap_handler: + addi sp, sp, -32*REGBYTES + + SREG x1, 0 * REGBYTES(sp) + SREG x2, 1 * REGBYTES(sp) + SREG x3, 2 * REGBYTES(sp) + SREG x4, 3 * REGBYTES(sp) + SREG x5, 4 * REGBYTES(sp) + SREG x6, 5 * REGBYTES(sp) + SREG x7, 6 * REGBYTES(sp) + SREG x8, 7 * REGBYTES(sp) + SREG x9, 8 * REGBYTES(sp) + SREG x10, 9 * REGBYTES(sp) + SREG x11, 10 * REGBYTES(sp) + SREG x12, 11 * REGBYTES(sp) + SREG x13, 12 * REGBYTES(sp) + SREG x14, 13 * REGBYTES(sp) + SREG x15, 14 * REGBYTES(sp) + SREG x16, 15 * REGBYTES(sp) + SREG x17, 16 * REGBYTES(sp) + SREG x18, 17 * REGBYTES(sp) + SREG x19, 18 * REGBYTES(sp) + SREG x20, 19 * REGBYTES(sp) + SREG x21, 20 * REGBYTES(sp) + SREG x22, 21 * REGBYTES(sp) + SREG x23, 22 * REGBYTES(sp) + SREG x24, 23 * REGBYTES(sp) + SREG x25, 24 * REGBYTES(sp) + SREG x26, 25 * REGBYTES(sp) + SREG x27, 26 * REGBYTES(sp) + SREG x28, 27 * REGBYTES(sp) + SREG x29, 28 * REGBYTES(sp) + SREG x30, 29 * REGBYTES(sp) + SREG x31, 30 * REGBYTES(sp) + + jal MSYS_EI3_IRQHandler + j generic_restore + +vector_MSYS_EI4_trap_handler: + addi sp, sp, -32*REGBYTES + + SREG x1, 0 * REGBYTES(sp) + SREG x2, 1 * REGBYTES(sp) + SREG x3, 2 * REGBYTES(sp) + SREG x4, 3 * REGBYTES(sp) + SREG x5, 4 * REGBYTES(sp) + SREG x6, 5 * REGBYTES(sp) + SREG x7, 6 * REGBYTES(sp) + SREG x8, 7 * REGBYTES(sp) + SREG x9, 8 * REGBYTES(sp) + SREG x10, 9 * REGBYTES(sp) + SREG x11, 10 * REGBYTES(sp) + SREG x12, 11 * REGBYTES(sp) + SREG x13, 12 * REGBYTES(sp) + SREG x14, 13 * REGBYTES(sp) + SREG x15, 14 * REGBYTES(sp) + SREG x16, 15 * REGBYTES(sp) + SREG x17, 16 * REGBYTES(sp) + SREG x18, 17 * REGBYTES(sp) + SREG x19, 18 * REGBYTES(sp) + SREG x20, 19 * REGBYTES(sp) + SREG x21, 20 * REGBYTES(sp) + SREG x22, 21 * REGBYTES(sp) + SREG x23, 22 * REGBYTES(sp) + SREG x24, 23 * REGBYTES(sp) + SREG x25, 24 * REGBYTES(sp) + SREG x26, 25 * REGBYTES(sp) + SREG x27, 26 * REGBYTES(sp) + SREG x28, 27 * REGBYTES(sp) + SREG x29, 28 * REGBYTES(sp) + SREG x30, 29 * REGBYTES(sp) + SREG x31, 30 * REGBYTES(sp) + + jal MSYS_EI4_IRQHandler + j generic_restore + +vector_MSYS_EI5_trap_handler: + addi sp, sp, -32*REGBYTES + + SREG x1, 0 * REGBYTES(sp) + SREG x2, 1 * REGBYTES(sp) + SREG x3, 2 * REGBYTES(sp) + SREG x4, 3 * REGBYTES(sp) + SREG x5, 4 * REGBYTES(sp) + SREG x6, 5 * REGBYTES(sp) + SREG x7, 6 * REGBYTES(sp) + SREG x8, 7 * REGBYTES(sp) + SREG x9, 8 * REGBYTES(sp) + SREG x10, 9 * REGBYTES(sp) + SREG x11, 10 * REGBYTES(sp) + SREG x12, 11 * REGBYTES(sp) + SREG x13, 12 * REGBYTES(sp) + SREG x14, 13 * REGBYTES(sp) + SREG x15, 14 * REGBYTES(sp) + SREG x16, 15 * REGBYTES(sp) + SREG x17, 16 * REGBYTES(sp) + SREG x18, 17 * REGBYTES(sp) + SREG x19, 18 * REGBYTES(sp) + SREG x20, 19 * REGBYTES(sp) + SREG x21, 20 * REGBYTES(sp) + SREG x22, 21 * REGBYTES(sp) + SREG x23, 22 * REGBYTES(sp) + SREG x24, 23 * REGBYTES(sp) + SREG x25, 24 * REGBYTES(sp) + SREG x26, 25 * REGBYTES(sp) + SREG x27, 26 * REGBYTES(sp) + SREG x28, 27 * REGBYTES(sp) + SREG x29, 28 * REGBYTES(sp) + SREG x30, 29 * REGBYTES(sp) + SREG x31, 30 * REGBYTES(sp) + + jal MSYS_EI5_IRQHandler + j generic_restore + +vector_OPSRV_IRQHandler: + addi sp, sp, -32*REGBYTES + + SREG x1, 0 * REGBYTES(sp) + SREG x2, 1 * REGBYTES(sp) + SREG x3, 2 * REGBYTES(sp) + SREG x4, 3 * REGBYTES(sp) + SREG x5, 4 * REGBYTES(sp) + SREG x6, 5 * REGBYTES(sp) + SREG x7, 6 * REGBYTES(sp) + SREG x8, 7 * REGBYTES(sp) + SREG x9, 8 * REGBYTES(sp) + SREG x10, 9 * REGBYTES(sp) + SREG x11, 10 * REGBYTES(sp) + SREG x12, 11 * REGBYTES(sp) + SREG x13, 12 * REGBYTES(sp) + SREG x14, 13 * REGBYTES(sp) + SREG x15, 14 * REGBYTES(sp) + SREG x16, 15 * REGBYTES(sp) + SREG x17, 16 * REGBYTES(sp) + SREG x18, 17 * REGBYTES(sp) + SREG x19, 18 * REGBYTES(sp) + SREG x20, 19 * REGBYTES(sp) + SREG x21, 20 * REGBYTES(sp) + SREG x22, 21 * REGBYTES(sp) + SREG x23, 22 * REGBYTES(sp) + SREG x24, 23 * REGBYTES(sp) + SREG x25, 24 * REGBYTES(sp) + SREG x26, 25 * REGBYTES(sp) + SREG x27, 26 * REGBYTES(sp) + SREG x28, 27 * REGBYTES(sp) + SREG x29, 28 * REGBYTES(sp) + SREG x30, 29 * REGBYTES(sp) + SREG x31, 30 * REGBYTES(sp) + + jal OPSRV_IRQHandler + j generic_restore +#endif /* MIV_LEGACY_RV32 */ + +generic_restore: + LREG x1, 0 * REGBYTES(sp) + LREG x2, 1 * REGBYTES(sp) + LREG x3, 2 * REGBYTES(sp) + LREG x4, 3 * REGBYTES(sp) + LREG x5, 4 * REGBYTES(sp) + LREG x6, 5 * REGBYTES(sp) + LREG x7, 6 * REGBYTES(sp) + LREG x8, 7 * REGBYTES(sp) + LREG x9, 8 * REGBYTES(sp) + LREG x10, 9 * REGBYTES(sp) + LREG x11, 10 * REGBYTES(sp) + LREG x12, 11 * REGBYTES(sp) + LREG x13, 12 * REGBYTES(sp) + LREG x14, 13 * REGBYTES(sp) + LREG x15, 14 * REGBYTES(sp) + LREG x16, 15 * REGBYTES(sp) + LREG x17, 16 * REGBYTES(sp) + LREG x18, 17 * REGBYTES(sp) + LREG x19, 18 * REGBYTES(sp) + LREG x20, 19 * REGBYTES(sp) + LREG x21, 20 * REGBYTES(sp) + LREG x22, 21 * REGBYTES(sp) + LREG x23, 22 * REGBYTES(sp) + LREG x24, 23 * REGBYTES(sp) + LREG x25, 24 * REGBYTES(sp) + LREG x26, 25 * REGBYTES(sp) + LREG x27, 26 * REGBYTES(sp) + LREG x28, 27 * REGBYTES(sp) + LREG x29, 28 * REGBYTES(sp) + LREG x30, 29 * REGBYTES(sp) + LREG x31, 30 * REGBYTES(sp) + + addi sp, sp, 32*REGBYTES + mret + + .section .text, "ax" +handle_reset: +/* Ensure instructions are not relaxed, since gp is not yet set */ +.option push +.option norelax + + csrwi mstatus, 0 + csrwi mie, 0 + la ra, _start + + csrr t0, misa + andi t0, t0, A_EXTENSION_MASK + bnez t0, ima_cores_setup /* Jump to IMA core handling */ + +/* For MIV_RV32 cores the mtvec exception base address is fixed at Reset vector + address + 0x4. Check the mode bits. */ + csrr t0, mtvec + andi t0, t0, MTVEC_MODE_BIT_MASK + li t1, MTVEC_VECTORED_MODE_VAL + bne t0, t1, ima_cores_setup /* Jump to IMA core handling */ + + /* When mode = 1 => this is vectored mode on MIV_RV32 core. + Verify that the trap_handler address matches the configuration in MTVEC */ + csrr t0, mtvec + andi t0, t0, 0xFFFFFFFC + la t1, trap_entry + bne t0, t1, vector_address_not_matching + j generic_reset_handling + +ima_cores_setup: + la t0, trap_entry + +#ifdef MIV_LEGACY_RV32_VECTORED_INTERRUPTS + addi t0, t0, 0x01 /* Set the mode bit for IMA cores. + For MIV_RV32 cores this is done by configurator. */ +#endif + csrw mtvec, t0 + +generic_reset_handling: +/* Copy sdata section first so that the gp is set and linker relaxation can be + used */ + la a4, __sdata_load + la a5, __sdata_start + la a6, __sdata_end + beq a4, a5, 1f /* Exit if source and dest are same */ + beq a5, a6, 1f /* Exit if section start and end addresses are same */ + call block_copy + +1: + /* initialize global pointer */ + la gp, __global_pointer$ + +.option pop + +/* Floating point support configuration */ +#ifdef __riscv_flen + csrr t0, mstatus + lui t1, 0xffffa + addi t1, t1, -1 + and t0, t0, t1 + lui t1, 0x4 + or t1, t0, t1 + csrw mstatus, t1 + + lui t0, 0x0 + fscsr t0 +#endif + call initializations + /* Initialize stack pointer */ + la sp, __stack_top + + /* Jump into C code */ + j _init + +/* Error: trap_entry is not at the expected address of reset_vector+mtvec offset + as configured in the MIV_RV32 core vectored mode */ +vector_address_not_matching: + ebreak + +initializations: +/* Initialize the .bss section */ + mv t0, ra /* Store ra for future use */ + la a5, __bss_start + la a6, __bss_end + beq a5, a6, 1f /* Section start and end address are the same */ + call zeroize_block + +1: +/* Initialize the .sbss section */ + la a5, __sbss_start + la a6, __sbss_end + beq a5, a6, 1f /* Section start and end address are the same */ + call zeroize_block + +/* Clear heap */ + la a5, __heap_start + la a6, __heap_end + beq a5, a6, 1f /* Section start and end address are the same */ + call zeroize_block + +1: +/* Copy data section */ + la a4, __data_load + la a5, __data_start + la a6, __data_end + beq a4, a5, 1f /* Exit early if source and dest are same */ + beq a5, a6, 1f /* Section start and end addresses are the same */ + call block_copy + +1: + mv ra, t0 /* Retrieve ra */ + ret + +zeroize_block: + bltu a6, a5, block_copy_error /* Error. End address is less than start */ + or a7, a6, a5 /* Check if start or end is unalined */ + andi a7, a7, 0x03u + bgtz a7, block_copy_error /* Unaligned addresses error*/ +zeroize_loop: + sw x0, 0(a5) + add a5, a5, __SIZEOF_POINTER__ + blt a5, a6, zeroize_loop + ret + +block_copy: + bltu a6, a5, block_copy_error /* Error. End address is less than start */ + or a7, a6, a5 /* Check if start or end is unalined */ + andi a7, a7, 0x03u + bgtz a7, block_copy_error /* Unaligned addresses error*/ +block_copy_loop: + lw a7, 0(a4) + sw a7, 0(a5) + addi a5, a5, 0x04 + addi a4, a4, 0x04 + blt a5, a6, block_copy_loop + j block_copy_exit + +block_copy_error: + j block_copy_error + +block_copy_exit: + ret + +#endif /*ENTRY_S*/ diff --git a/miv-rv32-udma/src/platform/miv_rv32_hal/miv_rv32_hal.c b/miv-rv32-udma/src/platform/miv_rv32_hal/miv_rv32_hal.c new file mode 100644 index 0000000..8fa82b1 --- /dev/null +++ b/miv-rv32-udma/src/platform/miv_rv32_hal/miv_rv32_hal.c @@ -0,0 +1,327 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_hal.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Implementation of Hardware Abstraction Layer for Mi-V soft processors + * + */ +#include +#include "miv_rv32_hal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SUCCESS 0U +#define ERROR 1U +#define MASK_32BIT 0xFFFFFFFFu + +/*------------------------------------------------------------------------------ + * Write in a sequence recommended by privileged spec to avoid spurious + * interrupts + + # New comparand is in a1:a0. + li t0, -1 + sw t0, mtimecmp # No smaller than old value. + sw a1, mtimecmp+4 # No smaller than new value. + sw a0, mtimecmp # New value. + */ +#define WRITE_MTIMECMP(value) MTIMECMPH = MASK_32BIT; \ + MTIMECMP = value & MASK_32BIT;\ + MTIMECMPH = (value >> 32u) & MASK_32BIT; + +#define WRITE_MTIME(value) MTIME = value & MASK_32BIT;\ + MTIMEH = (value >> 32u) & MASK_32BIT; + +extern void Software_IRQHandler(void); + +#ifdef MIV_LEGACY_RV32 +#define MTIME_PRESCALER 100UL +/*------------------------------------------------------------------------------ + * + */ +uint8_t Invalid_IRQHandler(void); +uint8_t External_1_IRQHandler(void); +uint8_t External_2_IRQHandler(void); +uint8_t External_3_IRQHandler(void); +uint8_t External_4_IRQHandler(void); +uint8_t External_5_IRQHandler(void); +uint8_t External_6_IRQHandler(void); +uint8_t External_7_IRQHandler(void); +uint8_t External_8_IRQHandler(void); +uint8_t External_9_IRQHandler(void); +uint8_t External_10_IRQHandler(void); +uint8_t External_11_IRQHandler(void); +uint8_t External_12_IRQHandler(void); +uint8_t External_13_IRQHandler(void); +uint8_t External_14_IRQHandler(void); +uint8_t External_15_IRQHandler(void); +uint8_t External_16_IRQHandler(void); +uint8_t External_17_IRQHandler(void); +uint8_t External_18_IRQHandler(void); +uint8_t External_19_IRQHandler(void); +uint8_t External_20_IRQHandler(void); +uint8_t External_21_IRQHandler(void); +uint8_t External_22_IRQHandler(void); +uint8_t External_23_IRQHandler(void); +uint8_t External_24_IRQHandler(void); +uint8_t External_25_IRQHandler(void); +uint8_t External_26_IRQHandler(void); +uint8_t External_27_IRQHandler(void); +uint8_t External_28_IRQHandler(void); +uint8_t External_29_IRQHandler(void); +uint8_t External_30_IRQHandler(void); +uint8_t External_31_IRQHandler(void); + + +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for external interrupts. + */ +uint8_t (* const ext_irq_handler_table[32])(void) = +{ + + Invalid_IRQHandler, + External_1_IRQHandler, + External_2_IRQHandler, + External_3_IRQHandler, + External_4_IRQHandler, + External_5_IRQHandler, + External_6_IRQHandler, + External_7_IRQHandler, + External_8_IRQHandler, + External_9_IRQHandler, + External_10_IRQHandler, + External_11_IRQHandler, + External_12_IRQHandler, + External_13_IRQHandler, + External_14_IRQHandler, + External_15_IRQHandler, + External_16_IRQHandler, + External_17_IRQHandler, + External_18_IRQHandler, + External_19_IRQHandler, + External_20_IRQHandler, + External_21_IRQHandler, + External_22_IRQHandler, + External_23_IRQHandler, + External_24_IRQHandler, + External_25_IRQHandler, + External_26_IRQHandler, + External_27_IRQHandler, + External_28_IRQHandler, + External_29_IRQHandler, + External_30_IRQHandler, + External_31_IRQHandler +}; + +#else +/*------------------------------------------------------------------------------ + * Interrupt handlers as mapped into the MIE register of the MIV_RV32 + */ +extern void External_IRQHandler(void); +extern void MGEUI_IRQHandler(void); +extern void MGECI_IRQHandler(void); +extern void MSYS_EI0_IRQHandler(void); +extern void MSYS_EI1_IRQHandler(void); +extern void MSYS_EI2_IRQHandler(void); +extern void MSYS_EI3_IRQHandler(void); +extern void MSYS_EI4_IRQHandler(void); +extern void MSYS_EI5_IRQHandler(void); +extern void OPSRV_IRQHandler(void); + +#endif + +/*------------------------------------------------------------------------------ + * 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; + +/*------------------------------------------------------------------------------ + * Configure the machine timer to generate an interrupt. + */ +uint32_t MRV_systick_config(uint64_t ticks) +{ + uint32_t ret_val = ERROR; + + g_systick_increment = (uint64_t)(ticks) / MTIME_PRESCALER; + + if (g_systick_increment > 0U) + { + +#ifndef MIV_RV32_EXT_TIMECMP + WRITE_MTIMECMP(MRV_read_mtime() + g_systick_increment) +#endif + set_csr(mie, MIP_MTIP); + MRV_enable_interrupts(); + + ret_val = SUCCESS; + } + + return ret_val; +} + +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for machine timer interrupts. + */ +void handle_m_timer_interrupt(void) +{ +#ifndef MIV_RV32_EXT_TIMECMP + WRITE_MTIMECMP(MRV_read_mtime() + g_systick_increment) +#endif + SysTick_Handler(); +} + +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for software interrupts. + */ +#ifdef MIV_LEGACY_RV32 +void handle_m_ext_interrupt(void) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; + uint8_t disable = EXT_IRQ_KEEP_ENABLED; + + if (0u !=int_num) + { + disable = ext_irq_handler_table[int_num](); + + PLIC->TARGET[hart_id].CLAIM_COMPLETE = int_num; + + if(EXT_IRQ_DISABLE == disable) + { + MRV_PLIC_disable_irq((IRQn_Type)int_num); + } + } +} +#endif + +void handle_m_soft_interrupt(void) +{ + Software_IRQHandler(); + MRV_clear_soft_irq(); +} + +/*------------------------------------------------------------------------------ + * Trap handler. This function is invoked in the non-vectored mode. + */ +void handle_trap(uintptr_t mcause, uintptr_t mepc) +{ + if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == IRQ_M_SOFT)) + { + handle_m_soft_interrupt(); + } + else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == IRQ_M_TIMER)) + { + handle_m_timer_interrupt(); + } + else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT)) + { +#ifdef MIV_LEGACY_RV32 + handle_m_ext_interrupt(); +#else + External_IRQHandler(); +#endif + } +#ifndef MIV_LEGACY_RV32 + else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == MSYS_EI0)) + { + MSYS_EI0_IRQHandler(); + } + else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == MSYS_EI1)) + { + MSYS_EI1_IRQHandler(); + } + else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == MSYS_EI2)) + { + MSYS_EI2_IRQHandler(); + } + else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == MSYS_EI3)) + { + MSYS_EI3_IRQHandler(); + } + else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == MSYS_EI4)) + { + MSYS_EI4_IRQHandler(); + } + else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == MSYS_EI5)) + { + MSYS_EI5_IRQHandler(); + } + else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == OPSRV_REG)) + { + OPSRV_IRQHandler(); + } + else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == MGEUI)) + { + MGEUI_IRQHandler(); + } + else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == MGECI)) + { + MGECI_IRQHandler(); + } +#endif + + else + { +#ifndef NDEBUG + /* + Arguments supplied to this function are mcause, mepc (exception PC) and + stack pointer. + Based on privileged-isa specification mcause values and meanings are: + + 0 Instruction address misaligned (mtval/mtval is the address) + 1 Instruction access fault (mtval/mtval is the address) + 2 Illegal instruction (mtval/mtval contains the + offending instruction opcode) + 3 Breakpoint + 4 Load address misaligned (mtval/mtval is the address) + 5 Load address fault (mtval/mtval is the address) + 6 Store/AMO address fault (mtval/mtval is the address) + 7 Store/AMO access fault (mtval/mtval is the address) + 8 Environment call from U-mode + 9 Environment call from S-mode + A Environment call from M-mode + B Instruction page fault + C Load page fault (mtval/mtval is the address) + E Store page fault (mtval/mtval is the address) + + # Please note: mtval is the newer name for register mbadaddr + # If you get a compile failure here, use the older name. + # At this point, both are supported in latest compiler, older compiler + # versions only support mbadaddr. + # See: https://github.com/riscv/riscv-gcc/issues/133 + */ + + /* interrupt pending */ + uintptr_t mip = read_csr(mip); + + /* additional info and meaning depends on mcause */ + uintptr_t mtval = read_csr(mtval); + + /* trap vector */ + uintptr_t mtvec = read_csr(mtvec); + + /* temporary, sometimes might hold temporary value of a0 */ + uintptr_t mscratch = read_csr(mscratch); + + /* status contains many smaller fields: */ + uintptr_t mstatus = read_csr(mstatus); + + /* PC value when the exception was taken*/ + uintptr_t mmepc = read_csr(mepc); + + /* breakpoint */ + __asm__("ebreak"); +#else + _exit(1 + mcause); +#endif + } +} + +#ifdef __cplusplus +} +#endif diff --git a/miv-rv32-udma/src/platform/miv_rv32_hal/miv_rv32_hal.h b/miv-rv32-udma/src/platform/miv_rv32_hal/miv_rv32_hal.h new file mode 100644 index 0000000..7231610 --- /dev/null +++ b/miv-rv32-udma/src/platform/miv_rv32_hal/miv_rv32_hal.h @@ -0,0 +1,521 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file miv_rv32_hal.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware Abstraction Layer functions for Mi-V soft processors + * + */ + +#ifndef RISCV_HAL_H +#define RISCV_HAL_H + +#include "miv_rv32_regs.h" +#include "miv_rv32_plic.h" + +#ifndef LEGACY_DIR_STRUCTURE +#include "fpga_design_config/fpga_design_config.h" +#else +#include "hw_platform.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + * Return value from External IRQ handler. This will be used to disable the + * External interrupt. + */ +#define EXT_IRQ_KEEP_ENABLED 0U +#define EXT_IRQ_DISABLE 1U + +/***************************************************************************//** + * System tick handler. This handler function gets called when the Machine + * timer interrupt asserts. An implementation of this function should be + * provided by the application to implement the application specific machine + * timer interrupt handling. If application does not provide such implementation + * the weakly linked handler stub function implemented in riscv_hal_stubs.c gets + * linked. + */ +void SysTick_Handler(void); + +/***************************************************************************//** + * System timer tick configuration. + * Configures the machine timer to generate a system tick interrupt at regular + * intervals. + * Takes the number of system clock ticks between interrupts. + * + * Returns 0 if successful. + * Returns 1 if the interrupt interval cannot be achieved. + */ +uint32_t MRV_systick_config(uint64_t ticks); + + +#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) + +/* To maintain backward compatibility with FreeRTOS config code */ +#define PRCI_BASE 0x44000000UL + +#else + +/* To maintain backward compatibility with FreeRTOS config code */ +#define PRCI_BASE 0x02000000UL + +/* OPSRV stands for "Offload Processor Subsystem for RISC-V" (OPSRV) on the + * MIV_RV32 IP core. Please see the handbook for more details. */ + +/* TCM ECC correctable error irq enable mask value */ +#define OPSRV_TCM_ECC_CE_IRQ 0x01u + +/* TCMECC uncorrectable error irq enable */ +#define OPSRV_TCM_ECC_UCE_IRQ 0x02u + +/* AXI write response error irq enable */ +#define OPSRV_AXI_WR_RESP_IRQ 0x10u + +#define OPSRV_BASE_ADDR 0x00006000UL + +typedef struct +{ + volatile uint32_t cfg; /*Parity is not being supported by MIV_RV32 v3.0*/ + volatile uint32_t reserved0[3]; + volatile uint32_t irq_en; /*offset 0x10*/ + volatile uint32_t irq_pend; + volatile uint32_t reserved1[2]; + volatile uint32_t soft_reg; /*offset 0x20*/ +} OPSRV_Type; + +#define OPSRV ((OPSRV_Type *)OPSRV_BASE_ADDR) + +#define EXT_INTR_SOURCES 1 + +#define MTIMECMP (*(volatile uint32_t*)0x02004000UL) +#define MTIMECMPH (*(volatile uint32_t*)0x02004004UL) + +/* 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 + * #define MTIME_PRESCALER 100u + */ +#define MTIME_PRESCALER (*(volatile uint32_t*)0x02005000UL) + +#ifndef MIV_RV32_EXT_TIMER +#define MTIME (*(volatile uint32_t*)0x0200BFF8UL) +#define MTIMEH (*(volatile uint32_t*)0x0200BFFCUL) +#else +#define MTIME HAL_ASSERT(0); +#endif + +/* These definitions are provided for convenient identification of the interrupts + * in the MIE/MIP registers. + * Apart from the standard software, timer and external interrupts, the names + * of the additional interrupts correspond to the names as used in the MIV_RV32 + * handbook. Please refer the MIV_RV32 handbook for more details. + * */ +#define MRV32_SOFT_IRQn MIE_3_IRQn +#define MRV32_TIMER_IRQn MIE_7_IRQn +#define MRV32_EXT_IRQn MIE_11_IRQn + +/*============================================================================== + * Interrupt numbers: + * This enum represents the interrupt enable bits in the MIE register. + */ +enum +{ + MIE_0_IRQn = (0x01u), + MIE_1_IRQn = (0x01u<<1u), + MIE_2_IRQn = (0x01u<<2u), + MIE_3_IRQn = (0x01u<<3u), /*MSIE*/ + MIE_4_IRQn = (0x01u<<4u), + MIE_5_IRQn = (0x01u<<5u), + MIE_6_IRQn = (0x01u<<6u), + MIE_7_IRQn = (0x01u<<7u), /*MTIE*/ + MIE_8_IRQn = (0x01u<<8u), + MIE_9_IRQn = (0x01u<<9u), + MIE_10_IRQn = (0x01u<<10u), + MIE_11_IRQn = (0x01u<<11u), /*MEIE*/ + MIE_12_IRQn = (0x01u<<12u), + MIE_13_IRQn = (0x01u<<13u), + MIE_14_IRQn = (0x01u<<14u), + MIE_15_IRQn = (0x01u<<15u), + MIE_16_IRQn = (0x01u<<16u), /*MGEUIE*/ + MIE_17_IRQn = (0x01u<<17u), /*MGECIE*/ + MIE_18_IRQn = (0x01u<<18u), + MIE_19_IRQn = (0x01u<<19u), + MIE_20_IRQn = (0x01u<<20u), + MIE_21_IRQn = (0x01u<<21u), + MIE_22_IRQn = (0x01u<<22u), + MIE_23_IRQn = (0x01u<<23u), + MIE_24_IRQn = (0x01u<<24u), /*MSYS_EIE0*/ + MIE_25_IRQn = (0x01u<<25u), /*MSYS_EIE1*/ + MIE_26_IRQn = (0x01u<<26u), /*MSYS_EIE2*/ + MIE_27_IRQn = (0x01u<<27u), /*MSYS_EIE3*/ + MIE_28_IRQn = (0x01u<<28u), /*MSYS_EIE4*/ + MIE_29_IRQn = (0x01u<<29u), /*MSYS_EIE5*/ + MIE_30_IRQn = (0x01u<<30u) /*OPSRV_IRQ_IE*/ + +} 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 +#define MRV32_MSYS_EIE1_IRQn MIE_25_IRQn +#define MRV32_MSYS_EIE2_IRQn MIE_26_IRQn +#define MRV32_MSYS_EIE3_IRQn MIE_27_IRQn +#define MRV32_MSYS_EIE4_IRQn MIE_28_IRQn +#define MRV32_MSYS_EIE5_IRQn MIE_29_IRQn +#define MRV32_MSYS_OPSRV_IRQn MIE_30_IRQn + +/***************************************************************************//** + Enable OPSRV interrupt. Parameter takes logical OR of following values + #define OPSRV_TCM_ECC_CE_IRQ 0x01u + #define OPSRV_TCM_ECC_UCE_IRQ 0x02u + #define OPSRV_AXI_WR_RESP_IRQ 0x10u + */ +static inline void MRV32_opsrv_enable_irq(uint32_t irq_mask) +{ + OPSRV->irq_en = irq_mask; +} + +/***************************************************************************//** + Disable OPSRV interrupt. Parameter takes logical OR of following values + #define OPSRV_TCM_ECC_CE_IRQ 0x01u + #define OPSRV_TCM_ECC_UCE_IRQ 0x02u + #define OPSRV_AXI_WR_RESP_IRQ 0x10u + */ +static inline void MRV32_opsrv_disable_irq(uint32_t irq_mask) +{ + OPSRV->irq_en &= ~irq_mask; +} + +/***************************************************************************//** + Clear OPSRV interrupt. Parameter takes logical OR of following values + #define OPSRV_TCM_ECC_CE_IRQ 0x01u + #define OPSRV_TCM_ECC_UCE_IRQ 0x02u + #define OPSRV_AXI_WR_RESP_IRQ 0x10u + */ +static inline void MRV32_opsrv_clear_irq(uint32_t irq_mask) +{ + OPSRV->irq_pend |= irq_mask; +} + +/***************************************************************************//** + * The function MRV32_is_gpr_ded() returns the core_gpr_ded_reset_reg bit value. + * When ECC is enabled, the core_gpr_ded_reset_reg is set when the core was + * reset due to GPR DED error. + */ +static inline uint32_t MRV32_is_gpr_ded(void) +{ + return((OPSRV->soft_reg & 0x04u) >> 0x02u); +} + +/***************************************************************************//** + * The function MRV32_clear_gpr_ded() can be used to clear the + * core_gpr_ded_reset_reg bit. When ECC is enabled, the core_gpr_ded_reset_reg + * is set when the core was previously reset due to GPR DED error. + */ +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); +} + +/***************************************************************************//** + When ECC is enabled for the GPRs and if that data has a single bit error then + the data coming out of the ECC block will be corrected and will not have the + error but the data source will still have the error. + The ECC block does not write back corrected data to memory. + Therefore, if data has a single bit error, then the corrected data should be + written back to prevent the single bit error from becoming a double bit error. + The MRV32_clear_gpr_ecc_errors() can be used for that. + + Clear the pending interrupt bit after this using MRV32_mgeci_clear_irq() + function to complete the ECC error handling. + */ +static inline void MRV32_clear_gpr_ecc_errors(void) +{ + uint32_t temp; + + __asm__ __volatile__ ( + "sw x31, %0" + :"=m" (temp)); + + __asm__ volatile ( + "mv x31, x1;" + "mv x1, x31;" + + "mv x31, x2;" + "mv x2, x31;" + + "mv x31, x3;" + "mv x3, x31;" + + "mv x31, x4;" + "mv x4, x31;" + + "mv x31, x5;" + "mv x5, x31;" + + "mv x31, x6;" + "mv x6, x31;" + + "mv x31, x7;" + "mv x7, x31;" + + "mv x31, x8;" + "mv x8, x31;" + + "mv x31, x9;" + "mv x9, x31;" + + "mv x31, x10;" + "mv x10, x31;" + + "mv x31, x11;" + "mv x11, x31;" + + "mv x31, x12;" + "mv x12, x31;" + + "mv x31, x13;" + "mv x13, x31;" + + "mv x31, x14;" + "mv x14, x31;" + + "mv x31, x15;" + "mv x15, x31;" + + "mv x31, x16;" + "mv x16, x31;" + + "mv x31, x17;" + "mv x17, x31;" + + "mv x31, x18;" + "mv x18, x31;" + + "mv x31, x19;" + "mv x19, x31;" + + "mv x31, x20;" + "mv x20, x31;" + + "mv x31, x21;" + "mv x21, x31;" + + "mv x31, x22;" + "mv x22, x31;" + + "mv x31, x23;" + "mv x23, x31;" + + "mv x31, x24;" + "mv x24, x31;" + + "mv x31, x25;" + "mv x25, x31;" + + "mv x31, x26;" + "mv x26, x31;" + + "mv x31, x27;" + "mv x27, x31;" + + "mv x31, x28;" + "mv x28, x31;" + + "mv x31, x29;" + "mv x29, x31;" + + "mv x31, x30;" + "mv x30, x31;"); + + __asm__ __volatile__ ( + "lw x31, %0;" + : + :"m" (temp)); +} + +#endif + +/***************************************************************************//** + * Enable interrupts. + This function takes a mask value as input. For each set bit in the mask value, + corresponding interrupt bit in the MIE register is enabled. + + MRV_enable_local_irq(MRV32_SOFT_IRQn | + MRV32_TIMER_IRQn | + MRV32_EXT_IRQn | + MRV32_MSYS_EIE0_IRQn | + MRV32_MSYS_OPSRV_IRQn); + */ +static inline void MRV_enable_local_irq(uint32_t mask) +{ + set_csr(mie, mask); +} + +/***************************************************************************//** + * Disable interrupts. + This function takes a mask value as input. For each set bit in the mask value, + corresponding interrupt bit in the MIE register is disabled. + + MRV_disable_local_irq(MRV32_SOFT_IRQn | + MRV32_TIMER_IRQn | + MRV32_EXT_IRQn | + MRV32_MSYS_EIE0_IRQn | + MRV32_MSYS_OPSRV_IRQn); + */ +static inline void MRV_disable_local_irq(uint32_t mask) +{ + clear_csr(mie, mask); +} +#endif + +/***************************************************************************//** + * The function MRV_raise_soft_irq() raises a synchronous software interrupt + * by writing into the MSIP register. + */ +static inline void MRV_raise_soft_irq(void) +{ + set_csr(mie, MIP_MSIP); /* Enable software interrupt bit */ + +#ifdef MIV_LEGACY_RV32 + /* You need to make sure that the global interrupt is enabled */ + MSIP = 0x01; /* raise soft interrupt */ +#else + /* Raise soft IRQ on MIV_RV32 processor */ + OPSRV->soft_reg |= (1u << 1u); +#endif +} + +/***************************************************************************//** + * The function MRV_clear_soft_irq() clears a synchronous software interrupt + * by clearing the MSIP register. + */ +static inline void MRV_clear_soft_irq(void) +{ +#ifdef MIV_LEGACY_RV32 + MSIP = 0x00u; /* clear soft interrupt */ +#else + /* Clear soft IRQ on MIV_RV32 processor */ + OPSRV->soft_reg &= ~(1u << 1u); +#endif +} + +/***************************************************************************//** + * The function MRV_enable_interrupts() enables all interrupts setting the + * machine mode interrupt enable bit in MSTATUS register. + */ +static inline void MRV_enable_interrupts(void) +{ + set_csr(mstatus, MSTATUS_MIE); +} + +/***************************************************************************//** + * The function MRV_disable_interrupts() disables all interrupts clearing the + * machine mode interrupt enable bit in MSTATUS register. + */ +static inline void MRV_disable_interrupts(void) +{ + clear_csr(mstatus, MSTATUS_MPIE); + clear_csr(mstatus, MSTATUS_MIE); +} + +/***************************************************************************//** + * The function MRV_read_mtime() returns the current MTIME register value. + */ +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 { + hi = MTIMEH; + lo = MTIME; + } while(hi != MTIMEH); + + return((((uint64_t)MTIMEH) << 32u) | lo); +#endif +} + +#ifdef __cplusplus +} +#endif + +#endif /* RISCV_HAL_H */ + diff --git a/miv-rv32-udma/src/platform/miv_rv32_hal/miv_rv32_init.c b/miv-rv32-udma/src/platform/miv_rv32_hal/miv_rv32_init.c new file mode 100644 index 0000000..e5f811f --- /dev/null +++ b/miv-rv32-udma/src/platform/miv_rv32_hal/miv_rv32_init.c @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_init.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor memory section initializations and start-up code. + * + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern void main(void); + +void _init(void) +{ + /* This function is a placeholder for the case where some more hardware + * specific initializations are required before jumping into the application + * code. You can implement it here. */ + + /* Jump to the application code after all initializations are completed */ + main(); +} + +/* Function called after main() finishes */ +void +_fini(void) +{ +} + +#ifdef __cplusplus +} +#endif + diff --git a/miv-rv32-udma/src/platform/miv_rv32_hal/miv_rv32_plic.h b/miv-rv32-udma/src/platform/miv_rv32_hal/miv_rv32_plic.h new file mode 100644 index 0000000..19050cf --- /dev/null +++ b/miv-rv32-udma/src/platform/miv_rv32_hal/miv_rv32_plic.h @@ -0,0 +1,213 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_plic.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V legacy RV32 soft processor PLIC access data structures and + * functions. + * Legacy RV32 soft processors are DEPRICATED. + * Migrate to MIV_RV32 v3.0 or later. + * + */ +#ifndef RISCV_PLIC_H +#define RISCV_PLIC_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================== + * Interrupt numbers: + */ +#ifdef MIV_LEGACY_RV32 +typedef enum +{ + NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + External_3_IRQn = 3, + External_4_IRQn = 4, + External_5_IRQn = 5, + External_6_IRQn = 6, + External_7_IRQn = 7, + External_8_IRQn = 8, + External_9_IRQn = 9, + External_10_IRQn = 10, + External_11_IRQn = 11, + External_12_IRQn = 12, + External_13_IRQn = 13, + External_14_IRQn = 14, + External_15_IRQn = 15, + External_16_IRQn = 16, + External_17_IRQn = 17, + External_18_IRQn = 18, + External_19_IRQn = 19, + External_20_IRQn = 20, + External_21_IRQn = 21, + External_22_IRQn = 22, + External_23_IRQn = 23, + External_24_IRQn = 24, + External_25_IRQn = 25, + External_26_IRQn = 26, + External_27_IRQn = 27, + External_28_IRQn = 28, + External_29_IRQn = 29, + External_30_IRQn = 30, + External_31_IRQn = 31 +} IRQn_Type; + +#define EXT_INTR_SOURCES 31 + +/*============================================================================== + * PLIC: Platform Level Interrupt Controller + */ +#define PLIC_BASE_ADDR 0x40000000UL + +typedef struct +{ + volatile uint32_t PRIORITY_THRESHOLD; + volatile uint32_t CLAIM_COMPLETE; + volatile uint32_t reserved[1022]; +} IRQ_Target_Type; + +typedef struct +{ + volatile uint32_t ENABLES[32]; +} Target_Enables_Type; + +typedef struct +{ + /*-------------------- Source Priority --------------------*/ + volatile uint32_t SOURCE_PRIORITY[1024]; + + /*-------------------- Pending array --------------------*/ + volatile const uint32_t PENDING_ARRAY[32]; + volatile uint32_t RESERVED1[992]; + + /*-------------------- Target enables --------------------*/ + volatile Target_Enables_Type TARGET_ENABLES[15808]; + + volatile uint32_t RESERVED2[16384]; + + /*--- Target Priority threshold and claim/complete---------*/ + IRQ_Target_Type TARGET[15872]; + +} PLIC_Type; + +#define PLIC ((PLIC_Type *)PLIC_BASE_ADDR) + +/*============================================================================== + * The function MRV_PLIC_init() initializes the PLIC controller and enables + * the global external interrupt bit. + */ +static inline void MRV_PLIC_init(void) +{ + uint32_t inc; + unsigned long hart_id = read_csr(mhartid); + + /* Disable all interrupts for the current hart. */ + for(inc = 0; inc < ((EXT_INTR_SOURCES + 32u) / 32u); ++inc) + { + PLIC->TARGET_ENABLES[hart_id].ENABLES[inc] = 0; + } + + /* Set priorities to zero. */ + for(inc = 0; inc < EXT_INTR_SOURCES; ++inc) + { + PLIC->SOURCE_PRIORITY[inc] = 0; + } + + /* Set the threshold to zero. */ + PLIC->TARGET[hart_id].PRIORITY_THRESHOLD = 0; + + /* Enable machine external interrupts. */ + set_csr(mie, MIP_MEIP); +} + +/*============================================================================== + * The function MRV_PLIC_enable_irq() enables the external interrupt for the + * interrupt number indicated by the parameter IRQn. + */ +static inline void MRV_PLIC_enable_irq(IRQn_Type IRQn) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t current = PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32]; + current |= (uint32_t)1 << (IRQn % 32); + PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32] = current; +} + +/*============================================================================== + * The function MRV_PLIC_disable_irq() disables the external interrupt for + * the interrupt number indicated by the parameter IRQn. + + * NOTE: + * This function can be used to disable the external interrupt from outside + * external interrupt handler function. + * This function MUST NOT be used from within the External Interrupt handler. + * If you wish to disable the external interrupt while the interrupt handler + * for that external interrupt is executing then you must use the return value + * EXT_IRQ_DISABLE to return from the extern interrupt handler. + */ +static inline void MRV_PLIC_disable_irq(IRQn_Type IRQn) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t current = PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32]; + + current &= ~((uint32_t)1 << (IRQn % 32)); + + PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32] = current; +} + +/*============================================================================== + * The function MRV_PLIC_set_priority() sets the priority for the external + * interrupt for the interrupt number indicated by the parameter IRQn. + */ +static inline void MRV_PLIC_set_priority(IRQn_Type IRQn, uint32_t priority) +{ + PLIC->SOURCE_PRIORITY[IRQn] = priority; +} + +/*============================================================================== + * The function MRV_PLIC_get_priority() returns the priority for the external + * interrupt for the interrupt number indicated by the parameter IRQn. + */ +static inline uint32_t MRV_PLIC_get_priority(IRQn_Type IRQn) +{ + return PLIC->SOURCE_PRIORITY[IRQn]; +} + +/***************************************************************************//** + * MRV_PLIC_clear_pending_irq(void) + * This is only called by the startup hart and only once + * Clears any pending interrupts as PLIC can be in unknown state on startup + */ +static inline void MRV_PLIC_clear_pending_irq(void) +{ + unsigned long hart_id = read_csr(mhartid); + volatile uint32_t int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; + volatile int32_t wait_possible_int; + + while (NoInterrupt_IRQn != int_num) + { + PLIC->TARGET[hart_id].CLAIM_COMPLETE = int_num; + wait_possible_int = 0xFU; + while (wait_possible_int) + { + wait_possible_int--; + } + + int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; + } +} + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* RISCV_PLIC_H */ diff --git a/miv-rv32-udma/src/platform/miv_rv32_hal/miv_rv32_regs.h b/miv-rv32-udma/src/platform/miv_rv32_hal/miv_rv32_regs.h new file mode 100644 index 0000000..1837f42 --- /dev/null +++ b/miv-rv32-udma/src/platform/miv_rv32_hal/miv_rv32_regs.h @@ -0,0 +1,543 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor register bit mask and shift constants encodings. + * + */ +#ifndef RISCV_REGS_H +#define RISCV_REGS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MSTATUS_UIE 0x00000001UL +#define MSTATUS_SIE 0x00000002UL +#define MSTATUS_HIE 0x00000004UL +#define MSTATUS_MIE 0x00000008UL +#define MSTATUS_UPIE 0x00000010UL +#define MSTATUS_SPIE 0x00000020UL +#define MSTATUS_HPIE 0x00000040UL +#define MSTATUS_MPIE 0x00000080UL +#define MSTATUS_SPP 0x00000100UL +#define MSTATUS_HPP 0x00000600UL +#define MSTATUS_MPP 0x00001800UL +#define MSTATUS_FS 0x00006000UL +#define MSTATUS_XS 0x00018000UL +#define MSTATUS_MPRV 0x00020000UL +#define MSTATUS_SUM 0x00040000UL +#define MSTATUS_MXR 0x00080000UL +#define MSTATUS_TVM 0x00100000UL +#define MSTATUS_TW 0x00200000UL +#define MSTATUS_TSR 0x00400000UL +#define MSTATUS_RES 0x7F800000UL +#define MSTATUS32_SD 0x80000000UL +#define MSTATUS64_SD 0x8000000000000000UL + +#define MCAUSE32_CAUSE 0x7FFFFFFFUL +#define MCAUSE64_CAUSE 0x7FFFFFFFFFFFFFFFUL +#define MCAUSE32_INT 0x80000000UL +#define MCAUSE64_INT 0x8000000000000000UL + +#define MIP_SSIP (1u << IRQ_S_SOFT) +#define MIP_HSIP (1u << IRQ_H_SOFT) +#define MIP_MSIP (1u << IRQ_M_SOFT) +#define MIP_STIP (1u << IRQ_S_TIMER) +#define MIP_HTIP (1u << IRQ_H_TIMER) +#define MIP_MTIP (1u << IRQ_M_TIMER) +#define MIP_SEIP (1u << IRQ_S_EXT) +#define MIP_HEIP (1u << IRQ_H_EXT) +#define MIP_MEIP (1u << IRQ_M_EXT) + +#ifndef MIV_LEGACY_RV32 +#define MGEUI 16U +#define MGECI 17U +#define MSYS_EI0 24U +#define MSYS_EI1 25U +#define MSYS_EI2 26U +#define MSYS_EI3 27U +#define MSYS_EI4 28U +#define MSYS_EI5 29U +#define OPSRV_REG 30U + +#define MGEUI_MEIP (1u << MGEUI) +#define MGECI_MEIP (1u << MGECI) +#define MSYS_EI0IP (1u << MSYS_EI0) +#define MSYS_EI1IP (1u << MSYS_EI1) +#define MSYS_EI2IP (1u << MSYS_EI2) +#define MSYS_EI3IP (1u << MSYS_EI3) +#define MSYS_EI4IP (1u << MSYS_EI4) +#define MSYS_EI5IP (1u << MSYS_EI5) +#define MSYS_EXTERNAL_INT (0x3Fu << MSYS_EI0) +#define MIP_OPSRV_REG (1u << OPSRV_REG) +#endif + +#define PRV_M 3U + +#define VM_MBARE 0U +#define VM_MBB 1U +#define VM_MBBID 2U +#define VM_SV32 8U +#define VM_SV39 9U +#define VM_SV48 10U + +#define IRQ_S_SOFT 1U +#define IRQ_H_SOFT 2U +#define IRQ_M_SOFT 3U +#define IRQ_S_TIMER 5U +#define IRQ_H_TIMER 6U +#define IRQ_M_TIMER 7U +#define IRQ_S_EXT 9U +#define IRQ_H_EXT 10U +#define IRQ_M_EXT 11U + +#define DEFAULT_RSTVEC 0x00001000 +#define DEFAULT_NMIVEC 0x00001004 +#define DEFAULT_MTVEC 0x00001010 +#define CONFIG_STRING_ADDR 0x0000100C +#define EXT_IO_BASE 0x40000000 +#define DRAM_BASE 0x80000000 + +#ifdef __riscv + +#if __riscv_xlen == 64 +# define MSTATUS_SD MSTATUS64_SD +# define SSTATUS_SD SSTATUS64_SD +# define MCAUSE_INT MCAUSE64_INT +# define MCAUSE_CAUSE MCAUSE64_CAUSE +# define RISCV_PGLEVEL_BITS 9 +#else +# define MSTATUS_SD MSTATUS32_SD +# define SSTATUS_SD SSTATUS32_SD +# define RISCV_PGLEVEL_BITS 10 +# define MCAUSE_INT MCAUSE32_INT +# define MCAUSE_CAUSE MCAUSE32_CAUSE +#endif + +#define RISCV_PGSHIFT 12U +#define RISCV_PGSIZE (1U << RISCV_PGSHIFT) + +#ifndef __ASSEMBLER__ + +#ifdef __GNUC__ + +#define read_csr(reg) ({ unsigned long __tmp; \ + __asm__ volatile ("csrr %0, " #reg : "=r"(__tmp)); \ + __tmp; }) + +#define write_csr(reg, val) ({ \ + __asm__ volatile ("csrw " #reg ", %0" :: "rK"(val)); }) + +#define swap_csr(reg, val) ({ unsigned long __tmp; \ + __asm__ volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "rK"(val)); \ + __tmp; }) + +#define set_csr(reg, bit) ({ unsigned long __tmp; \ + __asm__ volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ + __tmp; }) + +#define clear_csr(reg, bit) ({ unsigned long __tmp; \ + __asm__ volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ + __tmp; }) + +#ifdef __riscv_atomic + +#define MASK(nr) (1UL << nr) +#define MASK_NOT(nr) (~(1UL << nr)) + +/** + * atomic_read - read atomic variable + * @v: pointer of type int + * + * Atomically reads the value of @v. + */ +static inline int atomic_read(const int *v) +{ + return *((volatile int *)(v)); +} + +/** + * atomic_set - set atomic variable + * @v: pointer of type int + * @i: required value + * + * Atomically sets the value of @v to @i. + */ +static inline void atomic_set(int *v, int i) +{ + *v = i; +} + +/** + * atomic_add - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v. + */ +static inline void atomic_add(int i, int *v) +{ + __asm__ __volatile__ ( + "amoadd.w zero, %1, %0" + : "+A" (*v) + : "r" (i)); +} + +static inline int atomic_fetch_add(unsigned int mask, int *v) +{ + int out; + + __asm__ __volatile__ ( + "amoadd.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_sub - subtract integer from atomic variable + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v. + */ +static inline void atomic_sub(int i, int *v) +{ + atomic_add(-i, v); +} + +static inline int atomic_fetch_sub(unsigned int mask, int *v) +{ + int out; + + __asm__ __volatile__ ( + "amosub.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_add_return - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v and returns the result + */ +static inline int atomic_add_return(int i, int *v) +{ + register int c; + __asm__ __volatile__ ( + "amoadd.w %0, %2, %1" + : "=r" (c), "+A" (*v) + : "r" (i)); + return (c + i); +} + +/** + * atomic_sub_return - subtract integer from atomic variable + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v and returns the result + */ +static inline int atomic_sub_return(int i, int *v) +{ + return atomic_add_return(-i, v); +} + +/** + * atomic_inc - increment atomic variable + * @v: pointer of type int + * + * Atomically increments @v by 1. + */ +static inline void atomic_inc(int *v) +{ + atomic_add(1, v); +} + +/** + * atomic_dec - decrement atomic variable + * @v: pointer of type int + * + * Atomically decrements @v by 1. + */ +static inline void atomic_dec(int *v) +{ + atomic_add(-1, v); +} + +static inline int atomic_inc_return(int *v) +{ + return atomic_add_return(1, v); +} + +static inline int atomic_dec_return(int *v) +{ + return atomic_sub_return(1, v); +} + +/** + * atomic_sub_and_test - subtract value from variable and test result + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v and returns + * true if the result is zero, or false for all + * other cases. + */ +static inline int atomic_sub_and_test(int i, int *v) +{ + return (atomic_sub_return(i, v) == 0); +} + +/** + * atomic_inc_and_test - increment and test + * @v: pointer of type int + * + * Atomically increments @v by 1 + * and returns true if the result is zero, or false for all + * other cases. + */ +static inline int atomic_inc_and_test(int *v) +{ + return (atomic_inc_return(v) == 0); +} + +/** + * atomic_dec_and_test - decrement and test + * @v: pointer of type int + * + * Atomically decrements @v by 1 and + * returns true if the result is 0, or false for all other + * cases. + */ +static inline int atomic_dec_and_test(int *v) +{ + return (atomic_dec_return(v) == 0); +} + +/** + * atomic_add_negative - add and test if negative + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v and returns true + * if the result is negative, or false when + * result is greater than or equal to zero. + */ +static inline int atomic_add_negative(int i, int *v) +{ + return (atomic_add_return(i, v) < 0); +} + +static inline int atomic_xchg(int *v, int n) +{ + register int c; + __asm__ __volatile__ ( + "amoswap.w %0, %2, %1" + : "=r" (c), "+A" (*v) + : "r" (n)); + return c; +} + +/** + * atomic_and - Atomically clear bits in atomic variable + * @mask: Mask of the bits to be retained + * @v: pointer of type int + * + * Atomically retains the bits set in @mask from @v + */ +static inline void atomic_and(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoand.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_and(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoand.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_or - Atomically set bits in atomic variable + * @mask: Mask of the bits to be set + * @v: pointer of type int + * + * Atomically sets the bits set in @mask in @v + */ +static inline void atomic_or(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoor.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_or(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoor.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_xor - Atomically flips bits in atomic variable + * @mask: Mask of the bits to be flipped + * @v: pointer of type int + * + * Atomically flips the bits set in @mask in @v + */ +static inline void atomic_xor(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoxor.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_xor(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoxor.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * test_and_set_bit - Set a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_set_bit(int nr, volatile unsigned long *addr) +{ + unsigned long __res, __mask; + __mask = MASK(nr); + __asm__ __volatile__ ( \ + "amoor.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to clear + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_clear_bit(int nr, volatile unsigned long *addr) +{ + unsigned long __res, __mask; + __mask = MASK_NOT(nr); + __asm__ __volatile__ ( \ + "amoand.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * test_and_change_bit - Change a bit and return its old value + * @nr: Bit to change + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_change_bit(int nr, volatile unsigned long *addr) +{ + + unsigned long __res, __mask; + __mask = MASK(nr); + __asm__ __volatile__ ( \ + "amoxor.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * set_bit - Atomically set a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * This function is atomic and may not be reordered. + */ + +static inline void set_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOOR.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK(nr))); +} + +/** + * clear_bit - Clears a bit in memory + * @nr: Bit to clear + * @addr: Address to start counting from + * + * clear_bit() is atomic and may not be reordered. + */ +static inline void clear_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOAND.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK_NOT(nr))); +} + +/** + * change_bit - Toggle a bit in memory + * @nr: Bit to change + * @addr: Address to start counting from + * + * change_bit() is atomic and may not be reordered. + */ +static inline void change_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOXOR.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK(nr))); +} + +#endif /* __riscv_atomic */ + +#endif /* __GNUC__ */ + +#endif /* __ASSEMBLER__ */ + +#endif /* __riscv */ + +#ifdef __cplusplus +} +#endif + +#endif /* RISCV_REGS_H */ diff --git a/miv-rv32-udma/src/platform/miv_rv32_hal/miv_rv32_stubs.c b/miv-rv32-udma/src/platform/miv_rv32_hal/miv_rv32_stubs.c new file mode 100644 index 0000000..7f5042b --- /dev/null +++ b/miv-rv32-udma/src/platform/miv_rv32_hal/miv_rv32_stubs.c @@ -0,0 +1,239 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_stubs.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Stubs for the Mi-V soft processor Interrupt handler. + * + * The functions below will only be linked with the application code if the user + * does not provide an implementation for these functions. These functions are + * defined with weak linking so that they can be overridden by a function with + * same prototype in the user's application code. + * + */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +__attribute__((weak)) void Software_IRQHandler(void) +{ + _exit(10); +} + +__attribute__((weak)) void SysTick_Handler(void) +{ + /* Default handler */ +} + +#ifdef MIV_LEGACY_RV32 +__attribute__((weak)) uint8_t Invalid_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_1_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_2_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_3_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_4_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_5_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_6_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_7_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_8_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_9_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_10_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_11_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_12_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_13_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_14_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_15_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_16_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_17_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_18_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_19_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_20_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_21_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_22_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_23_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_24_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_25_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_26_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_27_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_28_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_29_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_30_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_31_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +#else + +__attribute__((weak)) void External_IRQHandler(void) +{ +} + +__attribute__((weak)) void MGECI_IRQHandler(void) +{ +} + +__attribute__((weak)) void MGEUI_IRQHandler(void) +{ +} + +__attribute__((weak)) void OPSRV_IRQHandler(void) +{ +} + +__attribute__((weak)) void MSYS_EI5_IRQHandler(void) +{ +} + +__attribute__((weak)) void MSYS_EI4_IRQHandler(void) +{ +} + +__attribute__((weak)) void MSYS_EI3_IRQHandler(void) +{ +} + +__attribute__((weak)) void MSYS_EI2_IRQHandler(void) +{ +} + +__attribute__((weak)) void MSYS_EI1_IRQHandler(void) +{ +} + +__attribute__((weak)) void MSYS_EI0_IRQHandler(void) +{ +} + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/miv-rv32-udma/src/platform/miv_rv32_hal/miv_rv32_syscall.c b/miv-rv32-udma/src/platform/miv_rv32_hal/miv_rv32_syscall.c new file mode 100644 index 0000000..b24e729 --- /dev/null +++ b/miv-rv32-udma/src/platform/miv_rv32_hal/miv_rv32_syscall.c @@ -0,0 +1,349 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_syscall.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Stubs for system calls. + * + */ +#include +#include +#include +#include +#include "miv_rv32_hal.h" + +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + +#ifndef LEGACY_DIR_STRUCTURE +#include "drivers/fabric_ip/CoreUARTapb/core_uart_apb.h" +#else +#include "core_uart_apb.h" +#endif + +#endif /*MSCC_STDIO_THRU_CORE_UART_APB*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + +/*------------------------------------------------------------------------------ + * CoreUARTapb instance data for the CoreUARTapb instance used for standard + * output. + */ +static UART_instance_t g_stdio_uart; + +/*============================================================================== + * Flag used to indicate if the UART driver needs to be initialized. + */ +static int g_stdio_uart_init_done = 0; + +/* + * Disable semihosting apis + */ +#pragma import(__use_no_semihosting_swi) + +/*============================================================================== + * sendchar() + */ +int sendchar(int ch) +{ + /*-------------------------------------------------------------------------- + * Initialize the UART driver if it is the first time this function is + * called. + */ + if ( !g_stdio_uart_init_done ) + { + /****************************************************************************** + * Baud value: + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + UART_init( &g_stdio_uart, + MSCC_STDIO_UART_BASE_ADDR, + ((SYS_CLK_FREQ/(16 * MSCC_STDIO_BAUD_VALUE))-1), + (DATA_8_BITS | NO_PARITY)); + + g_stdio_uart_init_done = 1; + } + + /*-------------------------------------------------------------------------- + * Output text to the UART. + */ + UART_send( &g_stdio_uart, (uint8_t *)&ch, 1 ); + + return (ch); +} + +/*============================================================================== + * getachar() + */ +int getachar(void) +{ + uint8_t rx_size; + uint8_t rx_byte; + + if ( !g_stdio_uart_init_done ) + { + /****************************************************************************** + * Baud value: + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + UART_init( &g_stdio_uart, + MSCC_STDIO_UART_BASE_ADDR, + ((SYS_CLK_FREQ/(16 * MSCC_STDIO_BAUD_VALUE))-1), + (DATA_8_BITS | NO_PARITY)); + + g_stdio_uart_init_done = 1; + } + + do + { + rx_size = UART_get_rx(&g_stdio_uart, &rx_byte, 1); + } while(0u == rx_size); + + return rx_byte; +} + +#endif /*MSCC_STDIO_THRU_CORE_UART_APB*/ + +#undef errno +static int errno; + +static char *__env[1] = { 0 }; +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--) + { + jj = ii-1U; + digit = ((hex & (0xFU << (jj*4U))) >> (jj*4U)); + towrite = digit < 0xAU ? (0x48U + digit) : (0x65U + (digit - 0xAU)); + write( fd, &towrite, 1U); + } +} + + +#ifdef GDB_TESTING +void __attribute__((optimize("O0"))) _exit(int code) +#else +void _exit(int code) +#endif +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + const char * message = "\nProgam has exited with code:"; + + write(STDERR_FILENO, message, strlen(message)); + write_hex(STDERR_FILENO, code); +#endif + + while (1){}; +} + +void *_sbrk(ptrdiff_t incr) +{ + extern char _end[]; + extern char _heap_end[]; + static char *curbrk = _end; + void * ret = NULL; + + if (((curbrk + incr) < _end) || ((curbrk + incr) > _heap_end)) + { + ret = ((char *) - 1); + } + else + { + curbrk += incr; + ret = curbrk - incr; + } + + return(ret); +} + +int _isatty(int fd) +{ + int ret = 0; + + if (fd <= 2) /* one of stdin, stdout, stderr */ + { + ret = 1; + } + else + { + errno = EBADF; + ret = 0; + } + + return(ret); +} + +static int stub(int err) +{ + errno = err; + return -1; +} + +int _open(const char* name, int flags, int mode) +{ + return stub(ENOENT); +} + +int _openat(int dirfd, const char* name, int flags, int mode) +{ + return stub(ENOENT); +} + +int _close(int fd) +{ + return stub(EBADF); +} + +int _execve(const char* name, char* const argv[], char* const env[]) +{ + return stub(ENOMEM); +} + +int _fork(void) +{ + return stub(EAGAIN); +} + +int _fstat(int fd, struct stat *st) +{ + int ret = 0; + + if (isatty(fd)) + { + st->st_mode = S_IFCHR; + ret = 0; + } + else + { + ret = stub(EBADF); + } + + return ret; +} + +int _getpid(void) +{ + return 1; +} + +int _kill(int pid, int sig) +{ + return stub(EINVAL); +} + +int _link(const char *old_name, const char *new_name) +{ + return stub(EMLINK); +} + +off_t _lseek(int fd, off_t ptr, int dir) +{ + off_t ret = 0; + if (_isatty(fd)) + { + ret = 0; + } + else + { + ret = stub(EBADF); + } + + return ret; +} + +ssize_t _read(int fd, void* ptr, size_t len) +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + + char* ptr1 = (char*)ptr; + + if (_isatty(fd)) + { + int count; + + for (count = 0; count < len; count++) + { + ptr1[count] = getachar(); + sendchar(ptr1[count]); + + /* Return partial buffer if we get EOL */ + if (('\r' == ptr1[count])||('\n' == ptr1[count])) + { + ptr1[count] = '\n'; + return count; + } + } + + return count; /* Filled the buffer */ + } +#endif + + return stub(EBADF); +} + +int _stat(const char* file, struct stat* st) +{ + return stub(EACCES); +} + +clock_t _times(struct tms* buf) +{ + return stub(EACCES); +} + +int _unlink(const char* name) +{ + return stub(ENOENT); +} + +int _wait(int* status) +{ + return stub(ECHILD); +} + +ssize_t _write(int fd, const void* ptr, size_t len) +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + int count_out; + char* ptr1 = (char*)ptr; + + /*-------------------------------------------------------------------------- + * Output text to the UART. + */ + count_out = 0; + while(len--) + { + sendchar(ptr1[count_out]); + count_out++; + } + + errno = 0; + return count_out; + +#else /* MSCC_STDIO_THRU_CORE_UART_APB */ + + return stub(EBADF); + +#endif /* MSCC_STDIO_THRU_CORE_UART_APB */ + +} + +#ifdef __cplusplus +} +#endif diff --git a/miv-rv32-udma/src/platform/miv_rv32_hal/sample_fpga_design_config.h b/miv-rv32-udma/src/platform/miv_rv32_hal/sample_fpga_design_config.h new file mode 100644 index 0000000..a380d96 --- /dev/null +++ b/miv-rv32-udma/src/platform/miv_rv32_hal/sample_fpga_design_config.h @@ -0,0 +1,167 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file sample_fpga_design_config.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Sample design configuration settings + * + */ + /*========================================================================*//** + @mainpage + Example file detailing how the fpga_design_config.h should be constructed + for the SoftConsole project targeted for Mi-V processors. + + @section intro_sec Introduction + The SoftConsole project targeted for Mi-V processors now have an improved + folder structure. Detailed description of the folder structure is available + at https://github.com/Mi-V-Soft-RISC-V/miv-rv32-documentation. + + The fpga_design_config.h must be stored as shown below + /boards//fpga_design_config.h + + Currently this file must be hand crafted when using the Mi-V Soft Processor. + In future, all the design and soft IP configurations will be automatically + generated from the Libero design description data. + + You can use this sample file as an example. + Rename this file from sample_fpga_design_config.h to fpga_design_config.h + and then customize it per your hardware design. + + @section Project configuration Instructions + 1. Change SYS_CLK_FREQ define to frequency of Mi-V Soft processor clock + 2 Add all the soft IP core BASE addresses + 3. Add the peripheral Core Interrupts to Mi-V Soft processor IRQ number + mappings + 4. Define MSCC_STDIO_UART_BASE_ADDR if you want a CoreUARTapb mapped to + STDIO + + **NOTE** + In the legacy folder structures, the file hw_config.h as was used at the + root of the project folder. This file is now depricated. + +*//*=========================================================================*/ + +#ifndef FPGA_DESIGN_CONFIG_H_ +#define FPGA_DESIGN_CONFIG_H_ + +/***************************************************************************//** + * Soft-processor clock definition + * This is the only clock brought over from the Mi-V Libero design. + */ +#ifndef SYS_CLK_FREQ +#define SYS_CLK_FREQ 50000000UL +#endif + +/***************************************************************************//** + * Peripheral base addresses. + * Format of define is: + * __BASE_ADDR + * The field is optional if there is only one instance of the core + * in the design + * MIV_ESS is an extended peripheral subsystem IP core with peripherals + * connections as defined below. + * The system can be further extended by attaching APB peripherals to the + * empty APB slots. + */ +#define MIV_ESS_PLIC_BASE_ADDR 0x70000000UL +#define COREUARTAPB0_BASE_ADDR 0x71000000UL +#define MIV_MTIMER_BASE_ADDR 0x72000000UL +#define MIV_ESS_APBSLOT3_BASE_ADDR 0x73000000UL +#define MIV_ESS_APBSLOT4_BASE_ADDR 0x74000000UL +#define COREGPIO_OUT_BASE_ADDR 0x75000000UL +#define CORESPI_BASE_ADDR 0x76000000UL +#define MIV_ESS_uDMA_BASE_ADDR 0x78000000UL +#define MIV_ESS_WDOG_BASE_ADDR 0x79000000UL +#define MIV_ESS_I2C_BASE_ADDR 0x7A000000UL +#define MIV_ESS_APBSLOTB_BASE_ADDR 0x7B000000UL +#define MIV_ESS_APBSLOTC_BASE_ADDR 0x7C000000UL +#define MIV_ESS_APBSLOTD_BASE_ADDR 0x7D000000UL +#define MIV_ESS_APBSLOTE_BASE_ADDR 0x7E000000UL +#define MIV_ESS_APBSLOTF_BASE_ADDR 0x7F000000UL + +/***************************************************************************//** + * Peripheral Interrupts are mapped to the corresponding Mi-V Soft processor + * interrupt in the Libero design. + * + * On the legacy RV32 cores, there can be up to 31 external interrupts (IRQ[30:0] + * pins). The legacy RV32 Soft processor external interrupts are defined in the + miv_rv32_plic.h + * + * These are of the form + * typedef enum +{ + NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + . + . + . + External_31_IRQn = 31 +} IRQn_Type; + + On the legacy RV32 processors, the PLIC identifies the interrupt and passes it + on to the processor core. The interrupt 0 is not used. The pin IRQ[0] should + map to External_1_IRQn likewise IRQ[30] should map to External_31_IRQn + +e.g + +#define TIMER0_IRQn External_30_IRQn +#define TIMER1_IRQn External_31_IRQn + + The MIV_RV32 soft processor has up to six optional system interrupts, MSYS_EI[n] + in addition to one EXT_IRQ. + The MIV_RV32 does not have an inbuilt PLIC and all the interrupts are directly + delivered to the processor core, hence unlike legacy RV32 cores, no interrupt + number mapping is necessary on MIV_RV32 core. + */ + +/**************************************************************************** + * Baud value to achieve a 115200 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ +#define BAUD_VALUE_115200 ((SYS_CLK_FREQ / (16 * 115200)) - 1) + +/****************************************************************************** + * Baud value to achieve a 57600 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + #define BAUD_VALUE_57600 ((SYS_CLK_FREQ / (16 * 57600)) - 1) + +/***************************************************************************//** + * Define MSCC_STDIO_THRU_CORE_UART_APB in the project settings if you want the + * standard IOs to be redirected to a terminal via UART. + */ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +/* + * A base address mapping for the STDIO printf/scanf mapping to CortUARTapb + * must be provided if it is being used + * + * e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR + */ +#define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB0_BASE_ADDR + +#ifndef MSCC_STDIO_UART_BASE_ADDR +#error MSCC_STDIO_UART_BASE_ADDR not defined- e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR +#endif + +#ifndef MSCC_STDIO_BAUD_VALUE +/* + * The MSCC_STDIO_BAUD_VALUE define should be set in your project's settings to + * specify the baud value used by the standard output CoreUARTapb instance for + * generating the UART's baud rate if you want a different baud rate from the + * default of 115200 baud + */ +#define MSCC_STDIO_BAUD_VALUE 115200 +#endif /*MSCC_STDIO_BAUD_VALUE*/ + +#endif /* end of MSCC_STDIO_THRU_CORE_UART_APB */ +/******************************************************************************* + * End of user edit section + */ +#endif /* FPGA_DESIGN_CONFIG_H_ */ diff --git a/miv-rv32-udma/src/platform/platform_config_reference/linker/miv-rv32-execute-in-place.ld b/miv-rv32-udma/src/platform/platform_config_reference/linker/miv-rv32-execute-in-place.ld new file mode 100644 index 0000000..19df5fb --- /dev/null +++ b/miv-rv32-udma/src/platform/platform_config_reference/linker/miv-rv32-execute-in-place.ld @@ -0,0 +1,154 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-execute-in-place.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * image executing from a one address space whereas the data, sdata and stack + * sections are placed in another address space. This could be used in cases such + * as: + * 1) When using MIV_RV32, the reset vector points to the LSRAM at address + * 0x80000000 and the data, sdata, bss and stack sections are placed in the + * TCM region. + * + * 2) Executing from a Non Volatile memory. The actual memory will depend on + * the FPGA platform. For exameple, it could be the eNVM on SmartFusion2, + * Igloo2 or on-board non-volatile memory which supports code execution. + * + * NOTE: Modify the memory section addresses and the sizes according to your + * Libero design. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + + +MEMORY +{ + rom (rx) : ORIGIN = 0x80000000, LENGTH = 16k + ram (rwx) : ORIGIN = 0x80004000, LENGTH = 16k +} + +STACK_SIZE = 1k; /* needs to be calculated for your application */ +HEAP_SIZE = 0; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > rom + + .text : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.text.entry))) + . = ALIGN(0x10); + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } >rom + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } >ram AT>rom + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } >ram AT>rom + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram +} + diff --git a/miv-rv32-udma/src/platform/platform_config_reference/linker/miv-rv32-ram.ld b/miv-rv32-udma/src/platform/platform_config_reference/linker/miv-rv32-ram.ld new file mode 100644 index 0000000..e0707df --- /dev/null +++ b/miv-rv32-udma/src/platform/platform_config_reference/linker/miv-rv32-ram.ld @@ -0,0 +1,150 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-ram.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * debug image executing in SRAM. + * + * This linker script assumes that a RAM is connected at on Mi-V soft processor + * memory space pointed by the reset vector address. + * + * NOTE : Modify the memory section address and the size according to your + * Libero design. + * For example: + * 1) If you want to download and step debug at a different RAM memory address in + * your design (For example TCM base address) than the one provided in this file. + * 2) The MIV_RV32, when used with MIV_ESS IP, provides ways to copy the executable + * HEX file from external Non-Volatile memory into the TCM at reset. In this + * case your executable must be linked to the TCM address. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +MEMORY +{ + ram (rwx) : ORIGIN = 0x80000000, LENGTH = 32k +} + +STACK_SIZE = 2k; /* needs to be calculated for your application */ +HEAP_SIZE = 0k; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > ram + + .text : ALIGN(0x10) + { + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } > ram + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } > ram + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } > ram + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram +} + diff --git a/miv-rv32-udma/src/platform/platform_config_reference/linker/readme.md b/miv-rv32-udma/src/platform/platform_config_reference/linker/readme.md new file mode 100644 index 0000000..5581d1b --- /dev/null +++ b/miv-rv32-udma/src/platform/platform_config_reference/linker/readme.md @@ -0,0 +1,2 @@ +# readme + diff --git a/miv-rv32-udma/src/platform/platform_config_reference/miv_rv32_hal_config/readme.md b/miv-rv32-udma/src/platform/platform_config_reference/miv_rv32_hal_config/readme.md new file mode 100644 index 0000000..5581d1b --- /dev/null +++ b/miv-rv32-udma/src/platform/platform_config_reference/miv_rv32_hal_config/readme.md @@ -0,0 +1,2 @@ +# readme +