diff --git a/Kconfig b/Kconfig index e2622f9a..33a41f83 100644 --- a/Kconfig +++ b/Kconfig @@ -245,7 +245,6 @@ config START_ADDRESS_BL33 hex "Start address BL33" depends on BOOTLOADER33 default 0x10040000 - range 0x10000000 0x10080000 ---help--- "Start address of BL33" diff --git a/README.md b/README.md index c5c4c128..753904c4 100644 --- a/README.md +++ b/README.md @@ -36,11 +36,11 @@ the beginnings of corresponding files; also, all licenses are listed in | Cortex-M23 | Cortex-M23 | Cortex-M33 (Qemu) | RISC-V | |-----------------------|---------------------------|-------------|-----------| -| **NuMaker-PFM-M2351** | **M2351-Badge** | **V2M-MPS2** | **SparkFun RedBoard** | +| **NuMaker-PFM-M2351** Cortex-M23 | **M2351-Badge** Cortex-M23 | **V2M-MPS2** Cortex-M33 (Qemu) | **SparkFun RedBoard** RISC-V | |[![](docs/images/platforms/numaker_pfm_m2351/numaker_pfm_m2351.png)](docs/numaker_pfm_m2351.md)|[![](docs/images/platforms/m2351_badge/m2351_badge.png)](docs/m2351_badge.md) |[![V2M-MPS2](docs/images/platforms/v2m-mps2/v2m-mps2.png)](docs/v2m-mps2-qemu.md)|[![](docs/images/platforms/sparkfun_redboard/sparkfun_redboard.png)](docs/sparkfun_redboard.md)| -| **How to add a platform** |||| -|[![](docs/images/platforms/add_new_board.jpg)](docs/port-new-platform.md)|||| - +| RISC-V |||| +| **Pine64 Ox64** | **How to add a platform** ||| +|[![](docs/images/platforms/pine64_ox64/pine64-ox64.jpg)](docs/pine64_ox64.md)|[![](docs/images/platforms/add_new_board.jpg)](docs/port-new-platform.md)||| Several platforms are supported. In order to manage slight differences between platforms, a `PLATFORM` flag has been introduced. @@ -51,6 +51,7 @@ between platforms, a `PLATFORM` flag has been introduced. | [M2351-Badge] |`PLATFORM=m2351_badge` | v0.5.0 | | [V2M-MPS2] |`PLATFORM=mps2_an505_qemu` | v0.5.0 | | [SparkFun RED-V RedBoard] |`PLATFORM=sparkfun_redboard` | v0.5.0 | +| [Pine64 Ox64] |`PLATFORM=pine64_ox64` | v0.5.0 | For information on adding a new platform see the [how to add a platform]. @@ -103,3 +104,4 @@ you can find here](.github/CONTRIBUTING.md). [M2351-Badge]: docs/schemes/m2351_badge [V2M-MPS2]: https://developer.arm.com/documentation/100964/1114/Microcontroller-Prototyping-System-2?lang=en [SparkFun RED-V RedBoard]: https://www.sparkfun.com/products/15594 +[Pine64 Ox64]: https://wiki.pine64.org/wiki/Ox64 diff --git a/arch/riscv32/Kconfig b/arch/riscv32/Kconfig index cd20ca5d..5966ff7b 100644 --- a/arch/riscv32/Kconfig +++ b/arch/riscv32/Kconfig @@ -29,8 +29,8 @@ comment "FE310 Configuration Options" source arch/riscv32/fe310/Kconfig endif -# if ARCH_FAMILY_BL808 -# comment "BL808 Configuration Options" -# source arch/riscv32/bl808/Kconfig -# endif +if ARCH_FAMILY_BL808 +comment "BL808 Configuration Options" +source arch/riscv32/bl808/Kconfig +endif \ No newline at end of file diff --git a/arch/riscv32/bl808/Kconfig b/arch/riscv32/bl808/Kconfig new file mode 100644 index 00000000..c26d746b --- /dev/null +++ b/arch/riscv32/bl808/Kconfig @@ -0,0 +1,2481 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the docs folder of mTower repository. +# + +choice + prompt "BL808 platform selection" + default PLATFORM_PINE64_OX64 + +config PLATFORM_PINE64_OX64 + bool "Pine64 Ox64 board" + ---help--- + Pine64 Ox64 board. + +endchoice + +config PLATFORM + string + default "pine64_ox64" if PLATFORM_PINE64_OX64 + + +if PLATFORM_PINE64_OX64 +#comment "Pine64 Ox64 board Peripheral Configuration Options" +# source arch/riscv32/bl808/src/pine64_ox64/Kconfig +endif # PLATFORM_PINE64_OX64 + +choice + prompt "Non-secure debug UART configuration" + default NONSECURE_DEBUG_UART1 + +config NONSECURE_DEBUG_UART0 + bool "UART0" + ---help--- + UART0 is non-secure debug port. + +config NONSECURE_DEBUG_UART1 + bool "UART1" + ---help--- + UART1 is non-secure debug port. + +config NONSECURE_DEBUG_UART2 + bool "UART2" + ---help--- + UART2 is non-secure debug port. + +config NONSECURE_DEBUG_UART3 + bool "UART3" + ---help--- + UART3 is non-secure debug port. + +config NONSECURE_DEBUG_UART4 + bool "UART4" + ---help--- + UART4 is non-secure debug port. + +config NONSECURE_DEBUG_UART5 + bool "UART5" + ---help--- + UART5 is non-secure debug port. +endchoice + +config NONSECURE_DEBUG_UART + string + default "UART0_NS" if NONSECURE_DEBUG_UART0 + default "UART1_NS" if NONSECURE_DEBUG_UART1 + default "UART2_NS" if NONSECURE_DEBUG_UART2 + default "UART3_NS" if NONSECURE_DEBUG_UART3 + default "UART4_NS" if NONSECURE_DEBUG_UART4 + default "UART5_NS" if NONSECURE_DEBUG_UART5 + +choice + prompt "Non-secure debug font color configuration" + default NONSECURE_DEBUG_RED + +config NONSECURE_FONT_RED + bool "RED" + ---help--- + Red is non-secure debug color. + +config NONSECURE_FONT_GREEN + bool "GREEN" + ---help--- + Green is non-secure debug color. + +config NONSECURE_FONT_YELLOW + bool "YELLOW" + ---help--- + Yellow is non-secure debug color. + +config NONSECURE_FONT_BLUE + bool "BLUE" + ---help--- + Blue is non-secure debug color. + +config NONSECURE_FONT_GRAY + bool "GRAY" + ---help--- + Gray is non-secure debug color. +endchoice + +config NONSECURE_FONT_COLOR + int + default 1 if NONSECURE_FONT_RED + default 2 if NONSECURE_FONT_GREEN + default 3 if NONSECURE_FONT_YELLOW + default 4 if NONSECURE_FONT_BLUE + default 7 if NONSECURE_FONT_GRAY + +choice + prompt "Secure debug UART configuration" + default SECURE_DEBUG_UART0 + +config SECURE_DEBUG_UART0 + bool "UART0" + ---help--- + UART0 is secure debug port. + +config SECURE_DEBUG_UART1 + bool "UART1" + ---help--- + UART1 is secure debug port. + +config SECURE_DEBUG_UART2 + bool "UART2" + ---help--- + UART2 is secure debug port. + +config SECURE_DEBUG_UART3 + bool "UART3" + ---help--- + UART3 is secure debug port. + +config SECURE_DEBUG_UART4 + bool "UART4" + ---help--- + UART4 is secure debug port. + +config SECURE_DEBUG_UART5 + bool "UART5" + ---help--- + UART5 is secure debug port. +endchoice + +config SECURE_DEBUG_UART + string + default "UART0" if SECURE_DEBUG_UART0 && !NONSECURE_DEBUG_UART0 + default "UART1" if SECURE_DEBUG_UART1 && !NONSECURE_DEBUG_UART1 + default "UART2" if SECURE_DEBUG_UART2 && !NONSECURE_DEBUG_UART2 + default "UART3" if SECURE_DEBUG_UART3 && !NONSECURE_DEBUG_UART3 + default "UART4" if SECURE_DEBUG_UART4 && !NONSECURE_DEBUG_UART4 + default "UART5" if SECURE_DEBUG_UART5 && !NONSECURE_DEBUG_UART5 + default "UART0_NS" if SECURE_DEBUG_UART0 && NONSECURE_DEBUG_UART0 + default "UART1_NS" if SECURE_DEBUG_UART1 && NONSECURE_DEBUG_UART1 + default "UART2_NS" if SECURE_DEBUG_UART2 && NONSECURE_DEBUG_UART2 + default "UART3_NS" if SECURE_DEBUG_UART3 && NONSECURE_DEBUG_UART3 + default "UART4_NS" if SECURE_DEBUG_UART4 && NONSECURE_DEBUG_UART4 + default "UART5_NS" if SECURE_DEBUG_UART5 && NONSECURE_DEBUG_UART5 + +choice + prompt "Secure debug font color configuration" + default SECURE_DEBUG_RED + +config SECURE_FONT_RED + bool "RED" + ---help--- + Red is secure debug color. + +config SECURE_FONT_GREEN + bool "GREEN" + ---help--- + Green is secure debug color. + +config SECURE_FONT_YELLOW + bool "YELLOW" + ---help--- + Yellow is secure debug color. + +config SECURE_FONT_BLUE + bool "BLUE" + ---help--- + Blue is secure debug color. + +config SECURE_FONT_GRAY + bool "GRAY" + ---help--- + Gray is secure debug color. +endchoice + +config SECURE_FONT_COLOR + int + default 1 if SECURE_FONT_RED + default 2 if SECURE_FONT_GREEN + default 3 if SECURE_FONT_YELLOW + default 4 if SECURE_FONT_BLUE + default 7 if NONSECURE_FONT_GRAY + +menu "Secure Attribution Configuration" + +menu "GPIO Secure Attribution Configuration" + +choice + prompt "Port A secure configuration" + default GPIO_SECURE_PA + +config GPIO_NONSECURE_PA + bool "PA non-secure" + ---help--- + GPIO PA is non-secure. + +config GPIO_SECURE_PA + bool "PA secure" + ---help--- + GPIO PA is secure. +endchoice + +choice + prompt "Port B secure configuration" + default GPIO_SECURE_PB + +config GPIO_NONSECURE_PB + bool "PB non-secure" + ---help--- + GPIO PB is non-secure. + +config GPIO_SECURE_PB + bool "PB secure" + ---help--- + GPIO PB is secure. +endchoice + +choice + prompt "Port C secure configuration" + default GPIO_SECURE_PC + +config GPIO_NONSECURE_PC + bool "PC non-secure" + ---help--- + GPIO PC is non-secure. + +config GPIO_SECURE_PC + bool "PC secure" + ---help--- + GPIO PC is secure. +endchoice + +choice + prompt "Port D secure configuration" + default GPIO_SECURE_PD + +config GPIO_NONSECURE_PD + bool "PD non-secure" + ---help--- + GPIO PD is non-secure. + +config GPIO_SECURE_PD + bool "PD secure" + ---help--- + GPIO PD is secure. +endchoice + +choice + prompt "Port E secure configuration" + default GPIO_SECURE_PE + +config GPIO_NONSECURE_PE + bool "PE non-secure" + ---help--- + GPIO PE is non-secure. + +config GPIO_SECURE_PE + bool "PE secure" + ---help--- + GPIO PE is secure. +endchoice + +choice + prompt "Port F secure configuration" + default GPIO_SECURE_PF + +config GPIO_NONSECURE_PF + bool "PF non-secure" + ---help--- + GPIO PF is non-secure. + +config GPIO_SECURE_PF + bool "PF secure" + ---help--- + GPIO PF is secure. +endchoice + +choice + prompt "Port G secure configuration" + default GPIO_SECURE_PG + +config GPIO_NONSECURE_PG + bool "PG non-secure" + ---help--- + GPIO PG is non-secure. + +config GPIO_SECURE_PG + bool "PG secure" + ---help--- + GPIO PG is secure. +endchoice + +choice + prompt "Port H secure configuration" + default GPIO_SECURE_PH + +config GPIO_NONSECURE_PH + bool "PH non-secure" + ---help--- + GPIO PH is non-secure. + +config GPIO_SECURE_PH + bool "PH secure" + ---help--- + GPIO PH is secure. +endchoice + +endmenu # GPIO Secure Attribution Configuration + +choice + prompt "Secure SRAM size" + default SCU_SECURE_SRAM_32 + +config SCU_SECURE_SRAM_0 + bool "Secure SRAM 0KB" +config SCU_SECURE_SRAM_8 + bool "Secure SRAM 8KB" +config SCU_SECURE_SRAM_16 + bool "Secure SRAM 16KB" +config SCU_SECURE_SRAM_24 + bool "Secure SRAM 24KB" +config SCU_SECURE_SRAM_32 + bool "Secure SRAM 32KB" +config SCU_SECURE_SRAM_40 + bool "Secure SRAM 40KB" +config SCU_SECURE_SRAM_48 + bool "Secure SRAM 48KB" +config SCU_SECURE_SRAM_56 + bool "Secure SRAM 56KB" +config SCU_SECURE_SRAM_64 + bool "Secure SRAM 64KB" +config SCU_SECURE_SRAM_72 + bool "Secure SRAM 72KB" +config SCU_SECURE_SRAM_80 + bool "Secure SRAM 80KB" +config SCU_SECURE_SRAM_88 + bool "Secure SRAM 88KB" +config SCU_SECURE_SRAM_96 + bool "Secure SRAM 96KB" +endchoice + +config SCU_SECURE_SRAM_SIZE + hex + default 0x0000 if SCU_SECURE_SRAM_0 + default 0x2000 if SCU_SECURE_SRAM_8 + default 0x4000 if SCU_SECURE_SRAM_16 + default 0x6000 if SCU_SECURE_SRAM_24 + default 0x8000 if SCU_SECURE_SRAM_32 + default 0xA000 if SCU_SECURE_SRAM_40 + default 0xC000 if SCU_SECURE_SRAM_48 + default 0xE000 if SCU_SECURE_SRAM_56 + default 0x10000 if SCU_SECURE_SRAM_64 + default 0x12000 if SCU_SECURE_SRAM_72 + default 0x14000 if SCU_SECURE_SRAM_80 + default 0x16000 if SCU_SECURE_SRAM_88 + default 0x18000 if SCU_SECURE_SRAM_96 + +config FMC_SECURE_ROM_SIZE + hex "Secure Flash ROM Size" + default 0x40000 + range 0x1000 0x40000 + ---help--- + "Secure Flash ROM Size." + +menu "Peripheral Secure Attribution Configuration" + +choice + prompt "USBH secure configuration" + default USBH_SECURE + +config USBH_NONSECURE + bool "USBH non-secure" + ---help--- + USBH is non-secure. + +config USBH_SECURE + bool "USBH secure" + ---help--- + USBH is secure. +endchoice + +choice + prompt "SDO secure configuration" + default SDO_SECURE + +config SDO_NONSECURE + bool "SDO non-secure" + ---help--- + SDO is non-secure. + +config SDO_SECURE + bool "SDO secure" + ---help--- + SDO is secure. +endchoice + +choice + prompt "EBI secure configuration" + default EBI_SECURE + +config EBI_NONSECURE + bool "EBI non-secure" + ---help--- + EBI is non-secure. + +config EBI_SECURE + bool "EBI secure" + ---help--- + EBI is secure. +endchoice + +choice + prompt "PDMA1 secure configuration" + default PDMA1_SECURE + +config PDMA1_NONSECURE + bool "PDMA1 non-secure" + ---help--- + PDMA1 is non-secure. + +config PDMA1_SECURE + bool "PDMA1 secure" + ---help--- + PDMA1 is secure. +endchoice + +choice + prompt "CRC secure configuration" + default CRC_SECURE + +config CRC_NONSECURE + bool "CRC non-secure" + ---help--- + CRC is non-secure. + +config CRC_SECURE + bool "CRC secure" + ---help--- + CRC is secure. +endchoice + +choice + prompt "CRPT secure configuration" + default CRPT_SECURE + +config CRPT_NONSECURE + bool "CRPT non-secure" + ---help--- + CRPT is non-secure. + +config CRPT_SECURE + bool "CRPT secure" + ---help--- + CRPT is secure. +endchoice + +choice + prompt "RTC secure configuration" + default RTC_SECURE + +config RTC_NONSECURE + bool "RTC non-secure" + ---help--- + RTC is non-secure. + +config RTC_SECURE + bool "RTC secure" + ---help--- + RTC is secure. +endchoice + +choice + prompt "EADC secure configuration" + default EADC_SECURE + +config EADC_NONSECURE + bool "EADC non-secure" + ---help--- + EADC is non-secure. + +config EADC_SECURE + bool "EADC secure" + ---help--- + EADC is secure. +endchoice + +choice + prompt "ACMP01 secure configuration" + default ACMP01_SECURE + +config ACMP01_NONSECURE + bool "ACMP01 non-secure" + ---help--- + ACMP01 is non-secure. + +config ACMP01_SECURE + bool "ACMP01 secure" + ---help--- + ACMP01 is secure. +endchoice + +choice + prompt "DAC secure configuration" + default DAC_SECURE + +config DAC_NONSECURE + bool "DAC non-secure" + ---help--- + DAC is non-secure. + +config DAC_SECURE + bool "DAC secure" + ---help--- + DAC is secure. +endchoice + +choice + prompt "I2S0 secure configuration" + default I2S0_SECURE + +config I2S0_NONSECURE + bool "I2S0 non-secure" + ---help--- + I2S0 is non-secure. + +config I2S0_SECURE + bool "I2S0 secure" + ---help--- + I2S0 is secure. +endchoice + +choice + prompt "OTG secure configuration" + default OTG_SECURE + +config OTG_NONSECURE + bool "OTG non-secure" + ---help--- + OTG is non-secure. + +config OTG_SECURE + bool "OTG secure" + ---help--- + OTG is secure. +endchoice + +choice + prompt "TMR23 secure configuration" + default TMR23_SECURE + +config TMR23_NONSECURE + bool "TMR23 non-secure" + ---help--- + TMR23 is non-secure. + +config TMR23_SECURE + bool "TMR23 secure" + ---help--- + TMR23 is secure. +endchoice + +choice + prompt "EPWM0 secure configuration" + default EPWM0_SECURE + +config EPWM0_NONSECURE + bool "EPWM0 non-secure" + ---help--- + EPWM0 is non-secure. + +config EPWM0_SECURE + bool "EPWM0 secure" + ---help--- + EPWM0 is secure. +endchoice + +choice + prompt "EPWM1 secure configuration" + default EPWM1_SECURE + +config EPWM1_NONSECURE + bool "EPWM1 non-secure" + ---help--- + EPWM1 is non-secure. + +config EPWM1_SECURE + bool "EPWM1 secure" + ---help--- + EPWM1 is secure. +endchoice + +choice + prompt "BPWM0 secure configuration" + default BPWM0_SECURE + +config BPWM0_NONSECURE + bool "BPWM0 non-secure" + ---help--- + BPWM0 is non-secure. + +config BPWM0_SECURE + bool "BPWM0 secure" + ---help--- + BPWM0 is secure. +endchoice + +choice + prompt "BPWM1 secure configuration" + default BPWM1_SECURE + +config BPWM1_NONSECURE + bool "BPWM1 non-secure" + ---help--- + BPWM1 is non-secure. + +config BPWM1_SECURE + bool "BPWM1 secure" + ---help--- + BPWM1 is secure. +endchoice + +choice + prompt "QSPI0 secure configuration" + default QSPI0_SECURE + +config QSPI0_NONSECURE + bool "QSPI0 non-secure" + ---help--- + QSPI0 is non-secure. + +config QSPI0_SECURE + bool "QSPI0 secure" + ---help--- + QSPI0 is secure. +endchoice + +choice + prompt "SPI0 secure configuration" + default SPI0_SECURE + +config SPI0_NONSECURE + bool "SPI0 non-secure" + ---help--- + SPI0 is non-secure. + +config SPI0_SECURE + bool "SPI0 secure" + ---help--- + SPI0 is secure. +endchoice + +choice + prompt "SPI1 secure configuration" + default SPI1_SECURE + +config SPI1_NONSECURE + bool "SPI1 non-secure" + ---help--- + SPI1 is non-secure. + +config SPI1_SECURE + bool "SPI1 secure" + ---help--- + SPI1 is secure. +endchoice + +choice + prompt "SPI2 secure configuration" + default SPI2_SECURE + +config SPI2_NONSECURE + bool "SPI2 non-secure" + ---help--- + SPI2 is non-secure. + +config SPI2_SECURE + bool "SPI2 secure" + ---help--- + SPI2 is secure. +endchoice + +choice + prompt "SPI3 secure configuration" + default SPI3_SECURE + +config SPI3_NONSECURE + bool "SPI3 non-secure" + ---help--- + SPI3 is non-secure. + +config SPI3_SECURE + bool "SPI3 secure" + ---help--- + SPI3 is secure. +endchoice + +choice + prompt "UART0 secure configuration" + default UART0_SECURE + +config UART0_NONSECURE + bool "UART0 non-secure" + ---help--- + UART0 is non-secure. + +config UART0_SECURE + bool "UART0 secure" + ---help--- + UART0 is secure. +endchoice + +choice + prompt "UART1 secure configuration" + default UART1_SECURE + +config UART1_NONSECURE + bool "UART1 non-secure" + ---help--- + UART1 is non-secure. + +config UART1_SECURE + bool "UART1 secure" + ---help--- + UART1 is secure. +endchoice + +choice + prompt "UART2 secure configuration" + default UART2_SECURE + +config UART2_NONSECURE + bool "UART2 non-secure" + ---help--- + UART2 is non-secure. + +config UART2_SECURE + bool "UART2 secure" + ---help--- + UART2 is secure. +endchoice + +choice + prompt "UART3 secure configuration" + default UART3_SECURE + +config UART3_NONSECURE + bool "UART3 non-secure" + ---help--- + UART3 is non-secure. + +config UART3_SECURE + bool "UART3 secure" + ---help--- + UART3 is secure. +endchoice + +choice + prompt "UART4 secure configuration" + default UART4_SECURE + +config UART4_NONSECURE + bool "UART4 non-secure" + ---help--- + UART4 is non-secure. + +config UART4_SECURE + bool "UART4 secure" + ---help--- + UART4 is secure. +endchoice + +choice + prompt "UART5 secure configuration" + default UART5_SECURE + +config UART5_NONSECURE + bool "UART5 non-secure" + ---help--- + UART5 is non-secure. + +config UART5_SECURE + bool "UART5 secure" + ---help--- + UART5 is secure. +endchoice + +choice + prompt "I2C0 secure configuration" + default I2C0_SECURE + +config I2C0_NONSECURE + bool "I2C0 non-secure" + ---help--- + I2C0 is non-secure. + +config I2C0_SECURE + bool "I2C0 secure" + ---help--- + I2C0 is secure. +endchoice + +choice + prompt "I2C1 secure configuration" + default I2C1_SECURE + +config I2C1_NONSECURE + bool "I2C1 non-secure" + ---help--- + I2C1 is non-secure. + +config I2C1_SECURE + bool "I2C1 secure" + ---help--- + I2C1 is secure. +endchoice + +choice + prompt "I2C2 secure configuration" + default I2C2_SECURE + +config I2C2_NONSECURE + bool "I2C2 non-secure" + ---help--- + I2C2 is non-secure. + +config I2C2_SECURE + bool "I2C2 secure" + ---help--- + I2C2 is secure. +endchoice + +choice + prompt "SC0 secure configuration" + default SC0_SECURE + +config SC0_NONSECURE + bool "SC0 non-secure" + ---help--- + SC0 is non-secure. + +config SC0_SECURE + bool "SC0 secure" + ---help--- + SC0 is secure. +endchoice + +choice + prompt "SC1 secure configuration" + default SC1_SECURE + +config SC1_NONSECURE + bool "SC1 non-secure" + ---help--- + SC1 is non-secure. + +config SC1_SECURE + bool "SC1 secure" + ---help--- + SC1 is secure. +endchoice + +choice + prompt "SC2 secure configuration" + default SC2_SECURE + +config SC2_NONSECURE + bool "SC2 non-secure" + ---help--- + SC2 is non-secure. + +config SC2_SECURE + bool "SC2 secure" + ---help--- + SC2 is secure. +endchoice + +choice + prompt "CAN0 secure configuration" + default CAN0_SECURE + +config CAN0_NONSECURE + bool "CAN0 non-secure" + ---help--- + CAN0 is non-secure. + +config CAN0_SECURE + bool "CAN0 secure" + ---help--- + CAN0 is secure. +endchoice + +choice + prompt "QEI0 secure configuration" + default QEI0_SECURE + +config QEI0_NONSECURE + bool "QEI0 non-secure" + ---help--- + QEI0 is non-secure. + +config QEI0_SECURE + bool "QEI0 secure" + ---help--- + QEI0 is secure. +endchoice + +choice + prompt "QEI1 secure configuration" + default QEI1_SECURE + +config QEI1_NONSECURE + bool "QEI1 non-secure" + ---help--- + QEI1 is non-secure. + +config QEI1_SECURE + bool "QEI1 secure" + ---help--- + QEI1 is secure. +endchoice + +choice + prompt "ECAP0 secure configuration" + default ECAP0_SECURE + +config ECAP0_NONSECURE + bool "ECAP0 non-secure" + ---help--- + ECAP0 is non-secure. + +config ECAP0_SECURE + bool "ECAP0 secure" + ---help--- + ECAP0 is secure. +endchoice + +choice + prompt "ECAP1 secure configuration" + default ECAP1_SECURE + +config ECAP1_NONSECURE + bool "ECAP1 non-secure" + ---help--- + ECAP1 is non-secure. + +config ECAP1_SECURE + bool "ECAP1 secure" + ---help--- + ECAP1 is secure. +endchoice + +choice + prompt "TRNG secure configuration" + default TRNG_SECURE + +config TRNG_NONSECURE + bool "TRNG non-secure" + ---help--- + TRNG is non-secure. + +config TRNG_SECURE + bool "TRNG secure" + ---help--- + TRNG is secure. +endchoice + +choice + prompt "USBD secure configuration" + default USBD_SECURE + +config USBD_NONSECURE + bool "USBD non-secure" + ---help--- + USBD is non-secure. + +config USBD_SECURE + bool "USBD secure" + ---help--- + USBD is secure. +endchoice + +choice + prompt "USCI0 secure configuration" + default USCI0_SECURE + +config USCI0_NONSECURE + bool "USCI0 non-secure" + ---help--- + USCI0 is non-secure. + +config USCI0_SECURE + bool "USCI0 secure" + ---help--- + USCI0 is secure. +endchoice + +choice + prompt "USCI1 secure configuration" + default USCI1_SECURE + +config USCI1_NONSECURE + bool "USCI1 non-secure" + ---help--- + USCI1 is non-secure. + +config USCI1_SECURE + bool "USCI1 secure" + ---help--- + USCI1 is secure. +endchoice + +endmenu # Peripheral Secure Attribution Configuration + +menu "Assign Interrupt to Secure or Non-secure Vector" +choice + prompt "RTC Interrupt target secure configuration" + default RTC_INTERRUPT_SECURE + +config RTC_INTERRUPT_NONSECURE + bool "RTC interrupt non-secure" + ---help--- + RTC interrupt is non-secure. + +config RTC_INTERRUPT_SECURE + bool "RTC interrupt secure" + ---help--- + RTC interrupt is secure. +endchoice + +choice + prompt "TAMPER Interrupt target secure configuration" + default TAMPER_INTERRUPT_SECURE + +config TAMPER_INTERRUPT_NONSECURE + bool "TAMPER interrupt non-secure" + ---help--- + TAMPER interrupt is non-secure. + +config TAMPER_INTERRUPT_SECURE + bool "TAMPER interrupt secure" + ---help--- + TAMPER interrupt is secure. +endchoice + +choice + prompt "EINT0 Interrupt target secure configuration" + default EINT0_INTERRUPT_SECURE + +config EINT0_INTERRUPT_NONSECURE + bool "EINT0 interrupt non-secure" + ---help--- + EINT0 interrupt is non-secure. + +config EINT0_INTERRUPT_SECURE + bool "EINT0 interrupt secure" + ---help--- + EINT0 interrupt is secure. +endchoice + +choice + prompt "EINT1 Interrupt target secure configuration" + default EINT1_INTERRUPT_SECURE + +config EINT1_INTERRUPT_NONSECURE + bool "EINT1 interrupt non-secure" + ---help--- + EINT1 interrupt is non-secure. + +config EINT1_INTERRUPT_SECURE + bool "EINT1 interrupt secure" + ---help--- + EINT1 interrupt is secure. +endchoice + +choice + prompt "EINT2 Interrupt target secure configuration" + default EINT2_INTERRUPT_SECURE + +config EINT2_INTERRUPT_NONSECURE + bool "EINT2 interrupt non-secure" + ---help--- + EINT2 interrupt is non-secure. + +config EINT2_INTERRUPT_SECURE + bool "EINT2 interrupt secure" + ---help--- + EINT2 interrupt is secure. +endchoice + +choice + prompt "EINT3 Interrupt target secure configuration" + default EINT3_INTERRUPT_SECURE + +config EINT3_INTERRUPT_NONSECURE + bool "EINT3 interrupt non-secure" + ---help--- + EINT3 interrupt is non-secure. + +config EINT3_INTERRUPT_SECURE + bool "EINT3 interrupt secure" + ---help--- + EINT3 interrupt is secure. +endchoice + +choice + prompt "EINT4 Interrupt target secure configuration" + default EINT4_INTERRUPT_SECURE + +config EINT4_INTERRUPT_NONSECURE + bool "EINT4 interrupt non-secure" + ---help--- + EINT4 interrupt is non-secure. + +config EINT4_INTERRUPT_SECURE + bool "EINT4 interrupt secure" + ---help--- + EINT4 interrupt is secure. +endchoice + +choice + prompt "EINT5 Interrupt target secure configuration" + default EINT5_INTERRUPT_SECURE + +config EINT5_INTERRUPT_NONSECURE + bool "EINT5 interrupt non-secure" + ---help--- + EINT5 interrupt is non-secure. + +config EINT5_INTERRUPT_SECURE + bool "EINT5 interrupt secure" + ---help--- + EINT5 interrupt is secure. +endchoice + +choice + prompt "GPA Interrupt target secure configuration" + default GPA_INTERRUPT_SECURE + +config GPA_INTERRUPT_NONSECURE + bool "GPA interrupt non-secure" + ---help--- + GPA interrupt is non-secure. + +config GPA_INTERRUPT_SECURE + bool "GPA interrupt secure" + ---help--- + GPA interrupt is secure. +endchoice + +choice + prompt "GPB Interrupt target secure configuration" + default GPB_INTERRUPT_SECURE + +config GPB_INTERRUPT_NONSECURE + bool "GPB interrupt non-secure" + ---help--- + GPB interrupt is non-secure. + +config GPB_INTERRUPT_SECURE + bool "GPB interrupt secure" + ---help--- + GPB interrupt is secure. +endchoice + +choice + prompt "GPC Interrupt target secure configuration" + default GPC_INTERRUPT_SECURE + +config GPC_INTERRUPT_NONSECURE + bool "GPC interrupt non-secure" + ---help--- + GPC interrupt is non-secure. + +config GPC_INTERRUPT_SECURE + bool "GPC interrupt secure" + ---help--- + GPC interrupt is secure. +endchoice + +choice + prompt "GPD Interrupt target secure configuration" + default GPD_INTERRUPT_SECURE + +config GPD_INTERRUPT_NONSECURE + bool "GPD interrupt non-secure" + ---help--- + GPD interrupt is non-secure. + +config GPD_INTERRUPT_SECURE + bool "GPD interrupt secure" + ---help--- + GPD interrupt is secure. +endchoice + +choice + prompt "GPE Interrupt target secure configuration" + default GPE_INTERRUPT_SECURE + +config GPE_INTERRUPT_NONSECURE + bool "GPE interrupt non-secure" + ---help--- + GPE interrupt is non-secure. + +config GPE_INTERRUPT_SECURE + bool "GPE interrupt secure" + ---help--- + GPE interrupt is secure. +endchoice + +choice + prompt "GPF Interrupt target secure configuration" + default GPF_INTERRUPT_SECURE + +config GPF_INTERRUPT_NONSECURE + bool "GPF interrupt non-secure" + ---help--- + GPF interrupt is non-secure. + +config GPF_INTERRUPT_SECURE + bool "GPF interrupt secure" + ---help--- + GPF interrupt is secure. +endchoice + +choice + prompt "QSPI0 Interrupt target secure configuration" + default QSPI0_INTERRUPT_SECURE + +config QSPI0_INTERRUPT_NONSECURE + bool "QSPI0 interrupt non-secure" + ---help--- + QSPI0 interrupt is non-secure. + +config QSPI0_INTERRUPT_SECURE + bool "QSPI0 interrupt secure" + ---help--- + QSPI0 interrupt is secure. +endchoice + +choice + prompt "SPI0 Interrupt target secure configuration" + default SPI0_INTERRUPT_SECURE + +config SPI0_INTERRUPT_NONSECURE + bool "SPI0 interrupt non-secure" + ---help--- + SPI0 interrupt is non-secure. + +config SPI0_INTERRUPT_SECURE + bool "SPI0 interrupt secure" + ---help--- + SPI0 interrupt is secure. +endchoice + +choice + prompt "BRAKE0 Interrupt target secure configuration" + default BRAKE0_INTERRUPT_SECURE + +config BRAKE0_INTERRUPT_NONSECURE + bool "BRAKE0 interrupt non-secure" + ---help--- + BRAKE0 interrupt is non-secure. + +config BRAKE0_INTERRUPT_SECURE + bool "BRAKE0 interrupt secure" + ---help--- + BRAKE0 interrupt is secure. +endchoice + +choice + prompt "EPWM0_P0 Interrupt target secure configuration" + default EPWM0_P0_INTERRUPT_SECURE + +config EPWM0_P0_INTERRUPT_NONSECURE + bool "EPWM0_P0 interrupt non-secure" + ---help--- + EPWM0_P0 interrupt is non-secure. + +config EPWM0_P0_INTERRUPT_SECURE + bool "EPWM0_P0 interrupt secure" + ---help--- + EPWM0_P0 interrupt is secure. +endchoice + +choice + prompt "EPWM0_P1 Interrupt target secure configuration" + default EPWM0_P1_INTERRUPT_SECURE + +config EPWM0_P1_INTERRUPT_NONSECURE + bool "EPWM0_P1 interrupt non-secure" + ---help--- + EPWM0_P1 interrupt is non-secure. + +config EPWM0_P1_INTERRUPT_SECURE + bool "EPWM0_P1 interrupt secure" + ---help--- + EPWM0_P1 interrupt is secure. +endchoice + +choice + prompt "EPWM0_P2 Interrupt target secure configuration" + default EPWM0_P2_INTERRUPT_SECURE + +config EPWM0_P2_INTERRUPT_NONSECURE + bool "EPWM0_P2 interrupt non-secure" + ---help--- + EPWM0_P2 interrupt is non-secure. + +config EPWM0_P2_INTERRUPT_SECURE + bool "EPWM0_P2 interrupt secure" + ---help--- + EPWM0_P2 interrupt is secure. +endchoice + +choice + prompt "BRAKE1 Interrupt target secure configuration" + default BRAKE1_INTERRUPT_SECURE + +config BRAKE1_INTERRUPT_NONSECURE + bool "BRAKE1 interrupt non-secure" + ---help--- + BRAKE1 interrupt is non-secure. + +config BRAKE1_INTERRUPT_SECURE + bool "BRAKE1 interrupt secure" + ---help--- + BRAKE1 interrupt is secure. +endchoice + +choice + prompt "EPWM1_P0 Interrupt target secure configuration" + default EPWM1_P0_INTERRUPT_SECURE + +config EPWM1_P0_INTERRUPT_NONSECURE + bool "EPWM1_P0 interrupt non-secure" + ---help--- + EPWM1_P0 interrupt is non-secure. + +config EPWM1_P0_INTERRUPT_SECURE + bool "EPWM1_P0 interrupt secure" + ---help--- + EPWM1_P0 interrupt is secure. +endchoice + +choice + prompt "EPWM1_P1 Interrupt target secure configuration" + default EPWM1_P1_INTERRUPT_SECURE + +config EPWM1_P1_INTERRUPT_NONSECURE + bool "EPWM1_P1 interrupt non-secure" + ---help--- + EPWM1_P1 interrupt is non-secure. + +config EPWM1_P1_INTERRUPT_SECURE + bool "EPWM1_P1 interrupt secure" + ---help--- + EPWM1_P1 interrupt is secure. +endchoice + +choice + prompt "EPWM1_P2 Interrupt target secure configuration" + default EPWM1_P2_INTERRUPT_SECURE + +config EPWM1_P2_INTERRUPT_NONSECURE + bool "EPWM1_P2 interrupt non-secure" + ---help--- + EPWM1_P2 interrupt is non-secure. + +config EPWM1_P2_INTERRUPT_SECURE + bool "EPWM1_P2 interrupt secure" + ---help--- + EPWM1_P2 interrupt is secure. +endchoice + +choice + prompt "TMR2 Interrupt target secure configuration" + default TMR2_INTERRUPT_SECURE + +config TMR2_INTERRUPT_NONSECURE + bool "TMR2 interrupt non-secure" + ---help--- + TMR2 interrupt is non-secure. + +config TMR2_INTERRUPT_SECURE + bool "TMR2 interrupt secure" + ---help--- + TMR2 interrupt is secure. +endchoice + +choice + prompt "TMR3 Interrupt target secure configuration" + default TMR3_INTERRUPT_SECURE + +config TMR3_INTERRUPT_NONSECURE + bool "TMR3 interrupt non-secure" + ---help--- + TMR3 interrupt is non-secure. + +config TMR3_INTERRUPT_SECURE + bool "TMR3 interrupt secure" + ---help--- + TMR3 interrupt is secure. +endchoice + +choice + prompt "UART0 Interrupt target secure configuration" + default UART0_INTERRUPT_SECURE + +config UART0_INTERRUPT_NONSECURE + bool "UART0 interrupt non-secure" + ---help--- + UART0 interrupt is non-secure. + +config UART0_INTERRUPT_SECURE + bool "UART0 interrupt secure" + ---help--- + UART0 interrupt is secure. +endchoice + +choice + prompt "UART1 Interrupt target secure configuration" + default UART1_INTERRUPT_SECURE + +config UART1_INTERRUPT_NONSECURE + bool "UART1 interrupt non-secure" + ---help--- + UART1 interrupt is non-secure. + +config UART1_INTERRUPT_SECURE + bool "UART1 interrupt secure" + ---help--- + UART1 interrupt is secure. +endchoice + +choice + prompt "I2C0 Interrupt target secure configuration" + default I2C0_INTERRUPT_SECURE + +config I2C0_INTERRUPT_NONSECURE + bool "I2C0 interrupt non-secure" + ---help--- + I2C0 interrupt is non-secure. + +config I2C0_INTERRUPT_SECURE + bool "I2C0 interrupt secure" + ---help--- + I2C0 interrupt is secure. +endchoice + +choice + prompt "I2C1 Interrupt target secure configuration" + default I2C1_INTERRUPT_SECURE + +config I2C1_INTERRUPT_NONSECURE + bool "I2C1 interrupt non-secure" + ---help--- + I2C1 interrupt is non-secure. + +config I2C1_INTERRUPT_SECURE + bool "I2C1 interrupt secure" + ---help--- + I2C1 interrupt is secure. +endchoice + +choice + prompt "DAC Interrupt target secure configuration" + default DAC_INTERRUPT_SECURE + +config DAC_INTERRUPT_NONSECURE + bool "DAC interrupt non-secure" + ---help--- + DAC interrupt is non-secure. + +config DAC_INTERRUPT_SECURE + bool "DAC interrupt secure" + ---help--- + DAC interrupt is secure. +endchoice + +choice + prompt "EADC0 Interrupt target secure configuration" + default EADC0_INTERRUPT_SECURE + +config EADC0_INTERRUPT_NONSECURE + bool "EADC0 interrupt non-secure" + ---help--- + EADC0 interrupt is non-secure. + +config EADC0_INTERRUPT_SECURE + bool "EADC0 interrupt secure" + ---help--- + EADC0 interrupt is secure. +endchoice + +choice + prompt "EADC1 Interrupt target secure configuration" + default EADC1_INTERRUPT_SECURE + +config EADC1_INTERRUPT_NONSECURE + bool "EADC1 interrupt non-secure" + ---help--- + EADC1 interrupt is non-secure. + +config EADC1_INTERRUPT_SECURE + bool "EADC1 interrupt secure" + ---help--- + EADC1 interrupt is secure. +endchoice + +choice + prompt "ACMP01 Interrupt target secure configuration" + default ACMP01_INTERRUPT_SECURE + +config ACMP01_INTERRUPT_NONSECURE + bool "ACMP01 interrupt non-secure" + ---help--- + ACMP01 interrupt is non-secure. + +config ACMP01_INTERRUPT_SECURE + bool "ACMP01 interrupt secure" + ---help--- + ACMP01 interrupt is secure. +endchoice + +choice + prompt "EADC2 Interrupt target secure configuration" + default EADC2_INTERRUPT_SECURE + +config EADC2_INTERRUPT_NONSECURE + bool "EADC2 interrupt non-secure" + ---help--- + EADC2 interrupt is non-secure. + +config EADC2_INTERRUPT_SECURE + bool "EADC2 interrupt secure" + ---help--- + EADC2 interrupt is secure. +endchoice + +choice + prompt "EADC3 Interrupt target secure configuration" + default EADC3_INTERRUPT_SECURE + +config EADC3_INTERRUPT_NONSECURE + bool "EADC3 interrupt non-secure" + ---help--- + EADC3 interrupt is non-secure. + +config EADC3_INTERRUPT_SECURE + bool "EADC3 interrupt secure" + ---help--- + EADC3 interrupt is secure. +endchoice + +choice + prompt "UART2 Interrupt target secure configuration" + default UART2_INTERRUPT_SECURE + +config UART2_INTERRUPT_NONSECURE + bool "UART2 interrupt non-secure" + ---help--- + UART2 interrupt is non-secure. + +config UART2_INTERRUPT_SECURE + bool "UART2 interrupt secure" + ---help--- + UART2 interrupt is secure. +endchoice + +choice + prompt "UART3 Interrupt target secure configuration" + default UART3_INTERRUPT_SECURE + +config UART3_INTERRUPT_NONSECURE + bool "UART3 interrupt non-secure" + ---help--- + UART3 interrupt is non-secure. + +config UART3_INTERRUPT_SECURE + bool "UART3 interrupt secure" + ---help--- + UART3 interrupt is secure. +endchoice + +choice + prompt "SPI1 Interrupt target secure configuration" + default SPI1_INTERRUPT_SECURE + +config SPI1_INTERRUPT_NONSECURE + bool "SPI1 interrupt non-secure" + ---help--- + SPI1 interrupt is non-secure. + +config SPI1_INTERRUPT_SECURE + bool "SPI1 interrupt secure" + ---help--- + SPI1 interrupt is secure. +endchoice + +choice + prompt "SPI2 Interrupt target secure configuration" + default SPI2_INTERRUPT_SECURE + +config SPI2_INTERRUPT_NONSECURE + bool "SPI2 interrupt non-secure" + ---help--- + SPI2 interrupt is non-secure. + +config SPI2_INTERRUPT_SECURE + bool "SPI2 interrupt secure" + ---help--- + SPI2 interrupt is secure. +endchoice + +choice + prompt "USBD Interrupt target secure configuration" + default USBD_INTERRUPT_SECURE + +config USBD_INTERRUPT_NONSECURE + bool "USBD interrupt non-secure" + ---help--- + USBD interrupt is non-secure. + +config USBD_INTERRUPT_SECURE + bool "USBD interrupt secure" + ---help--- + USBD interrupt is secure. +endchoice + +choice + prompt "USBH Interrupt target secure configuration" + default USBH_INTERRUPT_SECURE + +config USBH_INTERRUPT_NONSECURE + bool "USBH interrupt non-secure" + ---help--- + USBH interrupt is non-secure. + +config USBH_INTERRUPT_SECURE + bool "USBH interrupt secure" + ---help--- + USBH interrupt is secure. +endchoice + +choice + prompt "USBOTG Interrupt target secure configuration" + default USBOTG_INTERRUPT_SECURE + +config USBOTG_INTERRUPT_NONSECURE + bool "USBOTG interrupt non-secure" + ---help--- + USBOTG interrupt is non-secure. + +config USBOTG_INTERRUPT_SECURE + bool "USBOTG interrupt secure" + ---help--- + USBOTG interrupt is secure. +endchoice + +choice + prompt "CAN0 Interrupt target secure configuration" + default CAN0_INTERRUPT_SECURE + +config CAN0_INTERRUPT_NONSECURE + bool "CAN0 interrupt non-secure" + ---help--- + CAN0 interrupt is non-secure. + +config CAN0_INTERRUPT_SECURE + bool "CAN0 interrupt secure" + ---help--- + CAN0 interrupt is secure. +endchoice + +choice + prompt "SC0 Interrupt target secure configuration" + default SC0_INTERRUPT_SECURE + +config SC0_INTERRUPT_NONSECURE + bool "SC0 interrupt non-secure" + ---help--- + SC0 interrupt is non-secure. + +config SC0_INTERRUPT_SECURE + bool "SC0 interrupt secure" + ---help--- + SC0 interrupt is secure. +endchoice + +choice + prompt "SC1 Interrupt target secure configuration" + default SC1_INTERRUPT_SECURE + +config SC1_INTERRUPT_NONSECURE + bool "SC1 interrupt non-secure" + ---help--- + SC1 interrupt is non-secure. + +config SC1_INTERRUPT_SECURE + bool "SC1 interrupt secure" + ---help--- + SC1 interrupt is secure. +endchoice + +choice + prompt "SC2 Interrupt target secure configuration" + default SC2_INTERRUPT_SECURE + +config SC2_INTERRUPT_NONSECURE + bool "SC2 interrupt non-secure" + ---help--- + SC2 interrupt is non-secure. + +config SC2_INTERRUPT_SECURE + bool "SC2 interrupt secure" + ---help--- + SC2 interrupt is secure. +endchoice + +choice + prompt "SPI3 Interrupt target secure configuration" + default SPI3_INTERRUPT_SECURE + +config SPI3_INTERRUPT_NONSECURE + bool "SPI3 interrupt non-secure" + ---help--- + SPI3 interrupt is non-secure. + +config SPI3_INTERRUPT_SECURE + bool "SPI3 interrupt secure" + ---help--- + SPI3 interrupt is secure. +endchoice + +choice + prompt "SDH0 Interrupt target secure configuration" + default SDH0_INTERRUPT_SECURE + +config SDH0_INTERRUPT_NONSECURE + bool "SDH0 interrupt non-secure" + ---help--- + SDH0 interrupt is non-secure. + +config SDH0_INTERRUPT_SECURE + bool "SDH0 interrupt secure" + ---help--- + SDH0 interrupt is secure. +endchoice + +choice + prompt "I2S0 Interrupt target secure configuration" + default I2S0_INTERRUPT_SECURE + +config I2S0_INTERRUPT_NONSECURE + bool "I2S0 interrupt non-secure" + ---help--- + I2S0 interrupt is non-secure. + +config I2S0_INTERRUPT_SECURE + bool "I2S0 interrupt secure" + ---help--- + I2S0 interrupt is secure. +endchoice + +choice + prompt "CRYPTO Interrupt target secure configuration" + default CRYPTO_INTERRUPT_SECURE + +config CRYPTO_INTERRUPT_NONSECURE + bool "CRYPTO interrupt non-secure" + ---help--- + CRYPTO interrupt is non-secure. + +config CRYPTO_INTERRUPT_SECURE + bool "CRYPTO interrupt secure" + ---help--- + CRYPTO interrupt is secure. +endchoice + +choice + prompt "GPG Interrupt target secure configuration" + default GPG_INTERRUPT_SECURE + +config GPG_INTERRUPT_NONSECURE + bool "GPG interrupt non-secure" + ---help--- + GPG interrupt is non-secure. + +config GPG_INTERRUPT_SECURE + bool "GPG interrupt secure" + ---help--- + GPG interrupt is secure. +endchoice + +choice + prompt "EINT6 Interrupt target secure configuration" + default EINT6_INTERRUPT_SECURE + +config EINT6_INTERRUPT_NONSECURE + bool "EINT6 interrupt non-secure" + ---help--- + EINT6 interrupt is non-secure. + +config EINT6_INTERRUPT_SECURE + bool "EINT6 interrupt secure" + ---help--- + EINT6 interrupt is secure. +endchoice + +choice + prompt "UART4 Interrupt target secure configuration" + default UART4_INTERRUPT_SECURE + +config UART4_INTERRUPT_NONSECURE + bool "UART4 interrupt non-secure" + ---help--- + UART4 interrupt is non-secure. + +config UART4_INTERRUPT_SECURE + bool "UART4 interrupt secure" + ---help--- + UART4 interrupt is secure. +endchoice + +choice + prompt "UART5 Interrupt target secure configuration" + default UART5_INTERRUPT_SECURE + +config UART5_INTERRUPT_NONSECURE + bool "UART5 interrupt non-secure" + ---help--- + UART5 interrupt is non-secure. + +config UART5_INTERRUPT_SECURE + bool "UART5 interrupt secure" + ---help--- + UART5 interrupt is secure. +endchoice + +choice + prompt "USCI0 Interrupt target secure configuration" + default USCI0_INTERRUPT_SECURE + +config USCI0_INTERRUPT_NONSECURE + bool "USCI0 interrupt non-secure" + ---help--- + USCI0 interrupt is non-secure. + +config USCI0_INTERRUPT_SECURE + bool "USCI0 interrupt secure" + ---help--- + USCI0 interrupt is secure. +endchoice + +choice + prompt "USCI1 Interrupt target secure configuration" + default USCI1_INTERRUPT_SECURE + +config USCI1_INTERRUPT_NONSECURE + bool "USCI1 interrupt non-secure" + ---help--- + USCI1 interrupt is non-secure. + +config USCI1_INTERRUPT_SECURE + bool "USCI1 interrupt secure" + ---help--- + USCI1 interrupt is secure. +endchoice + +choice + prompt "BPWM0 Interrupt target secure configuration" + default BPWM0_INTERRUPT_SECURE + +config BPWM0_INTERRUPT_NONSECURE + bool "BPWM0 interrupt non-secure" + ---help--- + BPWM0 interrupt is non-secure. + +config BPWM0_INTERRUPT_SECURE + bool "BPWM0 interrupt secure" + ---help--- + BPWM0 interrupt is secure. +endchoice + +choice + prompt "BPWM1 Interrupt target secure configuration" + default BPWM1_INTERRUPT_SECURE + +config BPWM1_INTERRUPT_NONSECURE + bool "BPWM1 interrupt non-secure" + ---help--- + BPWM1 interrupt is non-secure. + +config BPWM1_INTERRUPT_SECURE + bool "BPWM1 interrupt secure" + ---help--- + BPWM1 interrupt is secure. +endchoice + +choice + prompt "I2C2 Interrupt target secure configuration" + default I2C2_INTERRUPT_SECURE + +config I2C2_INTERRUPT_NONSECURE + bool "I2C2 interrupt non-secure" + ---help--- + I2C2 interrupt is non-secure. + +config I2C2_INTERRUPT_SECURE + bool "I2C2 interrupt secure" + ---help--- + I2C2 interrupt is secure. +endchoice + +choice + prompt "QEI0 Interrupt target secure configuration" + default QEI0_INTERRUPT_SECURE + +config QEI0_INTERRUPT_NONSECURE + bool "QEI0 interrupt non-secure" + ---help--- + QEI0 interrupt is non-secure. + +config QEI0_INTERRUPT_SECURE + bool "QEI0 interrupt secure" + ---help--- + QEI0 interrupt is secure. +endchoice + +choice + prompt "QEI1 Interrupt target secure configuration" + default QEI1_INTERRUPT_SECURE + +config QEI1_INTERRUPT_NONSECURE + bool "QEI1 interrupt non-secure" + ---help--- + QEI1 interrupt is non-secure. + +config QEI1_INTERRUPT_SECURE + bool "QEI1 interrupt secure" + ---help--- + QEI1 interrupt is secure. +endchoice + +choice + prompt "ECAP0 Interrupt target secure configuration" + default ECAP0_INTERRUPT_SECURE + +config ECAP0_INTERRUPT_NONSECURE + bool "ECAP0 interrupt non-secure" + ---help--- + ECAP0 interrupt is non-secure. + +config ECAP0_INTERRUPT_SECURE + bool "ECAP0 interrupt secure" + ---help--- + ECAP0 interrupt is secure. +endchoice + +choice + prompt "ECAP1 Interrupt target secure configuration" + default ECAP1_INTERRUPT_SECURE + +config ECAP1_INTERRUPT_NONSECURE + bool "ECAP1 interrupt non-secure" + ---help--- + ECAP1 interrupt is non-secure. + +config ECAP1_INTERRUPT_SECURE + bool "ECAP1 interrupt secure" + ---help--- + ECAP1 interrupt is secure. +endchoice + +choice + prompt "GPH Interrupt target secure configuration" + default GPH_INTERRUPT_SECURE + +config GPH_INTERRUPT_NONSECURE + bool "GPH interrupt non-secure" + ---help--- + GPH interrupt is non-secure. + +config GPH_INTERRUPT_SECURE + bool "GPH interrupt secure" + ---help--- + GPH interrupt is secure. +endchoice + +choice + prompt "EINT7 Interrupt target secure configuration" + default EINT7_INTERRUPT_SECURE + +config EINT7_INTERRUPT_NONSECURE + bool "EINT7 interrupt non-secure" + ---help--- + EINT7 interrupt is non-secure. + +config EINT7_INTERRUPT_SECURE + bool "EINT7 interrupt secure" + ---help--- + EINT7 interrupt is secure. +endchoice + +choice + prompt "PDMA1 Interrupt target secure configuration" + default PDMA1_INTERRUPT_SECURE + +config PDMA1_INTERRUPT_NONSECURE + bool "PDMA1 interrupt non-secure" + ---help--- + PDMA1 interrupt is non-secure. + +config PDMA1_INTERRUPT_SECURE + bool "PDMA1 interrupt secure" + ---help--- + PDMA1 interrupt is secure. +endchoice + +choice + prompt "TRNG Interrupt target secure configuration" + default TRNG_INTERRUPT_SECURE + +config TRNG_INTERRUPT_NONSECURE + bool "TRNG interrupt non-secure" + ---help--- + TRNG interrupt is non-secure. + +config TRNG_INTERRUPT_SECURE + bool "TRNG interrupt secure" + ---help--- + TRNG interrupt is secure. +endchoice + +endmenu # Assign Interrupt to Secure or Non-secure Vector + +menu "Enable secure violation interrupts" + +config APB0IEN_SECURE_VIOLATION_INTERRUPT + bool "APB0 secure violation interrupt enable" + default n + ---help--- + APB0 secure violation interrupt enable. + +config APB1IEN_SECURE_VIOLATION_INTERRUPT + bool "APB1 secure violation interrupt enable" + default n + ---help--- + APB1 secure violation interrupt enable. + +config GPIOIEN_SECURE_VIOLATION_INTERRUPT + bool "GPIO secure violation interrupt enable" + default n + ---help--- + GPIO secure violation interrupt enable. + +config EBIIEN_SECURE_VIOLATION_INTERRUPT + bool "EBI secure violation interrupt enable" + default n + ---help--- + EBI secure violation interrupt enable. + +config USBHIEN_SECURE_VIOLATION_INTERRUPT + bool "USBH secure violation interrupt enable" + default n + ---help--- + USBH secure violation interrupt enable. + +config CRCIEN_SECURE_VIOLATION_INTERRUPT + bool "CRC secure violation interrupt enable" + default n + ---help--- + CRC secure violation interrupt enable. + +config SDH0IEN_SECURE_VIOLATION_INTERRUPT + bool "SDH0 secure violation interrupt enable" + default n + ---help--- + SDH0 secure violation interrupt enable. + +config PDMA0IEN_SECURE_VIOLATION_INTERRUPT + bool "PDMA0 secure violation interrupt enable" + default n + ---help--- + PDMA0 secure violation interrupt enable. + +config PDMA1IEN_SECURE_VIOLATION_INTERRUPT + bool "PDMA1 secure violation interrupt enable" + default n + ---help--- + PDMA1 secure violation interrupt enable. + +config SRAM0IEN_SECURE_VIOLATION_INTERRUPT + bool "SRAM0 secure violation interrupt enable" + default n + ---help--- + SRAM0 secure violation interrupt enable. + +config SRAM1IEN_SECURE_VIOLATION_INTERRUPT + bool "SRAM1 secure violation interrupt enable" + default n + ---help--- + SRAM1 secure violation interrupt enable. + +config FMCIEN_SECURE_VIOLATION_INTERRUPT + bool "FMC secure violation interrupt enable" + default n + ---help--- + FMC secure violation interrupt enable. + +config FLASHIEN_SECURE_VIOLATION_INTERRUPT + bool "FLASH secure violation interrupt enable" + default n + ---help--- + FLASH secure violation interrupt enable. + +config SCUIEN_SECURE_VIOLATION_INTERRUPT + bool "SCU secure violation interrupt enable" + default n + ---help--- + SCU secure violation interrupt enable. + +config SYSIEN_SECURE_VIOLATION_INTERRUPT + bool "SYS secure violation interrupt enable" + default n + ---help--- + SYS secure violation interrupt enable. + +config CRPTIEN_SECURE_VIOLATION_INTERRUPT + bool "CRPT secure violation interrupt enable" + default n + ---help--- + CRPT secure violation interrupt enable. + +endmenu # Enable sercure violation interrupts + +config SAU_CONTROL + bool "Secure Attribute Unit (SAU) Control" + default y + ---help--- + "Secure Attribute Unit (SAU) Control". + +config ENABLE_SAU + bool "Enable SAU" + depends on SAU_CONTROL + default y + ---help--- + "Enable SAU". + +choice + prompt "All Memory Attribute When SAU is disabled" + depends on SAU_CONTROL + default ALL_MEMORY_SECURE + +config ALL_MEMORY_NONSECURE + bool "All Memory non-secure" + ---help--- + All Memory is non-secure. + +config ALL_MEMORY_SECURE + bool "All Memory secure" + ---help--- + All Memory is secure. +endchoice + +menu "Enable and Set Secure/Non-Secure region" + +config SAU_INIT_REGION0 + bool "Setup SAU Region 0" + default y + ---help--- + Setup SAU Region 0. + +config SAU_INIT_START0 + hex "Start address of SAU region 0" + depends on SAU_INIT_REGION0 + default 0x20000000 + ---help--- + "Start address of SAU region 0." + +config SAU_INIT_END0 + hex "End address of SAU region 0" + depends on SAU_INIT_REGION0 + default 0x20008000 + ---help--- + "End address of SAU region 0." + +choice + prompt "Region 0 secure configuration" + depends on SAU_INIT_REGION0 + default REGION0_SECURE + +config REGION0_NONSECURE + bool "Region 0 non-secure" + ---help--- + Region 0 is non-secure. + +config REGION0_SECURE + bool "Region 0 secure" + ---help--- + Region 0 is secure. +endchoice + +config SAU_INIT_REGION1 + bool "Setup SAU Region 1" + default n + ---help--- + Setup SAU Region 1. + +config SAU_INIT_START1 + hex "Start address of SAU region 1" + depends on SAU_INIT_REGION1 + default 0x10040000 + ---help--- + "Start address of SAU region 1." + +config SAU_INIT_END1 + hex "End address of SAU region 1" + depends on SAU_INIT_REGION1 + default 0x1007FFFF + ---help--- + "End address of SAU region 1." + +choice + prompt "Region 1 secure configuration" + depends on SAU_INIT_REGION1 + default REGION1_NONSECURE + +config REGION1_NONSECURE + bool "Region 1 non-secure" + ---help--- + Region 1 is non-secure. + +config REGION1_SECURE + bool "Region 1 secure" + ---help--- + Region 1 is secure. +endchoice + +config SAU_INIT_REGION2 + bool "Setup SAU Region 2" + default n + ---help--- + Setup SAU Region 2. + +config SAU_INIT_START2 + hex "Start address of SAU region 2" + depends on SAU_INIT_REGION2 + default 0x2000F000 + ---help--- + "Start address of SAU region 2." + +config SAU_INIT_END2 + hex "End address of SAU region 2" + depends on SAU_INIT_REGION2 + default 0x2000FFFF + ---help--- + "End address of SAU region 2." + +choice + prompt "Region 2 secure configuration" + depends on SAU_INIT_REGION2 + default REGION2_SECURE + +config REGION2_NONSECURE + bool "Region 2 non-secure" + ---help--- + Region 2 is non-secure. + +config REGION2_SECURE + bool "Region 2 secure" + ---help--- + Region 2 is secure. +endchoice + +config SAU_INIT_REGION3 + bool "Setup SAU Region 3" + default y + ---help--- + Setup SAU Region 3. + +config SAU_INIT_START3 + hex "Start address of SAU region 3" + depends on SAU_INIT_REGION3 + default 0x0003F000 + ---help--- + "Start address of SAU region 3." + +config SAU_INIT_END3 + hex "End address of SAU region 3" + depends on SAU_INIT_REGION3 + default 0x0003F7FF + ---help--- + "End address of SAU region 3." + +choice + prompt "Region 3 secure configuration" + depends on SAU_INIT_REGION3 + default REGION3_SECURE + +config REGION3_NONSECURE + bool "Region 3 non-secure" + ---help--- + Region 3 is non-secure. + +config REGION3_SECURE + bool "Region 3 secure" + ---help--- + Region 3 is secure. +endchoice + +config SAU_INIT_REGION4 + bool "Setup SAU Region 4" + default y + ---help--- + Setup SAU Region 4. + +config SAU_INIT_START4 + hex "Start address of SAU region 4" + depends on SAU_INIT_REGION4 + default 0x10040000 + ---help--- + "Start address of SAU region 4." + +config SAU_INIT_END4 + hex "End address of SAU region 4" + depends on SAU_INIT_REGION4 + default 0x1007FFFF + ---help--- + "End address of SAU region 4." + +choice + prompt "Region 4 secure configuration" + depends on SAU_INIT_REGION4 + default REGION4_NONSECURE + +config REGION4_NONSECURE + bool "Region 4 non-secure" + ---help--- + Region 4 is non-secure. + +config REGION4_SECURE + bool "Region 4 secure" + ---help--- + Region 4 is secure. +endchoice + +config SAU_INIT_REGION5 + bool "Setup SAU Region 5" + default y + ---help--- + Setup SAU Region 5. + +config SAU_INIT_START5 + hex "Start address of SAU region 5" + depends on SAU_INIT_REGION5 + default 0x00807E00 + ---help--- + "Start address of SAU region 5." + +config SAU_INIT_END5 + hex "End address of SAU region 5" + depends on SAU_INIT_REGION5 + default 0x00807FFF + ---help--- + "End address of SAU region 5." + +choice + prompt "Region 5 secure configuration" + depends on SAU_INIT_REGION5 + default REGION5_SECURE + +config REGION5_NONSECURE + bool "Region 5 non-secure" + ---help--- + Region 5 is non-secure. + +config REGION5_SECURE + bool "Region 5 secure" + ---help--- + Region 5 is secure. +endchoice + +config SAU_INIT_REGION6 + bool "Setup SAU Region 6" + default y + ---help--- + Setup SAU Region 6. + +config SAU_INIT_START6 + hex "Start address of SAU region 6" + depends on SAU_INIT_REGION6 + default 0x30008000 + ---help--- + "Start address of SAU region 6." + +config SAU_INIT_END6 + hex "End address of SAU region 6" + depends on SAU_INIT_REGION6 + default 0x30017FFF + ---help--- + "End address of SAU region 6." + +choice + prompt "Region 6 secure configuration" + depends on SAU_INIT_REGION6 + default REGION6_NONSECURE + +config REGION6_NONSECURE + bool "Region 6 non-secure" + ---help--- + Region 6 is non-secure. + +config REGION6_SECURE + bool "Region 6 secure" + ---help--- + Region 6 is secure. +endchoice + +config SAU_INIT_REGION7 + bool "Setup SAU Region 7" + default y + ---help--- + Setup SAU Region 7. + +config SAU_INIT_START7 + hex "Start address of SAU region 7" + depends on SAU_INIT_REGION7 + default 0x50000000 + ---help--- + "Start address of SAU region 7." + +config SAU_INIT_END7 + hex "End address of SAU region 7" + depends on SAU_INIT_REGION7 + default 0x5FFFFFFF + ---help--- + "End address of SAU region 7." + +choice + prompt "Region 7 secure configuration" + depends on SAU_INIT_REGION7 + default REGION7_NONSECURE + +config REGION7_NONSECURE + bool "Region 7 non-secure" + ---help--- + Region 7 is non-secure. + +config REGION7_SECURE + bool "Region 7 secure" + ---help--- + Region 7 is secure. +endchoice + +endmenu # Enable and Set Secure/Non-Secure region + +endmenu # Secure Attribution Configuration + +#if PLATFORM_M2351_BADGE +#comment "M2351-Badge Peripheral Configuration Options" +#source arch/cortex-m23/m2351/src/m2351_badge/Kconfig +#endif # PLATFORM_M2351_BADGE + +#if PLATFORM_NUMAKER_PFM_M2351 +#comment "NuMaker-PFM-M2351 Peripheral Configuration Options" +#source arch/cortex-m23/m2351/src/numaker_pfm_m2351/Kconfig +#endif # PLATFORM_NUMAKER_PFM_M2351 diff --git a/arch/riscv32/bl808/src/Makefile b/arch/riscv32/bl808/src/Makefile new file mode 100644 index 00000000..e4672dfb --- /dev/null +++ b/arch/riscv32/bl808/src/Makefile @@ -0,0 +1,184 @@ +############################################################################ +# arch/riscv32/bl808/src/Makefile +# +# Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved. +# Author: Taras Drozdovskyi t.drozdovsky@samsung.com +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +############################################################################ + +-include $(TOPDIR)/Make.defs +-include $(TOPDIR)/.config + +# ifeq ($(WORLD), secure) +# CFLAGS += -mcmse +# endif + +SRCS_LIBC = components/libc/newlib/syscalls_nosys.c +SRCS_LIBC += components/libc/vsnprintf.c +SRCS_LIBC += components/libc/snprintf.c +SRCS_LIBC += components/libc/sprintf.c +SRCS_LIBC += components/libc/vsprintf.c +SRCS_LIBC += components/libc/printf.c + +SRCS_MM = components/mm/tlsf/bflb_tlsf.c +SRCS_MM += components/mm/tlsf/tlsf.c +SRCS_MM += components/mm/mem.c + +SRCS_LHAL = drivers/lhal/config/bl808/device_table.c +SRCS_LHAL += drivers/lhal/src/bflb_common.c +# SRCS_LHAL += drivers/lhal/src/bflb_adc.c +# SRCS_LHAL += drivers/lhal/src/bflb_cks.c +# SRCS_LHAL += drivers/lhal/src/bflb_ef_ctrl.c +SRCS_LHAL += drivers/lhal/src/bflb_gpio.c +# SRCS_LHAL += drivers/lhal/src/bflb_i2c.c +# SRCS_LHAL += drivers/lhal/src/bflb_dma.c +# SRCS_LHAL += drivers/lhal/src/bflb_rtc.c +# SRCS_LHAL += drivers/lhal/src/bflb_sec_aes.c +# SRCS_LHAL += drivers/lhal/src/bflb_sec_sha.c +# SRCS_LHAL += drivers/lhal/src/bflb_sec_trng.c +# SRCS_LHAL += drivers/lhal/src/bflb_spi.c +# SRCS_LHAL += drivers/lhal/src/bflb_timer.c +SRCS_LHAL += drivers/lhal/src/bflb_uart.c +# SRCS_LHAL += drivers/lhal/src/bflb_wdg.c +SRCS_LHAL += drivers/lhal/src/bflb_flash.c +# SRCS_LHAL += drivers/lhal/src/bflb_dac.c +# SRCS_LHAL += drivers/lhal/src/bflb_emac.c +# SRCS_LHAL += drivers/lhal/src/bflb_ir.c +# SRCS_LHAL += drivers/lhal/src/bflb_mjpeg.c +# SRCS_LHAL += drivers/lhal/src/bflb_pwm_v2.c +# SRCS_LHAL += drivers/lhal/src/bflb_cam.c +# SRCS_LHAL += drivers/lhal/src/bflb_iso11898.c +# SRCS_LHAL += drivers/lhal/src/bflb_csi.c +# SRCS_LHAL += drivers/lhal/src/bflb_i2s.c +SRCS_LHAL += drivers/lhal/src/bflb_irq.c +# SRCS_LHAL += drivers/lhal/src/bflb_l1c.c +SRCS_LHAL += drivers/lhal/src/bflb_mtimer.c +SRCS_LHAL += drivers/lhal/include/arch/risc-v/t-head/rv_hart.c +SRCS_LHAL += drivers/lhal/include/arch/risc-v/t-head/rv_pmp.c +SRCS_LHAL += drivers/lhal/src/flash/bflb_sf_ctrl.c +SRCS_LHAL += drivers/lhal/src/flash/bflb_sflash.c +SRCS_LHAL += drivers/lhal/src/flash/bflb_sf_cfg.c +SRCS_LHAL += drivers/lhal/src/flash/bflb_xip_sflash.c +# SRCS_LHAL += drivers/lhal/src/bflb_kys.c +# SRCS_LHAL += drivers/lhal/src/bflb_pwm_v1.c +# SRCS_LHAL += drivers/lhal/src/bflb_auadc.c +# SRCS_LHAL += drivers/lhal/src/bflb_clock.c +# SRCS_LHAL += drivers/lhal/src/bflb_dbi.c +# SRCS_LHAL += drivers/lhal/src/bflb_sec_irq.c +# SRCS_LHAL += drivers/lhal/src/bflb_audac.c +# SRCS_LHAL += drivers/lhal/src/bflb_sdio2.c + +SRCS_STD = drivers/soc/bl808/std/src/bl808_aon.c +SRCS_STD += drivers/soc/bl808/std/src/bl808_clock.c +SRCS_STD += drivers/soc/bl808/std/port/bl808_clock.c +SRCS_STD += drivers/soc/bl808/std/src/bl808_common.c +SRCS_STD += drivers/soc/bl808/std/src/bl808_ef_cfg.c +SRCS_STD += drivers/soc/bl808/std/src/bl808_glb.c +SRCS_STD += drivers/soc/bl808/std/src/bl808_glb_gpio.c +SRCS_STD += drivers/soc/bl808/std/src/bl808_hbn.c +SRCS_STD += drivers/soc/bl808/std/src/bl808_l1c.c +SRCS_STD += drivers/soc/bl808/std/src/bl808_pds.c +# SRCS_STD += drivers/soc/bl808/std/src/bl808_psram_uhs.c +# SRCS_STD += drivers/soc/bl808/std/src/bl808_sdh.c +# SRCS_STD += drivers/soc/bl808/std/src/bl808_tzc_sec.c +# SRCS_STD += drivers/soc/bl808/std/src/bl808_uhs_phy.c +SRCS_STD += drivers/soc/bl808/std/startup/m0/interrupt.c +SRCS_STD += drivers/soc/bl808/std/startup/m0/start_load.c +SRCS_STD += drivers/soc/bl808/std/startup/m0/system_bl808.c + +SRCS_ASM_STD += drivers/soc/bl808/std/startup/m0/riscv_fpu.S +SRCS_ASM_STD += drivers/soc/bl808/std/startup/m0/start.S +SRCS_ASM_STD += drivers/soc/bl808/std/startup/m0/vector.S + +SRCS_ASM_FREERTOS = $(TOPDIR)/freertos/portable/GCC/RISC-V/portASM.S + +SRCS_FREERTOS += $(TOPDIR)/freertos/croutine.c +SRCS_FREERTOS += $(TOPDIR)/freertos/event_groups.c +SRCS_FREERTOS += $(TOPDIR)/freertos/list.c +SRCS_FREERTOS += $(TOPDIR)/freertos/queue.c +SRCS_FREERTOS += $(TOPDIR)/freertos/tasks.c +SRCS_FREERTOS += $(TOPDIR)/freertos/timers.c +SRCS_FREERTOS += $(TOPDIR)/freertos/portable/MemMang/heap_4.c +SRCS_FREERTOS += $(TOPDIR)/freertos/portable/GCC/RISC-V/pmp.c +SRCS_FREERTOS += $(TOPDIR)/freertos/portable/GCC/RISC-V/bl808_port.c +SRCS_FREERTOS += $(TOPDIR)/freertos/portable/Common/mpu_wrappers.c +SRCS_FREERTOS += $(TOPDIR)/freertos/stream_buffer.c + +# ifeq ($(WORLD), secure) +# SRCS += clk.c +# endif + +# ifneq ($(WORLD), secure) +# CFLAGS += -DDEBUG_PORT=$(subst ",,$(CONFIG_NONSECURE_DEBUG_UART)) +# CFLAGS += -DDEBUG_OUT_PREFIX=$(CONFIG_NONSECURE_FONT_COLOR) +OBJDIR = $(TOPDIR)/build/nonsecure$(subst $(TOPDIR),,$(shell pwd)) +# endif + +# ifeq ($(WORLD), secure) +# CFLAGS += -DDEBUG_PORT=$(subst ",,$(CONFIG_SECURE_DEBUG_UART)) +# CFLAGS += -DDEBUG_OUT_PREFIX=$(CONFIG_SECURE_FONT_COLOR) +# OBJDIR = $(TOPDIR)/build/secure$(subst $(TOPDIR),,$(shell pwd)) +# endif + +# OBJS = $(addprefix $(OBJDIR)/, $(SRCS:.c=.o)) + +OBJS_LIBC = $(addprefix $(OBJDIR)/, $(SRCS_LIBC:.c=.o)) +OBJS_MM = $(addprefix $(OBJDIR)/, $(SRCS_MM:.c=.o)) +OBJS_LHAL = $(addprefix $(OBJDIR)/, $(SRCS_LHAL:.c=.o)) +OBJS_STD = $(addprefix $(OBJDIR)/, $(SRCS_STD:.c=.o)) +AOBJS_STD += $(addprefix $(OBJDIR)/, $(SRCS_ASM_STD:.S=.o)) +OBJS_FREERTOS = $(addprefix $(OBJDIR)/, $(SRCS_FREERTOS:.c=.o)) +AOBJS_FREERTOS = $(addprefix $(OBJDIR)/, $(SRCS_ASM_FREERTOS:.S=.o)) + +current_dir = $(subst $(TOPDIR),,$(shell pwd)) + +$(OBJDIR)/%.o : %.c + $(Q) mkdir -p $(OBJDIR)/$(dir $<) + @echo "CC: $<" + $(Q) $(CC) $(CFLAGS) -c -o $@ $^ + +$(OBJDIR)/%.o : %.S + $(Q) mkdir -p $(OBJDIR)/$(dir $<) + @echo "CC: $<" + $(Q) $(CC) $(CFLAGS) -c -o $@ $^ + +#$(AOBJS_NS): $(OBJDIR)/%$(OBJEXT): %.S +# $(Q) mkdir -p $(OBJDIR)/$(dir $<) +# @echo "AS: $<" +# $(Q) $(CC) -c $(CFLAGS) $< -o $@ + +liblibc.a: $(OBJS_LIBC) + $(Q) $(AR) $(OBJDIR)/$@ $(OBJS_LIBC) + $(Q) cp $(OBJDIR)/$@ $(TOPDIR)/lib/$@ + +libmm.a: $(OBJS_MM) + $(Q) $(AR) $(OBJDIR)/$@ $(OBJS_MM) + $(Q) cp $(OBJDIR)/$@ $(TOPDIR)/lib/$@ + +liblhal.a: $(OBJS_LHAL) + $(Q) $(AR) $(OBJDIR)/$@ $(OBJS_LHAL) + $(Q) cp $(OBJDIR)/$@ $(TOPDIR)/lib/$@ + +libstd.a: $(OBJS_STD) $(AOBJS_STD) + $(Q) $(AR) $(OBJDIR)/$@ $(OBJS_STD) $(AOBJS_STD) + $(Q) cp $(OBJDIR)/$@ $(TOPDIR)/lib/$@ + +libfreertos.a: $(OBJS_FREERTOS) $(AOBJS_FREERTOS) + $(Q) $(AR) $(OBJDIR)/$@ $(OBJS_FREERTOS) $(AOBJS_FREERTOS) + $(Q) cp $(OBJDIR)/$@ $(TOPDIR)/lib/$@ + +clean: + rm -f liblibc.a libmm.a liblhal.a libstd.a libfreertos.a + diff --git a/arch/riscv32/bl808/src/NuBL2/.gitignore b/arch/riscv32/bl808/src/NuBL2/.gitignore new file mode 100644 index 00000000..c3edecc2 --- /dev/null +++ b/arch/riscv32/bl808/src/NuBL2/.gitignore @@ -0,0 +1,4 @@ +FwInfo.c +NuBL2.h +VerifyNuBL3x.c +main.c diff --git a/arch/riscv32/bl808/src/NuBL2/KeyInfo/NuBL3xKeyStorage.S b/arch/riscv32/bl808/src/NuBL2/KeyInfo/NuBL3xKeyStorage.S new file mode 100644 index 00000000..c9b96b2e --- /dev/null +++ b/arch/riscv32/bl808/src/NuBL2/KeyInfo/NuBL3xKeyStorage.S @@ -0,0 +1,33 @@ + .syntax unified + .arch armv8 - m.base + + .section .rodata + .align 3 + + .global g_NuBL32KeyStart + .global g_NuBL32KeyEnd + .global g_NuBL32KeyHashStart + .global g_NuBL32KeyHashEnd + + .global g_NuBL33KeyStart + .global g_NuBL33KeyEnd + .global g_NuBL33KeyHashStart + .global g_NuBL33KeyHashEnd + +g_NuBL32KeyStart: + .incbin "KeyInfo/NuBL32PubKeyEncrypted.bin" +g_NuBL32KeyEnd: + +g_NuBL32KeyHashStart: + .incbin "KeyInfo/NuBL32PubKeyEncryptedHash.bin" +g_NuBL32KeyHashEnd: + + +g_NuBL33KeyStart: + .incbin "KeyInfo/NuBL33PubKeyEncrypted.bin" +g_NuBL33KeyEnd: + +g_NuBL33KeyHashStart: + .incbin "KeyInfo/NuBL33PubKeyEncryptedHash.bin" +g_NuBL33KeyHashEnd: + diff --git a/arch/riscv32/bl808/src/NuBL2/Make.defs b/arch/riscv32/bl808/src/NuBL2/Make.defs new file mode 100644 index 00000000..77d2679c --- /dev/null +++ b/arch/riscv32/bl808/src/NuBL2/Make.defs @@ -0,0 +1,42 @@ +############################################################################ +# arch/cortex-m23/m2351/src/NuBL2/Make.defs +# +# Copyright (c) 2018-2019 Samsung Electronics Co., Ltd. All Rights Reserved. +# Author: Taras Drozdovskyi t.drozdovsky@samsung.com +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +############################################################################ + +-include $(TOPDIR)/Make.defs +-include $(TOPDIR)/.config + +HEAD_ASRC = + +# Common m2351 files + +CMN_ASRCS = + +CMN_CSRCS = + +# Required CHIP files + +CHIP_ASRCS_S = ../Device/Nuvoton/M2351/Source/GCC/startup_M2351.S \ + KeyInfo/NuBL3xKeyStorage.S + +CHIP_CSRCS_S = ../Device/Nuvoton/M2351/Source/system_M2351.c \ + ../Device/Nuvoton/M2351/Source/GCC/_syscalls.c \ + main.c \ + VerifyNuBL3x.c \ + FwInfo.c + diff --git a/arch/riscv32/bl808/src/NuBL2/Makefile b/arch/riscv32/bl808/src/NuBL2/Makefile new file mode 100644 index 00000000..e0989154 --- /dev/null +++ b/arch/riscv32/bl808/src/NuBL2/Makefile @@ -0,0 +1,77 @@ +############################################################################ +# arch/cortex-m23/m2351/src/NuBL2/Makefile +# +# Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved. +# Author: Taras Drozdovskyi t.drozdovsky@samsung.com +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +############################################################################ + +-include $(TOPDIR)/Make.defs +-include $(TOPDIR)/.config +-include Make.defs + +CFLAGS += -I./ +CFLAGS += -I$(TOPDIR)/arch/$(CONFIG_ARCH)/$(CONFIG_ARCH_FAMILY)/src/$(CONFIG_PLATFORM) +CFLAGS += -I$(TOPDIR)/include/mtower +CFLAGS += -I../CMSIS/Include +CFLAGS += -I../StdDriver/inc +CFLAGS += -I../Device/Nuvoton/M2351/Include + +CFLAGS += -DDEBUG_PORT=$(subst ",,$(CONFIG_SECURE_DEBUG_UART)) + +OBJDIR = $(TOPDIR)/build/secure$(subst $(TOPDIR),,$(shell pwd)) + +NuBL2 = NuBL2$(EXEEXT) + +ASRCS_S = $(CHIP_ASRCS_S) $(CMN_ASRCS) +AOBJS_S = $(addprefix $(OBJDIR)/, $(ASRCS_S:.S=$(OBJEXT))) + +CSRCS_S = $(CHIP_CSRCS_S) $(CMN_CSRCS) +COBJS_S = $(addprefix $(OBJDIR)/, $(CSRCS_S:.c=$(OBJEXT))) + +OBJS_S = $(AOBJS_S) $(COBJS_S) + +LIBPATHS = -L. -L"$(TOPDIR)/lib" -L"../StdDriver/src" + +LIBS = -lm -lc -lnosys -lm2351_StdDriver_s -lmkrom + +$(AOBJS_S): $(OBJDIR)/%$(OBJEXT): %.S + $(Q) mkdir -p $(OBJDIR)/$(dir $<) + @echo "AS: $<" + $(Q) $(CC) -c $(AFLAGS) -mcmse $< -o $@ + +$(COBJS_S): $(OBJDIR)/%$(OBJEXT): %.c + $(Q) mkdir -p $(OBJDIR)/$(dir $<) + @echo "CC: $<" + $(Q) $(CC) -c $(CFLAGS) -mcmse $< -o $@ + +Ecdsa_key: + $(Q) $(TOPDIR)/tools/ecdsa_keygen KeyInfo/ + +NuBL2$(EXEEXT): Ecdsa_key $(OBJS_S) + $(Q) $(MAKE) -C ../StdDriver/src/ TOPDIR="$(TOPDIR)" WORLD=secure libm2351_StdDriver_s.a +# $(Q) $(MAKE) -C $(TOPDIR)/crypto/ TOPDIR="$(TOPDIR)" WORLD=secure libcrypt_s.a + + @echo "CC: NuBL2$(EXEEXT)" + $(Q) $(CC) $(CFLAGS) -mcmse -Wl,--section-start=.text=0x00000000 -Tsecure.ld $(OBJS_S) $(LIBPATHS) $(LIBS) -o $(OBJDIR)/$(NuBL2) +# -$(Q) $(LD) --section-start=.gnu.sgstubs=0x3f000 --out-implib=libnsc$(LIBEXT) --cmse-implib $(OBJS_S) $(LIBPATHS) $(LIBS) +# $(Q) cp -f libnsc$(LIBEXT) $(TOPDIR)/lib/ + $(Q) $(OBJCOPY) -O binary $(OBJDIR)/$(NuBL2) $(OBJDIR)/bl2.bin + +clean: + $(Q) rm -f KeyInfo/*.bin + +distclean: clean + diff --git a/arch/riscv32/bl808/src/NuBL2/secure.ld b/arch/riscv32/bl808/src/NuBL2/secure.ld new file mode 100644 index 00000000..63648fca --- /dev/null +++ b/arch/riscv32/bl808/src/NuBL2/secure.ld @@ -0,0 +1,231 @@ +/* Linker script to configure memory regions. */ +MEMORY +{ + /* FLASH (rx) : ORIGIN = 0x00010000, LENGTH = 0x80000 */ /* 512k */ + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x18000 /* 160k */ + FLASH_NCS (rx) : ORIGIN = 0x0003F000, LENGTH = 0x00000400 +} + +/* Library configurations */ +GROUP(libgcc.a libc.a libm.a libnosys.a) + +/* Linker script to place sections and symbol values. Should be used together + * with other linker script that defines memory regions FLASH and RAM. + * It references following symbols, which must be defined in code: + * Reset_Handler : Entry of reset handler + * + * It defines following symbols, which code can use without definition: + * __exidx_start + * __exidx_end + * __copy_table_start__ + * __copy_table_end__ + * __zero_table_start__ + * __zero_table_end__ + * __etext + * __data_start__ + * __preinit_array_start + * __preinit_array_end + * __init_array_start + * __init_array_end + * __fini_array_start + * __fini_array_end + * __data_end__ + * __bss_start__ + * __bss_end__ + * __end__ + * end + * __HeapLimit + * __StackLimit + * __StackTop + * __stack + * __Vectors_End + * __Vectors_Size + */ +ENTRY(Reset_Handler) + +SECTIONS +{ + .text : + { + KEEP(*(.vectors)) + __Vectors_End = .; + __Vectors_Size = __Vectors_End - __Vectors; + __end__ = .; + + *(.text*) + + KEEP(*(.init)) + KEEP(*(.fini)) + + /* .ctors */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + + /* .dtors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + /* *(.rodata*) */ + + KEEP(*(.eh_frame*)) + } > FLASH + + .rodata : ALIGN(4) + { + __rodata_start = .; + *(.rodata .rodata.*) + /* + * 8 to avoid unwanted padding between __start_ta_head_section + * and the first structure in ta_head_section, in 64-bit + * builds + */ + . = ALIGN(4); + __start_ta_head_section = . ; + KEEP(*(ta_head_section)) + __stop_ta_head_section = . ; + . = ALIGN(4); + __start_user_ta_head_section = . ; + KEEP(*(user_ta_head_section)) + __stop_user_ta_head_section = . ; + . = ALIGN(4); + __rodata_end = .; + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH + __exidx_end = .; + + /* To copy multiple ROM to RAM sections, + * uncomment .copy.table section and, + * define __STARTUP_COPY_MULTIPLE in startup_ARMCMx.S */ + /* + .copy.table : + { + . = ALIGN(4); + __copy_table_start__ = .; + LONG (__etext) + LONG (__data_start__) + LONG (__data_end__ - __data_start__) + LONG (__etext2) + LONG (__data2_start__) + LONG (__data2_end__ - __data2_start__) + __copy_table_end__ = .; + } > FLASH + */ + + /* To clear multiple BSS sections, + * uncomment .zero.table section and, + * define __STARTUP_CLEAR_BSS_MULTIPLE in startup_ARMCMx.S */ + /* + .zero.table : + { + . = ALIGN(4); + __zero_table_start__ = .; + LONG (__bss_start__) + LONG (__bss_end__ - __bss_start__) + LONG (__bss2_start__) + LONG (__bss2_end__ - __bss2_start__) + __zero_table_end__ = .; + } > FLASH + */ + + .gnu.sgstubs : ALIGN(2048) + { + __start_NSC = .; + . = ALIGN(4); + _ssgstubs = .; + } > FLASH + . = ALIGN(2048); + __end_NSC = .; + __etext = .; + + .data : AT (__etext) + { + __data_start__ = .; + *(vtable) + *(.data*) + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP(*(SORT(.fini_array.*))) + KEEP(*(.fini_array)) + PROVIDE_HIDDEN (__fini_array_end = .); + + KEEP(*(.jcr*)) + . = ALIGN(4); + /* All data end */ + __data_end__ = .; + + } > RAM + + .bss : + { + . = ALIGN(4); + __bss_start__ = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + } > RAM + + .heap (COPY): + { + __HeapBase = .; + __end__ = .; + end = __end__; + KEEP(*(.heap*)) + __HeapLimit = .; + } > RAM + + /* .stack_dummy section doesn't contains any symbols. It is only + * used for linker to calculate size of stack sections, and assign + * values to stack symbols later */ + .stack_dummy (COPY): + { + KEEP(*(.stack*)) + } > RAM + + /* Set stack top to end of RAM, and stack limit move down by + * size of stack_dummy section */ + /* + __StackTop = ORIGIN(RAM) + LENGTH(RAM); + __StackLimit = __StackTop - SIZEOF(.stack_dummy); + */ + + __StackTop = __HeapLimit + SIZEOF(.stack_dummy); + __StackLimit = __HeapLimit; + + PROVIDE(__stack = __StackTop); + + /* Check if data + heap + stack exceeds RAM limit */ + ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack") +} diff --git a/arch/riscv32/bl808/src/components/libc/CMakeLists.txt b/arch/riscv32/bl808/src/components/libc/CMakeLists.txt new file mode 100644 index 00000000..4ddad13e --- /dev/null +++ b/arch/riscv32/bl808/src/components/libc/CMakeLists.txt @@ -0,0 +1,111 @@ +sdk_generate_library() + +add_subdirectory(newlib) + +# use newlib stdlib or nuttx stdlib +if(NOT CONFIG_NEWLIB_STANDARD) +sdk_library_add_sources( +nuttx/libc/stdlib/lib_abs.c +nuttx/libc/stdlib/lib_atof.c +nuttx/libc/stdlib/lib_atoi.c +nuttx/libc/stdlib/lib_atol.c +nuttx/libc/stdlib/lib_atoll.c +nuttx/libc/stdlib/lib_bsearch.c +nuttx/libc/stdlib/lib_checkbase.c +nuttx/libc/stdlib/lib_itoa.c +nuttx/libc/stdlib/lib_llabs.c +nuttx/libc/stdlib/lib_lldiv.c +nuttx/libc/stdlib/lib_qsort.c +nuttx/libc/stdlib/lib_strtod.c +# nuttx/libc/stdlib/lib_strtof.c +# nuttx/libc/stdlib/lib_strtol.c +# nuttx/libc/stdlib/lib_strtold.c +# nuttx/libc/stdlib/lib_strtoll.c +# nuttx/libc/stdlib/lib_strtoull.c +) +endif() + +# use newlib string or nuttx string +if(NOT CONFIG_NEWLIB_STANDARD) +sdk_library_add_sources( +nuttx/libc/string/lib_ffs.c +nuttx/libc/string/lib_ffsl.c +nuttx/libc/string/lib_ffsll.c +nuttx/libc/string/lib_fls.c +nuttx/libc/string/lib_flsl.c +nuttx/libc/string/lib_flsll.c +nuttx/libc/string/lib_index.c +nuttx/libc/string/lib_memccpy.c +nuttx/libc/string/lib_memchr.c +nuttx/libc/string/lib_memcmp.c +nuttx/libc/string/lib_memmove.c +nuttx/libc/string/lib_memrchr.c +nuttx/libc/string/lib_memset.c +nuttx/libc/string/lib_stpcpy.c +nuttx/libc/string/lib_stpncpy.c +nuttx/libc/string/lib_strcasecmp.c +nuttx/libc/string/lib_strcasestr.c +nuttx/libc/string/lib_strcat.c +nuttx/libc/string/lib_strchr.c +nuttx/libc/string/lib_strcmp.c +nuttx/libc/string/lib_strcspn.c +nuttx/libc/string/lib_strdup.c +nuttx/libc/string/lib_strnlen.c +nuttx/libc/string/lib_strpbrk.c +nuttx/libc/string/lib_strrchr.c +nuttx/libc/string/lib_strsep.c +nuttx/libc/string/lib_strspn.c +nuttx/libc/string/lib_strstr.c +nuttx/libc/string/lib_strtok.c +nuttx/libc/string/lib_strtokr.c +# nuttx/libc/string/lib_isbasedigit.c +# nuttx/libc/string/lib_skipspace.c +) +endif() + +# is boot2 +if(NOT CONFIG_BOOT2) +# use newlib memcpy or nuttx memcpy +if(NOT CONFIG_NEWLIB_STANDARD) +sdk_library_add_sources( +nuttx/libc/string/lib_vikmemcpy.c +) +endif() +else() +sdk_library_add_sources( +nuttx/libc/string/lib_memcpy.c +) +endif() + +sdk_add_include_directories(.) + +if(NOT CONFIG_NEWLIB_STANDARD) +if(CONFIG_VSNPRINTF_NANO) +sdk_library_add_sources(vsnprintf_nano.c) +else() +sdk_library_add_sources(vsnprintf.c) +endif() +endif() + +if(NOT CONFIG_NEWLIB) +sdk_library_add_sources(snprintf.c) +sdk_library_add_sources(sprintf.c) +sdk_library_add_sources(vsprintf.c) +sdk_library_add_sources(printf.c) +endif() + +# vsnprintf %f %F +if(CONFIG_VSNPRINTF_FLOAT) + sdk_add_compile_definitions(-DCONFIG_LIBC_FLOAT=${CONFIG_VSNPRINTF_FLOAT}) +endif() +# vsnprintf %g %G %e %E +if(CONFIG_VSNPRINTF_FLOAT_EX) + sdk_add_compile_definitions(-DCONFIG_LIBC_FLOAT_EX=${CONFIG_VSNPRINTF_FLOAT_EX}) +endif() +# vsnprintf %lld %lli %llu %llx %llX %llo +if(CONFIG_VSNPRINTF_LONG_LONG) + sdk_add_compile_definitions(-DCONFIG_LIBC_LONG_LONG=${CONFIG_VSNPRINTF_LONG_LONG}) +endif() + +# use custom apis first, if not exist, then use builtin apis +sdk_add_compile_options(-fno-builtin) diff --git a/arch/riscv32/bl808/src/components/libc/newlib/syscalls_nosys.c b/arch/riscv32/bl808/src/components/libc/newlib/syscalls_nosys.c new file mode 100644 index 00000000..7822b2ac --- /dev/null +++ b/arch/riscv32/bl808/src/components/libc/newlib/syscalls_nosys.c @@ -0,0 +1,144 @@ +#include +#include +#include +#include +#include +#include + +#undef errno +int errno; + +char *__env[1] = { 0 }; +char **environ = __env; + +void _exit(int rc) +{ + for (;;) + ; +} + +int _chown(const char *path, uid_t owner, gid_t group) +{ + errno = ENOSYS; + return -1; +} + +int _close(int fildes) +{ + errno = ENOSYS; + return -1; +} + +int _execve(char *name, char **argv, char **env) +{ + errno = ENOSYS; + return -1; +} + +int _fork(void) +{ + errno = ENOSYS; + return -1; +} + +int _fstat(int fildes, struct stat *st) +{ + errno = ENOSYS; + return -1; +} + +int _getpid(void) +{ + errno = ENOSYS; + return -1; +} + +int _gettimeofday(struct timeval *ptimeval, void *ptimezone) +{ + errno = ENOSYS; + return -1; +} + +int _isatty(int file) +{ + errno = ENOSYS; + return 0; +} + +int _kill(int pid, int sig) +{ + errno = ENOSYS; + return -1; +} + +int _link(char *existing, char *new) +{ + errno = ENOSYS; + return -1; +} + +int _lseek(int file, int ptr, int dir) +{ + errno = ENOSYS; + return -1; +} + +int _open(char *file, int flags, int mode) +{ + errno = ENOSYS; + return -1; +} + +int _read(int file, char *ptr, int len) +{ + errno = ENOSYS; + return -1; +} + +int _readlink(const char *path, char *buf, size_t bufsize) +{ + errno = ENOSYS; + return -1; +} + +void *_sbrk(int incr) +{ + errno = ENOSYS; + return NULL; +} + +int _stat(const char *file, struct stat *st) +{ + errno = ENOSYS; + return -1; +} + +int _symlink(const char *path1, const char *path2) +{ + errno = ENOSYS; + return -1; +} + +clock_t _times(struct tms *buf) +{ + errno = ENOSYS; + return -1; +} + +int _unlink(char *name) +{ + errno = ENOSYS; + return -1; +} + +int _wait(int *status) +{ + errno = ENOSYS; + return -1; +} + +int _write(int file, char *ptr, int len) +{ + errno = ENOSYS; + return -1; +} \ No newline at end of file diff --git a/arch/riscv32/bl808/src/components/libc/printf.c b/arch/riscv32/bl808/src/components/libc/printf.c new file mode 100644 index 00000000..ad7cbf6c --- /dev/null +++ b/arch/riscv32/bl808/src/components/libc/printf.c @@ -0,0 +1,112 @@ +#include "bflb_uart.h" +#include "stdarg.h" + +struct bflb_device_s *console = NULL; + +int puts(const char* c) +{ + if (console == NULL) { + return 0; + } + + bflb_uart_put(console, (uint8_t *)c, 1); + + return 0; +} + +int putstring(const char* c) +{ + if (console == NULL) { + return 0; + } + + bflb_uart_put(console, (uint8_t *)c, strlen(c)); + + return 0; +} + +int printf(const char *fmt, ...) +{ + char print_buf[1024]; + uint32_t len; + va_list ap; + + if (console == NULL) { + return 0; + } + + va_start(ap, fmt); + len = vsnprintf(print_buf, sizeof(print_buf), fmt, ap); + va_end(ap); + + len = (len > sizeof(print_buf)) ? sizeof(print_buf) : len; + + bflb_uart_put(console, (uint8_t *)print_buf, len); + + return 0; +} + +#define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ') +void bflb_dump_hex(const void *ptr, uint32_t buflen) +{ + unsigned char *buf = (unsigned char *)ptr; + int i, j; + + for (i = 0; i < buflen; i += 16) { + printf("%08X:", i); + + for (j = 0; j < 16; j++) + if (i + j < buflen) { + if ((j % 8) == 0) { + printf(" "); + } + + printf("%02X ", buf[i + j]); + } else + printf(" "); + printf(" "); + + for (j = 0; j < 16; j++) + if (i + j < buflen) + printf("%c", __is_print(buf[i + j]) ? buf[i + j] : '.'); + printf("\n"); + } +} + +// void bflb_dump_hex(uint8_t *data, uint32_t len) +// { +// uint32_t i = 0; + +// for (i = 0; i < len; i++) { +// if (i % 16 == 0) { +// printf("\r\n"); +// } + +// printf("%02x ", data[i]); +// } + +// printf("\r\n"); +// } + +void bflb_reg_dump(uint32_t addr) +{ + printf("%08lx[31:0]=%08lx\r\n", addr, *(volatile uint32_t *)(addr)); +} + +int bflb_data_compare(const uint8_t *expected, uint8_t *input, uint32_t len) +{ + int i = 0; + for (i = 0; i < len; i++) { + if (input[i] != expected[i]) { + printf("Compare fail at %d,input %02x, but expect %02x\r\n", i, input[i], expected[i]); + return -1; + } + } + + return 0; +} + +void bflb_uart_set_console(struct bflb_device_s *dev) +{ + console = dev; +} \ No newline at end of file diff --git a/arch/riscv32/bl808/src/components/libc/snprintf.c b/arch/riscv32/bl808/src/components/libc/snprintf.c new file mode 100644 index 00000000..b08ddbde --- /dev/null +++ b/arch/riscv32/bl808/src/components/libc/snprintf.c @@ -0,0 +1,27 @@ +#include +#include +#include +#include + +/** + * This function will fill a formatted string to buffer. + * + * @param buf is the buffer to save formatted string. + * + * @param size is the size of buffer. + * + * @param fmt is the format parameters. + * + * @return The number of characters actually written to buffer. + */ +int snprintf(char *__restrict buf, size_t size, const char *__restrict fmt, ...) +{ + int n; + va_list args; + + va_start(args, fmt); + n = vsnprintf(buf, size, fmt, args); + va_end(args); + + return n; +} \ No newline at end of file diff --git a/arch/riscv32/bl808/src/components/libc/sprintf.c b/arch/riscv32/bl808/src/components/libc/sprintf.c new file mode 100644 index 00000000..0337c35b --- /dev/null +++ b/arch/riscv32/bl808/src/components/libc/sprintf.c @@ -0,0 +1,25 @@ +#include +#include +#include +#include + +/** + * This function will fill a formatted string to buffer + * + * @param buf the buffer to save formatted string. + * + * @param format is the format parameters. + * + * @return The number of characters actually written to buffer. + */ +int sprintf(char *buf, const char *format, ...) +{ + int32_t n; + va_list arg_ptr; + + va_start(arg_ptr, format); + n = vsprintf(buf, format, arg_ptr); + va_end(arg_ptr); + + return n; +} \ No newline at end of file diff --git a/arch/riscv32/bl808/src/components/libc/vsnprintf.c b/arch/riscv32/bl808/src/components/libc/vsnprintf.c new file mode 100644 index 00000000..2035408a --- /dev/null +++ b/arch/riscv32/bl808/src/components/libc/vsnprintf.c @@ -0,0 +1,1074 @@ +/** + * @author (c) Eyal Rozenberg + * 2021, Haifa, Palestine/Israel + * @author (c) Marco Paland (info@paland.com) + * 2014-2019, PALANDesign Hannover, Germany + * + * @note Others have made smaller contributions to this file: see the + * contributors page at https://github.com/eyalroz/printf/graphs/contributors + * or ask one of the authors. + * + * @brief Small stand-alone implementation of the printf family of functions + * (`(v)printf`, `(v)s(n)printf` etc., geared towards use on embedded systems with + * a very limited resources. + * + * @note the implementations are thread-safe; re-entrant; use no functions from + * the standard library; and do not dynamically allocate any memory. + * + * @license The MIT License (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. + */ + +#include +#include +#include +#include + +// 'ntoa' conversion buffer size, this must be big enough to hold one converted +// numeric number including padded zeros (dynamically created on stack) +#ifndef PRINTF_INTEGER_BUFFER_SIZE +#define PRINTF_INTEGER_BUFFER_SIZE 32 +#endif + +// 'ftoa' conversion buffer size, this must be big enough to hold one converted +// float number including padded zeros (dynamically created on stack) +#ifndef PRINTF_FTOA_BUFFER_SIZE +#define PRINTF_FTOA_BUFFER_SIZE 32 +#endif + +// Support for the decimal notation floating point conversion specifiers (%f, %F) +#ifndef CONFIG_LIBC_FLOAT +#define CONFIG_LIBC_FLOAT 1 +#endif + +// Support for the exponential notatin floating point conversion specifiers (%e, %g, %E, %G) +#ifndef CONFIG_LIBC_FLOAT_EX +#define CONFIG_LIBC_FLOAT_EX 0 +#endif + +// Default precision for the floating point conversion specifiers (the C standard sets this at 6) +#ifndef PRINTF_DEFAULT_FLOAT_PRECISION +#define PRINTF_DEFAULT_FLOAT_PRECISION 6 +#endif + +// According to the C languages standard, printf() and related functions must be able to print any +// integral number in floating-point notation, regardless of length, when using the %f specifier - +// possibly hundreds of characters, potentially overflowing your buffers. In this implementation, +// all values beyond this threshold are switched to exponential notation. +#ifndef PRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL +#define PRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL 9 +#endif + +// Support for the long long integral types (with the ll, z and t length modifiers for specifiers +// %d,%i,%o,%x,%X,%u, and with the %p specifier). Note: 'L' (long double) is not supported. +#ifndef CONFIG_LIBC_LONG_LONG +#define CONFIG_LIBC_LONG_LONG 1 +#endif + +#ifndef PRINTF_SUPPORT_LENGTH_FILED +#define PRINTF_SUPPORT_LENGTH_FILED 1 +#endif + +#ifndef PRINTF_SUPPORT_CHAR +#define PRINTF_SUPPORT_CHAR 1 +#endif + +#ifndef PRINTF_SUPPORT_ADDR +#define PRINTF_SUPPORT_ADDR 1 +#endif + + +#if CONFIG_LIBC_LONG_LONG +typedef unsigned long long printf_unsigned_value_t; +typedef long long printf_signed_value_t; +#else +typedef unsigned long printf_unsigned_value_t; +typedef long printf_signed_value_t; +#endif + +#define PRINTF_PREFER_DECIMAL false +#define PRINTF_PREFER_EXPONENTIAL true + +/////////////////////////////////////////////////////////////////////////////// + +// The following will convert the number-of-digits into an exponential-notation literal +#define PRINTF_CONCATENATE(s1, s2) s1##s2 +#define PRINTF_EXPAND_THEN_CONCATENATE(s1, s2) PRINTF_CONCATENATE(s1, s2) +#define PRINTF_FLOAT_NOTATION_THRESHOLD PRINTF_EXPAND_THEN_CONCATENATE(1e,PRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL) + +// internal flag definitions +#define FLAGS_ZEROPAD (1U << 0U) +#define FLAGS_LEFT (1U << 1U) +#define FLAGS_PLUS (1U << 2U) +#define FLAGS_SPACE (1U << 3U) +#define FLAGS_HASH (1U << 4U) +#define FLAGS_UPPERCASE (1U << 5U) +#define FLAGS_CHAR (1U << 6U) +#define FLAGS_SHORT (1U << 7U) +#define FLAGS_LONG (1U << 8U) +#define FLAGS_LONG_LONG (1U << 9U) +#define FLAGS_PRECISION (1U << 10U) +#define FLAGS_ADAPT_EXP (1U << 11U) +#define FLAGS_POINTER (1U << 12U) +// Note: Similar, but not identical, effect as FLAGS_HASH + +#define BASE_BINARY 2 +#define BASE_OCTAL 8 +#define BASE_DECIMAL 10 +#define BASE_HEX 16 + +typedef uint8_t numeric_base_t; + +#if (CONFIG_LIBC_FLOAT || CONFIG_LIBC_FLOAT_EX) +#include +#if FLT_RADIX != 2 +#error "Non-binary-radix floating-point types are unsupported." +#endif + +#if DBL_MANT_DIG == 24 + +#define DOUBLE_SIZE_IN_BITS 32 +typedef uint32_t double_uint_t; +#define DOUBLE_EXPONENT_MASK 0xFFU +#define DOUBLE_BASE_EXPONENT 127 + +#elif DBL_MANT_DIG == 53 + +#define DOUBLE_SIZE_IN_BITS 64 +typedef uint64_t double_uint_t; +#define DOUBLE_EXPONENT_MASK 0x7FFU +#define DOUBLE_BASE_EXPONENT 1023 + +#else +#error "Unsupported double type configuration" +#endif +#define DOUBLE_STORED_MANTISSA_BITS (DBL_MANT_DIG - 1) + +typedef union { + double_uint_t U; + double F; +} double_with_bit_access; + +// This is unnecessary in C99, since compound initializers can be used, +// but: 1. Some compilers are finicky about this; 2. Some people may want to convert this to C89; +// 3. If you try to use it as C++, only C++20 supports compound literals +static inline double_with_bit_access get_bit_access(double x) +{ + double_with_bit_access dwba; + dwba.F = x; + return dwba; +} + +static inline int get_sign(double x) +{ + // The sign is stored in the highest bit + return get_bit_access(x).U >> (DOUBLE_SIZE_IN_BITS - 1); +} + +static inline int get_exp2(double_with_bit_access x) +{ + // The exponent in an IEEE-754 floating-point number occupies a contiguous + // sequence of bits (e.g. 52..62 for 64-bit doubles), but with a non-trivial representation: An + // unsigned offset from some negative value (with the extremal offset values reserved for + // special use). + return (int)((x.U >> DOUBLE_STORED_MANTISSA_BITS ) & DOUBLE_EXPONENT_MASK) - DOUBLE_BASE_EXPONENT; +} +#define PRINTF_ABS(_x) ( (_x) > 0 ? (_x) : -(_x) ) + +#endif // (CONFIG_LIBC_FLOAT || CONFIG_LIBC_FLOAT_EX) + +// Note in particular the behavior here on LONG_MIN or LLONG_MIN; it is valid +// and well-defined, but if you're not careful you can easily trigger undefined +// behavior with -LONG_MIN or -LLONG_MIN +#define ABS_FOR_PRINTING(_x) ((printf_unsigned_value_t) ( (_x) > 0 ? (_x) : -((printf_signed_value_t)_x) )) + +// output function type +typedef void (*out_fct_type)(char character, void* buffer, size_t idx, size_t maxlen); + + +// wrapper (used as buffer) for output function type +typedef struct { + void (*fct)(char character, void* arg); + void* arg; +} out_function_wrapper_type; + + +// internal buffer output +static inline void out_buffer(char character, void* buffer, size_t idx, size_t maxlen) +{ + if (idx < maxlen) { + ((char*)buffer)[idx] = character; + } +} + + +// internal null output +static inline void out_discard(char character, void* buffer, size_t idx, size_t maxlen) +{ + (void)character; (void)buffer; (void)idx; (void)maxlen; +} + + +// internal secure strlen +// @return The length of the string (excluding the terminating 0) limited by 'maxsize' +static inline unsigned int strnlen_s_(const char* str, size_t maxsize) +{ + const char* s; + for (s = str; *s && maxsize--; ++s); + return (unsigned int)(s - str); +} + + +// internal test if char is a digit (0-9) +// @return true if char is a digit +static inline bool is_digit_(char ch) +{ + return (ch >= '0') && (ch <= '9'); +} + + +// internal ASCII string to unsigned int conversion +static unsigned int atoi_(const char** str) +{ + unsigned int i = 0U; + while (is_digit_(**str)) { + i = i * 10U + (unsigned int)(*((*str)++) - '0'); + } + return i; +} + + +// output the specified string in reverse, taking care of any zero-padding +static size_t out_rev_(out_fct_type out, char* buffer, size_t idx, size_t maxlen, const char* buf, size_t len, unsigned int width, unsigned int flags) +{ + const size_t start_idx = idx; + + // pad spaces up to given width + if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) { + for (size_t i = len; i < width; i++) { + out(' ', buffer, idx++, maxlen); + } + } + + // reverse string + while (len) { + out(buf[--len], buffer, idx++, maxlen); + } + + // append pad spaces up to given width + if (flags & FLAGS_LEFT) { + while (idx - start_idx < width) { + out(' ', buffer, idx++, maxlen); + } + } + + return idx; +} + + +// Invoked by print_integer after the actual number has been printed, performing necessary +// work on the number's prefix (as the number is initially printed in reverse order) +static size_t print_integer_finalization(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len, bool negative, numeric_base_t base, unsigned int precision, unsigned int width, unsigned int flags) +{ + size_t unpadded_len = len; + + // pad with leading zeros + { + if (!(flags & FLAGS_LEFT)) { + if (width && (flags & FLAGS_ZEROPAD) && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { + width--; + } + while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_INTEGER_BUFFER_SIZE)) { + buf[len++] = '0'; + } + } + + while ((len < precision) && (len < PRINTF_INTEGER_BUFFER_SIZE)) { + buf[len++] = '0'; + } + + if (base == BASE_OCTAL && (len > unpadded_len)) { + // Since we've written some zeros, we've satisfied the alternative format leading space requirement + flags &= ~FLAGS_HASH; + } + } + + // handle hash + if (flags & (FLAGS_HASH | FLAGS_POINTER)) { + if (!(flags & FLAGS_PRECISION) && len && ((len == precision) || (len == width))) { + // Let's take back some padding digits to fit in what will eventually + // be the format-specific prefix + if (unpadded_len < len) { + len--; + } + if (len && (base == BASE_HEX)) { + if (unpadded_len < len) { + len--; + } + } + } + if ((base == BASE_HEX) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_INTEGER_BUFFER_SIZE)) { + buf[len++] = 'x'; + } + else if ((base == BASE_HEX) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_INTEGER_BUFFER_SIZE)) { + buf[len++] = 'X'; + } + else if ((base == BASE_BINARY) && (len < PRINTF_INTEGER_BUFFER_SIZE)) { + buf[len++] = 'b'; + } + if (len < PRINTF_INTEGER_BUFFER_SIZE) { + buf[len++] = '0'; + } + } + + if (len < PRINTF_INTEGER_BUFFER_SIZE) { + if (negative) { + buf[len++] = '-'; + } + else if (flags & FLAGS_PLUS) { + buf[len++] = '+'; // ignore the space if the '+' exists + } + else if (flags & FLAGS_SPACE) { + buf[len++] = ' '; + } + } + + return out_rev_(out, buffer, idx, maxlen, buf, len, width, flags); +} + +// An internal itoa-like function +static size_t print_integer(out_fct_type out, char* buffer, size_t idx, size_t maxlen, printf_unsigned_value_t value, bool negative, numeric_base_t base, unsigned int precision, unsigned int width, unsigned int flags) +{ + char buf[PRINTF_INTEGER_BUFFER_SIZE]; + size_t len = 0U; + + if (!value) { + if ( !(flags & FLAGS_PRECISION) ) { + buf[len++] = '0'; + flags &= ~FLAGS_HASH; + // We drop this flag this since either the alternative and regular modes of the specifier + // don't differ on 0 values, or (in the case of octal) we've already provided the special + // handling for this mode. + } + else if (base == BASE_HEX) { + flags &= ~FLAGS_HASH; + // We drop this flag this since either the alternative and regular modes of the specifier + // don't differ on 0 values + } + } + else { + do { + const char digit = (char)(value % base); + buf[len++] = (char)(digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10); + value /= base; + } while (value && (len < PRINTF_INTEGER_BUFFER_SIZE)); + } + + return print_integer_finalization(out, buffer, idx, maxlen, buf, len, negative, base, precision, width, flags); +} + +#if (CONFIG_LIBC_FLOAT || CONFIG_LIBC_FLOAT_EX) + +struct double_components { + int_fast64_t integral; + int_fast64_t fractional; + bool is_negative; +}; + +#define NUM_DECIMAL_DIGITS_IN_INT64_T 18 +#define PRINTF_MAX_PRECOMPUTED_POWER_OF_10 NUM_DECIMAL_DIGITS_IN_INT64_T +static const double powers_of_10[NUM_DECIMAL_DIGITS_IN_INT64_T] = { + 1e00, 1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08, + 1e09, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17 +}; + +#define PRINTF_MAX_SUPPORTED_PRECISION NUM_DECIMAL_DIGITS_IN_INT64_T - 1 + + +// Break up a double number - which is known to be a finite non-negative number - +// into its base-10 parts: integral - before the decimal point, and fractional - after it. +// Taken the precision into account, but does not change it even internally. +static struct double_components get_components(double number, unsigned int precision) +{ + struct double_components number_; + number_.is_negative = get_sign(number); + double abs_number = (number_.is_negative) ? -number : number; + number_.integral = (int_fast64_t)abs_number; + double remainder = (abs_number - number_.integral) * powers_of_10[precision]; + number_.fractional = (int_fast64_t)remainder; + + remainder -= (double) number_.fractional; + + if (remainder > 0.5) { + ++number_.fractional; + // handle rollover, e.g. case 0.99 with precision 1 is 1.0 + if ((double) number_.fractional >= powers_of_10[precision]) { + number_.fractional = 0; + ++number_.integral; + } + } + else if (remainder == 0.5) { + if ((number_.fractional == 0U) || (number_.fractional & 1U)) { + // if halfway, round up if odd OR if last digit is 0 + ++number_.fractional; + } + } + + if (precision == 0U) { + remainder = abs_number - (double) number_.integral; + if ((!(remainder < 0.5) || (remainder > 0.5)) && (number_.integral & 1)) { + // exactly 0.5 and ODD, then round up + // 1.5 -> 2, but 2.5 -> 2 + ++number_.integral; + } + } + return number_; +} + +struct scaling_factor { + double raw_factor; + bool multiply; // if true, need to multiply by raw_factor; otherwise need to divide by it +}; + +double apply_scaling(double num, struct scaling_factor normalization) +{ + return normalization.multiply ? num * normalization.raw_factor : num / normalization.raw_factor; +} + +double unapply_scaling(double normalized, struct scaling_factor normalization) +{ + return normalization.multiply ? normalized / normalization.raw_factor : normalized * normalization.raw_factor; +} + +struct scaling_factor update_normalization(struct scaling_factor sf, double extra_multiplicative_factor) +{ + struct scaling_factor result; + if (sf.multiply) { + result.multiply = true; + result.raw_factor = sf.raw_factor * extra_multiplicative_factor; + } + else { + int factor_exp2 = get_exp2(get_bit_access(sf.raw_factor)); + int extra_factor_exp2 = get_exp2(get_bit_access(extra_multiplicative_factor)); + + // Divide the larger-exponent raw raw_factor by the smaller + if (PRINTF_ABS(factor_exp2) > PRINTF_ABS(extra_factor_exp2)) { + result.multiply = false; + result.raw_factor = sf.raw_factor / extra_multiplicative_factor; + } + else { + result.multiply = true; + result.raw_factor = extra_multiplicative_factor / sf.raw_factor; + } + } + return result; +} + +#if CONFIG_LIBC_FLOAT_EX +static struct double_components get_normalized_components(bool negative, unsigned int precision, double non_normalized, struct scaling_factor normalization) +{ + struct double_components components; + components.is_negative = negative; + components.integral = (int_fast64_t) apply_scaling(non_normalized, normalization); + double remainder = non_normalized - unapply_scaling((double) components.integral, normalization); + double prec_power_of_10 = powers_of_10[precision]; + struct scaling_factor account_for_precision = update_normalization(normalization, prec_power_of_10); + double scaled_remainder = apply_scaling(remainder, account_for_precision); + double rounding_threshold = 0.5; + + if (precision == 0U) { + components.fractional = 0; + components.integral += (scaled_remainder >= rounding_threshold); + if (scaled_remainder == rounding_threshold) { + // banker's rounding: Round towards the even number (making the mean error 0) + components.integral &= ~((int_fast64_t) 0x1); + } + } + else { + components.fractional = (int_fast64_t) scaled_remainder; + scaled_remainder -= components.fractional; + + components.fractional += (scaled_remainder >= rounding_threshold); + if (scaled_remainder == rounding_threshold) { + // banker's rounding: Round towards the even number (making the mean error 0) + components.fractional &= ~((int_fast64_t) 0x1); + } + // handle rollover, e.g. the case of 0.99 with precision 1 becoming (0,100), + // and must then be corrected into (1, 0). + if ((double) components.fractional >= prec_power_of_10) { + components.fractional = 0; + ++components.integral; + } + } + return components; +} +#endif + +static size_t print_broken_up_decimal( + struct double_components number_, out_fct_type out, char *buffer, size_t idx, size_t maxlen, unsigned int precision, + unsigned int width, unsigned int flags, char *buf, size_t len) +{ + if (precision != 0U) { + // do fractional part, as an unsigned number + + unsigned int count = precision; + + if (flags & FLAGS_ADAPT_EXP && !(flags & FLAGS_HASH)) { + // %g/%G mandates we skip the trailing 0 digits... + if (number_.fractional > 0) { + while(true) { + int_fast64_t digit = number_.fractional % 10U; + if (digit != 0) { + break; + } + --count; + number_.fractional /= 10U; + } + + } + // ... and even the decimal point if there are no + // non-zero fractional part digits (see below) + } + + if (number_.fractional > 0 || !(flags & FLAGS_ADAPT_EXP) || (flags & FLAGS_HASH) ) { + while (len < PRINTF_FTOA_BUFFER_SIZE) { + --count; + buf[len++] = (char)('0' + number_.fractional % 10U); + if (!(number_.fractional /= 10U)) { + break; + } + } + // add extra 0s + while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) { + buf[len++] = '0'; + } + if (len < PRINTF_FTOA_BUFFER_SIZE) { + buf[len++] = '.'; + } + } + } + else { + if (flags & FLAGS_HASH) { + if (len < PRINTF_FTOA_BUFFER_SIZE) { + buf[len++] = '.'; + } + } + } + + // Write the integer part of the number (it comes after the fractional + // since the character order is reversed) + while (len < PRINTF_FTOA_BUFFER_SIZE) { + buf[len++] = (char)('0' + (number_.integral % 10)); + if (!(number_.integral /= 10)) { + break; + } + } + + // pad leading zeros + if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) { + if (width && (number_.is_negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { + width--; + } + while ((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + } + + if (len < PRINTF_FTOA_BUFFER_SIZE) { + if (number_.is_negative) { + buf[len++] = '-'; + } + else if (flags & FLAGS_PLUS) { + buf[len++] = '+'; // ignore the space if the '+' exists + } + else if (flags & FLAGS_SPACE) { + buf[len++] = ' '; + } + } + + return out_rev_(out, buffer, idx, maxlen, buf, len, width, flags); +} + + // internal ftoa for fixed decimal floating point +static size_t print_decimal_number(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double number, unsigned int precision, unsigned int width, unsigned int flags, char* buf, size_t len) +{ + struct double_components value_ = get_components(number, precision); + return print_broken_up_decimal(value_, out, buffer, idx, maxlen, precision, width, flags, buf, len); +} + +#if CONFIG_LIBC_FLOAT_EX +// internal ftoa variant for exponential floating-point type, contributed by Martijn Jasperse +static size_t print_exponential_number(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double number, unsigned int precision, unsigned int width, unsigned int flags, char* buf, size_t len) +{ + const bool negative = get_sign(number); + // This number will decrease gradually (by factors of 10) as we "extract" the exponent out of it + double abs_number = negative ? -number : number; + + int exp10; + bool abs_exp10_covered_by_powers_table; + struct scaling_factor normalization; + + + // Determine the decimal exponent + if (abs_number == 0.0) { + // TODO: This is a special-case for 0.0 (and -0.0); but proper handling is required for denormals more generally. + exp10 = 0; // ... and no need to set a normalization factor or check the powers table + } + else { + double_with_bit_access conv = get_bit_access(abs_number); + { + // based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c) + int exp2 = get_exp2(conv); + // drop the exponent, so conv.F comes into the range [1,2) + conv.U = (conv.U & (( (double_uint_t)(1) << DOUBLE_STORED_MANTISSA_BITS) - 1U)) | ((double_uint_t) DOUBLE_BASE_EXPONENT << DOUBLE_STORED_MANTISSA_BITS); + // now approximate log10 from the log2 integer part and an expansion of ln around 1.5 + exp10 = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168); + // now we want to compute 10^exp10 but we want to be sure it won't overflow + exp2 = (int)(exp10 * 3.321928094887362 + 0.5); + const double z = exp10 * 2.302585092994046 - exp2 * 0.6931471805599453; + const double z2 = z * z; + conv.U = ((double_uint_t)(exp2) + DOUBLE_BASE_EXPONENT) << DOUBLE_STORED_MANTISSA_BITS; + // compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex + conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14))))); + // correct for rounding errors + if (abs_number < conv.F) { + exp10--; + conv.F /= 10; + } + } + abs_exp10_covered_by_powers_table = PRINTF_ABS(exp10) < PRINTF_MAX_PRECOMPUTED_POWER_OF_10; + normalization.raw_factor = abs_exp10_covered_by_powers_table ? powers_of_10[PRINTF_ABS(exp10)] : conv.F; + } + + // We now begin accounting for the widths of the two parts of our printed field: + // the decimal part after decimal exponent extraction, and the base-10 exponent part. + // For both of these, the value of 0 has a special meaning, but not the same one: + // a 0 exponent-part width means "don't print the exponent"; a 0 decimal-part width + // means "use as many characters as necessary". + + bool fall_back_to_decimal_only_mode = false; + if (flags & FLAGS_ADAPT_EXP) { + int required_significant_digits = (precision == 0) ? 1 : (int) precision; + // Should we want to fall-back to "%f" mode, and only print the decimal part? + fall_back_to_decimal_only_mode = (exp10 >= -4 && exp10 < required_significant_digits); + // Now, let's adjust the precision + // This also decided how we adjust the precision value - as in "%g" mode, + // "precision" is the number of _significant digits_, and this is when we "translate" + // the precision value to an actual number of decimal digits. + int precision_ = (fall_back_to_decimal_only_mode) ? + (int) precision - 1 - exp10 : + (int) precision - 1; // the presence of the exponent ensures only one significant digit comes before the decimal point + precision = (precision_ > 0 ? (unsigned) precision_ : 0U); + flags |= FLAGS_PRECISION; // make sure print_broken_up_decimal respects our choice above + } + + normalization.multiply = (exp10 < 0 && abs_exp10_covered_by_powers_table); + bool should_skip_normalization = (fall_back_to_decimal_only_mode || exp10 == 0); + struct double_components decimal_part_components = + should_skip_normalization ? + get_components(negative ? -abs_number : abs_number, precision) : + get_normalized_components(negative, precision, abs_number, normalization); + + // Account for roll-over, e.g. rounding from 9.99 to 100.0 - which effects + // the exponent and may require additional tweaking of the parts + if (fall_back_to_decimal_only_mode) { + if ( (flags & FLAGS_ADAPT_EXP) && exp10 >= -1 && decimal_part_components.integral == powers_of_10[exp10 + 1]) { + exp10++; // Not strictly necessary, since exp10 is no longer really used + precision--; + // ... and it should already be the case that decimal_part_components.fractional == 0 + } + // TODO: What about rollover strictly within the fractional part? + } + else { + if (decimal_part_components.integral >= 10) { + exp10++; + decimal_part_components.integral = 1; + decimal_part_components.fractional = 0; + } + } + + // the exp10 format is "E%+03d" and largest possible exp10 value for a 64-bit double + // is "307" (for 2^1023), so we set aside 4-5 characters overall + unsigned int exp10_part_width = fall_back_to_decimal_only_mode ? 0U : (PRINTF_ABS(exp10) < 100) ? 4U : 5U; + + unsigned int decimal_part_width = + ((flags & FLAGS_LEFT) && exp10_part_width) ? + // We're padding on the right, so the width constraint is the exponent part's + // problem, not the decimal part's, so we'll use as many characters as we need: + 0U : + // We're padding on the left; so the width constraint is the decimal part's + // problem. Well, can both the decimal part and the exponent part fit within our overall width? + ((width > exp10_part_width) ? + // Yes, so we limit our decimal part's width. + // (Note this is trivially valid even if we've fallen back to "%f" mode) + width - exp10_part_width : + // No; we just give up on any restriction on the decimal part and use as many + // characters as we need + 0U); + + const size_t start_idx = idx; + idx = print_broken_up_decimal(decimal_part_components, out, buffer, idx, maxlen, precision, decimal_part_width, flags, buf, len); + + if (! fall_back_to_decimal_only_mode) { + out((flags & FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen); + idx = print_integer(out, buffer, idx, maxlen, + ABS_FOR_PRINTING(exp10), + exp10 < 0, 10, 0, exp10_part_width - 1, + FLAGS_ZEROPAD | FLAGS_PLUS); + if (flags & FLAGS_LEFT) { + // We need to right-pad with spaces to meet the width requirement + while (idx - start_idx < width) out(' ', buffer, idx++, maxlen); + } + } + return idx; +} +#endif // CONFIG_LIBC_FLOAT_EX + + +static size_t print_floating_point(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int precision, unsigned int width, unsigned int flags, bool prefer_exponential) +{ + char buf[PRINTF_FTOA_BUFFER_SIZE]; + size_t len = 0U; + + // test for special values + if (value != value) + return out_rev_(out, buffer, idx, maxlen, "nan", 3, width, flags); + if (value < -DBL_MAX) + return out_rev_(out, buffer, idx, maxlen, "fni-", 4, width, flags); + if (value > DBL_MAX) + return out_rev_(out, buffer, idx, maxlen, (flags & FLAGS_PLUS) ? "fni+" : "fni", (flags & FLAGS_PLUS) ? 4U : 3U, width, flags); + + if (!prefer_exponential && ((value > PRINTF_FLOAT_NOTATION_THRESHOLD) || (value < -PRINTF_FLOAT_NOTATION_THRESHOLD))) { + // The required behavior of standard printf is to print _every_ integral-part digit -- which could mean + // printing hundreds of characters, overflowing any fixed internal buffer and necessitating a more complicated + // implementation. +#if CONFIG_LIBC_FLOAT_EX + return print_exponential_number(out, buffer, idx, maxlen, value, precision, width, flags, buf, len); +#else + return 0U; +#endif + } + + // set default precision, if not set explicitly + if (!(flags & FLAGS_PRECISION)) { + precision = PRINTF_DEFAULT_FLOAT_PRECISION; + } + + // limit precision so that our integer holding the fractional part does not overflow + while ((len < PRINTF_FTOA_BUFFER_SIZE) && (precision > PRINTF_MAX_SUPPORTED_PRECISION)) { + buf[len++] = '0'; // This respects the precision in terms of result length only + precision--; + } + + return +#if CONFIG_LIBC_FLOAT_EX + prefer_exponential ? + print_exponential_number(out, buffer, idx, maxlen, value, precision, width, flags, buf, len) : +#endif + print_decimal_number(out, buffer, idx, maxlen, value, precision, width, flags, buf, len); +} + +#endif // (CONFIG_LIBC_FLOAT || CONFIG_LIBC_FLOAT_EX) + +// internal vsnprintf +static int __vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, va_list va) +{ + unsigned int flags, width, precision, n; + size_t idx = 0U; + + if (!buffer) { + // use null output function + out = out_discard; + } + + while (*format) + { + // format specifier? %[flags][width][.precision][length] + if (*format != '%') { + // no + out(*format, buffer, idx++, maxlen); + format++; + continue; + } + else { + // yes, evaluate it + format++; + } + + // evaluate flags + flags = 0U; + do { + switch (*format) { + case '0': flags |= FLAGS_ZEROPAD; format++; n = 1U; break; + case '-': flags |= FLAGS_LEFT; format++; n = 1U; break; + case '+': flags |= FLAGS_PLUS; format++; n = 1U; break; + case ' ': flags |= FLAGS_SPACE; format++; n = 1U; break; + case '#': flags |= FLAGS_HASH; format++; n = 1U; break; + default : n = 0U; break; + } + } while (n); + + // evaluate width field + width = 0U; + if (is_digit_(*format)) { + width = atoi_(&format); + } + else if (*format == '*') { + const int w = va_arg(va, int); + if (w < 0) { + flags |= FLAGS_LEFT; // reverse padding + width = (unsigned int)-w; + } + else { + width = (unsigned int)w; + } + format++; + } + + // evaluate precision field + precision = 0U; + if (*format == '.') { + flags |= FLAGS_PRECISION; + format++; + if (is_digit_(*format)) { + precision = atoi_(&format); + } + else if (*format == '*') { + const int precision_ = (int)va_arg(va, int); + precision = precision_ > 0 ? (unsigned int)precision_ : 0U; + format++; + } + } +#if PRINTF_SUPPORT_LENGTH_FILED + // evaluate length field + switch (*format) { + case 'l' : + flags |= FLAGS_LONG; + format++; + if (*format == 'l') { + flags |= FLAGS_LONG_LONG; + format++; + } + break; + case 'h' : + flags |= FLAGS_SHORT; + format++; + if (*format == 'h') { + flags |= FLAGS_CHAR; + format++; + } + break; + case 't' : + flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; + case 'j' : + flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; + case 'z' : + flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; + default: + break; + } +#endif + // evaluate specifier + switch (*format) { + case 'd' : + case 'i' : + case 'u' : + case 'x' : + case 'X' : + case 'o' : + case 'b' : { + // set the base + numeric_base_t base; + if (*format == 'x' || *format == 'X') { + base = BASE_HEX; + } + else if (*format == 'o') { + base = BASE_OCTAL; + } + else if (*format == 'b') { + base = BASE_BINARY; + } + else { + base = BASE_DECIMAL; + flags &= ~FLAGS_HASH; // no hash for dec format + } + // uppercase + if (*format == 'X') { + flags |= FLAGS_UPPERCASE; + } + + // no plus or space flag for u, x, X, o, b + if ((*format != 'i') && (*format != 'd')) { + flags &= ~(FLAGS_PLUS | FLAGS_SPACE); + } + + // ignore '0' flag when precision is given + if (flags & FLAGS_PRECISION) { + flags &= ~FLAGS_ZEROPAD; + } + + // convert the integer + if ((*format == 'i') || (*format == 'd')) { + // signed + if (flags & FLAGS_LONG_LONG) { +#if CONFIG_LIBC_LONG_LONG + const long long value = va_arg(va, long long); + idx = print_integer(out, buffer, idx, maxlen, ABS_FOR_PRINTING(value), value < 0, base, precision, width, flags); +#endif + } + else if (flags & FLAGS_LONG) { + const long value = va_arg(va, long); + idx = print_integer(out, buffer, idx, maxlen, ABS_FOR_PRINTING(value), value < 0, base, precision, width, flags); + } + else { + const int value = (flags & FLAGS_CHAR) ? (signed char)va_arg(va, int) : (flags & FLAGS_SHORT) ? (short int)va_arg(va, int) : va_arg(va, int); + idx = print_integer(out, buffer, idx, maxlen, ABS_FOR_PRINTING(value), value < 0, base, precision, width, flags); + } + } + else { + // unsigned + if (flags & FLAGS_LONG_LONG) { +#if CONFIG_LIBC_LONG_LONG + idx = print_integer(out, buffer, idx, maxlen, (printf_unsigned_value_t) va_arg(va, unsigned long long), false, base, precision, width, flags); +#endif + } + else if (flags & FLAGS_LONG) { + idx = print_integer(out, buffer, idx, maxlen, (printf_unsigned_value_t) va_arg(va, unsigned long), false, base, precision, width, flags); + } + else { + const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int) : (flags & FLAGS_SHORT) ? (unsigned short int)va_arg(va, unsigned int) : va_arg(va, unsigned int); + idx = print_integer(out, buffer, idx, maxlen, (printf_unsigned_value_t) value, false, base, precision, width, flags); + } + } + format++; + break; + } +#if CONFIG_LIBC_FLOAT + case 'f' : + case 'F' : + if (*format == 'F') flags |= FLAGS_UPPERCASE; + idx = print_floating_point(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags, PRINTF_PREFER_DECIMAL); + format++; + break; +#endif +#if CONFIG_LIBC_FLOAT_EX + case 'e': + case 'E': + case 'g': + case 'G': + if ((*format == 'g')||(*format == 'G')) flags |= FLAGS_ADAPT_EXP; + if ((*format == 'E')||(*format == 'G')) flags |= FLAGS_UPPERCASE; + idx = print_floating_point(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags, PRINTF_PREFER_EXPONENTIAL); + format++; + break; +#endif // CONFIG_LIBC_FLOAT_EX + +#if PRINTF_SUPPORT_CHAR + case 'c' : { + unsigned int l = 1U; + // pre padding + if (!(flags & FLAGS_LEFT)) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + // char output + out((char)va_arg(va, int), buffer, idx++, maxlen); + // post padding + if (flags & FLAGS_LEFT) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + format++; + break; + } +#endif + case 's' : { + const char* p = va_arg(va, char*); + if (p == NULL) { + idx = out_rev_(out, buffer, idx, maxlen, ")llun(", 6, width, flags); + } + else { + unsigned int l = strnlen_s_(p, precision ? precision : (size_t)-1); + // pre padding + if (flags & FLAGS_PRECISION) { + l = (l < precision ? l : precision); + } + if (!(flags & FLAGS_LEFT)) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + // string output + while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) { + out(*(p++), buffer, idx++, maxlen); + } + // post padding + if (flags & FLAGS_LEFT) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + } + format++; + break; + } +#if PRINTF_SUPPORT_ADDR + case 'p' : { + width = sizeof(void*) * 2U + 2; // 2 hex chars per byte + the "0x" prefix + flags |= FLAGS_ZEROPAD | FLAGS_POINTER; + uintptr_t value = (uintptr_t)va_arg(va, void*); + idx = (value == (uintptr_t) NULL) ? + out_rev_(out, buffer, idx, maxlen, ")lin(", 5, width, flags) : + print_integer(out, buffer, idx, maxlen, (printf_unsigned_value_t) value, false, BASE_HEX, precision, width, flags); + format++; + break; + } +#endif + case '%' : + out('%', buffer, idx++, maxlen); + format++; + break; + + default : + out(*format, buffer, idx++, maxlen); + format++; + break; + } + } + + // termination + out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen); + + // return written chars without terminating \0 + return (int)idx; +} + +int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) +{ + return __vsnprintf(out_buffer, buf, size, fmt, args); +} \ No newline at end of file diff --git a/arch/riscv32/bl808/src/components/libc/vsnprintf_nano.c b/arch/riscv32/bl808/src/components/libc/vsnprintf_nano.c new file mode 100644 index 00000000..8b7d9dfd --- /dev/null +++ b/arch/riscv32/bl808/src/components/libc/vsnprintf_nano.c @@ -0,0 +1,521 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2006-03-16 Bernard the first version + * 2006-05-25 Bernard rewrite vsprintf + * 2006-08-10 Bernard add rt_show_version + * 2010-03-17 Bernard remove rt_strlcpy function + * fix gcc compiling issue. + * 2010-04-15 Bernard remove weak definition on ICCM16C compiler + * 2012-07-18 Arda add the alignment display for signed integer + * 2012-11-23 Bernard fix IAR compiler error. + * 2012-12-22 Bernard fix rt_kprintf issue, which found by Grissiom. + * 2013-06-24 Bernard remove rt_kprintf if RT_USING_CONSOLE is not defined. + * 2013-09-24 aozima make sure the device is in STREAM mode when used by rt_kprintf. + * 2015-07-06 Bernard Add rt_assert_handler routine. + * 2021-02-28 Meco Man add RT_KSERVICE_USING_STDLIB + */ + +#include "string.h" +#include "stdint.h" +#include "stdarg.h" + +/* use precision */ +#define RT_PRINTF_PRECISION + +/* private function */ +#define _ISDIGIT(c) ((unsigned)((c) - '0') < 10) + +#ifdef RT_PRINTF_LONGLONG +/** + * This function will duplicate a string. + * + * @param n is the string to be duplicated. + * + * @param base is support divide instructions value. + * + * @return the duplicated string pointer. + */ +static inline int divide(long long *n, int base) +{ + int res; + + /* optimized for processor which does not support divide instructions. */ + if (base == 10) { + res = (int)(((unsigned long long)*n) % 10U); + *n = (long long)(((unsigned long long)*n) / 10U); + } else { + res = (int)(((unsigned long long)*n) % 16U); + *n = (long long)(((unsigned long long)*n) / 16U); + } + + return res; +} +#else +static inline int divide(long *n, int base) +{ + int res; + + /* optimized for processor which does not support divide instructions. */ + if (base == 10) { + res = (int)(((unsigned long)*n) % 10U); + *n = (long)(((unsigned long)*n) / 10U); + } else { + res = (int)(((unsigned long)*n) % 16U); + *n = (long)(((unsigned long)*n) / 16U); + } + + return res; +} +#endif /* RT_PRINTF_LONGLONG */ + +static inline int skip_atoi(const char **s) +{ + register int i = 0; + while (_ISDIGIT(**s)) + i = i * 10 + *((*s)++) - '0'; + + return i; +} + +#define ZEROPAD (1 << 0) /* pad with zero */ +#define SIGN (1 << 1) /* unsigned/signed long */ +#define PLUS (1 << 2) /* show plus */ +#define SPACE (1 << 3) /* space if plus */ +#define LEFT (1 << 4) /* left justified */ +#define SPECIAL (1 << 5) /* 0x */ +#define LARGE (1 << 6) /* use 'ABCDEF' instead of 'abcdef' */ + +#ifdef RT_PRINTF_PRECISION +static char *print_number(char *buf, + char *end, +#ifdef RT_PRINTF_LONGLONG + long long num, +#else + long num, +#endif /* RT_PRINTF_LONGLONG */ + int base, + int s, + int precision, + int type) +#else +static char *print_number(char *buf, + char *end, +#ifdef RT_PRINTF_LONGLONG + long long num, +#else + long num, +#endif /* RT_PRINTF_LONGLONG */ + int base, + int s, + int type) +#endif /* RT_PRINTF_PRECISION */ +{ + char c, sign; +#ifdef RT_PRINTF_LONGLONG + char tmp[32]; +#else + char tmp[16]; +#endif /* RT_PRINTF_LONGLONG */ + int precision_bak = precision; + const char *digits; + static const char small_digits[] = "0123456789abcdef"; + static const char large_digits[] = "0123456789ABCDEF"; + register int i; + register int size; + + size = s; + + digits = (type & LARGE) ? large_digits : small_digits; + if (type & LEFT) + type &= ~ZEROPAD; + + c = (type & ZEROPAD) ? '0' : ' '; + + /* get sign */ + sign = 0; + if (type & SIGN) { + if (num < 0) { + sign = '-'; + num = -num; + } else if (type & PLUS) + sign = '+'; + else if (type & SPACE) + sign = ' '; + } + +#ifdef RT_PRINTF_SPECIAL + if (type & SPECIAL) { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } +#endif /* RT_PRINTF_SPECIAL */ + + i = 0; + if (num == 0) + tmp[i++] = '0'; + else { + while (num != 0) + tmp[i++] = digits[divide(&num, base)]; + } + +#ifdef RT_PRINTF_PRECISION + if (i > precision) + precision = i; + size -= precision; +#else + size -= i; +#endif /* RT_PRINTF_PRECISION */ + + if (!(type & (ZEROPAD | LEFT))) { + if ((sign) && (size > 0)) + size--; + + while (size-- > 0) { + if (buf < end) + *buf = ' '; + ++buf; + } + } + + if (sign) { + if (buf < end) { + *buf = sign; + } + --size; + ++buf; + } + +#ifdef RT_PRINTF_SPECIAL + if (type & SPECIAL) { + if (base == 8) { + if (buf < end) + *buf = '0'; + ++buf; + } else if (base == 16) { + if (buf < end) + *buf = '0'; + ++buf; + if (buf < end) { + *buf = type & LARGE ? 'X' : 'x'; + } + ++buf; + } + } +#endif /* RT_PRINTF_SPECIAL */ + + /* no align to the left */ + if (!(type & LEFT)) { + while (size-- > 0) { + if (buf < end) + *buf = c; + ++buf; + } + } + +#ifdef RT_PRINTF_PRECISION + while (i < precision--) { + if (buf < end) + *buf = '0'; + ++buf; + } +#endif /* RT_PRINTF_PRECISION */ + + /* put number in the temporary buffer */ + while (i-- > 0 && (precision_bak != 0)) { + if (buf < end) + *buf = tmp[i]; + ++buf; + } + + while (size-- > 0) { + if (buf < end) + *buf = ' '; + ++buf; + } + + return buf; +} + +/** + * This function will fill a formatted string to buffer. + * + * @param buf is the buffer to save formatted string. + * + * @param size is the size of buffer. + * + * @param fmt is the format parameters. + * + * @param args is a list of variable parameters. + * + * @return The number of characters actually written to buffer. + */ +int32_t vsnprintf(char *buf, + size_t size, + const char *fmt, + va_list args) +{ +#ifdef RT_PRINTF_LONGLONG + unsigned long long num; +#else + uint32_t num; +#endif /* RT_PRINTF_LONGLONG */ + int i, len; + char *str, *end, c; + const char *s; + + uint8_t base; /* the base of number */ + uint8_t flags; /* flags to print number */ + uint8_t qualifier; /* 'h', 'l', or 'L' for integer fields */ + int32_t field_width; /* width of output field */ + +#ifdef RT_PRINTF_PRECISION + int precision; /* min. # of digits for integers and max for a string */ +#endif /* RT_PRINTF_PRECISION */ + + str = buf; + end = buf + size; + + /* Make sure end is always >= buf */ + if (end < buf) { + end = ((char *)-1); + size = end - buf; + } + + for (; *fmt; ++fmt) { + if (*fmt != '%') { + if (str < end) + *str = *fmt; + ++str; + continue; + } + + /* process flags */ + flags = 0; + + while (1) { + /* skips the first '%' also */ + ++fmt; + if (*fmt == '-') + flags |= LEFT; + else if (*fmt == '+') + flags |= PLUS; + else if (*fmt == ' ') + flags |= SPACE; + else if (*fmt == '#') + flags |= SPECIAL; + else if (*fmt == '0') + flags |= ZEROPAD; + else + break; + } + + /* get field width */ + field_width = -1; + if (_ISDIGIT(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + +#ifdef RT_PRINTF_PRECISION + /* get the precision */ + precision = -1; + if (*fmt == '.') { + ++fmt; + if (_ISDIGIT(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } +#endif /* RT_PRINTF_PRECISION */ + /* get the conversion qualifier */ + qualifier = 0; +#ifdef RT_PRINTF_LONGLONG + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') +#else + if (*fmt == 'h' || *fmt == 'l') +#endif /* RT_PRINTF_LONGLONG */ + { + qualifier = *fmt; + ++fmt; +#ifdef RT_PRINTF_LONGLONG + if (qualifier == 'l' && *fmt == 'l') { + qualifier = 'L'; + ++fmt; + } +#endif /* RT_PRINTF_LONGLONG */ + } + + /* the default base */ + base = 10; + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) { + while (--field_width > 0) { + if (str < end) + *str = ' '; + ++str; + } + } + + /* get character */ + c = (uint8_t)va_arg(args, int); + if (str < end) + *str = c; + ++str; + + /* put width */ + while (--field_width > 0) { + if (str < end) + *str = ' '; + ++str; + } + continue; + + case 's': + s = va_arg(args, char *); + if (!s) + s = "(NULL)"; + + for (len = 0; (len != field_width) && (s[len] != '\0'); len++) + ; +#ifdef RT_PRINTF_PRECISION + if (precision > 0 && len > precision) + len = precision; +#endif /* RT_PRINTF_PRECISION */ + + if (!(flags & LEFT)) { + while (len < field_width--) { + if (str < end) + *str = ' '; + ++str; + } + } + + for (i = 0; i < len; ++i) { + if (str < end) + *str = *s; + ++str; + ++s; + } + + while (len < field_width--) { + if (str < end) + *str = ' '; + ++str; + } + continue; + + case 'p': + if (field_width == -1) { + field_width = sizeof(void *) << 1; + flags |= ZEROPAD; + } +#ifdef RT_PRINTF_PRECISION + str = print_number(str, end, + (long)va_arg(args, void *), + 16, field_width, precision, flags); +#else + str = print_number(str, end, + (long)va_arg(args, void *), + 16, field_width, flags); +#endif /* RT_PRINTF_PRECISION */ + continue; + + case '%': + if (str < end) + *str = '%'; + ++str; + continue; + + /* integer number formats - set up the flags and "break" */ + case 'o': + base = 8; + break; + + case 'X': + flags |= LARGE; + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + break; + + default: + if (str < end) + *str = '%'; + ++str; + + if (*fmt) { + if (str < end) + *str = *fmt; + ++str; + } else { + --fmt; + } + continue; + } + +#ifdef RT_PRINTF_LONGLONG + if (qualifier == 'L') + num = va_arg(args, long long); + else if (qualifier == 'l') +#else + if (qualifier == 'l') +#endif /* RT_PRINTF_LONGLONG */ + { + num = va_arg(args, uint32_t); + if (flags & SIGN) + num = (int32_t)num; + } else if (qualifier == 'h') { + num = (uint16_t)va_arg(args, int32_t); + if (flags & SIGN) + num = (int16_t)num; + } else { + num = va_arg(args, uint32_t); + if (flags & SIGN) + num = (int32_t)num; + } +#ifdef RT_PRINTF_PRECISION + str = print_number(str, end, num, base, field_width, precision, flags); +#else + str = print_number(str, end, num, base, field_width, flags); +#endif /* RT_PRINTF_PRECISION */ + } + + if (size > 0) { + if (str < end) + *str = '\0'; + else { + end[-1] = '\0'; + } + } + + /* the trailing null byte doesn't count towards the total + * ++str; + */ + return str - buf; +} diff --git a/arch/riscv32/bl808/src/components/libc/vsprintf.c b/arch/riscv32/bl808/src/components/libc/vsprintf.c new file mode 100644 index 00000000..ebed3f2d --- /dev/null +++ b/arch/riscv32/bl808/src/components/libc/vsprintf.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include + +/** + * This function will fill a formatted string to buffer. + * + * @param buf is the buffer to save formatted string. + * + * @param format is the format parameters. + * + * @param arg_ptr is a list of variable parameters. + * + * @return The number of characters actually written to buffer. + */ +int vsprintf(char *buf, const char *format, va_list arg_ptr) +{ + return vsnprintf(buf, (size_t) - 1, format, arg_ptr); +} \ No newline at end of file diff --git a/arch/riscv32/bl808/src/components/mm/CMakeLists.txt b/arch/riscv32/bl808/src/components/mm/CMakeLists.txt new file mode 100644 index 00000000..81dc22ec --- /dev/null +++ b/arch/riscv32/bl808/src/components/mm/CMakeLists.txt @@ -0,0 +1,12 @@ +sdk_generate_library() + +sdk_add_include_directories(.) + +sdk_library_add_sources(mem.c) + +# memheap +if (CONFIG_TLSF) + add_subdirectory(tlsf) +else() + add_subdirectory(mmheap) +endif() diff --git a/arch/riscv32/bl808/src/components/mm/mem.c b/arch/riscv32/bl808/src/components/mm/mem.c new file mode 100644 index 00000000..43d4645b --- /dev/null +++ b/arch/riscv32/bl808/src/components/mm/mem.c @@ -0,0 +1,190 @@ +/**************************************************************************** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "mem.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +struct mem_heap_s g_memheap; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: kmem_init + * + * Description: + * Allocate memory from the user heap. + * + * Input Parameters: + * + ****************************************************************************/ + +void kmem_init(void *heapstart, size_t heapsize) +{ + MEM_LOG("Heap: start=%p size=%zu\r\n", heapstart, heapsize); + + bflb_mem_init(KMEM_HEAP, heapstart, heapsize); +} + +/**************************************************************************** + * Name: usr_mem_init + * + * Description: + * Allocate memory from the user heap. + * + * Input Parameters: + * + ****************************************************************************/ + +void umem_init(struct mem_heap_s *heap, void *heapstart, size_t heapsize) +{ + bflb_mem_init(heap, heapstart, heapsize); +} + +/**************************************************************************** + * Name: malloc + * + * Description: + * Allocate memory from the user heap. + * + * Input Parameters: + * size - Size (in bytes) of the memory region to be allocated. + * + * Returned Value: + * The address of the allocated memory (NULL on failure to allocate) + * + ****************************************************************************/ + +void *malloc(size_t size) +{ + return bflb_malloc(KMEM_HEAP, size); +} + +/**************************************************************************** + * Name: realloc + * + * Description: + * Re-allocate memory in the user heap. + * + * Input Parameters: + * oldmem - The old memory allocated + * newsize - Size (in bytes) of the new memory region to be re-allocated. + * + * Returned Value: + * The address of the re-allocated memory (NULL on failure to re-allocate) + * + ****************************************************************************/ + +void *realloc(void *old, size_t newlen) +{ + return bflb_realloc(KMEM_HEAP, old, newlen); +} + +/**************************************************************************** + * Name: calloc + * + * Description: + * Allocate and zero memory from the user heap. + * + * Input Parameters: + * size - Size (in bytes) of the memory region to be allocated. + * + * Returned Value: + * The address of the allocated memory (NULL on failure to allocate) + * + ****************************************************************************/ + +void *calloc(size_t size, size_t len) +{ + return bflb_calloc(KMEM_HEAP, size, len); +} + +/**************************************************************************** + * Name: memalign + * + * Description: + * memalign requests more than enough space from malloc, finds a region + * within that chunk that meets the alignment request and then frees any + * leading or trailing space. + * + * The alignment argument must be a power of two (not checked). 8-byte + * alignment is guaranteed by normal malloc calls. + * + ****************************************************************************/ + +void *memalign(size_t align, size_t size) +{ + return bflb_malloc_align(KMEM_HEAP, align, size); +} + +/**************************************************************************** + * Name: free + * + * Description: + * Returns a chunk of user memory to the list of free nodes, merging with + * adjacent free chunks if possible. + * + ****************************************************************************/ + +void free(void *addr) +{ + bflb_free(KMEM_HEAP, addr); +} + + +#ifdef CONFIG_SHELL +#include + +int cmd_free(int argc, char **argv) +{ + const char *Header = "total free alloc mxblk frnode alnode \r\n"; + struct meminfo info; + char *mem; + + mem = malloc(64); + bflb_mem_usage(KMEM_HEAP, &info); + + sprintf(mem, "%-8d%-8d%-8d%-8d%-8d%-8d\r\n", info.total_size, info.free_size, info.used_size, info.max_free_size, + info.free_node, info.used_node); + + printf(Header); + printf(mem); + + free(mem); + + return 0; +} +SHELL_CMD_EXPORT_ALIAS(cmd_free, free, show memory usage); +#endif diff --git a/arch/riscv32/bl808/src/components/mm/mem.h b/arch/riscv32/bl808/src/components/mm/mem.h new file mode 100644 index 00000000..03f73727 --- /dev/null +++ b/arch/riscv32/bl808/src/components/mm/mem.h @@ -0,0 +1,120 @@ +/**************************************************************************** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __BFLB_MM_MEM_H +#define __BFLB_MM_MEM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define MEM_ASSERT(x) \ + { \ + if (!(x)) { \ + printf("[MEM] !!! assert " #x "\r\n"); \ + while (1) \ + ; \ + } \ + } + +#define MEM_LOG(fmt, ...) //printf("[MEM] "fmt, __VA_ARGS__) + +#define MEM_IS_VALID(heap) ((heap) != NULL && (heap)->mem_impl != NULL) + + +#define KMEM_HEAP &g_memheap + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct mem_heap_impl_s; /* Forward reference */ +struct mem_heap_s { + struct mem_heap_impl_s *mem_impl; +}; + +struct meminfo +{ + int total_size; /* This is the total size of memory allocated + * for use by malloc in bytes. */ + int free_node; /* This is the number of free (not in use) chunks */ + int used_node; /* This is the number of allocated (in use) chunks */ + int max_free_size; /* Size of the largest free (not in use) chunk */ + int used_size; /* This is the total size of memory occupied by + * chunks handed out by malloc. */ + int free_size; /* This is the total size of memory occupied + * by free (not in use) chunks. */ +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + + +EXTERN struct mem_heap_s g_memheap; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +void kmem_init(void *heapstart, size_t heapsize); + +void umem_init(struct mem_heap_s *heap, void *heapstart, size_t heapsize); + +/* private api for mm*/ + +void bflb_mem_init(struct mem_heap_s *heap, void *heapstart, size_t heapsize); + +void *bflb_malloc(struct mem_heap_s *heap, size_t nbytes); + +void bflb_free(struct mem_heap_s *heap, void *ptr); + +void *bflb_realloc(struct mem_heap_s *heap, void *ptr, size_t nbytes); + +void *bflb_calloc(struct mem_heap_s *heap, size_t count, size_t size); + +void *bflb_malloc_align(struct mem_heap_s *heap, size_t align, size_t size); + +void bflb_mem_usage(struct mem_heap_s *heap, struct meminfo *info); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __BFLB_MM_MEM_H */ + diff --git a/arch/riscv32/bl808/src/components/mm/mmheap/CMakeLists.txt b/arch/riscv32/bl808/src/components/mm/mmheap/CMakeLists.txt new file mode 100644 index 00000000..b05030cf --- /dev/null +++ b/arch/riscv32/bl808/src/components/mm/mmheap/CMakeLists.txt @@ -0,0 +1,9 @@ +sdk_library_add_sources(mmheap.c) +sdk_library_add_sources(bflb_mmheap.c) + +sdk_add_include_directories(.) + +# memheap lock user config +if(CONFIG_MMHEAP_USER) + sdk_add_compile_definitions(-DCONFIG_MMHEAP_USER) +endif() diff --git a/arch/riscv32/bl808/src/components/mm/mmheap/bflb_mmheap.c b/arch/riscv32/bl808/src/components/mm/mmheap/bflb_mmheap.c new file mode 100644 index 00000000..8d29bc79 --- /dev/null +++ b/arch/riscv32/bl808/src/components/mm/mmheap/bflb_mmheap.c @@ -0,0 +1,415 @@ +/**************************************************************************** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "mem.h" +#include "mmheap.h" + +#ifdef CONFIG_FREERTOS +#include "FreeRTOS.h" +#include "semphr.h" +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_FREERTOS + +#define _IRQ_CONTEXT() xPortIsInsideInterrupt() +#define _SCHED_LOCK() (taskSCHEDULER_RUNNING != xTaskGetSchedulerState()) +#define _ENTER_CRITICAL() portENTER_CRITICAL() +#define _EXIT_CRITICAL() portEXIT_CRITICAL() +#define _SEM_INIT(s, p, c) xSemaphoreCreateRecursiveMutexStatic(s) +#define _SEM_WAIT(s) xSemaphoreTakeRecursive((SemaphoreHandle_t)s, portMAX_DELAY) +#define _SEM_POST(s) xSemaphoreGiveRecursive((SemaphoreHandle_t)s) + +#else + +#include "bflb_irq.h" +static volatile uintptr_t s_irq_flag; +static volatile uintptr_t s_irq_entry; + +#define _IRQ_CONTEXT() (0) +#define _ENTER_CRITICAL() \ + { \ + s_irq_flag = bflb_irq_save(); \ + s_irq_entry += 1; \ + } + +#define _EXIT_CRITICAL() \ + { \ + if (s_irq_entry > 0) { \ + s_irq_entry -= 1; \ + if (s_irq_entry == 0) { \ + bflb_irq_restore(s_irq_flag); \ + } \ + } \ + } + +#endif + +#ifdef CONFIG_FREERTOS +#define CONFIG_MEM_USE_OS +#endif + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Adapted to the lock provided by the operating system */ +#ifdef CONFIG_FREERTOS +typedef StaticSemaphore_t sem_t; +typedef TaskHandle_t task_t; +#else + +#endif /* CONFIG_FREERTOS */ + +struct mem_delaynode_s +{ + struct mem_delaynode_s *flink; +}; + +/* Private memory management structure */ +struct mem_heap_impl_s { + struct heap_info info; +#ifdef CONFIG_MEM_USE_OS + sem_t sem; + + /* Free delay list, for some situation can't do free immdiately */ + + struct mem_delaynode_s *mem_delaylist; +#endif +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: bflb_mem_sem_init + * + * Description: + * Initialize the MM mutex + * + ****************************************************************************/ + +static void bflb_mem_sem_init(struct mem_heap_impl_s *impl) +{ +#ifdef CONFIG_MEM_USE_OS + /* Initialize the MM semaphore to one (to support one-at-a-time access to + * private data sets). + */ + + _SEM_INIT(&impl->sem, 0, 1); +#endif /* CONFIG_MEM_USE_OS */ +} + +/**************************************************************************** + * Name: bflb_mem_sem_take + * + * Description: + * Take the MM mutex. This is the normal action before all memory + * management actions. + * + ****************************************************************************/ + +static void bflb_mem_sem_take(struct mem_heap_impl_s *impl) +{ +#ifdef CONFIG_MEM_USE_OS + if (!_SCHED_LOCK()) { + _SEM_WAIT(&impl->sem); + } else { + _ENTER_CRITICAL(); + } +#else + + _ENTER_CRITICAL(); + +#endif /* CONFIG_MEM_USE_OS */ +} + +/**************************************************************************** + * Name: bflb_mem_sem_give + * + * Description: + * Release the MM mutex when it is not longer needed. + * + ****************************************************************************/ + +static void bflb_mem_sem_give(struct mem_heap_impl_s *impl) +{ +#ifdef CONFIG_MEM_USE_OS + if (!_SCHED_LOCK()) { + _SEM_POST(&impl->sem); + } else { + _EXIT_CRITICAL(); + } +#else + + _EXIT_CRITICAL(); + +#endif /* CONFIG_MEM_USE_OS */ +} + +/**************************************************************************** + * Name: bflb_mem_add_delaylist + ****************************************************************************/ + +static void bflb_mem_add_delaylist(struct mem_heap_s *heap, void *mem) +{ +#ifdef CONFIG_MEM_USE_OS + struct mem_heap_impl_s *impl; + struct mem_delaynode_s *tmp = mem; + + MEM_ASSERT(MEM_IS_VALID(heap)); + impl = heap->mem_impl; + + /* Delay the deallocation until a more appropriate time. */ + + _ENTER_CRITICAL(); + + tmp->flink = impl->mem_delaylist; + impl->mem_delaylist = tmp; + + _EXIT_CRITICAL(); +#endif /* CONFIG_MEM_USE_OS */ +} + +/**************************************************************************** + * Name: bflb_mem_free_delaylist + ****************************************************************************/ + +static void bflb_mem_free_delaylist(struct mem_heap_s *heap) +{ +#ifdef CONFIG_MEM_USE_OS + struct mem_heap_impl_s *impl; + struct mem_delaynode_s *tmp; + + MEM_ASSERT(MEM_IS_VALID(heap)); + impl = heap->mem_impl; + + /* Move the delay list to local */ + + _ENTER_CRITICAL(); + + tmp = impl->mem_delaylist; + impl->mem_delaylist = NULL; + + _EXIT_CRITICAL(); + + /* Test if the delayed is empty */ + + while (tmp) { + void *address; + + /* Get the first delayed deallocation */ + + address = tmp; + tmp = tmp->flink; + + /* The address should always be non-NULL since that was checked in the + * 'while' condition above. + */ + + bflb_free(heap, address); + } +#endif /* CONFIG_MEM_USE_OS */ +} + +/**************************************************************************** + * Functions + ****************************************************************************/ + +void bflb_mem_init(struct mem_heap_s *heap, void *heapstart, size_t heapsize) +{ + struct mem_heap_impl_s *impl; + struct heap_region region[] = { + { NULL, 0 }, + { NULL, 0 } + }; + + /* Reserve a block space for mm_heap_impl_s context */ + + MEM_ASSERT(heapsize > sizeof(struct mem_heap_impl_s)); + + heap->mem_impl = (struct mem_heap_impl_s *)heapstart; + + heapstart += sizeof(struct mem_heap_impl_s); + heapsize -= sizeof(struct mem_heap_impl_s); + + region[0].addr = heapstart; + region[0].mem_size = heapsize; + + /* Zero implmeentation context */ + + impl = heap->mem_impl; + memset(impl, 0, sizeof(struct mem_heap_impl_s)); + + bflb_mem_sem_init(impl); + + bflb_mmheap_init(&impl->info, region); +} + +void *bflb_malloc(struct mem_heap_s *heap, size_t nbytes) +{ + struct mem_heap_impl_s *impl; + void *ret = NULL; + + MEM_ASSERT(MEM_IS_VALID(heap)); + + MEM_LOG("malloc %d\r\n", nbytes); + + impl = heap->mem_impl; + + /* Firstly, free mm_delaylist */ + + bflb_mem_free_delaylist(heap); + + /* Allocate from the tlsf pool */ + + bflb_mem_sem_take(impl); + ret = bflb_mmheap_alloc(&impl->info, nbytes); + bflb_mem_sem_give(impl); + + return ret; +} + +void bflb_free(struct mem_heap_s *heap, void *ptr) +{ + struct mem_heap_impl_s *impl; + + MEM_LOG("Freeing %p\r\n", ptr); + + /* Protect against attempts to free a NULL reference */ + + if (!ptr) { + return; + } + + MEM_ASSERT(MEM_IS_VALID(heap)); + impl = heap->mem_impl; + + if (_IRQ_CONTEXT()) { + + /* We are in ISR, add to mm_delaylist */ + + bflb_mem_add_delaylist(heap, ptr); + return; + } + + /* We need to hold the MM semaphore while we muck with the + * nodelist. + */ + + bflb_mem_sem_take(impl); + + /* Return to the tlsf pool */ + + bflb_mmheap_free(&heap->mem_impl->info, ptr); + + bflb_mem_sem_give(impl); +} + +void *bflb_realloc(struct mem_heap_s *heap, void *ptr, size_t nbytes) +{ + struct mem_heap_impl_s *impl; + void *ret; + + MEM_ASSERT(MEM_IS_VALID(heap)); + impl = heap->mem_impl; + + /* Firstly, free mm_delaylist */ + + bflb_mem_free_delaylist(heap); + + /* Allocate from the tlsf pool */ + + bflb_mem_sem_take(impl); + ret = bflb_mmheap_realloc(&impl->info, ptr, nbytes); + bflb_mem_sem_give(impl); + + return ret; +} + +void *bflb_calloc(struct mem_heap_s *heap, size_t count, size_t nbytes) +{ + struct mem_heap_impl_s *impl; + void *ret; + + MEM_ASSERT(MEM_IS_VALID(heap)); + impl = heap->mem_impl; + + /* Firstly, free mm_delaylist */ + + bflb_mem_free_delaylist(heap); + + /* Allocate from the tlsf pool */ + + bflb_mem_sem_take(impl); + ret = bflb_mmheap_calloc(&impl->info, count, nbytes); + bflb_mem_sem_give(impl); + + return ret; +} + +void *bflb_malloc_align(struct mem_heap_s *heap, size_t align, size_t size) +{ + struct mem_heap_impl_s *impl; + void *ret; + + MEM_ASSERT(MEM_IS_VALID(heap)); + impl = heap->mem_impl; + + /* Firstly, free mm_delaylist */ + + bflb_mem_free_delaylist(heap); + + /* Allocate from the tlsf pool */ + + bflb_mem_sem_take(impl); + ret = bflb_mmheap_align_alloc(&impl->info, align, size); + bflb_mem_sem_give(impl); + + return ret; +} + +void bflb_mem_usage(struct mem_heap_s *heap, struct meminfo *info) +{ + struct mem_heap_impl_s *impl; + struct heap_state state; + + MEM_ASSERT(MEM_IS_VALID(heap)); + impl = heap->mem_impl; + + bflb_mmheap_get_state(&impl->info, &state); + + info->total_size = impl->info.total_size; + info->free_node = state.free_node_num; + info->max_free_size = state.max_node_size; + info->free_size = state.remain_size; + info->used_size = info->total_size - info->free_size; +} diff --git a/arch/riscv32/bl808/src/components/mm/mmheap/mmheap.c b/arch/riscv32/bl808/src/components/mm/mmheap/mmheap.c new file mode 100644 index 00000000..c7b46142 --- /dev/null +++ b/arch/riscv32/bl808/src/components/mm/mmheap/mmheap.c @@ -0,0 +1,422 @@ +/** + * @file bflb_mmheap.c + * @brief + * + * Copyright (c) 2021 Bouffalolab team + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + */ + +#include "mmheap.h" + +#define MEM_MANAGE_ALIGNMENT_BYTE_DEFAULT 8 +#define MEM_MANAGE_BITS_PER_BYTE 8 +#define MEM_MANAGE_MEM_STRUCT_SIZE mmheap_align_up(sizeof(struct heap_node), MEM_MANAGE_ALIGNMENT_BYTE_DEFAULT) +#define MEM_MANAGE_MINUM_MEM_SIZE (MEM_MANAGE_MEM_STRUCT_SIZE << 1) +#define MEM_MANAGE_ALLOCA_LABAL ((size_t)((size_t)1 << (sizeof(size_t) * MEM_MANAGE_BITS_PER_BYTE - 1))) + + +static inline size_t mmheap_align_down(size_t data, size_t align_byte) +{ + return data & ~(align_byte - 1); +} + +static inline size_t mmheap_align_up(size_t data, size_t align_byte) +{ + return (data + align_byte - 1) & ~(align_byte - 1); +} + +static inline struct heap_node *mmheap_addr_sub(const void *addr) +{ + return (struct heap_node *)((const uint8_t *)addr - MEM_MANAGE_MEM_STRUCT_SIZE); +} + +static inline void *mmheap_addr_add(const struct heap_node *mem_node) +{ + return (void *)((const uint8_t *)mem_node + MEM_MANAGE_MEM_STRUCT_SIZE); +} + +/** + * @brief mmheap_insert_node_to_freelist + * + * @param pRoot + * @param pNode + */ +static inline void mmheap_insert_node_to_freelist(struct heap_info *pRoot, struct heap_node *pNode) +{ + struct heap_node *pPriv_Node; + struct heap_node *pNext_Node; + /*Find the node with an address similar to pNode*/ + for (pPriv_Node = pRoot->pStart; pPriv_Node->next_node < pNode; pPriv_Node = pPriv_Node->next_node) { + } + + pNext_Node = pPriv_Node->next_node; + /*Try to merge the pNode with the previous block*/ + if ((uint8_t *)mmheap_addr_add(pPriv_Node) + pPriv_Node->mem_size == (uint8_t *)pNode) { + if (pPriv_Node != pRoot->pStart) { /*can merge if not start block*/ + pPriv_Node->mem_size += MEM_MANAGE_MEM_STRUCT_SIZE + pNode->mem_size; + pNode = pPriv_Node; + } else { + /*The latter is not merged if it is a Start block to avoid wasting memory*/ + pRoot->pStart->next_node = pNode; + } + } else { + /*Insert directly into the free single-chain table when merging is not possible*/ + pPriv_Node->next_node = pNode; + } + /*Try to merge the pNode with the next block*/ + if ((uint8_t *)mmheap_addr_add(pNode) + pNode->mem_size == (uint8_t *)pNext_Node) { + if (pNext_Node != pRoot->pEnd) { + pNode->mem_size += MEM_MANAGE_MEM_STRUCT_SIZE + pNext_Node->mem_size; + pNode->next_node = pNext_Node->next_node; + } else { + pNode->next_node = pRoot->pEnd; + } + } else { + /*Insert directly into the free single-chain table when merging is not possible*/ + pNode->next_node = pNext_Node; + } +} + +/** + * @brief mmheap_get_state + * + * @param pRoot + * @param pState + */ +void bflb_mmheap_get_state(struct heap_info *pRoot, struct heap_state *pState) +{ + MMHEAP_ASSERT(pRoot->pStart != NULL); + MMHEAP_ASSERT(pRoot->pEnd != NULL); + pState->max_node_size = pRoot->pStart->next_node->mem_size; + pState->min_node_size = pRoot->pStart->next_node->mem_size; + pState->remain_size = 0; + pState->free_node_num = 0; + MMHEAP_LOCK(); + for (struct heap_node *pNode = pRoot->pStart->next_node; pNode->next_node != NULL; pNode = pNode->next_node) { + pState->remain_size += pNode->mem_size; + pState->free_node_num++; + if (pNode->mem_size > pState->max_node_size) + pState->max_node_size = pNode->mem_size; + if (pNode->mem_size < pState->min_node_size) + pState->min_node_size = pNode->mem_size; + } + MMHEAP_UNLOCK(); +} +/** + * @brief bflb_mmheap_align_alloc + * + * @param pRoot + * @param align_size + * @param want_size + * @return void* + */ +void *bflb_mmheap_align_alloc(struct heap_info *pRoot, size_t align_size, size_t want_size) +{ + void *pReturn = NULL; + struct heap_node *pPriv_Node, *pNow_Node; + + MMHEAP_ASSERT(pRoot->pStart != NULL); + MMHEAP_ASSERT(pRoot->pEnd != NULL); + + if (want_size == 0) { + return NULL; + } + + if ((want_size & MEM_MANAGE_ALLOCA_LABAL) != 0) { + MMHEAP_MALLOC_FAIL(); + return NULL; + } + + if (align_size & (align_size - 1)) { + MMHEAP_MALLOC_FAIL(); + return NULL; + } + + MMHEAP_LOCK(); + if (want_size < MEM_MANAGE_MINUM_MEM_SIZE) + want_size = MEM_MANAGE_MINUM_MEM_SIZE; + if (align_size < MEM_MANAGE_ALIGNMENT_BYTE_DEFAULT) + align_size = MEM_MANAGE_ALIGNMENT_BYTE_DEFAULT; + + want_size = mmheap_align_up(want_size, MEM_MANAGE_ALIGNMENT_BYTE_DEFAULT); + + pPriv_Node = pRoot->pStart; + pNow_Node = pRoot->pStart->next_node; + + while (pNow_Node->next_node != NULL) { + if (pNow_Node->mem_size >= want_size + MEM_MANAGE_MEM_STRUCT_SIZE) { + size_t use_align_size; + size_t new_size; + pReturn = (void *)mmheap_align_up((size_t)mmheap_addr_add(pNow_Node), align_size); /*Calculate the aligned address*/ + use_align_size = (uint8_t *)pReturn - (uint8_t *)mmheap_addr_add(pNow_Node); /*Calculate the memory consumed by the alignment*/ + if (use_align_size != 0) { /*if Memory misalignment*/ + if (use_align_size < MEM_MANAGE_MINUM_MEM_SIZE + MEM_MANAGE_MEM_STRUCT_SIZE) { /*The unaligned value is too small*/ + pReturn = (void *)mmheap_align_up( + (size_t)mmheap_addr_add(pNow_Node) + MEM_MANAGE_MINUM_MEM_SIZE + MEM_MANAGE_MEM_STRUCT_SIZE, align_size); + use_align_size = (uint8_t *)pReturn - (uint8_t *)mmheap_addr_add(pNow_Node); + } + if (use_align_size <= pNow_Node->mem_size) { + new_size = pNow_Node->mem_size - use_align_size; /*Calculate the remaining memory size by removing the memory consumed by alignment*/ + if (new_size >= want_size) { /*Meet the conditions for distribution*/ + struct heap_node *pNew_Node = mmheap_addr_sub(pReturn); + pNow_Node->mem_size -= new_size + MEM_MANAGE_MEM_STRUCT_SIZE; /*Split Node*/ + pNew_Node->mem_size = new_size; /*The new node is also not in the free chain and does not need to be discharged from the free chain*/ + pNew_Node->next_node = NULL; + pNow_Node = pNew_Node; + break; + } + } + } else { /*Memory is directly aligned*/ + pPriv_Node->next_node = pNow_Node->next_node; + pNow_Node->next_node = NULL; + break; + } + } + pPriv_Node = pNow_Node; + pNow_Node = pNow_Node->next_node; + } + + if (pNow_Node == pRoot->pEnd) { + MMHEAP_UNLOCK(); + MMHEAP_MALLOC_FAIL(); + return NULL; + } + + if (pNow_Node->mem_size >= MEM_MANAGE_MINUM_MEM_SIZE + MEM_MANAGE_MEM_STRUCT_SIZE + want_size) { /*Node memory is still available*/ + struct heap_node *pNew_Node = (struct heap_node *)((uint8_t *)mmheap_addr_add(pNow_Node) + want_size); /*Calculate the address of the node that will be moved into the free chain table*/ + pNew_Node->mem_size = pNow_Node->mem_size - want_size - MEM_MANAGE_MEM_STRUCT_SIZE; + pNew_Node->next_node = NULL; + pNow_Node->mem_size = want_size; + mmheap_insert_node_to_freelist(pRoot, pNew_Node); + } + pNow_Node->mem_size |= MEM_MANAGE_ALLOCA_LABAL; + MMHEAP_UNLOCK(); + return pReturn; +} +/** + * @brief bflb_mmheap_alloc + * + * @param pRoot + * @param want_size + * @return void* + */ +void *bflb_mmheap_alloc(struct heap_info *pRoot, size_t want_size) +{ + return bflb_mmheap_align_alloc(pRoot, MEM_MANAGE_ALIGNMENT_BYTE_DEFAULT, want_size); +} +/** + * @brief bflb_mmheap_realloc + * + * @param pRoot + * @param src_addr + * @param want_size + * @return void* + */ +void *bflb_mmheap_realloc(struct heap_info *pRoot, void *src_addr, size_t want_size) +{ + void *pReturn = NULL; + struct heap_node *pNext_Node, *pPriv_Node; + struct heap_node *pSrc_Node; + MMHEAP_ASSERT(pRoot->pStart != NULL); + MMHEAP_ASSERT(pRoot->pEnd != NULL); + if (src_addr == NULL) { + return bflb_mmheap_align_alloc(pRoot, MEM_MANAGE_ALIGNMENT_BYTE_DEFAULT, want_size); + } + if (want_size == 0) { + bflb_mmheap_free(pRoot, src_addr); + return NULL; + } + + MMHEAP_LOCK(); + if ((want_size & MEM_MANAGE_ALLOCA_LABAL) != 0) { + MMHEAP_UNLOCK(); + MMHEAP_MALLOC_FAIL(); + return NULL; + } + + pSrc_Node = mmheap_addr_sub(src_addr); + + if ((pSrc_Node->mem_size & MEM_MANAGE_ALLOCA_LABAL) == 0) { + MMHEAP_UNLOCK(); + MMHEAP_ASSERT((pSrc_Node->mem_size & MEM_MANAGE_ALLOCA_LABAL) != 0); + MMHEAP_MALLOC_FAIL(); + return NULL; + } + + pSrc_Node->mem_size &= ~MEM_MANAGE_ALLOCA_LABAL; + if (pSrc_Node->mem_size >= want_size) { + pSrc_Node->mem_size |= MEM_MANAGE_ALLOCA_LABAL; + pReturn = src_addr; + MMHEAP_UNLOCK(); + return pReturn; + } + /*Start looking in the free list for blocks similar to this block*/ + for (pPriv_Node = pRoot->pStart; pPriv_Node->next_node < pSrc_Node; pPriv_Node = pPriv_Node->next_node) { + } + pNext_Node = pPriv_Node->next_node; + + if (pNext_Node != pRoot->pEnd && + ((uint8_t *)src_addr + pSrc_Node->mem_size == (uint8_t *)pNext_Node) && + (pSrc_Node->mem_size + pNext_Node->mem_size + MEM_MANAGE_MEM_STRUCT_SIZE >= want_size)) { + /*Meet next node non-end, memory contiguous, enough memory left*/ + pReturn = src_addr; + pPriv_Node->next_node = pNext_Node->next_node; + pSrc_Node->mem_size += MEM_MANAGE_MEM_STRUCT_SIZE + pNext_Node->mem_size; + want_size = mmheap_align_up(want_size, MEM_MANAGE_ALIGNMENT_BYTE_DEFAULT); + if (pSrc_Node->mem_size >= MEM_MANAGE_MINUM_MEM_SIZE + MEM_MANAGE_MEM_STRUCT_SIZE + want_size) { /*Removing the remaining space allocated is enough to open new blocks*/ + struct heap_node *pNew_Node = (struct heap_node *)((uint8_t *)mmheap_addr_add(pSrc_Node) + want_size); + pNew_Node->next_node = NULL; + pNew_Node->mem_size = pSrc_Node->mem_size - want_size - MEM_MANAGE_MEM_STRUCT_SIZE; + pSrc_Node->mem_size = want_size; + mmheap_insert_node_to_freelist(pRoot, pNew_Node); + } + pSrc_Node->mem_size |= MEM_MANAGE_ALLOCA_LABAL; + MMHEAP_UNLOCK(); + } else { + MMHEAP_UNLOCK(); + pReturn = bflb_mmheap_align_alloc(pRoot, MEM_MANAGE_ALIGNMENT_BYTE_DEFAULT, want_size); + if (pReturn == NULL) { + pSrc_Node->mem_size |= MEM_MANAGE_ALLOCA_LABAL; + MMHEAP_MALLOC_FAIL(); + return NULL; + } + MMHEAP_LOCK(); + memcpy(pReturn, src_addr, pSrc_Node->mem_size); + pSrc_Node->mem_size |= MEM_MANAGE_ALLOCA_LABAL; + MMHEAP_UNLOCK(); + bflb_mmheap_free(pRoot, src_addr); + } + return pReturn; +} +/** + * @brief + * + * @param pRoot + * @param num + * @param size + * @return void* + */ +void *bflb_mmheap_calloc(struct heap_info *pRoot, size_t num, size_t size) +{ + void *pReturn = NULL; + + pReturn = (void *)bflb_mmheap_alloc(pRoot, size * num); + + if (pReturn) { + memset(pReturn, 0, num * size); + } + + return pReturn; +} +/** + * @brief bflb_mmheap_free + * + * @param pRoot + * @param addr + */ +void bflb_mmheap_free(struct heap_info *pRoot, void *addr) +{ + struct heap_node *pFree_Node; + MMHEAP_ASSERT(pRoot->pStart != NULL); + MMHEAP_ASSERT(pRoot->pEnd != NULL); + MMHEAP_LOCK(); + if (addr == NULL) { + MMHEAP_UNLOCK(); + return; + } + pFree_Node = mmheap_addr_sub(addr); + + if ((pFree_Node->mem_size & MEM_MANAGE_ALLOCA_LABAL) == 0) { + MMHEAP_UNLOCK(); + MMHEAP_ASSERT((pFree_Node->mem_size & MEM_MANAGE_ALLOCA_LABAL) != 0); + return; + } + + if (pFree_Node->next_node != NULL) { + MMHEAP_UNLOCK(); + MMHEAP_ASSERT(pFree_Node->next_node == NULL); + return; + } + pFree_Node->mem_size &= ~MEM_MANAGE_ALLOCA_LABAL; + mmheap_insert_node_to_freelist(pRoot, pFree_Node); + MMHEAP_UNLOCK(); +} +/** + * @brief bflb_mmheap_init + * + * @param pRoot + * @param pRegion + */ +void bflb_mmheap_init(struct heap_info *pRoot, const struct heap_region *pRegion) +{ + struct heap_node *align_addr; + size_t align_size; + struct heap_node *pPriv_node = NULL; + + pRoot->total_size = 0; + pRoot->pEnd = NULL; + pRoot->pStart = NULL; + + for (; pRegion->addr != NULL; pRegion++) { + align_addr = (struct heap_node *)mmheap_align_up((size_t)pRegion->addr, MEM_MANAGE_ALIGNMENT_BYTE_DEFAULT); /*Calculate the aligned address*/ + if ((uint8_t *)align_addr > pRegion->mem_size + (uint8_t *)pRegion->addr) /*Alignment consumes more memory than the memory area*/ + continue; + align_size = pRegion->mem_size - ((uint8_t *)align_addr - (uint8_t *)pRegion->addr); /*Calculate the size of memory left after alignment*/ + if (align_size < MEM_MANAGE_MINUM_MEM_SIZE + MEM_MANAGE_MEM_STRUCT_SIZE) /*if Aligning the remaining memory is too small*/ + continue; + align_size -= MEM_MANAGE_MEM_STRUCT_SIZE; /*Find the size of the memory block after removing the table header*/ + align_addr->mem_size = align_size; + align_addr->next_node = NULL; + if (pRoot->pStart == NULL) { + pRoot->pStart = align_addr; /*set current addr for start*/ + if (align_size >= MEM_MANAGE_MINUM_MEM_SIZE + MEM_MANAGE_MEM_STRUCT_SIZE) { /*If the remaining blocks are large enough*/ + align_size -= MEM_MANAGE_MEM_STRUCT_SIZE; /*Remove the next block of table headers remaining memory size*/ + align_addr = (struct heap_node *)((uint8_t *)pRoot->pStart + MEM_MANAGE_MEM_STRUCT_SIZE); //the next block addr + align_addr->mem_size = align_size; + align_addr->next_node = NULL; + pRoot->pStart->mem_size = 0; + pRoot->pStart->next_node = align_addr; + pRoot->total_size = align_addr->mem_size; + } else { /*The memory is too small, and the address of the current memory block is recorded as start*/ + pRoot->total_size = 0; + pRoot->pStart->mem_size = 0; + } + } else { + pPriv_node->next_node = align_addr; + pRoot->total_size += align_size; + } + pPriv_node = align_addr; + } + //At this point, pPriv_node is the last block, then place the end of the table at the end of the block, find the address to place the end block, end block is only convenient for traversal, so as small as possible, assigned to MEM_MANAGE_MEM_STRUCT_SIZE + align_addr = (struct heap_node *)mmheap_align_down( + (size_t)mmheap_addr_add(pPriv_node) + pPriv_node->mem_size - MEM_MANAGE_MEM_STRUCT_SIZE, MEM_MANAGE_ALIGNMENT_BYTE_DEFAULT); + align_size = (uint8_t *)align_addr - (uint8_t *)mmheap_addr_add(pPriv_node); /*Find the remaining size of the previous block after the end block is allocated*/ + if (align_size >= MEM_MANAGE_MINUM_MEM_SIZE) { + pRoot->total_size -= pPriv_node->mem_size - align_size; /*Removing memory consumed by allocating end blocks*/ + pRoot->pEnd = align_addr; /*Update the address at the end of the list*/ + pPriv_node->next_node = align_addr; + pPriv_node->mem_size = align_size; + align_addr->next_node = NULL; + align_addr->mem_size = 0; /*The end block is not involved in memory allocation, so a direct 0 is sufficient*/ + } else { /*The last block is too small, directly as the end block*/ + pRoot->pEnd = pPriv_node; + pRoot->total_size -= pPriv_node->mem_size; + } + MMHEAP_ASSERT(pRoot->pStart != NULL); + MMHEAP_ASSERT(pRoot->pEnd != NULL); +} diff --git a/arch/riscv32/bl808/src/components/mm/mmheap/mmheap.h b/arch/riscv32/bl808/src/components/mm/mmheap/mmheap.h new file mode 100644 index 00000000..3585a27c --- /dev/null +++ b/arch/riscv32/bl808/src/components/mm/mmheap/mmheap.h @@ -0,0 +1,163 @@ +/** + * @file bflb_mmheap.h + * @brief + * + * Copyright (c) 2021 Bouffalolab team + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + */ +#ifndef __MM_MMHEAP_H +#define __MM_MMHEAP_H + +#include +#include +#include + +#ifdef CONFIG_MMHEAP_USER +#include "mmheap_user.h" +#endif + +#ifndef MMHEAP_LOCK +#define MMHEAP_LOCK() +#endif + +#ifndef MMHEAP_UNLOCK +#define MMHEAP_UNLOCK() +#endif + +#ifndef MMHEAP_ASSERT +#define MMHEAP_ASSERT(A) \ + if (!(A)) \ + printf("mmheap malloc error:drv_mmheap,%d\r\n", __LINE__) + +#endif + +#ifndef MMHEAP_MALLOC_FAIL +#define MMHEAP_MALLOC_FAIL() printf("mmheap malloc fail:drv_mmheap,%d\r\n", __LINE__) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +struct heap_region { + void *addr; + size_t mem_size; +}; + +struct heap_node { + struct heap_node *next_node; + size_t mem_size; +}; + +struct heap_info { + struct heap_node *pStart; + struct heap_node *pEnd; + size_t total_size; +}; + +struct heap_state { + size_t remain_size; + size_t free_node_num; + size_t max_node_size; + size_t min_node_size; +}; + +void bflb_mmheap_init(struct heap_info *pRoot, const struct heap_region *pRigon); +/** + * @brief Alloc start address aligned memory from the heap. + * Alloc aligned address and specified size memory from the heap. + * + * @attention + * + * @param[in] pRoot heap info. + * @param[in] align_size address align mask of the memory. + * @param[in] want_size size of the memory. + * + * @return the pointer to the allocated memory. + */ +void *bflb_mmheap_align_alloc(struct heap_info *pRoot, size_t align_size, size_t want_size); +/** + * @brief Alloc memory. + * Allocate size bytes and returns a pointer to the allocated memory. + * + * @attention size should no bigger than MMHEAP_BLK_SIZE_MAX. + * + * @param[in] pRoot heap info. + * @param[in] want_size size of the memory. + * + * @return the pointer to the allocated memory. + */ +void *bflb_mmheap_alloc(struct heap_info *pRoot, size_t want_size); +/** + * @brief Realloc memory from the heap. + * Change the size of the memory block pointed to by ptr to size bytes. + * + * @attention + *
    + *
  • if ptr is NULL, then the call is equivalent to mmheap_alloc(size), for all values of size. + *
  • if ptr is if size is equal to zero, and ptr is not NULL, then the call is equivalent to mmheap_free(ptr). + *
+ * + * @param[in] pRoot heap info. + * @param[in] src_addr old pointer to the memory space. + * @param[in] want_size new size of the memory space. + * + * @return the new pointer to the allocated memory. + */ +void *bflb_mmheap_realloc(struct heap_info *pRoot, void *src_addr, size_t want_size); +/** + * @brief Cealloc memory from the heap. + * Change the size of the memory block pointed to by ptr to size bytes. + * + * @attention + *
    + *
  • if ptr is NULL, then the call is equivalent to mmheap_alloc(size), for all values of size. + *
  • if ptr is if size is equal to zero, and ptr is not NULL, then the call is equivalent to mmheap_free(ptr). + *
+ * + * @param[in] pRoot heap info. + * @param[in] num size number. + * @param[in] size new size of the memory space. + * + * @return the new pointer to the allocated memory. + */ +void *bflb_mmheap_calloc(struct heap_info *pRoot, size_t num, size_t size); +/** + * @brief Free the memory. + * Free the memory space pointed to by ptr, which must have been returned by a previous call to mmheap_alloc(), mmheap_aligned_alloc(), or mmheap_realloc(). + * + * @attention + * + * @param[in] pRoot heap info. + * @param[in] addr pointer to the memory. + * + * @return None. + */ +void bflb_mmheap_free(struct heap_info *pRoot, void *addr); +/** + * @brief get mmheap state + * + * @param pRoot heap info. + * @param pState heap state + */ +void bflb_mmheap_get_state(struct heap_info *pRoot, struct heap_state *pState); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/arch/riscv32/bl808/src/components/mm/tlsf/CMakeLists.txt b/arch/riscv32/bl808/src/components/mm/tlsf/CMakeLists.txt new file mode 100644 index 00000000..16e27aae --- /dev/null +++ b/arch/riscv32/bl808/src/components/mm/tlsf/CMakeLists.txt @@ -0,0 +1,3 @@ +sdk_library_add_sources(tlsf.c bflb_tlsf.c) +sdk_add_include_directories(.) +sdk_add_compile_definitions(-DCONFIG_TLSF) \ No newline at end of file diff --git a/arch/riscv32/bl808/src/components/mm/tlsf/bflb_tlsf.c b/arch/riscv32/bl808/src/components/mm/tlsf/bflb_tlsf.c new file mode 100644 index 00000000..f79f25dc --- /dev/null +++ b/arch/riscv32/bl808/src/components/mm/tlsf/bflb_tlsf.c @@ -0,0 +1,463 @@ +/**************************************************************************** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "mem.h" +#include "tlsf.h" + +#ifdef CONFIG_FREERTOS +#include "FreeRTOS.h" +#include "semphr.h" +#endif /* CONFIG_FREERTOS */ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_FREERTOS + +#define _IRQ_CONTEXT() xPortIsInsideInterrupt() +#define _SCHED_LOCK() (taskSCHEDULER_RUNNING != xTaskGetSchedulerState()) +#define _ENTER_CRITICAL() portENTER_CRITICAL() +#define _EXIT_CRITICAL() portEXIT_CRITICAL() +#define _SEM_INIT(s, p, c) xSemaphoreCreateRecursiveMutexStatic(s) +#define _SEM_WAIT(s) xSemaphoreTakeRecursive((SemaphoreHandle_t)s, portMAX_DELAY) +#define _SEM_POST(s) xSemaphoreGiveRecursive((SemaphoreHandle_t)s) + +#else + +#include "bflb_irq.h" +static volatile uintptr_t s_irq_flag; +static volatile uintptr_t s_irq_entry; + +#define _GET_HOLDER(x) +#define _IRQ_CONTEXT() (0) +#define _ENTER_CRITICAL() \ + { \ + s_irq_flag = bflb_irq_save(); \ + s_irq_entry += 1; \ + } + +#define _EXIT_CRITICAL() \ + { \ + if (s_irq_entry > 0) { \ + s_irq_entry -= 1; \ + if (s_irq_entry == 0) { \ + bflb_irq_restore(s_irq_flag); \ + } \ + } \ + } + +#endif + +#ifdef CONFIG_FREERTOS +#define CONFIG_MEM_USE_OS +#endif + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Adapted to the lock provided by the operating system */ +#ifdef CONFIG_FREERTOS +typedef StaticSemaphore_t sem_t; +typedef TaskHandle_t task_t; +#else + +#endif /* CONFIG_FREERTOS */ + + +struct mem_delaynode_s +{ + struct mem_delaynode_s *flink; +}; + +/* Private memory management structure */ +struct mem_heap_impl_s { + tlsf_t mem_tlsf; + void *heapstart; + size_t heapsize; + +#ifdef CONFIG_MEM_USE_OS + sem_t sem; + + /* Free delay list, for some situation can't do free immdiately */ + struct mem_delaynode_s *mem_delaylist; +#endif +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: bflb_mem_sem_init + * + * Description: + * Initialize the MM mutex + * + ****************************************************************************/ + +static void bflb_mem_sem_init(struct mem_heap_impl_s *impl) +{ +#ifdef CONFIG_MEM_USE_OS + /* Initialize the MM semaphore to one (to support one-at-a-time access to + * private data sets). + */ + + _SEM_INIT(&impl->sem, 0, 1); +#endif /* CONFIG_MEM_USE_OS */ +} + +/**************************************************************************** + * Name: bflb_mem_sem_take + * + * Description: + * Take the MM mutex. This is the normal action before all memory + * management actions. + * + ****************************************************************************/ + +static void bflb_mem_sem_take(struct mem_heap_impl_s *impl) +{ +#ifdef CONFIG_MEM_USE_OS + if (!_SCHED_LOCK()) { + _SEM_WAIT(&impl->sem); + } else { + _ENTER_CRITICAL(); + } +#else + + _ENTER_CRITICAL(); + +#endif /* CONFIG_MEM_USE_OS */ +} + +/**************************************************************************** + * Name: bflb_mem_sem_give + * + * Description: + * Release the MM mutex when it is not longer needed. + * + ****************************************************************************/ + +static void bflb_mem_sem_give(struct mem_heap_impl_s *impl) +{ +#ifdef CONFIG_MEM_USE_OS + if (!_SCHED_LOCK()) { + _SEM_POST(&impl->sem); + } else { + _EXIT_CRITICAL(); + } + +#else + + _EXIT_CRITICAL(); + +#endif /* CONFIG_MEM_USE_OS */ +} + +/**************************************************************************** + * Name: bflb_mem_add_delaylist + ****************************************************************************/ + +static void bflb_mem_add_delaylist(struct mem_heap_s *heap, void *mem) +{ +#ifdef CONFIG_MEM_USE_OS + struct mem_heap_impl_s *impl; + struct mem_delaynode_s *tmp = mem; + + MEM_ASSERT(MEM_IS_VALID(heap)); + impl = heap->mem_impl; + + /* Delay the deallocation until a more appropriate time. */ + + _ENTER_CRITICAL(); + + tmp->flink = impl->mem_delaylist; + impl->mem_delaylist = tmp; + + _EXIT_CRITICAL(); +#endif /* CONFIG_MEM_USE_OS */ +} + +/**************************************************************************** + * Name: bflb_mem_free_delaylist + ****************************************************************************/ + +static void bflb_mem_free_delaylist(struct mem_heap_s *heap) +{ +#ifdef CONFIG_MEM_USE_OS + struct mem_heap_impl_s *impl; + struct mem_delaynode_s *tmp; + + MEM_ASSERT(MEM_IS_VALID(heap)); + impl = heap->mem_impl; + + /* Move the delay list to local */ + + _ENTER_CRITICAL(); + + tmp = impl->mem_delaylist; + impl->mem_delaylist = NULL; + + _EXIT_CRITICAL(); + + /* Test if the delayed is empty */ + + while (tmp) { + void *address; + + /* Get the first delayed deallocation */ + + address = tmp; + tmp = tmp->flink; + + /* The address should always be non-NULL since that was checked in the + * 'while' condition above. + */ + + bflb_free(heap, address); + } +#endif /* CONFIG_MEM_USE_OS */ +} + +/**************************************************************************** + * Name: mem_tlfsinfo_walker + ****************************************************************************/ + +static void mem_tlfsinfo_walker(void *ptr, size_t size, int used, + void *user) +{ + struct meminfo *info = user; + + if (!used) { + info->free_node++; + info->free_size += size; + if (size > info->max_free_size) { + info->max_free_size = size; + } + } +} + +/**************************************************************************** + * Functions + ****************************************************************************/ + +void bflb_mem_init(struct mem_heap_s *heap, void *heapstart, size_t heapsize) +{ + struct mem_heap_impl_s *impl; + + MEM_LOG("Heap: start=%p size=%zu\r\n", heapstart, heapsize); + + /* Reserve a block space for mem_heap_impl_s context */ + + MEM_ASSERT(heapsize > sizeof(struct mem_heap_impl_s)); + + heap->mem_impl = (struct mem_heap_impl_s *)heapstart; + + heapstart += sizeof(struct mem_heap_impl_s); + heapsize -= sizeof(struct mem_heap_impl_s); + + /* Zero implmeentation context */ + + impl = heap->mem_impl; + memset(impl, 0, sizeof(struct mem_heap_impl_s)); + + /* Allocate and create TLSF context */ + + MEM_ASSERT(heapsize > tlsf_size()); + + impl->mem_tlsf = tlsf_create(heapstart); + heapstart += tlsf_size(); + heapsize -= tlsf_size(); + + bflb_mem_sem_init(impl); + + impl->heapstart = heapstart; + impl->heapsize = heapsize; + + /* Add the initial region of memory to the heap */ + + tlsf_add_pool(impl->mem_tlsf, heapstart, heapsize); +} + +void *bflb_malloc(struct mem_heap_s *heap, size_t nbytes) +{ + struct mem_heap_impl_s *impl; + void *ret = NULL; + + MEM_ASSERT(MEM_IS_VALID(heap)); + + MEM_LOG("malloc %d\r\n", nbytes); + + impl = heap->mem_impl; + + /* Firstly, free mm_delaylist */ + + bflb_mem_free_delaylist(heap); + + /* Allocate from the tlsf pool */ + + bflb_mem_sem_take(impl); + ret = tlsf_malloc(heap->mem_impl->mem_tlsf, nbytes); + bflb_mem_sem_give(impl); + + return ret; +} + +void bflb_free(struct mem_heap_s *heap, void *ptr) +{ + struct mem_heap_impl_s *impl; + + MEM_LOG("Freeing %p\r\n", ptr); + + /* Protect against attempts to free a NULL reference */ + + if (!ptr) { + return; + } + + MEM_ASSERT(MEM_IS_VALID(heap)); + impl = heap->mem_impl; + + if (_IRQ_CONTEXT()) { + + /* We are in ISR, add to mm_delaylist */ + + bflb_mem_add_delaylist(heap, ptr); + return; + } + + /* We need to hold the MM semaphore while we muck with the + * nodelist. + */ + + bflb_mem_sem_take(impl); + + /* Return to the tlsf pool */ + + tlsf_free(heap->mem_impl->mem_tlsf, ptr); + + bflb_mem_sem_give(impl); +} + +void *bflb_realloc(struct mem_heap_s *heap, void *ptr, size_t nbytes) +{ + struct mem_heap_impl_s *impl; + void *ret; + + MEM_ASSERT(MEM_IS_VALID(heap)); + impl = heap->mem_impl; + + /* Firstly, free mm_delaylist */ + + bflb_mem_free_delaylist(heap); + + /* Allocate from the tlsf pool */ + + bflb_mem_sem_take(impl); + + ret = tlsf_realloc(heap->mem_impl->mem_tlsf, ptr, nbytes); + + bflb_mem_sem_give(impl); + + return ret; +} + +void *bflb_calloc(struct mem_heap_s *heap, size_t count, size_t size) +{ + struct mem_heap_impl_s *impl; + void *ptr = NULL; + size_t total = count * size; + + MEM_ASSERT(MEM_IS_VALID(heap)); + impl = heap->mem_impl; + + /* Firstly, free mm_delaylist */ + + bflb_mem_free_delaylist(heap); + + /* Allocate from the tlsf pool */ + + bflb_mem_sem_take(impl); + + if (count > 0 && size > 0) { + if (count <= (SIZE_MAX / size)) { + ptr = tlsf_malloc(heap->mem_impl->mem_tlsf, total); + if (ptr) { + memset(ptr, 0, total); + } + } + } + + bflb_mem_sem_give(impl); + + return ptr; +} + +void *bflb_malloc_align(struct mem_heap_s *heap, size_t align, size_t size) +{ + struct mem_heap_impl_s *impl; + void *ret; + + MEM_ASSERT(MEM_IS_VALID(heap)); + impl = heap->mem_impl; + + /* Firstly, free mm_delaylist */ + + bflb_mem_free_delaylist(heap); + + /* Allocate from the tlsf pool */ + + bflb_mem_sem_take(impl); + + ret = tlsf_memalign(heap->mem_impl->mem_tlsf, align, size); + + bflb_mem_sem_give(impl); + + return ret; +} + +void bflb_mem_usage(struct mem_heap_s *heap, struct meminfo *info) +{ + struct mem_heap_impl_s *impl; + + MEM_ASSERT(MEM_IS_VALID(heap)); + impl = heap->mem_impl; + + memset(info, 0, sizeof(struct meminfo)); + + /* Retake the semaphore for each region to reduce latencies */ + + bflb_mem_sem_take(impl); + tlsf_walk_pool(impl->heapstart, + mem_tlfsinfo_walker, info); + bflb_mem_sem_give(impl); + + info->total_size = impl->heapsize; + info->used_size = info->total_size - info->free_size; +} diff --git a/arch/riscv32/bl808/src/components/mm/tlsf/tlsf.c b/arch/riscv32/bl808/src/components/mm/tlsf/tlsf.c new file mode 100644 index 00000000..fe309c25 --- /dev/null +++ b/arch/riscv32/bl808/src/components/mm/tlsf/tlsf.c @@ -0,0 +1,1288 @@ +#include +#include +#include +#include +#include +#include + +#include "tlsf.h" + +#pragma GCC diagnostic ignored "-Wunused-value" + +#if defined(__cplusplus) + #define tlsf_decl inline +#else + #define tlsf_decl static +#endif + +/* +** Architecture-specific bit manipulation routines. +** +** TLSF achieves O(1) cost for malloc and free operations by limiting +** the search for a free block to a free list of guaranteed size +** adequate to fulfill the request, combined with efficient free list +** queries using bitmasks and architecture-specific bit-manipulation +** routines. +** +** Most modern processors provide instructions to count leading zeroes +** in a word, find the lowest and highest set bit, etc. These +** specific implementations will be used when available, falling back +** to a reasonably efficient generic implementation. +** +** NOTE: TLSF spec relies on ffs/fls returning value 0..31. +** ffs/fls return 1-32 by default, returning 0 for error. +*/ + +/* +** Detect whether or not we are building for a 32- or 64-bit (LP/LLP) +** architecture. There is no reliable portable method at compile-time. +*/ +#if defined (__alpha__) || defined (__ia64__) || defined (__x86_64__) \ + || defined (_WIN64) || defined (__LP64__) || defined (__LLP64__) + #define TLSF_64BIT +#endif + +/* +** gcc 3.4 and above have builtin support, specialized for architecture. +** Some compilers masquerade as gcc; patchlevel test filters them out. +*/ +#if defined (__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) \ + && defined (__GNUC_PATCHLEVEL__) + +#if defined (__SNC__) +/* SNC for Playstation 3. */ + +tlsf_decl int tlsf_ffs(unsigned int word) +{ + const unsigned int reverse = word & (~word + 1); + const int bit = 32 - __builtin_clz(reverse); + return bit - 1; +} + +#else + +tlsf_decl int tlsf_ffs(unsigned int word) +{ + return __builtin_ffs(word) - 1; +} + +#endif + +tlsf_decl int tlsf_fls(unsigned int word) +{ + const int bit = word ? 32 - __builtin_clz(word) : 0; + return bit - 1; +} + +#elif defined (_MSC_VER) && (_MSC_VER >= 1400) && (defined (_M_IX86) || defined (_M_X64)) +/* Microsoft Visual C++ support on x86/X64 architectures. */ + +#include + +#pragma intrinsic(_BitScanReverse) +#pragma intrinsic(_BitScanForward) + +tlsf_decl int tlsf_fls(unsigned int word) +{ + unsigned long index; + return _BitScanReverse(&index, word) ? index : -1; +} + +tlsf_decl int tlsf_ffs(unsigned int word) +{ + unsigned long index; + return _BitScanForward(&index, word) ? index : -1; +} + +#elif defined (_MSC_VER) && defined (_M_PPC) +/* Microsoft Visual C++ support on PowerPC architectures. */ + +#include + +tlsf_decl int tlsf_fls(unsigned int word) +{ + const int bit = 32 - _CountLeadingZeros(word); + return bit - 1; +} + +tlsf_decl int tlsf_ffs(unsigned int word) +{ + const unsigned int reverse = word & (~word + 1); + const int bit = 32 - _CountLeadingZeros(reverse); + return bit - 1; +} + +#elif defined (__ARMCC_VERSION) +/* RealView Compilation Tools for ARM */ + +tlsf_decl int tlsf_ffs(unsigned int word) +{ + const unsigned int reverse = word & (~word + 1); + const int bit = 32 - __clz(reverse); + return bit - 1; +} + +tlsf_decl int tlsf_fls(unsigned int word) +{ + const int bit = word ? 32 - __clz(word) : 0; + return bit - 1; +} + +#elif defined (__ghs__) +/* Green Hills support for PowerPC */ + +#include + +tlsf_decl int tlsf_ffs(unsigned int word) +{ + const unsigned int reverse = word & (~word + 1); + const int bit = 32 - __CLZ32(reverse); + return bit - 1; +} + +tlsf_decl int tlsf_fls(unsigned int word) +{ + const int bit = word ? 32 - __CLZ32(word) : 0; + return bit - 1; +} + +#else +/* Fall back to generic implementation. */ + +tlsf_decl int tlsf_fls_generic(unsigned int word) +{ + int bit = 32; + + if (!word) bit -= 1; + if (!(word & 0xffff0000)) + { + word <<= 16; + bit -= 16; + } + if (!(word & 0xff000000)) + { + word <<= 8; + bit -= 8; + } + if (!(word & 0xf0000000)) + { + word <<= 4; + bit -= 4; + } + if (!(word & 0xc0000000)) + { + word <<= 2; + bit -= 2; + } + if (!(word & 0x80000000)) + { + word <<= 1; + bit -= 1; + } + + return bit; +} + +/* Implement ffs in terms of fls. */ +tlsf_decl int tlsf_ffs(unsigned int word) +{ + return tlsf_fls_generic(word & (~word + 1)) - 1; +} + +tlsf_decl int tlsf_fls(unsigned int word) +{ + return tlsf_fls_generic(word) - 1; +} + +#endif + +/* Possibly 64-bit version of tlsf_fls. */ +#if defined (TLSF_64BIT) +tlsf_decl int tlsf_fls_sizet(size_t size) +{ + int high = (int)(size >> 32); + int bits = 0; + if (high) + { + bits = 32 + tlsf_fls(high); + } + else + { + bits = tlsf_fls((int)size & 0xffffffff); + + } + return bits; +} +#else +#define tlsf_fls_sizet tlsf_fls +#endif + +#undef tlsf_decl + +/* +** Constants. +*/ + +/* Public constants: may be modified. */ +enum tlsf_public +{ + /* log2 of number of linear subdivisions of block sizes. Larger + ** values require more memory in the control structure. Values of + ** 4 or 5 are typical. + */ + SL_INDEX_COUNT_LOG2 = 5, +}; + +/* Private constants: do not modify. */ +enum tlsf_private +{ +#if defined (TLSF_64BIT) + /* All allocation sizes and addresses are aligned to 8 bytes. */ + ALIGN_SIZE_LOG2 = 3, +#else + /* All allocation sizes and addresses are aligned to 4 bytes. */ + ALIGN_SIZE_LOG2 = 2, +#endif + ALIGN_SIZE = (1 << ALIGN_SIZE_LOG2), + + /* + ** We support allocations of sizes up to (1 << FL_INDEX_MAX) bits. + ** However, because we linearly subdivide the second-level lists, and + ** our minimum size granularity is 4 bytes, it doesn't make sense to + ** create first-level lists for sizes smaller than SL_INDEX_COUNT * 4, + ** or (1 << (SL_INDEX_COUNT_LOG2 + 2)) bytes, as there we will be + ** trying to split size ranges into more slots than we have available. + ** Instead, we calculate the minimum threshold size, and place all + ** blocks below that size into the 0th first-level list. + */ + +#if defined (TLSF_64BIT) + /* + ** TODO: We can increase this to support larger sizes, at the expense + ** of more overhead in the TLSF structure. + */ + FL_INDEX_MAX = 32, +#else + FL_INDEX_MAX = 30, +#endif + SL_INDEX_COUNT = (1 << SL_INDEX_COUNT_LOG2), + FL_INDEX_SHIFT = (SL_INDEX_COUNT_LOG2 + ALIGN_SIZE_LOG2), + FL_INDEX_COUNT = (FL_INDEX_MAX - FL_INDEX_SHIFT + 1), + + SMALL_BLOCK_SIZE = (1 << FL_INDEX_SHIFT), +}; + +/* +** Cast and min/max macros. +*/ + +#define tlsf_cast(t, exp) ((t) (exp)) +#define tlsf_min(a, b) ((a) < (b) ? (a) : (b)) +#define tlsf_max(a, b) ((a) > (b) ? (a) : (b)) + +#define tlsf_assert(s) +/* +** Set assert macro, if it has not been provided by the user. +*/ +#if !defined (tlsf_assert) + #define tlsf_assert assert +#endif + +/* +** Static assertion mechanism. +*/ + +#define _tlsf_glue2(x, y) x ## y +#define _tlsf_glue(x, y) _tlsf_glue2(x, y) +#define tlsf_static_assert(exp) \ + typedef char _tlsf_glue(static_assert, __LINE__) [(exp) ? 1 : -1] + +/* This code has been tested on 32- and 64-bit (LP/LLP) architectures. */ +tlsf_static_assert(sizeof(int) * CHAR_BIT == 32); +tlsf_static_assert(sizeof(size_t) * CHAR_BIT >= 32); +tlsf_static_assert(sizeof(size_t) * CHAR_BIT <= 64); + +/* SL_INDEX_COUNT must be <= number of bits in sl_bitmap's storage type. */ +tlsf_static_assert(sizeof(unsigned int) * CHAR_BIT >= SL_INDEX_COUNT); + +/* Ensure we've properly tuned our sizes. */ +tlsf_static_assert(ALIGN_SIZE == SMALL_BLOCK_SIZE / SL_INDEX_COUNT); + +/* +** Data structures and associated constants. +*/ + +/* +** Block header structure. +** +** There are several implementation subtleties involved: +** - The prev_phys_block field is only valid if the previous block is free. +** - The prev_phys_block field is actually stored at the end of the +** previous block. It appears at the beginning of this structure only to +** simplify the implementation. +** - The next_free / prev_free fields are only valid if the block is free. +*/ +typedef struct block_header_t +{ + /* Points to the previous physical block. */ + struct block_header_t *prev_phys_block; + + /* The size of this block, excluding the block header. */ + size_t size; + + /* Next and previous free blocks. */ + struct block_header_t *next_free; + struct block_header_t *prev_free; +} block_header_t; + +/* +** Since block sizes are always at least a multiple of 4, the two least +** significant bits of the size field are used to store the block status: +** - bit 0: whether block is busy or free +** - bit 1: whether previous block is busy or free +*/ +static const size_t block_header_free_bit = 1 << 0; +static const size_t block_header_prev_free_bit = 1 << 1; + +/* +** The size of the block header exposed to used blocks is the size field. +** The prev_phys_block field is stored *inside* the previous free block. +*/ +static const size_t block_header_overhead = sizeof(size_t); + +/* User data starts directly after the size field in a used block. */ +static const size_t block_start_offset = + offsetof(block_header_t, size) + sizeof(size_t); + +/* +** A free block must be large enough to store its header minus the size of +** the prev_phys_block field, and no larger than the number of addressable +** bits for FL_INDEX. +*/ +static const size_t block_size_min = + sizeof(block_header_t) - sizeof(block_header_t *); +static const size_t block_size_max = tlsf_cast(size_t, 1) << FL_INDEX_MAX; + + +/* The TLSF control structure. */ +typedef struct control_t +{ + /* Empty lists point at this block to indicate they are free. */ + block_header_t block_null; + + /* Bitmaps for free lists. */ + unsigned int fl_bitmap; + unsigned int sl_bitmap[FL_INDEX_COUNT]; + + /* Head of free lists. */ + block_header_t *blocks[FL_INDEX_COUNT][SL_INDEX_COUNT]; +} control_t; + +/* A type used for casting when doing pointer arithmetic. */ +typedef ptrdiff_t tlsfptr_t; + +/* +** block_header_t member functions. +*/ + +static size_t block_size(const block_header_t *block) +{ + return block->size & ~(block_header_free_bit | block_header_prev_free_bit); +} + +static void block_set_size(block_header_t *block, size_t size) +{ + const size_t oldsize = block->size; + block->size = size | (oldsize & (block_header_free_bit | block_header_prev_free_bit)); +} + +static int block_is_last(const block_header_t *block) +{ + return block_size(block) == 0; +} + +static int block_is_free(const block_header_t *block) +{ + return tlsf_cast(int, block->size & block_header_free_bit); +} + +static void block_set_free(block_header_t *block) +{ + block->size |= block_header_free_bit; +} + +static void block_set_used(block_header_t *block) +{ + block->size &= ~block_header_free_bit; +} + +static int block_is_prev_free(const block_header_t *block) +{ + return tlsf_cast(int, block->size & block_header_prev_free_bit); +} + +static void block_set_prev_free(block_header_t *block) +{ + block->size |= block_header_prev_free_bit; +} + +static void block_set_prev_used(block_header_t *block) +{ + block->size &= ~block_header_prev_free_bit; +} + +static block_header_t *block_from_ptr(const void *ptr) +{ + return tlsf_cast(block_header_t *, + tlsf_cast(unsigned char *, ptr) - block_start_offset); +} + +static void *block_to_ptr(const block_header_t *block) +{ + return tlsf_cast(void *, + tlsf_cast(unsigned char *, block) + block_start_offset); +} + +/* Return location of next block after block of given size. */ +static block_header_t *offset_to_block(const void *ptr, size_t size) +{ + return tlsf_cast(block_header_t *, tlsf_cast(tlsfptr_t, ptr) + size); +} + +/* Return location of previous block. */ +static block_header_t *block_prev(const block_header_t *block) +{ + tlsf_assert(block_is_prev_free(block) && "previous block must be free"); + return block->prev_phys_block; +} + +/* Return location of next existing block. */ +static block_header_t *block_next(const block_header_t *block) +{ + block_header_t *next = offset_to_block(block_to_ptr(block), + block_size(block) - block_header_overhead); + tlsf_assert(!block_is_last(block)); + return next; +} + +/* Link a new block with its physical neighbor, return the neighbor. */ +static block_header_t *block_link_next(block_header_t *block) +{ + block_header_t *next = block_next(block); + next->prev_phys_block = block; + return next; +} + +static void block_mark_as_free(block_header_t *block) +{ + /* Link the block to the next block, first. */ + block_header_t *next = block_link_next(block); + block_set_prev_free(next); + block_set_free(block); +} + +static void block_mark_as_used(block_header_t *block) +{ + block_header_t *next = block_next(block); + block_set_prev_used(next); + block_set_used(block); +} + +static size_t align_up(size_t x, size_t align) +{ + tlsf_assert(0 == (align & (align - 1)) && "must align to a power of two"); + return (x + (align - 1)) & ~(align - 1); +} + +static size_t align_down(size_t x, size_t align) +{ + tlsf_assert(0 == (align & (align - 1)) && "must align to a power of two"); + return x - (x & (align - 1)); +} + +static void *align_ptr(const void *ptr, size_t align) +{ + const tlsfptr_t aligned = + (tlsf_cast(tlsfptr_t, ptr) + (align - 1)) & ~(align - 1); + tlsf_assert(0 == (align & (align - 1)) && "must align to a power of two"); + return tlsf_cast(void *, aligned); +} + +/* +** Adjust an allocation size to be aligned to word size, and no smaller +** than internal minimum. +*/ +static size_t adjust_request_size(size_t size, size_t align) +{ + size_t adjust = 0; + if (size) + { + const size_t aligned = align_up(size, align); + + /* aligned sized must not exceed block_size_max or we'll go out of bounds on sl_bitmap */ + if (aligned < block_size_max) + { + adjust = tlsf_max(aligned, block_size_min); + } + } + return adjust; +} + +/* +** TLSF utility functions. In most cases, these are direct translations of +** the documentation found in the white paper. +*/ + +static void mapping_insert(size_t size, int *fli, int *sli) +{ + int fl, sl; + if (size < SMALL_BLOCK_SIZE) + { + /* Store small blocks in first list. */ + fl = 0; + sl = tlsf_cast(int, size) / (SMALL_BLOCK_SIZE / SL_INDEX_COUNT); + } + else + { + fl = tlsf_fls_sizet(size); + sl = tlsf_cast(int, size >> (fl - SL_INDEX_COUNT_LOG2)) ^ (1 << SL_INDEX_COUNT_LOG2); + fl -= (FL_INDEX_SHIFT - 1); + } + *fli = fl; + *sli = sl; +} + +/* This version rounds up to the next block size (for allocations) */ +static void mapping_search(size_t size, int *fli, int *sli) +{ + if (size >= SMALL_BLOCK_SIZE) + { + const size_t round = (1 << (tlsf_fls_sizet(size) - SL_INDEX_COUNT_LOG2)) - 1; + size += round; + } + mapping_insert(size, fli, sli); +} + +static block_header_t *search_suitable_block(control_t *control, int *fli, int *sli) +{ + int fl = *fli; + int sl = *sli; + + /* + ** First, search for a block in the list associated with the given + ** fl/sl index. + */ + unsigned int sl_map = control->sl_bitmap[fl] & (~0U << sl); + if (!sl_map) + { + /* No block exists. Search in the next largest first-level list. */ + const unsigned int fl_map = control->fl_bitmap & (~0U << (fl + 1)); + if (!fl_map) + { + /* No free blocks available, memory has been exhausted. */ + return 0; + } + + fl = tlsf_ffs(fl_map); + *fli = fl; + sl_map = control->sl_bitmap[fl]; + } + tlsf_assert(sl_map && "internal error - second level bitmap is null"); + sl = tlsf_ffs(sl_map); + *sli = sl; + + /* Return the first block in the free list. */ + return control->blocks[fl][sl]; +} + +/* Remove a free block from the free list.*/ +static void remove_free_block(control_t *control, block_header_t *block, int fl, int sl) +{ + block_header_t *prev = block->prev_free; + block_header_t *next = block->next_free; + tlsf_assert(prev && "prev_free field can not be null"); + tlsf_assert(next && "next_free field can not be null"); + next->prev_free = prev; + prev->next_free = next; + + /* If this block is the head of the free list, set new head. */ + if (control->blocks[fl][sl] == block) + { + control->blocks[fl][sl] = next; + + /* If the new head is null, clear the bitmap. */ + if (next == &control->block_null) + { + control->sl_bitmap[fl] &= ~(1U << sl); + + /* If the second bitmap is now empty, clear the fl bitmap. */ + if (!control->sl_bitmap[fl]) + { + control->fl_bitmap &= ~(1U << fl); + } + } + } +} + +/* Insert a free block into the free block list. */ +static void insert_free_block(control_t *control, block_header_t *block, int fl, int sl) +{ + block_header_t *current = control->blocks[fl][sl]; + tlsf_assert(current && "free list cannot have a null entry"); + tlsf_assert(block && "cannot insert a null entry into the free list"); + block->next_free = current; + block->prev_free = &control->block_null; + current->prev_free = block; + + tlsf_assert(block_to_ptr(block) == align_ptr(block_to_ptr(block), ALIGN_SIZE) + && "block not aligned properly"); + /* + ** Insert the new block at the head of the list, and mark the first- + ** and second-level bitmaps appropriately. + */ + control->blocks[fl][sl] = block; + control->fl_bitmap |= (1U << fl); + control->sl_bitmap[fl] |= (1U << sl); +} + +/* Remove a given block from the free list. */ +static void block_remove(control_t *control, block_header_t *block) +{ + int fl, sl; + mapping_insert(block_size(block), &fl, &sl); + remove_free_block(control, block, fl, sl); +} + +/* Insert a given block into the free list. */ +static void block_insert(control_t *control, block_header_t *block) +{ + int fl, sl; + mapping_insert(block_size(block), &fl, &sl); + insert_free_block(control, block, fl, sl); +} + +static int block_can_split(block_header_t *block, size_t size) +{ + return block_size(block) >= sizeof(block_header_t) + size; +} + +/* Split a block into two, the second of which is free. */ +static block_header_t *block_split(block_header_t *block, size_t size) +{ + /* Calculate the amount of space left in the remaining block. */ + block_header_t *remaining = + offset_to_block(block_to_ptr(block), size - block_header_overhead); + + const size_t remain_size = block_size(block) - (size + block_header_overhead); + + tlsf_assert(block_to_ptr(remaining) == align_ptr(block_to_ptr(remaining), ALIGN_SIZE) + && "remaining block not aligned properly"); + + tlsf_assert(block_size(block) == remain_size + size + block_header_overhead); + block_set_size(remaining, remain_size); + tlsf_assert(block_size(remaining) >= block_size_min && "block split with invalid size"); + + block_set_size(block, size); + block_mark_as_free(remaining); + + return remaining; +} + +/* Absorb a free block's storage into an adjacent previous free block. */ +static block_header_t *block_absorb(block_header_t *prev, block_header_t *block) +{ + tlsf_assert(!block_is_last(prev) && "previous block can't be last"); + /* Note: Leaves flags untouched. */ + prev->size += block_size(block) + block_header_overhead; + block_link_next(prev); + return prev; +} + +/* Merge a just-freed block with an adjacent previous free block. */ +static block_header_t *block_merge_prev(control_t *control, block_header_t *block) +{ + if (block_is_prev_free(block)) + { + block_header_t *prev = block_prev(block); + tlsf_assert(prev && "prev physical block can't be null"); + tlsf_assert(block_is_free(prev) && "prev block is not free though marked as such"); + block_remove(control, prev); + block = block_absorb(prev, block); + } + + return block; +} + +/* Merge a just-freed block with an adjacent free block. */ +static block_header_t *block_merge_next(control_t *control, block_header_t *block) +{ + block_header_t *next = block_next(block); + tlsf_assert(next && "next physical block can't be null"); + + if (block_is_free(next)) + { + tlsf_assert(!block_is_last(block) && "previous block can't be last"); + block_remove(control, next); + block = block_absorb(block, next); + } + + return block; +} + +/* Trim any trailing block space off the end of a block, return to pool. */ +static void block_trim_free(control_t *control, block_header_t *block, size_t size) +{ + tlsf_assert(block_is_free(block) && "block must be free"); + if (block_can_split(block, size)) + { + block_header_t *remaining_block = block_split(block, size); + block_link_next(block); + block_set_prev_free(remaining_block); + block_insert(control, remaining_block); + } +} + +/* Trim any trailing block space off the end of a used block, return to pool. */ +static void block_trim_used(control_t *control, block_header_t *block, size_t size) +{ + tlsf_assert(!block_is_free(block) && "block must be used"); + if (block_can_split(block, size)) + { + /* If the next block is free, we must coalesce. */ + block_header_t *remaining_block = block_split(block, size); + block_set_prev_used(remaining_block); + + remaining_block = block_merge_next(control, remaining_block); + block_insert(control, remaining_block); + } +} + +static block_header_t *block_trim_free_leading(control_t *control, block_header_t *block, size_t size) +{ + block_header_t *remaining_block = block; + if (block_can_split(block, size)) + { + /* We want the 2nd block. */ + remaining_block = block_split(block, size - block_header_overhead); + block_set_prev_free(remaining_block); + + block_link_next(block); + block_insert(control, block); + } + + return remaining_block; +} + +static block_header_t *block_locate_free(control_t *control, size_t size) +{ + int fl = 0, sl = 0; + block_header_t *block = 0; + + if (size) + { + mapping_search(size, &fl, &sl); + + /* + ** mapping_search can futz with the size, so for excessively large sizes it can sometimes wind up + ** with indices that are off the end of the block array. + ** So, we protect against that here, since this is the only callsite of mapping_search. + ** Note that we don't need to check sl, since it comes from a modulo operation that guarantees it's always in range. + */ + if (fl < FL_INDEX_COUNT) + { + block = search_suitable_block(control, &fl, &sl); + } + } + + if (block) + { + tlsf_assert(block_size(block) >= size); + remove_free_block(control, block, fl, sl); + } + + return block; +} + +static void *block_prepare_used(control_t *control, block_header_t *block, size_t size) +{ + void *p = 0; + if (block) + { + tlsf_assert(size && "size must be non-zero"); + block_trim_free(control, block, size); + block_mark_as_used(block); + p = block_to_ptr(block); + } + return p; +} + +/* Clear structure and point all empty lists at the null block. */ +static void control_construct(control_t *control) +{ + int i, j; + + control->block_null.next_free = &control->block_null; + control->block_null.prev_free = &control->block_null; + + control->fl_bitmap = 0; + for (i = 0; i < FL_INDEX_COUNT; ++i) + { + control->sl_bitmap[i] = 0; + for (j = 0; j < SL_INDEX_COUNT; ++j) + { + control->blocks[i][j] = &control->block_null; + } + } +} + +/* +** Debugging utilities. +*/ + +typedef struct integrity_t +{ + int prev_status; + int status; +} integrity_t; + +#define tlsf_insist(x) { tlsf_assert(x); if (!(x)) { status--; } } + +static void integrity_walker(void *ptr, size_t size, int used, void *user) +{ + block_header_t *block = block_from_ptr(ptr); + integrity_t *integ = tlsf_cast(integrity_t *, user); + const int this_prev_status = block_is_prev_free(block) ? 1 : 0; + const int this_status = block_is_free(block) ? 1 : 0; + const size_t this_block_size = block_size(block); + + int status = 0; + (void)used; + tlsf_insist(integ->prev_status == this_prev_status && "prev status incorrect"); + tlsf_insist(size == this_block_size && "block size incorrect"); + + integ->prev_status = this_status; + integ->status += status; +} + +int tlsf_check(tlsf_t tlsf) +{ + int i, j; + + control_t *control = tlsf_cast(control_t *, tlsf); + int status = 0; + + /* Check that the free lists and bitmaps are accurate. */ + for (i = 0; i < FL_INDEX_COUNT; ++i) + { + for (j = 0; j < SL_INDEX_COUNT; ++j) + { + const int fl_map = control->fl_bitmap & (1U << i); + const int sl_list = control->sl_bitmap[i]; + const int sl_map = sl_list & (1U << j); + const block_header_t *block = control->blocks[i][j]; + + /* Check that first- and second-level lists agree. */ + if (!fl_map) + { + tlsf_insist(!sl_map && "second-level map must be null"); + } + + if (!sl_map) + { + tlsf_insist(block == &control->block_null && "block list must be null"); + continue; + } + + /* Check that there is at least one free block. */ + tlsf_insist(sl_list && "no free blocks in second-level map"); + tlsf_insist(block != &control->block_null && "block should not be null"); + + while (block != &control->block_null) + { + int fli, sli; + tlsf_insist(block_is_free(block) && "block should be free"); + tlsf_insist(!block_is_prev_free(block) && "blocks should have coalesced"); + tlsf_insist(!block_is_free(block_next(block)) && "blocks should have coalesced"); + tlsf_insist(block_is_prev_free(block_next(block)) && "block should be free"); + tlsf_insist(block_size(block) >= block_size_min && "block not minimum size"); + + mapping_insert(block_size(block), &fli, &sli); + tlsf_insist(fli == i && sli == j && "block size indexed in wrong list"); + block = block->next_free; + } + } + } + + return status; +} + +#undef tlsf_insist + +static void default_walker(void *ptr, size_t size, int used, void *user) +{ + (void)user; + printf("\t%x %s size: %x (%x)\n", ptr, used ? "used" : "free", (unsigned int)size, block_from_ptr(ptr)); +} + +void tlsf_walk_pool(pool_t pool, tlsf_walker walker, void *user) +{ + tlsf_walker pool_walker = walker ? walker : default_walker; + block_header_t *block = + offset_to_block(pool, -(size_t)block_header_overhead); + + while (block && !block_is_last(block)) + { + pool_walker( + block_to_ptr(block), + block_size(block), + !block_is_free(block), + user); + block = block_next(block); + } +} + +size_t tlsf_block_size(void *ptr) +{ + size_t size = 0; + if (ptr) + { + const block_header_t *block = block_from_ptr(ptr); + size = block_size(block); + } + return size; +} + +int tlsf_check_pool(pool_t pool) +{ + /* Check that the blocks are physically correct. */ + integrity_t integ = { 0, 0 }; + tlsf_walk_pool(pool, integrity_walker, &integ); + + return integ.status; +} + +/* +** Size of the TLSF structures in a given memory block passed to +** tlsf_create, equal to the size of a control_t +*/ +size_t tlsf_size(void) +{ + return sizeof(control_t); +} + +size_t tlsf_align_size(void) +{ + return ALIGN_SIZE; +} + +size_t tlsf_block_size_min(void) +{ + return block_size_min; +} + +size_t tlsf_block_size_max(void) +{ + return block_size_max; +} + +/* +** Overhead of the TLSF structures in a given memory block passed to +** tlsf_add_pool, equal to the overhead of a free block and the +** sentinel block. +*/ +size_t tlsf_pool_overhead(void) +{ + return 2 * block_header_overhead; +} + +size_t tlsf_alloc_overhead(void) +{ + return block_header_overhead; +} + +pool_t tlsf_add_pool(tlsf_t tlsf, void *mem, size_t bytes) +{ + block_header_t *block; + block_header_t *next; + + const size_t pool_overhead = tlsf_pool_overhead(); + const size_t pool_bytes = align_down(bytes - pool_overhead, ALIGN_SIZE); + + if (((ptrdiff_t)mem % ALIGN_SIZE) != 0) + { + printf("tlsf_add_pool: Memory must be aligned by %u bytes.\n", + (unsigned int)ALIGN_SIZE); + return 0; + } + + if (pool_bytes < block_size_min || pool_bytes > block_size_max) + { +#if defined (TLSF_64BIT) + printf("tlsf_add_pool: Memory size must be between 0x%x and 0x%x00 bytes.\n", + (unsigned int)(pool_overhead + block_size_min), + (unsigned int)((pool_overhead + block_size_max) / 256)); +#else + printf("tlsf_add_pool: Memory size must be between %u and %u bytes.\n", + (unsigned int)(pool_overhead + block_size_min), + (unsigned int)(pool_overhead + block_size_max)); +#endif + return 0; + } + + /* + ** Create the main free block. Offset the start of the block slightly + ** so that the prev_phys_block field falls outside of the pool - + ** it will never be used. + */ + block = offset_to_block(mem, -(size_t)block_header_overhead); + block_set_size(block, pool_bytes); + block_set_free(block); + block_set_prev_used(block); + block_insert(tlsf_cast(control_t *, tlsf), block); + + /* Split the block to create a zero-size sentinel block. */ + next = block_link_next(block); + block_set_size(next, 0); + block_set_used(next); + block_set_prev_free(next); + + return mem; +} + +void tlsf_remove_pool(tlsf_t tlsf, pool_t pool) +{ + control_t *control = tlsf_cast(control_t *, tlsf); + block_header_t *block = offset_to_block(pool, -(size_t)block_header_overhead); + + int fl = 0, sl = 0; + + tlsf_assert(block_is_free(block) && "block should be free"); + tlsf_assert(!block_is_free(block_next(block)) && "next block should not be free"); + tlsf_assert(block_size(block_next(block)) == 0 && "next block size should be zero"); + + mapping_insert(block_size(block), &fl, &sl); + remove_free_block(control, block, fl, sl); +} + +/* +** TLSF main interface. +*/ + +#ifdef _DEBUG +int test_ffs_fls() +{ + /* Verify ffs/fls work properly. */ + int rv = 0; + rv += (tlsf_ffs(0) == -1) ? 0 : 0x1; + rv += (tlsf_fls(0) == -1) ? 0 : 0x2; + rv += (tlsf_ffs(1) == 0) ? 0 : 0x4; + rv += (tlsf_fls(1) == 0) ? 0 : 0x8; + rv += (tlsf_ffs(0x80000000) == 31) ? 0 : 0x10; + rv += (tlsf_ffs(0x80008000) == 15) ? 0 : 0x20; + rv += (tlsf_fls(0x80000008) == 31) ? 0 : 0x40; + rv += (tlsf_fls(0x7FFFFFFF) == 30) ? 0 : 0x80; + +#if defined (TLSF_64BIT) + rv += (tlsf_fls_sizet(0x80000000) == 31) ? 0 : 0x100; + rv += (tlsf_fls_sizet(0x100000000) == 32) ? 0 : 0x200; + rv += (tlsf_fls_sizet(0xffffffffffffffff) == 63) ? 0 : 0x400; +#endif + + if (rv) + { + printf("test_ffs_fls: %x ffs/fls tests failed.\n", rv); + } + return rv; +} +#endif + +tlsf_t tlsf_create(void *mem) +{ +#ifdef _DEBUG + if (test_ffs_fls()) + { + return 0; + } +#endif + + if (((tlsfptr_t)mem % ALIGN_SIZE) != 0) + { + printf("tlsf_create: Memory must be aligned to %u bytes.\n", + (unsigned int)ALIGN_SIZE); + return 0; + } + + control_construct(tlsf_cast(control_t *, mem)); + + return tlsf_cast(tlsf_t, mem); +} + +tlsf_t tlsf_create_with_pool(void *mem, size_t bytes) +{ + tlsf_t tlsf = tlsf_create(mem); + tlsf_add_pool(tlsf, (char *)mem + tlsf_size(), bytes - tlsf_size()); + return tlsf; +} + +void tlsf_destroy(tlsf_t tlsf) +{ + /* Nothing to do. */ + (void)tlsf; +} + +pool_t tlsf_get_pool(tlsf_t tlsf) +{ + return tlsf_cast(pool_t, (char *)tlsf + tlsf_size()); +} + +void *tlsf_malloc(tlsf_t tlsf, size_t size) +{ + control_t *control = tlsf_cast(control_t *, tlsf); + const size_t adjust = adjust_request_size(size, ALIGN_SIZE); + block_header_t *block = block_locate_free(control, adjust); + return block_prepare_used(control, block, adjust); +} + +void *tlsf_memalign(tlsf_t tlsf, size_t align, size_t size) +{ + control_t *control = tlsf_cast(control_t *, tlsf); + const size_t adjust = adjust_request_size(size, ALIGN_SIZE); + + /* + ** We must allocate an additional minimum block size bytes so that if + ** our free block will leave an alignment gap which is smaller, we can + ** trim a leading free block and release it back to the pool. We must + ** do this because the previous physical block is in use, therefore + ** the prev_phys_block field is not valid, and we can't simply adjust + ** the size of that block. + */ + const size_t gap_minimum = sizeof(block_header_t); + const size_t size_with_gap = adjust_request_size(adjust + align + gap_minimum, align); + + /* + ** If alignment is less than or equals base alignment, we're done. + ** If we requested 0 bytes, return null, as tlsf_malloc(0) does. + */ + const size_t aligned_size = (adjust && align > ALIGN_SIZE) ? size_with_gap : adjust; + + block_header_t *block = block_locate_free(control, aligned_size); + + /* This can't be a static assert. */ + tlsf_assert(sizeof(block_header_t) == block_size_min + block_header_overhead); + + if (block) + { + void *ptr = block_to_ptr(block); + void *aligned = align_ptr(ptr, align); + size_t gap = tlsf_cast(size_t, + tlsf_cast(tlsfptr_t, aligned) - tlsf_cast(tlsfptr_t, ptr)); + + /* If gap size is too small, offset to next aligned boundary. */ + if (gap && gap < gap_minimum) + { + const size_t gap_remain = gap_minimum - gap; + const size_t offset = tlsf_max(gap_remain, align); + const void *next_aligned = tlsf_cast(void *, + tlsf_cast(tlsfptr_t, aligned) + offset); + + aligned = align_ptr(next_aligned, align); + gap = tlsf_cast(size_t, + tlsf_cast(tlsfptr_t, aligned) - tlsf_cast(tlsfptr_t, ptr)); + } + + if (gap) + { + tlsf_assert(gap >= gap_minimum && "gap size too small"); + block = block_trim_free_leading(control, block, gap); + } + } + + return block_prepare_used(control, block, adjust); +} + +void tlsf_free(tlsf_t tlsf, void *ptr) +{ + /* Don't attempt to free a NULL pointer. */ + if (ptr) + { + control_t *control = tlsf_cast(control_t *, tlsf); + block_header_t *block = block_from_ptr(ptr); + tlsf_assert(!block_is_free(block) && "block already marked as free"); + block_mark_as_free(block); + block = block_merge_prev(control, block); + block = block_merge_next(control, block); + block_insert(control, block); + } +} + +/* +** The TLSF block information provides us with enough information to +** provide a reasonably intelligent implementation of realloc, growing or +** shrinking the currently allocated block as required. +** +** This routine handles the somewhat esoteric edge cases of realloc: +** - a non-zero size with a null pointer will behave like malloc +** - a zero size with a non-null pointer will behave like free +** - a request that cannot be satisfied will leave the original buffer +** untouched +** - an extended buffer size will leave the newly-allocated area with +** contents undefined +*/ +void *tlsf_realloc(tlsf_t tlsf, void *ptr, size_t size) +{ + control_t *control = tlsf_cast(control_t *, tlsf); + void *p = 0; + + /* Zero-size requests are treated as free. */ + if (ptr && size == 0) + { + tlsf_free(tlsf, ptr); + } + /* Requests with NULL pointers are treated as malloc. */ + else if (!ptr) + { + p = tlsf_malloc(tlsf, size); + } + else + { + block_header_t *block = block_from_ptr(ptr); + block_header_t *next = block_next(block); + + const size_t cursize = block_size(block); + const size_t combined = cursize + block_size(next) + block_header_overhead; + const size_t adjust = adjust_request_size(size, ALIGN_SIZE); + + tlsf_assert(!block_is_free(block) && "block already marked as free"); + + /* + ** If the next block is used, or when combined with the current + ** block, does not offer enough space, we must reallocate and copy. + */ + if (adjust > cursize && (!block_is_free(next) || adjust > combined)) + { + p = tlsf_malloc(tlsf, size); + if (p) + { + const size_t minsize = tlsf_min(cursize, size); + memcpy(p, ptr, minsize); + tlsf_free(tlsf, ptr); + } + } + else + { + /* Do we need to expand to the next block? */ + if (adjust > cursize) + { + block_merge_next(control, block); + block_mark_as_used(block); + } + + /* Trim the resulting block and return the original pointer. */ + block_trim_used(control, block, adjust); + p = ptr; + } + } + + return p; +} + diff --git a/arch/riscv32/bl808/src/components/mm/tlsf/tlsf.h b/arch/riscv32/bl808/src/components/mm/tlsf/tlsf.h new file mode 100644 index 00000000..5e390626 --- /dev/null +++ b/arch/riscv32/bl808/src/components/mm/tlsf/tlsf.h @@ -0,0 +1,90 @@ +#ifndef INCLUDED_tlsf +#define INCLUDED_tlsf + +/* +** Two Level Segregated Fit memory allocator, version 3.1. +** Written by Matthew Conte +** http://tlsf.baisoku.org +** +** Based on the original documentation by Miguel Masmano: +** http://www.gii.upv.es/tlsf/main/docs +** +** This implementation was written to the specification +** of the document, therefore no GPL restrictions apply. +** +** Copyright (c) 2006-2016, Matthew Conte +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** * Neither the name of the copyright holder nor the +** names of its contributors may be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +** DISCLAIMED. IN NO EVENT SHALL MATTHEW CONTE BE LIABLE FOR ANY +** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +/* tlsf_t: a TLSF structure. Can contain 1 to N pools. */ +/* pool_t: a block of memory that TLSF can manage. */ +typedef void *tlsf_t; +typedef void *pool_t; + +/* Create/destroy a memory pool. */ +tlsf_t tlsf_create(void *mem); +tlsf_t tlsf_create_with_pool(void *mem, size_t bytes); +void tlsf_destroy(tlsf_t tlsf); +pool_t tlsf_get_pool(tlsf_t tlsf); + +/* Add/remove memory pools. */ +pool_t tlsf_add_pool(tlsf_t tlsf, void *mem, size_t bytes); +void tlsf_remove_pool(tlsf_t tlsf, pool_t pool); + +/* malloc/memalign/realloc/free replacements. */ +void *tlsf_malloc(tlsf_t tlsf, size_t bytes); +void *tlsf_memalign(tlsf_t tlsf, size_t align, size_t bytes); +void *tlsf_realloc(tlsf_t tlsf, void *ptr, size_t size); +void tlsf_free(tlsf_t tlsf, void *ptr); + +/* Returns internal block size, not original request size */ +size_t tlsf_block_size(void *ptr); + +/* Overheads/limits of internal structures. */ +size_t tlsf_size(void); +size_t tlsf_align_size(void); +size_t tlsf_block_size_min(void); +size_t tlsf_block_size_max(void); +size_t tlsf_pool_overhead(void); +size_t tlsf_alloc_overhead(void); + +/* Debugging. */ +typedef void (*tlsf_walker)(void *ptr, size_t size, int used, void *user); +void tlsf_walk_pool(pool_t pool, tlsf_walker walker, void *user); +/* Returns nonzero if any internal consistency check fails. */ +int tlsf_check(tlsf_t tlsf); +int tlsf_check_pool(pool_t pool); + +#if defined(__cplusplus) +}; +#endif + +#endif diff --git a/arch/riscv32/bl808/src/drivers/lhal/CMakeLists.txt b/arch/riscv32/bl808/src/drivers/lhal/CMakeLists.txt new file mode 100644 index 00000000..8b0e3c0b --- /dev/null +++ b/arch/riscv32/bl808/src/drivers/lhal/CMakeLists.txt @@ -0,0 +1,138 @@ +sdk_generate_library() + +if(NOT CONFIG_ROMAPI) +sdk_library_add_sources(src/bflb_common.c) +else() +if((NOT ("${CHIP}" STREQUAL "bl602")) AND (NOT ("${CHIP}" STREQUAL "bl702"))) +sdk_library_add_sources(src/bflb_common.c) +endif() +endif() + +sdk_library_add_sources( +src/bflb_adc.c +src/bflb_cks.c +src/bflb_ef_ctrl.c +src/bflb_gpio.c +src/bflb_i2c.c +src/bflb_dma.c +src/bflb_rtc.c +src/bflb_sec_aes.c +src/bflb_sec_sha.c +src/bflb_sec_trng.c +src/bflb_spi.c +src/bflb_timer.c +src/bflb_uart.c +src/bflb_wdg.c +src/bflb_flash.c +src/flash/bflb_sf_cfg.c +src/flash/bflb_xip_sflash.c +src/flash/bflb_sflash.c +src/flash/bflb_sf_ctrl.c +) + +if("${CHIP}" STREQUAL "bl602") +sdk_library_add_sources( +src/bflb_dac.c +src/bflb_ir.c +src/bflb_pwm_v1.c +src/bflb_sdio2.c +) +elseif("${CHIP}" STREQUAL "bl702") +sdk_library_add_sources( +src/bflb_dac.c +src/bflb_emac.c +src/bflb_ir.c +src/bflb_pwm_v1.c +src/bflb_cam.c +src/bflb_spi_psram.c +) +elseif("${CHIP}" STREQUAL "bl702l") +sdk_library_add_sources( +src/bflb_kys.c +src/bflb_pwm_v1.c +src/bflb_pwm_v2.c +src/bflb_spi_psram.c +) +elseif("${CHIP}" STREQUAL "bl616") +sdk_library_add_sources( +src/bflb_dac.c +src/bflb_emac.c +src/bflb_ir.c +src/bflb_mjpeg.c +src/bflb_pwm_v2.c +src/bflb_cam.c +src/bflb_iso11898.c +src/bflb_sdio2.c +src/bflb_i2s.c +src/bflb_dbi.c +src/bflb_audac.c +src/bflb_auadc.c +) +elseif("${CHIP}" STREQUAL "bl628") +sdk_library_add_sources( +src/bflb_dac.c +src/bflb_emac.c +src/bflb_clock.c +src/bflb_pwm_v2.c +src/bflb_iso11898.c +) +elseif("${CHIP}" STREQUAL "bl808") +sdk_library_add_sources( +src/bflb_dac.c +src/bflb_emac.c +src/bflb_ir.c +src/bflb_mjpeg.c +src/bflb_pwm_v2.c +src/bflb_cam.c +src/bflb_iso11898.c +src/bflb_csi.c +src/bflb_i2s.c +) +endif() + +if(CONFIG_CHERRYUSB) +if("${CHIP}" STREQUAL "bl702") +sdk_library_add_sources(src/bflb_usb_v1.c) +elseif(("${CHIP}" STREQUAL "bl602") OR ("${CHIP}" STREQUAL "bl702l")) +# no usb +elseif(("${CHIP}" STREQUAL "bl628")) +else() +sdk_library_add_sources(src/bflb_usb_v2.c) +endif() +endif() + +# optional +sdk_library_add_sources(src/bflb_irq.c) +sdk_library_add_sources(src/bflb_l1c.c) +sdk_library_add_sources(src/bflb_mtimer.c) + +sdk_add_include_directories(include) +sdk_add_include_directories(include/arch) +sdk_add_include_directories(include/arch/risc-v/t-head) +sdk_add_include_directories(include/arch/risc-v/t-head/Core/Include) +sdk_add_include_directories(config/${CHIP}) +sdk_add_include_directories(src/flash) + +if((NOT ("${CHIP}" STREQUAL "bl702")) AND (NOT ("${CHIP}" STREQUAL "bl602")) AND (NOT ("${CHIP}" STREQUAL "bl702l"))) +sdk_library_add_sources(include/arch/risc-v/t-head/rv_hart.c) +sdk_library_add_sources(include/arch/risc-v/t-head/rv_pmp.c) +endif() + +sdk_library_add_sources(config/${CHIP}/device_table.c) + +string(TOUPPER ${CHIP} CHIPNAME) +sdk_add_compile_definitions(-D${CHIPNAME}) + +if(CPU_ID) +string(TOUPPER ${CPU_ID} CPU_ID_NAME) +sdk_add_compile_definitions(-DCPU_${CPU_ID_NAME}) +endif() + +if((NOT ("${CPU_ID}" STREQUAL "d0")) AND (NOT ("${CPU_ID}" STREQUAL "lp"))) +sdk_add_static_library(src/pka/libpka.a) +endif() +# add_subdirectory(src/pka) +if(("${CHIP}" STREQUAL "bl616") OR ("${CHIP}" STREQUAL "bl628")) +# sdk_add_static_library(src/pec/libpec.a) +#add_subdirectory(src/pec) +endif() diff --git a/arch/riscv32/bl808/src/drivers/lhal/Doxyfile b/arch/riscv32/bl808/src/drivers/lhal/Doxyfile new file mode 100644 index 00000000..40709eb2 --- /dev/null +++ b/arch/riscv32/bl808/src/drivers/lhal/Doxyfile @@ -0,0 +1,2768 @@ +# Doxyfile 1.9.5 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). +# +# Note: +# +# Use doxygen to compare the used configuration file with the template +# configuration file: +# doxygen -x [configFile] +# Use doxygen to compare the used configuration file with the template +# configuration file without replacing the environment variables or CMake type +# replacement variables: +# doxygen -x_noenv [configFile] + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "LHAL Driver" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = 1.0 + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "LHAL Drivers for bouffalolab Series MicroController" + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = doc + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096 +# sub-directories (in 2 levels) under the output directory of each output format +# and will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to +# control the number of sub-directories. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# Controls the number of sub-directories that will be created when +# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every +# level increment doubles the number of directories, resulting in 4096 +# directories at level 8 which is the default and also the maximum value. The +# sub-directories are organized in 2 levels, the first level always has a fixed +# numer of 16 directories. +# Minimum value: 0, maximum value: 8, default value: 8. +# This tag requires that the tag CREATE_SUBDIRS is set to YES. + +CREATE_SUBDIRS_LEVEL = 8 + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian, +# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English +# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek, +# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with +# English messages), Korean, Korean-en (Korean with English messages), Latvian, +# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, +# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, +# Swedish, Turkish, Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = Chinese + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# By default Python docstrings are displayed as preformatted text and doxygen's +# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the +# doxygen's special commands can be used and the contents of the docstring +# documentation blocks is shown as doxygen documentation. +# The default value is: YES. + +PYTHON_DOCSTRING = YES + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:^^" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". Note that you cannot put \n's in the value part of an alias +# to insert newlines (in the resulting output). You can put ^^ in the value part +# of an alias to insert a newline as if a physical newline was in the original +# file. When you need a literal { or } or , in the value part of an alias you +# have to escape them by means of a backslash (\), this can lead to conflicts +# with the commands \{ and \} for these it is advised to use the version @{ and +# @} or use a double escape (\\{ and \\}) + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, +# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice, +# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files). For instance to make doxygen treat .inc files +# as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. When specifying no_extension you should add +# * to the FILE_PATTERNS. +# +# Note see also the list of default file extension mappings. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See https://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 5. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 5 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use +# during processing. When set to 0 doxygen will based this on the number of +# cores available in the system. You can set it explicitly to a value larger +# than 0 to get more control over the balance between CPU load and processing +# speed. At this moment only the input processing can be done using multiple +# threads. Since this is still an experimental feature the default is set to 1, +# which effectively disables parallel processing. Please report any issues you +# encounter. Generating dot graphs in parallel is controlled by the +# DOT_NUM_THREADS setting. +# Minimum value: 0, maximum value: 32, default value: 1. + +NUM_PROC_THREADS = 1 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = YES + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = YES + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If this flag is set to YES, the name of an unnamed parameter in a declaration +# will be determined by the corresponding definition. By default unnamed +# parameters remain unnamed in the output. +# The default value is: YES. + +RESOLVE_UNNAMED_PARAMS = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# declarations. If set to NO, these declarations will be included in the +# documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# With the correct setting of option CASE_SENSE_NAMES doxygen will better be +# able to match the capabilities of the underlying filesystem. In case the +# filesystem is case sensitive (i.e. it supports files in the same directory +# whose names only differ in casing), the option must be set to YES to properly +# deal with such files in case they appear in the input. For filesystems that +# are not case sensitive the option should be set to NO to properly deal with +# output files written for symbols that only differ in casing, such as for two +# classes, one named CLASS and the other named Class, and to also support +# references to files without having to specify the exact matching casing. On +# Windows (including Cygwin) and MacOS, users should typically set this option +# to NO, whereas on Linux or other Unix flavors it should typically be set to +# YES. +# Possible values are: SYSTEM, NO and YES. +# The default value is: SYSTEM. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = YES + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class +# will show which file needs to be included to use the class. +# The default value is: YES. + +SHOW_HEADERFILE = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. See also section "Changing the +# layout of pages" for information. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as documenting some parameters in +# a documented function twice, or documenting parameters that don't exist or +# using markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete +# function parameter documentation. If set to NO, doxygen will accept that some +# parameters have no documentation without warning. +# The default value is: YES. + +WARN_IF_INCOMPLETE_DOC = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong parameter +# documentation, but not about the absence of documentation. If EXTRACT_ALL is +# set to YES then this flag will automatically be disabled. See also +# WARN_IF_INCOMPLETE_DOC +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS +# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but +# at the end of the doxygen process doxygen will return with a non-zero status. +# Possible values are: NO, YES and FAIL_ON_WARNINGS. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# See also: WARN_LINE_FORMAT +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# In the $text part of the WARN_FORMAT command it is possible that a reference +# to a more specific place is given. To make it easier to jump to this place +# (outside of doxygen) the user can define a custom "cut" / "paste" string. +# Example: +# WARN_LINE_FORMAT = "'vi $file +$line'" +# See also: WARN_FORMAT +# The default value is: at line $line of file $file. + +WARN_LINE_FORMAT = "at line $line of file $file" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). In case the file specified cannot be opened for writing the +# warning and error messages are written to standard error. When as file - is +# specified the warning and error messages are written to standard output +# (stdout). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = include + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: +# https://www.gnu.org/software/libiconv/) for the list of possible encodings. +# See also: INPUT_FILE_ENCODING +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify +# character encoding on a per file pattern basis. Doxygen will compare the file +# name with each pattern and apply the encoding instead of the default +# INPUT_ENCODING) if there is a match. The character encodings are a list of the +# form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding +# "INPUT_ENCODING" for further information on supported encodings. + +INPUT_FILE_ENCODING = + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# Note the list of default checked file patterns might differ from the list of +# default file extension mappings. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, +# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C +# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, +# *.vhdl, *.ucf, *.qsf and *.ice. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.idl \ + *.ddl \ + *.odl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.cs \ + *.d \ + *.php \ + *.php4 \ + *.php5 \ + *.phtml \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.pyw \ + *.f90 \ + *.f95 \ + *.f03 \ + *.f08 \ + *.f18 \ + *.f \ + *.for \ + *.vhd \ + *.vhdl \ + *.ucf \ + *.qsf \ + *.ice + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# ANamespace::AClass, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that doxygen will use the data processed and written to standard output +# for further processing, therefore nothing else, like debug statements or used +# commands (so in case of a Windows batch file always use @echo OFF), should be +# written to standard output. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +# The Fortran standard specifies that for fixed formatted Fortran code all +# characters from position 72 are to be considered as comment. A common +# extension is to allow longer lines before the automatic comment starts. The +# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can +# be processed before the automatic comment starts. +# Minimum value: 7, maximum value: 10000, default value: 72. + +FORTRAN_COMMENT_AFTER = 72 + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# entity all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see https://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the +# clang parser (see: +# http://clang.llvm.org/) for more accurate parsing at the cost of reduced +# performance. This can be particularly helpful with template rich C++ code for +# which doxygen's built-in parser lacks the necessary type information. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = NO + +# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS +# tag is set to YES then doxygen will add the directory of each input to the +# include path. +# The default value is: YES. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_ADD_INC_PATHS = YES + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + +# If clang assisted parsing is enabled you can provide the clang parser with the +# path to the directory containing a file called compile_commands.json. This +# file is the compilation database (see: +# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the +# options used when the source files were built. This is equivalent to +# specifying the -p option to a clang tool, such as clang-check. These options +# will then be passed to the parser. Any options specified with CLANG_OPTIONS +# will be added as well. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. + +CLANG_DATABASE_PATH = + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output +# should be rendered with a dark or light theme. Default setting AUTO_LIGHT +# enables light output unless the user preference is dark output. Other options +# are DARK to always use dark mode, LIGHT to always use light mode, AUTO_DARK to +# default to dark mode unless the user prefers light mode, and TOGGLE to let the +# user toggle between dark and light mode via a button. +# Possible values are: LIGHT Always generate light output., DARK Always generate +# dark output., AUTO_LIGHT Automatically set the mode according to the user +# preference, use light mode if no preference is set (the default)., AUTO_DARK +# Automatically set the mode according to the user preference, use dark mode if +# no preference is set. and TOGGLE Allow to user to switch between light and +# dark mode via a button.. +# The default value is: AUTO_LIGHT. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE = AUTO_LIGHT + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a color-wheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 234 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use gray-scales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 35 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 110 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via JavaScript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have JavaScript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: +# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To +# create a documentation set, doxygen will generate a Makefile in the HTML +# output directory. Running make will produce the docset in that directory and +# running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag determines the URL of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDURL = + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# on Windows. In the beginning of 2021 Microsoft took the original page, with +# a.o. the download links, offline the HTML help workshop was already many years +# in maintenance mode). You can download the HTML help workshop from the web +# archives at Installation executable (see: +# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo +# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe). +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the main .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location (absolute path +# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to +# run qhelpgenerator on the generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine tune the look of the index (see "Fine-tuning the output"). As an +# example, the default style sheet generated by doxygen has an example that +# shows how to put an image at the root of the tree instead of the PROJECT_NAME. +# Since the tree basically has the same information as the tab index, you could +# consider setting DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = YES + +# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the +# FULL_SIDEBAR option determines if the side bar is limited to only the treeview +# area (value NO) or if it should extend to the full height of the window (value +# YES). Setting this to YES gives a layout similar to +# https://docs.readthedocs.io with more room for contents, but less room for the +# project logo, title, and description. If either GENERATE_TREEVIEW or +# DISABLE_INDEX is set to NO, this option has no effect. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FULL_SIDEBAR = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email +# addresses. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +OBFUSCATE_EMAILS = YES + +# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg +# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see +# https://inkscape.org) to generate formulas as SVG images instead of PNGs for +# the HTML output. These images will generally look nicer at scaled resolutions. +# Possible values are: png (the default) and svg (looks nicer but requires the +# pdf2svg or inkscape tool). +# The default value is: png. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FORMULA_FORMAT = png + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands +# to create new LaTeX commands to be used in formulas as building blocks. See +# the section "Including formulas" for details. + +FORMULA_MACROFILE = + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# https://www.mathjax.org) which uses client side JavaScript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# With MATHJAX_VERSION it is possible to specify the MathJax version to be used. +# Note that the different versions of MathJax have different requirements with +# regards to the different settings, so it is possible that also other MathJax +# settings have to be changed when switching between the different MathJax +# versions. +# Possible values are: MathJax_2 and MathJax_3. +# The default value is: MathJax_2. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_VERSION = MathJax_2 + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. For more details about the output format see MathJax +# version 2 (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3 +# (see: +# http://docs.mathjax.org/en/latest/web/components/output.html). +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility. This is the name for Mathjax version 2, for MathJax version 3 +# this will be translated into chtml), NativeMML (i.e. MathML. Only supported +# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This +# is the name for Mathjax version 3, for MathJax version 2 this will be +# translated into HTML-CSS) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from https://www.mathjax.org before deployment. The default value is: +# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2 +# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3 +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = https://cdn.jsdelivr.net/npm/mathjax@2 + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# for MathJax version 2 (see +# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions): +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# For example for MathJax version 3 (see +# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html): +# MATHJAX_EXTENSIONS = ams +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /