diff --git a/driver-examples/miv-watchdog/miv-rv32-wdog/.cproject b/driver-examples/miv-watchdog/miv-rv32-wdog/.cproject new file mode 100644 index 0000000..1469831 --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/.cproject @@ -0,0 +1,622 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/driver-examples/miv-watchdog/miv-rv32-wdog/.gitignore b/driver-examples/miv-watchdog/miv-rv32-wdog/.gitignore new file mode 100644 index 0000000..01bd439 --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/.gitignore @@ -0,0 +1,5 @@ +/.settings/ +/Debug/ +/Release/ +/miv32imc-Debug/ +/miv32imc-Release/ diff --git a/driver-examples/miv-watchdog/miv-rv32-wdog/.project b/driver-examples/miv-watchdog/miv-rv32-wdog/.project new file mode 100644 index 0000000..85bcd65 --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/.project @@ -0,0 +1,36 @@ + + + miv-rv32-wdog + + + + + + 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 + + + + PLATFORM_LOC + $%7BPARENT-1-PROJECT_LOC%7D/platform + + + PLATFORM_LOC1 + $%7BPARENT-3-ECLIPSE_HOME%7D/BB5/g/new/mss-i2c-examples/myprojects/miv_rv32/platform + + + diff --git a/driver-examples/miv-watchdog/miv-rv32-wdog/README.md b/driver-examples/miv-watchdog/miv-rv32-wdog/README.md new file mode 100644 index 0000000..b5f48fb --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/README.md @@ -0,0 +1,57 @@ +# MIV Watchdog Example + +This project demonstrates the Mi-V Soft IP WDOG module functionality, which is delivered as a +part of MIV Extended Sub System(MIV_ESS). +This project will perform the watchdog configurations, the time-out interrupt and the +Maximum Value up to which Refresh is Permitted (MVRP) interrupt and their handling. + +The MIV ESS Core generates MVRP_IRQ and WDOG_IRQ interrupts which can be connected +to any of the external interrupt pins on the MIV_RV32. The application developer +will have to handle these interrupts in the respective interrupt handlers. + +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 interface1 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 with MIV_RV32 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/driver-examples/miv-watchdog/miv-rv32-wdog/miv-rv32-wdog hw attach.launch b/driver-examples/miv-watchdog/miv-rv32-wdog/miv-rv32-wdog hw attach.launch new file mode 100644 index 0000000..5558a29 --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/miv-rv32-wdog hw attach.launch @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/driver-examples/miv-watchdog/miv-rv32-wdog/miv-rv32-wdog hw debug.launch b/driver-examples/miv-watchdog/miv-rv32-wdog/miv-rv32-wdog hw debug.launch new file mode 100644 index 0000000..1945fac --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/miv-rv32-wdog hw debug.launch @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/driver-examples/miv-watchdog/miv-rv32-wdog/src/application/main.c b/driver-examples/miv-watchdog/miv-rv32-wdog/src/application/main.c new file mode 100644 index 0000000..bebe4da --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/src/application/main.c @@ -0,0 +1,186 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Sample project to demonstrate the MIV Watchdog functionality. + * + * 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_watchdog/miv_watchdog.h" + +/****************************************************************************** + * MIV Peripheral instance data. + *****************************************************************************/ + UART_instance_t g_uart; + miv_wdog_config_t wd0_config; + +/*----------------------------------------------------------------------------- + * Watchdog instance data. + */ +volatile uint8_t h0_triggered = 0u; +volatile uint8_t h0_mvrp = 0u; + +/*============================================================================== + * Messages displayed over the UART. + */ +const uint8_t g_greeting_msg[] = +"\r\n***********************************************************************\r\n\n\ +******************** Mi-V Watchdog Example ***********************\r\n\n\ +***************************************************************************\r\n\r\n\ +The MVRP interrupt will occur after 34 seconds, after system reset \r\n\ +The Time out interrupt will occur after 85 seconds, after system reset \r\n\n "; + +const uint8_t g_separator[] = +"\r\n----------------------------------------------------------------------\r\n"; + +static void display_greeting(void); + +uint8_t data_buffer [1024]; +uint8_t input_text[506] = {0x00}; + +static void clear_data_buffer(void) +{ + uint32_t idx = 0u; + + while (idx < 1024u) + { + data_buffer[idx++] = 0x00u; + } +} +/*============================================================================== + * Display greeting message when application is started. + */ +static void display_greeting(void) +{ + UART_polled_tx_string(&g_uart, g_greeting_msg); +} + +void MSYS_EI3_IRQHandler() +{ + h0_mvrp = 1; + + /* Un-commenting the below statement will refresh the Watchdog and then the + * timer will be reloaded to original TIME value and start decrementing. + * This will avoid the timeout interrupt and RESET. + * + * Not reloading the Watchdog will make the down counter to pass below + * trigger value and cause a timeout interrupt. When the down counter rolls + * down to zero, it would generate a RESET. + * */ + +// MIV_WDOG_reload(); + + MIV_WDOG_clear_mvrp_irq(); + +} + +void MSYS_EI4_IRQHandler() +{ + h0_triggered = 1u; + + MIV_WDOG_clear_timeout_irq(); +} + +/****************************************************************************** + * main function. + *****************************************************************************/ +void main(void) +{ + size_t rx_size; + uint8_t rx_buff[1] = {0x00}; + uint32_t counter = 0; + uint32_t read_data[100] = {0}; + uint32_t icount = 0u; + uint32_t current_value = 0u; + + clear_data_buffer(); + + /* 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_EIE3_IRQn | MRV32_MSYS_EIE4_IRQn ); + + HAL_enable_interrupts(); + + MIV_WDOG_init(MIV_ESS_WDOG_BASE_ADDR); + /* Read the default config */ + MIV_WDOG_get_config(&wd0_config); + + /* Set such that the MVRP interrupt will happen after ~13 seconds after + * reset and the Trigger interrupt will happen after ~25 seconds. + */ + + wd0_config.forbidden_en = MIV_WDOG_ENABLE; + wd0_config.timeout_val = 0x3e0u; + wd0_config.mvrp_val = (10000000UL); + wd0_config.time_val = (2UL*10000000UL); + + MIV_WDOG_configure(&wd0_config); + + MIV_WDOG_enable_mvrp_irq(); + + while(1u) + { + icount++; + + if (0x90000u == icount) + { + /* + * Read the current value after 90000 ticks. + */ + icount = 0u; + current_value = MIV_WDOG_current_value(); + snprintf((char *)data_buffer, sizeof(data_buffer), + "WD0 value = %x\r\n", *(uint32_t*)0x79000000); + + + UART_polled_tx_string(&g_uart, + data_buffer); + } + + if(h0_mvrp) + { + UART_polled_tx_string(&g_uart, + (const uint8_t *)"\r\nMVRP Interrupt...\n"); + h0_mvrp = 0; + + UART_polled_tx_string(&g_uart, + (const uint8_t *)"\r\nMVRP IRQ Cleared \r\n"); + + snprintf((char *)data_buffer, sizeof(data_buffer), + "\r\nH0 MVRP - Returned to Local\r\n\n"); + + UART_polled_tx_string(&g_uart, + data_buffer); + } + + if(h0_triggered) + { + UART_polled_tx_string(&g_uart, + (const uint8_t *)"\r\nWDOG Interrupt...\n"); + + h0_triggered = 0; + + UART_polled_tx_string(&g_uart, + (const uint8_t *)"\r\nWDOG IRQ Cleared \r\n"); + + snprintf((char *)data_buffer, sizeof(data_buffer), + "\r\nH0 timeout - Returned to Local\r\n"); + + + UART_polled_tx_string(&g_uart, + data_buffer); + } + + } +} diff --git a/driver-examples/miv-watchdog/miv-rv32-wdog/src/boards/polarfire-eval-kit/fpga_design/design_description/README.md b/driver-examples/miv-watchdog/miv-rv32-wdog/src/boards/polarfire-eval-kit/fpga_design/design_description/README.md new file mode 100644 index 0000000..4f7aa4b --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/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/driver-examples/miv-watchdog/miv-rv32-wdog/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h b/driver-examples/miv-watchdog/miv-rv32-wdog/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h new file mode 100644 index 0000000..cd52abc --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h @@ -0,0 +1,150 @@ +/******************************************************************************* + * 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_WDOG_BASE_ADDR 0x79000000UL + +/***************************************************************************//** + * 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/driver-examples/miv-watchdog/miv-rv32-wdog/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-execute-in-place.ld b/driver-examples/miv-watchdog/miv-rv32-wdog/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-execute-in-place.ld new file mode 100644 index 0000000..19df5fb --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/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/driver-examples/miv-watchdog/miv-rv32-wdog/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld b/driver-examples/miv-watchdog/miv-rv32-wdog/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld new file mode 100644 index 0000000..e0707df --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/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/driver-examples/miv-watchdog/miv-rv32-wdog/src/boards/polarfire-eval-kit/platform_config/miv_rv32_hal_config/readme.md b/driver-examples/miv-watchdog/miv-rv32-wdog/src/boards/polarfire-eval-kit/platform_config/miv_rv32_hal_config/readme.md new file mode 100644 index 0000000..46ee0bd --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/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/driver-examples/miv-watchdog/miv-rv32-wdog/src/middleware/README.md b/driver-examples/miv-watchdog/miv-rv32-wdog/src/middleware/README.md new file mode 100644 index 0000000..dafa1d2 --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/src/middleware/README.md @@ -0,0 +1 @@ +Place holder readme file in the middleware directory. diff --git a/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c new file mode 100644 index 0000000..63cd377 --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/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/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h new file mode 100644 index 0000000..3491d68 --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/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/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h new file mode 100644 index 0000000..0c13e28 --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/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/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c new file mode 100644 index 0000000..2b2087a --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/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/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h new file mode 100644 index 0000000..2ce0b88 --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/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/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h new file mode 100644 index 0000000..8651f0c --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/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/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c new file mode 100644 index 0000000..5cf19c5 --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c @@ -0,0 +1,93 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Mi-V Watchdog Soft IP bare-metal driver. This module is delivered as part of + * Extended Sub System(ESS) MIV_ESS. + * Please refer to miv_watchdog.h file for more information. + */ + +#include "miv_watchdog.h" + +addr_t g_this_wdog; + +/***************************************************************************//* + * Please refer to miv_watchdog.h for more info about this function + */ +void +MIV_WDOG_init +( + addr_t base_addr +) +{ + /* Register the Mi-V Watchdog base address to the driver */ + g_this_wdog = base_addr; +} + +/***************************************************************************//* + * Please refer to miv_watchdog.h for more info about this function + */ +uint8_t MIV_WDOG_configure +( + const miv_wdog_config_t *config +) +{ + uint8_t error = 0u; + + /* check load value and trigger max value */ + if (config->timeout_val <= MIV_WDOG_TRIGGER_MAX) + { + HAL_set_32bit_reg(g_this_wdog, WDOGTRIG,(config->timeout_val)); + } + else + { + error = 1u; + } + + if (config->time_val <= MIV_WDOG_TIMER_MAX) + { + HAL_set_32bit_reg(g_this_wdog, WDOGMSVP,(config->mvrp_val)); + } + else + { + error = 1u; + } + + HAL_set_32bit_reg_field(g_this_wdog, WDOGCNTL_NEXT_ENFORBIDDEN, + config->forbidden_en); + + /* Reload watchdog with new load if it is not in forbidden window */ + if (!(WDOGSTAT_FORBIDDEN_MASK & (HAL_get_32bit_reg(g_this_wdog, WDOGSTAT)))) + { + HAL_set_32bit_reg(g_this_wdog, WDOGRFSH, MIV_WDOG_REFRESH_KEY); + } + else + { + error = 1u; + } + + return (error); +} + +/***************************************************************************//* + * Please refer to miv_watchdog.h for more info about this function + */ +void MIV_WDOG_get_config +( + miv_wdog_config_t *config +) +{ + if (0 != g_this_wdog) + { + + config->time_val = HAL_get_32bit_reg(g_this_wdog, WDOGTIME); + + config->timeout_val = HAL_get_32bit_reg(g_this_wdog, WDOGTRIG); + + config->mvrp_val = HAL_get_32bit_reg(g_this_wdog, WDOGMSVP); + + config->forbidden_en = HAL_get_32bit_reg_field(g_this_wdog, + WDOGCNTL_NEXT_ENFORBIDDEN); + } +} diff --git a/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h new file mode 100644 index 0000000..8877e55 --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h @@ -0,0 +1,553 @@ +/******************************************************************************* + * 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 + * Watchdog module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(MIV_ESS). + */ +/*=========================================================================*//** + @mainpage MiV Watchdog Bare Metal Driver + + ============================================================================== + Introduction + ============================================================================== + The Mi-V Watchdog module in the MIV_ESS is used to generate a reset for the + system automatically if the software doesn't periodically update or refresh + the timer countdown register. This software driver provides set of functions + for controlling Mi-V Watchdog module as a part of bare metal system where no + operating system is available. The driver can be adapted for use as a 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 the + driver. + + Mi-V Watchdog provides following features: + - Initializing the Mi-V Watchdog + - Reading current value and status of watchdog timer + - Refreshing the watchdog timer value + - Enabling, disabling and clearing timeout and Maximum Value up to which + Refresh is Permitted (MVRP) interrupts. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + The application software should initialize and configure the Mi-V Watchdog + module the the call to the MIV_WDOG_init() and MIV_WDOG_configure() functions. + + No MIV_WDOG hardware configuration parameter are used by the driver, apart + from the MIV_WDOG base address. Hence, no additional configuration files are + required to use the driver. + + ============================================================================== + Theory of Operation + ============================================================================== + The Mi-V Watchdog driver functions are grouped into the following categories: + - Initialization and configuration + - Reading the current value and status of the watchdog timer + - Refreshing the watchdog timer value + - Support for enabling, disabling and clearing time-out and MVRP interrupts. + + -------------------------------- + Initialization and Configuration + -------------------------------- + The MIV_WDOG_init() function stores the base of MIV_WDT module in the MIV_ESS. + This base address is used by rest of the functions to access the Mi-V Watchdog + registers. Please make call this function before calling any other function + from this driver. + Note: The Mi-V Watchdog driver supports only one instance of MIV_WDT in the + hardware. + The Mi-V Watchdog driver provides the MIV_WDOG_configure() function to + configure the MIV_WDOG module with desired configuration values. It also + provides the MIV_WDOG_get_config() to read back the current configuration of + the MIV_WDOG. You can use this function to retrieve the current configurations + and then overwrite them with the application specific values, such as initial + watchdog timer value, Maximum Value (up to which) Refresh (is) Permitted, + watchdog time-out value, enable/disable forbidden region, enable/disable + MVRP interrupt and interrupt type. + + -------------------------------------------- + Reading the Watchdog Timer Value and Status + -------------------------------------------- + Mi-V Watchdog is a down counter. A refresh forbidden window can be created by + configuring the watchdog Maximum Value up to which Refresh is Permitted (MVRP). + When the current value of the watchdog timer is greater than the MVRP value, + refreshing the watchdog is forbidden. Attempting to refresh the watchdog timer + in the forbidden window will assert a timeout interrupt. The + MIV_WDOG_forbidden_status() function can be used to know whether the watchdog + timer is in forbidden window or has crossed it. By default, the forbidden + window is disabled. It can be enabled by providing an appropriate value as + parameter to the MIV_WDOG_configure() function. When the forbidden window is + disabled, any attempt to refresh the watchdog timer is ignored and the counter + keeps on down counting. + + The current value of the watchdog timer can be read using the + MIV_WDOG_current_value() function. This function can be called at any time. + + -------------------------------------------- + Refreshing the Watchdog Timer Value + -------------------------------------------- + The watchdog timer value is refreshed using the MIV_WDOG_reload() function. + The value reloaded into the watchdog timer down-counter is specified at the + configuration time with an appropriate value as parameter to the + MIV_WDOG_get_config() function. + + -------------------------------------------- + Interrupt Control + -------------------------------------------- + The Mi-V Watchdog generates two interrupts, The MVRP interrupt and + the timeout interrupt. + The MVRP interrupt is generated when the watchdog down-counter crosses the + Maximum Value up to which Refresh is Permitted (MVRP). Following functions to + control MVRP interrupt: + - MIV_WDOG_enable_mvrp_irq + - MIV_WDOG_disable_mvrp_irq + - MIV_WDOG_clear_mvrp_irq + + The timeout interrupt is generated when the watchdog down-counter crosses the + watchdog timeout value. The timeout value is a non-zero value and it can be + set to a maximum of MIV_WDOG_TRIGGER_MAX. The non-maskable interrupt is + generated when the watchdog crosses this timeout value, the down counter + keeps on down counting and a reset signal is generated when reaches zero. + Following functions to control timeout interrupt: + - MIV_WDOG_enable_timeout_irq + - MIV_WDOG_disable_timeout_irq + - MIV_WDOG_clear_timeout_irq + +*//*=========================================================================*/ + +#ifndef MIV_WATCHDOG_H_ +#define MIV_WATCHDOG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "miv_watchdog_regs.h" + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#else +#include "hal.h" +#endif + +/****************************************************************************//* + * The following constants can be used to configure the Mi-V Watchdog where a + * zero or non-zero value such as enable or disable is to be provided as a input + * parameter as shown below: + */ +#define MIV_WDOG_ENABLE 1u +#define MIV_WDOG_DISABLE 0u + +/***************************************************************************//** + The miv_wdog_config_t type for the watchdog Configuration structure. This + type is used as a parameter for the MIV_WDOG_configure() and the + MIV_WDOG_get_config() functions. + + Following are the values as part of this structure +| Parameter | Description | +|------------------|-----------------------------------------------------------| +| time_val | The value from which the watchdog timer counts down | +| mvrp_val | The Watchdog MVRP value | +| timeout_val | The watchdog timeout value | +| forbidden_en | Enable/disable the forbidden window | +| | When set, if a refresh occurs in the forbidden window, | +| | the watchdog timeout interrupt will be generated. | + +Time calculation example: + + time_val = 0xFFFFF0u + mvrp_val = 0x989680u + timeout_val = 0x3e8u + + A prescaler = 256 is used. + Considering clock = 50Mhz + + The MVRP interrupt will happen after + (0xFFFFF0 - 0x989680) * ( 1/(50MHz/256)) + mvrp interrupt will happen after 34 sec. after system reset + + (0xFFFFF0 - 0x3e8) * ( 1/(50MHz/256)) + timeout interrupt will happen after 85 sec. after system reset + */ +typedef struct miv_wdog_config +{ + uint32_t time_val; + uint32_t mvrp_val; + uint32_t timeout_val; + uint32_t forbidden_en; + uint32_t intr_type; +}miv_wdog_config_t; + +extern addr_t g_this_wdog; + +/***************************************************************************//* + Internal constants and types +*******************************************************************************/ + +/// @cond private +#define MIV_WDOG_TRIGGER_MAX 4095u +#define MIV_WDOG_TIMER_MAX 16777200u +/// @endcond + +/*-------------------------------------------------------------------------*//* +MIV_WDOG_REFRESH_KEY +===================== + +The MIV_WDOG_REFRESH_KEY macro holds the magic value which will cause a +reload of the watchdog's down counter when written to the watchdog's +WDOGREFRESH register. +*/ +#define MIV_WDOG_REFRESH_KEY (uint32_t)0xDEADC0DEU + +/*-------------------------------------------------------------------------*//* +MIV_WDOG_FORCE_RESET_KEY +===================== +The MIV_WDOG_FORCE_RESET_KEY macro holds the magic value which will force a +reset if the watchdog is already timeout. Writing any other value or writing +TRIGGER register at other times will trigger the watchdog NMI sequence +(i.e raise a timeout interrupt) + */ +#define MIV_WDOG_FORCE_RESET_KEY (uint32_t)0xDEADU + +/***************************************************************************//** + * The MIV_WDOG_init() is used to register the Mi-V Watchdog module base + * address to the driver. + * + * Note: User should call this function before calling any other Mi-V watchdog + * driver function. + * + * @param base_addr + * The base address of the Mi-V watchdog module. This address is used by + * rest of the watchdog driver functions to access the registers. + * + * @return + * This function does not return any value. + */ +void +MIV_WDOG_init +( + addr_t base_addr +); + +/***************************************************************************//** + * The MIV_WDOG_get_config() function returns the current configurations of the + * Mi-V Watchdog. The Mi-V Watchdog is pre-initialized by the flash + * bits at the design time. When used for the first time before calling the + * MIV_WDOG_configure() function, this function will return the default + * configurations as configured at the design time. + * + * @param config + * The config parameter is used to store the current configuration of the Mi-V + * Watchdog. + * + * Please see the description of miv_wdog_config_t for details. + * + * @return + * This function does not return any value. + * + * Example: + */ +void +MIV_WDOG_get_config +( + miv_wdog_config_t* config +); + +/***************************************************************************//** + * The MIV_WDOG_configure() function configures the watchdog module. The + * Watchdog module is pre-initialized by the flash bits at the design time to the + * default values. You can reconfigure the Watchdog module using + * MIV_WDOG_configure() function. + * + * Note that the MIV_WDOG_configure() function can be used only once, as it + * writes into the TIME register. After a write into the TIME register, the TIME, + * TRIGGER and MSVP register values are frozen and can't be altered again unless + * a system reset happens. + * + * Note also that the Mi-V Watchdog is not enabled at reset, calling this function + * will start the watchdog, it cannot then be disabled and must be refreshed + * periodically. + * + * @param config + * The config parameter is the input parameter in which the configurations to + * be applied to the watchdog module are provided by the application. + * Please see the description of miv_wdog_config_t for details. + * + * @return + * This function returns a zero value when executed successfully. A non-zero + * value is returned when the configuration values are out of bound. + * + * Example: + */ +uint8_t +MIV_WDOG_configure +( + const miv_wdog_config_t * config +); + +/***************************************************************************//** + * The MIV_WDOG_reload() function causes the watchdog to reload its down-counter + * timer with the load value configured through interrupt handler. This function + * must be called regularly to avoid a system reset or a watchdog interrupt. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_reload +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg(g_this_wdog, WDOGRFSH, MIV_WDOG_REFRESH_KEY); + } +} + +/***************************************************************************//** + * The MIV_WDOG_current_value() function returns the current value of the + * watchdog's down-counter. + * + * @param + * Void + * + * @return + * This function returns the current value of the watchdog’s down-counter as + * a 32-bit unsigned integer. + */ +static inline uint32_t +MIV_WDOG_current_value +( + void +) +{ + return (HAL_get_32bit_reg(g_this_wdog, WDOGRFSH)); +} + +/***************************************************************************//** + * The MIV_WDOG_forbidden_status() function returns the refresh status of the + * Mi-V Watchdog. + * + * @param + * Void + * + * @return + * This function returns the refresh status of the watchdog. A value of 1 + * indicates that watchdog's down-counter is within the forbidden window and + * that a reload should not be done. A value of 0 indicates that the watchdog's + * down counter is within the permitted window and that a reload is allowed. + */ +static inline uint32_t +MIV_WDOG_forbidden_status +( + void +) +{ + return (HAL_get_32bit_reg_field(g_this_wdog, WDOGSTAT_FORBIDDEN)); +} + +/***************************************************************************//** + * The MIV_WDOG_enable_mvrp_irq() function enables the MVRP interrupt. + * This interrupt is asserted when the timer countdown register leaves the + * maximum value up to which refresh is permitted (MVRP) window. + * + * @param + * Void + * + * @return + * This function does not return a value. + * + * Example: + */ +static inline void +MIV_WDOG_enable_mvrp_irq +( + void +) +{ + + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGCNTL_NEXT_INTENT_MSVP, 0x01u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_disable_mvrp_irq() function disables the generation of the + * MVRP interrupt. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_disable_mvrp_irq +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGCNTL_NEXT_INTENT_MSVP, 0x0u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_clear_timeout_irq() function clears the watchdog’s timeout + * interrupt which is connected to the MIV-RV32 interrupt. Calling + * MIV_WDOG_clear_timeout_irq() results in clearing the MIV-RV32 interrupt. + * Note: You must call the MIV_WDOG_clear_timeout_irq() function as part of your + * implementation of the interrupt handler in order to prevent the same + * interrupt event re-triggering a call to the timeout ISR. + * + * @param + * Void + * + * @return + * This function does not return any value. + * + */ +static inline void +MIV_WDOG_clear_timeout_irq +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_WDOG_TRIPPED, 0x01u); + /* + * Perform a second write to ensure that the first write completed before + * returning from this function. This is to account for posted writes across + * the AHB matrix. The second write ensures that the first write has + * completed and that the interrupt line has been de-asserted by the time + * the function returns. Omitting the second write may result in a delay + * in the de-assertion of the interrupt line going to the RISC-V and a + * retriggering of the interrupt. + */ + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_WDOG_TRIPPED, 0x01u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_clear_mvrp_irq() function clears the mvrp interrupt. + * + * Note: You must call the MIV_WDOG_clear_mvrp_irq() function as part of your + * implementation of the interrupt service routine (ISR) in order to + * prevent the same interrupt event re-triggering a call to the mvrp ISR. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_clear_mvrp_irq +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_MSVP_TRIPPED, 0x01u); + /* + * Perform a second write to ensure that the first write completed before + * returning from this function. This is to account for posted writes across + * the AHB matrix. The second write ensures that the first write has + * completed and that the interrupt line has been de-asserted by the time + * the function returns. Omitting the second write may result in a delay + * in the de-assertion of the interrupt line going to the RISC-V and a + * re-triggering of the interrupt. + */ + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_MSVP_TRIPPED, 0x01u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_timeout_occured() function reports the occurrence of a timeout + * event. + * + * @param + * Void + * + * @return + * A zero value indicates no watchdog timeout event occurred. A value of 1 + * indicates that a timeout event occurred. + */ +static inline uint32_t +MIV_WDOG_timeout_occured +( + void +) +{ + return (HAL_get_32bit_reg_field(g_this_wdog, WDOGSTAT_TRIGGERED)); +} + +/***************************************************************************//** + * The MIV_WDOG_force_reset() function is used to force an immediate reset + * if the watchdog has already triggered. Writing any value in this condition + * will result in watchdog timeout. + * The time out interrupt WDOG_IRQ will be set to high and watchdog timer + * countdown register updated with watchdog trigger timeout register value. + * If the Watchdog has timed out, a special 16-bit value needs to be written + * to the register to force a reset on CPU_RESETN, 0xDEAD + * Then the Watchdog countdown is reset/updated with the top Watchdog Runtime + * register value. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_force_reset +( + void +) +{ + if (WDOGSTAT_TRIGGERED_MASK == + HAL_get_32bit_reg_field(g_this_wdog, WDOGSTAT_TRIGGERED)) + + { + HAL_set_32bit_reg(g_this_wdog, WDOGFORCE, MIV_WDOG_FORCE_RESET_KEY); + } + + else + { + HAL_set_32bit_reg(g_this_wdog, WDOGFORCE, 0x0u); + } +} + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_WATCHDOG_H_ */ diff --git a/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h new file mode 100644 index 0000000..2fca983 --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h @@ -0,0 +1,122 @@ + /******************************************************************************* + * 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 watchdog module driver. This module is delivered as a part of Mi-V + * extended Sub-System(ESS) MIV_ESS. + */ + +#ifndef MIV_WDOG_REGISTERS +#define MIV_WDOG_REGISTERS 1u + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * Refresh register details + */ +#define WDOGRFSH_REG_OFFSET 0x00u + +/* Refresh register bits */ +#define WDOGRFSH_OFFSET 0x00u +#define WDOGRFSH_MASK 0xFFFFFFFFu +#define WDOGRFSH_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Control register details + */ +#define WDOGCNTL_REG_OFFSET 0x04u + +/* Control register next intent msvp bit */ +#define WDOGCNTL_NEXT_INTENT_MSVP_OFFSET 0x04u +#define WDOGCNTL_NEXT_INTENT_MSVP_MASK 0x01u +#define WDOGCNTL_NEXT_INTENT_MSVP_SHIFT 0u + +/* Control register next intent wdog bit */ +#define WDOGCNTL_NEXT_INTENT_WDOG_OFFSET 0x04u +#define WDOGCNTL_NEXT_INTENT_WDOG_MASK 0x02u +#define WDOGCNTL_NEXT_INTENT_WDOG_SHIFT 1u + +/* Control register next enforbidden bit */ +#define WDOGCNTL_NEXT_ENFORBIDDEN_OFFSET 0x04u +#define WDOGCNTL_NEXT_ENFORBIDDEN_MASK 0x10u +#define WDOGCNTL_NEXT_ENFORBIDDEN_SHIFT 4u + +/*------------------------------------------------------------------------------ + * Watchdog status register + */ +#define WDOGSTAT_REG_OFFSET 0x08u + +/* msvp_tripped bit */ +#define WDOGSTAT_MSVP_TRIPPED_OFFSET 0x08u +#define WDOGSTAT_MSVP_TRIPPED_MASK 0x01u +#define WDOGSTAT_MSVP_TRIPPED_SHIFT 0u + +/* WDOG Tripped bit */ +#define WDOGSTAT_WDOG_TRIPPED_OFFSET 0x08u +#define WDOGSTAT_WDOG_TRIPPED_MASK 0x02u +#define WDOGSTAT_WDOG_TRIPPED_SHIFT 1u + +/* Forbidden bit */ +#define WDOGSTAT_FORBIDDEN_OFFSET 0x08u +#define WDOGSTAT_FORBIDDEN_MASK 0x04u +#define WDOGSTAT_FORBIDDEN_SHIFT 2u + +/* Triggered bit */ +#define WDOGSTAT_TRIGGERED_OFFSET 0x08u +#define WDOGSTAT_TRIGGERED_MASK 0x08u +#define WDOGSTAT_TRIGGERED_SHIFT 3u + +/* wdoglocked bit */ +#define WDOGSTAT_WDOGLOCKED_OFFSET 0x08u +#define WDOGSTAT_WDOGLOCKED_MASK 0x10u +#define WDOGSTAT_WDOGLOCKED_SHIFT 4u + +/*------------------------------------------------------------------------------ + * Watchdog runtime register + */ +#define WDOGTIME_REG_OFFSET 0x0Cu + +/* wdogmsvp bit */ +#define WDOGTIME_WDOGVALUE_OFFSET 0x0Cu +#define WDOGTIME_WDOGVALUE_MASK 0xFFFFFFu +#define WDOGTIME_WDOGVALUE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Watchdog MVRP register + */ +#define WDOGMSVP_REG_OFFSET 0x10u + +/* wdogmsvp bit */ +#define WDOGMSVP_OFFSET 0x10u +#define WDOGMSVP_MASK 0xFFFFFFu +#define WDOGMSVP_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Watchdog Trigger Timeout register + */ +#define WDOGTRIG_REG_OFFSET 0x14u + +/* wdogmsvp bit */ +#define WDOGTRIG_WDOGRST_OFFSET 0x14u +#define WDOGTRIG_WDOGRST_MASK 0xFFFFFFu +#define WDOGTRIG_WDOGRST_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Watchdog Force Reset register details + */ +#define WDOGFORCE_REG_OFFSET 0x18u + +/* Refresh register bits */ +#define WDOGFORCE_OFFSET 0x18u +#define WDOGFORCE_MASK 0xFFFFFFFFu +#define WDOGFORCE_SHIFT 0u + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_WATCHDOG_REGS_H_ */ diff --git a/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/hal/cpu_types.h b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/hal/cpu_types.h new file mode 100644 index 0000000..ef8ab20 --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/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/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/hal/hal.h b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/hal/hal.h new file mode 100644 index 0000000..7eec17a --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/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/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/hal/hal_assert.h b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/hal/hal_assert.h new file mode 100644 index 0000000..8e0c747 --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/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/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/hal/hal_irq.c b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/hal/hal_irq.c new file mode 100644 index 0000000..6fe7fce --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/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/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/hal/hw_macros.h b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/hal/hw_macros.h new file mode 100644 index 0000000..ed2c681 --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/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/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/hal/hw_reg_access.S b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/hal/hw_reg_access.S new file mode 100644 index 0000000..f4aa0a0 --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/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/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/hal/hw_reg_access.h b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/hal/hw_reg_access.h new file mode 100644 index 0000000..1f6a551 --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/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/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/hal/readme.md b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/hal/readme.md new file mode 100644 index 0000000..c756b34 --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/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/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld new file mode 100644 index 0000000..19df5fb --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/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/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/miv_rv32_hal/miv-rv32-ram.ld b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/miv_rv32_hal/miv-rv32-ram.ld new file mode 100644 index 0000000..e0707df --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/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/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/miv_rv32_hal/miv_rv32_entry.S b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/miv_rv32_hal/miv_rv32_entry.S new file mode 100644 index 0000000..a19a813 --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/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/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/miv_rv32_hal/miv_rv32_hal.c b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/miv_rv32_hal/miv_rv32_hal.c new file mode 100644 index 0000000..8fa82b1 --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/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/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/miv_rv32_hal/miv_rv32_hal.h b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/miv_rv32_hal/miv_rv32_hal.h new file mode 100644 index 0000000..7231610 --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/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/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/miv_rv32_hal/miv_rv32_init.c b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/miv_rv32_hal/miv_rv32_init.c new file mode 100644 index 0000000..e5f811f --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/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/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/miv_rv32_hal/miv_rv32_plic.h b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/miv_rv32_hal/miv_rv32_plic.h new file mode 100644 index 0000000..19050cf --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/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/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/miv_rv32_hal/miv_rv32_regs.h b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/miv_rv32_hal/miv_rv32_regs.h new file mode 100644 index 0000000..1837f42 --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/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/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/miv_rv32_hal/miv_rv32_stubs.c b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/miv_rv32_hal/miv_rv32_stubs.c new file mode 100644 index 0000000..7f5042b --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/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/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/miv_rv32_hal/miv_rv32_syscall.c b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/miv_rv32_hal/miv_rv32_syscall.c new file mode 100644 index 0000000..b24e729 --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/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/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/miv_rv32_hal/sample_fpga_design_config.h b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/miv_rv32_hal/sample_fpga_design_config.h new file mode 100644 index 0000000..a380d96 --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/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/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/platform_config_reference/linker/readme.md b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/platform_config_reference/linker/readme.md new file mode 100644 index 0000000..5581d1b --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/platform_config_reference/linker/readme.md @@ -0,0 +1,2 @@ +# readme + diff --git a/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/platform_config_reference/miv_rv32_hal_config/readme.md b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/platform_config_reference/miv_rv32_hal_config/readme.md new file mode 100644 index 0000000..5581d1b --- /dev/null +++ b/driver-examples/miv-watchdog/miv-rv32-wdog/src/platform/platform_config_reference/miv_rv32_hal_config/readme.md @@ -0,0 +1,2 @@ +# readme +