mirror of
https://github.com/hathach/tinyusb.git
synced 2025-01-31 05:52:55 +08:00
Add BSP support for F1C100s
This commit is contained in:
parent
dff54d854d
commit
68ca62dfd7
@ -182,6 +182,11 @@ flash-jlink: $(BUILD)/$(PROJECT).hex
|
||||
flash-stlink: $(BUILD)/$(PROJECT).elf
|
||||
STM32_Programmer_CLI --connect port=swd --write $< --go
|
||||
|
||||
flash-xfel: $(BUILD)/$(PROJECT).bin
|
||||
xfel ddr
|
||||
xfel write 0x80000000 $<
|
||||
xfel exec 0x80000000
|
||||
|
||||
# Flash using pyocd
|
||||
PYOCD_OPTION ?=
|
||||
flash-pyocd: $(BUILD)/$(PROJECT).hex
|
||||
|
17
hw/bsp/f1c100s/README.md
Normal file
17
hw/bsp/f1c100s/README.md
Normal file
@ -0,0 +1,17 @@
|
||||
# BSP support for F1Cx00s boards
|
||||
|
||||
This folder contains necessary file and scripts to run TinyUSB examples on F1Cx00s boards.
|
||||
|
||||
Currently tested on:
|
||||
|
||||
* Lichee Pi Nano (F1C100s)
|
||||
|
||||
## make flash
|
||||
`make flash` will use [xfel](https://github.com/xboot/xfel) to write the code to onchip DDR memory and execute it. It will not write the program to SPI Flash.
|
||||
|
||||
To enter FEL mode, you have to press BOOT button, then press RESET once, and release BOOT button. You will find VID/PID=1f3a:efe8 on your PC.
|
||||
|
||||
## TODO
|
||||
* Test on Tiny200 v2 (F1C200s)
|
||||
* Make it able to load .bin directly to SPI Flash and boot
|
||||
* Add F1C100s to `#if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX` high speed MCU check in examples (maybe we should extract the logic?)
|
1
hw/bsp/f1c100s/board.h
Normal file
1
hw/bsp/f1c100s/board.h
Normal file
@ -0,0 +1 @@
|
||||
// Nothing valuable here
|
45
hw/bsp/f1c100s/board.mk
Normal file
45
hw/bsp/f1c100s/board.mk
Normal file
@ -0,0 +1,45 @@
|
||||
DEFINES += -D__ARM32_ARCH__=5 -D__ARM926EJS__
|
||||
|
||||
CFLAGS += \
|
||||
-ffreestanding \
|
||||
-std=gnu99 \
|
||||
-march=armv5te \
|
||||
-mtune=arm926ej-s \
|
||||
-mfloat-abi=soft \
|
||||
-marm \
|
||||
-mno-thumb-interwork \
|
||||
-Wno-unused-parameter \
|
||||
-Wno-float-equal \
|
||||
-DCFG_TUSB_MCU=OPT_MCU_F1C100S \
|
||||
-Wno-error=cast-align \
|
||||
-Wno-error=address-of-packed-member \
|
||||
$(DEFINES)
|
||||
|
||||
LD_FILE = hw/mcu/allwinner/f1c100s/f1c100s.ld
|
||||
LDFLAGS += -nostdlib -lgcc
|
||||
MCU_DIR = hw/mcu/allwinner/f1c100s
|
||||
|
||||
SRC_C += \
|
||||
src/portable/sunxi/dcd_sunxi_musb.c \
|
||||
$(MCU_DIR)/machine/sys-uart.c \
|
||||
$(MCU_DIR)/machine/exception.c \
|
||||
$(MCU_DIR)/machine/sys-clock.c \
|
||||
$(MCU_DIR)/machine/sys-copyself.c \
|
||||
$(MCU_DIR)/machine/sys-dram.c \
|
||||
$(MCU_DIR)/machine/sys-mmu.c \
|
||||
$(MCU_DIR)/machine/sys-spi-flash.c \
|
||||
$(MCU_DIR)/machine/f1c100s-intc.c \
|
||||
$(MCU_DIR)/lib/malloc.c \
|
||||
$(MCU_DIR)/lib/printf.c
|
||||
|
||||
SRC_S += \
|
||||
$(MCU_DIR)/machine/start.S \
|
||||
$(MCU_DIR)/lib/memcpy.S \
|
||||
$(MCU_DIR)/lib/memset.S
|
||||
|
||||
INC += \
|
||||
$(TOP)/$(MCU_DIR)/include \
|
||||
$(TOP)/$(BOARD_PATH)
|
||||
|
||||
# flash target using on-board stlink
|
||||
flash: flash-xfel
|
130
hw/bsp/f1c100s/f1c100s.c
Normal file
130
hw/bsp/f1c100s/f1c100s.c
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <malloc.h>
|
||||
#include <irqflags.h>
|
||||
#include <f1c100s-irq.h>
|
||||
#include "bsp/board.h"
|
||||
#include "board.h"
|
||||
|
||||
extern void sys_uart_putc(char c);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Board porting API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
static void timer_init(void);
|
||||
|
||||
void board_init(void)
|
||||
{
|
||||
arch_local_irq_disable();
|
||||
do_init_mem_pool();
|
||||
f1c100s_intc_init();
|
||||
timer_init();
|
||||
printf("Timer INIT done\n");
|
||||
arch_local_irq_enable();
|
||||
}
|
||||
|
||||
// No LED, no button, sorry
|
||||
void board_led_write(bool state)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
uint32_t board_button_read(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int board_uart_read(uint8_t* buf, int len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int board_uart_write(void const * buf, int len)
|
||||
{
|
||||
int txsize = len;
|
||||
while (txsize--) {
|
||||
sys_uart_putc(*(uint8_t const*)buf);
|
||||
buf++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
#if CFG_TUSB_OS == OPT_OS_NONE
|
||||
volatile uint32_t system_ticks = 0;
|
||||
|
||||
uint32_t board_millis(void)
|
||||
{
|
||||
return system_ticks;
|
||||
}
|
||||
|
||||
static void timer_handler(void)
|
||||
{
|
||||
volatile uint32_t *temp_addr = (uint32_t *)(0x01C20C00 + 0x04);
|
||||
|
||||
/* clear timer */
|
||||
*temp_addr |= 0x01;
|
||||
|
||||
system_ticks++;
|
||||
}
|
||||
|
||||
static void timer_init(void) {
|
||||
uint32_t temp;
|
||||
volatile uint32_t *temp_addr;
|
||||
|
||||
/* reload value */
|
||||
temp = 12000000 / 1000;
|
||||
temp_addr = (uint32_t *)(0x01C20C00 + 0x14);
|
||||
*temp_addr = temp;
|
||||
|
||||
/* continuous | /2 | 24Mhz | reload*/
|
||||
temp = (0x00 << 7) | (0x01 << 4) | (0x01 << 2) | (0x00 << 1);
|
||||
temp_addr = (uint32_t *)(0x01C20C00 + 0x10);
|
||||
*temp_addr &= 0xffffff00;
|
||||
*temp_addr |= temp;
|
||||
|
||||
/* open timer irq */
|
||||
temp = 0x01 << 0;
|
||||
temp_addr = (uint32_t *)(0x01C20C00);
|
||||
*temp_addr |= temp;
|
||||
|
||||
/* set init value */
|
||||
temp_addr = (uint32_t *)(0x01C20C00 + 0x18);
|
||||
*temp_addr = 0;
|
||||
|
||||
/* begin run timer */
|
||||
temp = 0x01 << 0;
|
||||
temp_addr = (uint32_t *)(0x01C20C00 + 0x10);
|
||||
*temp_addr |= temp;
|
||||
|
||||
f1c100s_intc_set_isr(F1C100S_IRQ_TIMER0, timer_handler);
|
||||
f1c100s_intc_enable_irq(F1C100S_IRQ_TIMER0);
|
||||
}
|
||||
#else
|
||||
static void timer_init(void) { }
|
||||
#endif
|
137
hw/mcu/allwinner/f1c100s/f1c100s.ld
Normal file
137
hw/mcu/allwinner/f1c100s/f1c100s.ld
Normal file
@ -0,0 +1,137 @@
|
||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
|
||||
OUTPUT_ARCH(arm)
|
||||
ENTRY(_start)
|
||||
|
||||
STACK_UND_SIZE = 0x10000;
|
||||
STACK_ABT_SIZE = 0x10000;
|
||||
STACK_IRQ_SIZE = 0x10000;
|
||||
STACK_FIQ_SIZE = 0x10000;
|
||||
STACK_SRV_SIZE = 0x40000;
|
||||
|
||||
MEMORY
|
||||
{
|
||||
ram : org = 0x80000000, len = 8M
|
||||
heap : org = 0x81000000, len = 16M
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.bootloader :
|
||||
{
|
||||
PROVIDE(__bootloader_start = .);
|
||||
PROVIDE(__image_start = .);
|
||||
PROVIDE(__text_start = .);
|
||||
*/machine/start.o (.text)
|
||||
*/lib/memcpy.o (.text)
|
||||
*/lib/memset.o (.text)
|
||||
*/machine/sys-uart.o (.text)
|
||||
*/machine/sys-clock.o (.text)
|
||||
*/machine/sys-dram.o (.text)
|
||||
*/machine/sys-mmu.o (.text)
|
||||
*/machine/sys-spi-flash.o (.text)
|
||||
*/machine/sys-copyself.o (.text)
|
||||
PROVIDE(__bootloader_end = .);
|
||||
} > ram
|
||||
|
||||
__bootloader_size = SIZEOF(.bootloader);
|
||||
|
||||
.text :
|
||||
{
|
||||
*/main.o (.text)
|
||||
*(.text*)
|
||||
*(.glue*)
|
||||
*(.note.gnu.build-id)
|
||||
PROVIDE(__text_end = .);
|
||||
} > ram
|
||||
|
||||
.rodata ALIGN(8) :
|
||||
{
|
||||
PROVIDE(__rodata_start = .);
|
||||
*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
|
||||
PROVIDE(__rodata_end = .);
|
||||
} > ram
|
||||
|
||||
.data_shadow ALIGN(8) :
|
||||
{
|
||||
PROVIDE(__data_shadow_start = .);
|
||||
PROVIDE(__data_shadow_end = (. + SIZEOF(.data)));
|
||||
PROVIDE(__image_end = __data_shadow_end);
|
||||
} > ram
|
||||
|
||||
.data : AT(ADDR(.data_shadow))
|
||||
{
|
||||
PROVIDE(__data_start = .);
|
||||
*(.data*)
|
||||
. = ALIGN(8);
|
||||
PROVIDE(__data_end = .);
|
||||
} > ram
|
||||
|
||||
.ARM.exidx ALIGN(8) :
|
||||
{
|
||||
PROVIDE (__exidx_start = .);
|
||||
*(.ARM.exidx*)
|
||||
PROVIDE (__exidx_end = .);
|
||||
} > ram
|
||||
|
||||
.ARM.extab ALIGN(8) :
|
||||
{
|
||||
PROVIDE (__extab_start = .);
|
||||
*(.ARM.extab*)
|
||||
PROVIDE (__extab_end = .);
|
||||
} > ram
|
||||
|
||||
.bss ALIGN(8) (NOLOAD) :
|
||||
{
|
||||
PROVIDE(__bss_start = .);
|
||||
*(.bss*)
|
||||
*(.sbss*)
|
||||
*(COMMON)
|
||||
. = ALIGN(8);
|
||||
PROVIDE(__bss_end = .);
|
||||
} > ram
|
||||
|
||||
.stack ALIGN(8) (NOLOAD) :
|
||||
{
|
||||
PROVIDE(__stack_start = .);
|
||||
PROVIDE(__stack_und_start = .);
|
||||
. += STACK_UND_SIZE;
|
||||
PROVIDE(__stack_und_end = .);
|
||||
. = ALIGN(8);
|
||||
PROVIDE(__stack_abt_start = .);
|
||||
. += STACK_ABT_SIZE;
|
||||
PROVIDE(__stack_abt_end = .);
|
||||
. = ALIGN(8);
|
||||
PROVIDE(__stack_irq_start = .);
|
||||
. += STACK_IRQ_SIZE;
|
||||
PROVIDE(__stack_irq_end = .);
|
||||
. = ALIGN(8);
|
||||
PROVIDE(__stack_fiq_start = .);
|
||||
. += STACK_FIQ_SIZE;
|
||||
PROVIDE(__stack_fiq_end = .);
|
||||
. = ALIGN(8);
|
||||
PROVIDE(__stack_srv_start = .);
|
||||
. += STACK_SRV_SIZE;
|
||||
PROVIDE(__stack_srv_end = .);
|
||||
. = ALIGN(8);
|
||||
PROVIDE(__stack_end = .);
|
||||
} > ram
|
||||
|
||||
.heap ALIGN(8) (NOLOAD) :
|
||||
{
|
||||
PROVIDE(__heap_start = ORIGIN(heap));
|
||||
PROVIDE(__heap_end = ORIGIN(heap) + LENGTH(heap));
|
||||
} > heap
|
||||
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
.comment 0 : { *(.comment) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_info 0 : { *(.debug_info) }
|
||||
.debug_line 0 : { *(.debug_line) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
}
|
150
hw/mcu/allwinner/f1c100s/include/arm32.h
Normal file
150
hw/mcu/allwinner/f1c100s/include/arm32.h
Normal file
@ -0,0 +1,150 @@
|
||||
#ifndef __ARM32_H__
|
||||
#define __ARM32_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct arm_regs_t {
|
||||
uint32_t r[13];
|
||||
uint32_t sp;
|
||||
uint32_t lr;
|
||||
uint32_t pc;
|
||||
uint32_t cpsr;
|
||||
};
|
||||
|
||||
static inline uint32_t arm32_read_p15_c1(void)
|
||||
{
|
||||
uint32_t value;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"mrc p15, 0, %0, c1, c0, 0"
|
||||
: "=r" (value)
|
||||
:
|
||||
: "memory");
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static inline void arm32_write_p15_c1(uint32_t value)
|
||||
{
|
||||
__asm__ __volatile__(
|
||||
"mcr p15, 0, %0, c1, c0, 0"
|
||||
:
|
||||
: "r" (value)
|
||||
: "memory");
|
||||
arm32_read_p15_c1();
|
||||
}
|
||||
|
||||
static inline void arm32_interrupt_enable(void)
|
||||
{
|
||||
uint32_t tmp;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"mrs %0, cpsr\n"
|
||||
"bic %0, %0, #(1<<7)\n"
|
||||
"msr cpsr_cxsf, %0"
|
||||
: "=r" (tmp)
|
||||
:
|
||||
: "memory");
|
||||
}
|
||||
|
||||
static inline void arm32_interrupt_disable(void)
|
||||
{
|
||||
uint32_t tmp;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"mrs %0, cpsr\n"
|
||||
"orr %0, %0, #(1<<7)\n"
|
||||
"msr cpsr_cxsf, %0"
|
||||
: "=r" (tmp)
|
||||
:
|
||||
: "memory");
|
||||
}
|
||||
|
||||
static inline void arm32_mmu_enable(void)
|
||||
{
|
||||
uint32_t value = arm32_read_p15_c1();
|
||||
arm32_write_p15_c1(value | (1 << 0));
|
||||
}
|
||||
|
||||
static inline void arm32_mmu_disable(void)
|
||||
{
|
||||
uint32_t value = arm32_read_p15_c1();
|
||||
arm32_write_p15_c1(value & ~(1 << 0));
|
||||
}
|
||||
|
||||
static inline void arm32_dcache_enable(void)
|
||||
{
|
||||
uint32_t value = arm32_read_p15_c1();
|
||||
arm32_write_p15_c1(value | (1 << 2));
|
||||
}
|
||||
|
||||
static inline void arm32_dcache_disable(void)
|
||||
{
|
||||
uint32_t value = arm32_read_p15_c1();
|
||||
arm32_write_p15_c1(value & ~(1 << 2));
|
||||
}
|
||||
|
||||
static inline void arm32_icache_enable(void)
|
||||
{
|
||||
uint32_t value = arm32_read_p15_c1();
|
||||
arm32_write_p15_c1(value | (1 << 12));
|
||||
}
|
||||
|
||||
static inline void arm32_icache_disable(void)
|
||||
{
|
||||
uint32_t value = arm32_read_p15_c1();
|
||||
arm32_write_p15_c1(value & ~(1 << 12));
|
||||
}
|
||||
|
||||
static inline uint32_t arm32_smp_processor_id(void)
|
||||
{
|
||||
uint32_t tmp;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"mrc p15,0,%0,c0,c0,5\n"
|
||||
"and %0,%0,#0x3\n"
|
||||
: "=r" (tmp)
|
||||
:
|
||||
: "memory");
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static inline void arm32_ttb_set(uint32_t base)
|
||||
{
|
||||
__asm__ __volatile__(
|
||||
"mcr p15, 0, %0, c2, c0, 0"
|
||||
:
|
||||
: "r" (base)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
static inline void arm32_domain_set(uint32_t domain)
|
||||
{
|
||||
__asm__ __volatile__(
|
||||
"mcr p15, 0, %0, c3, c0, 0"
|
||||
:
|
||||
: "r" (domain)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
static inline void arm32_tlb_invalidate(void)
|
||||
{
|
||||
__asm__ __volatile__(
|
||||
"mov r0, #0\n"
|
||||
"mcr p15, 0, r0, c7, c10, 4\n"
|
||||
"mcr p15, 0, r0, c8, c6, 0\n"
|
||||
"mcr p15, 0, r0, c8, c5, 0\n"
|
||||
:
|
||||
:
|
||||
: "r0");
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ARM32_H__ */
|
66
hw/mcu/allwinner/f1c100s/include/f1c100s-gpio.h
Normal file
66
hw/mcu/allwinner/f1c100s/include/f1c100s-gpio.h
Normal file
@ -0,0 +1,66 @@
|
||||
#ifndef __F1C100S_GPIO_H__
|
||||
#define __F1C100S_GPIO_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define F1C100S_GPIOA0 (0)
|
||||
#define F1C100S_GPIOA1 (1)
|
||||
#define F1C100S_GPIOA2 (2)
|
||||
#define F1C100S_GPIOA3 (3)
|
||||
|
||||
#define F1C100S_GPIOC0 (64)
|
||||
#define F1C100S_GPIOC1 (65)
|
||||
#define F1C100S_GPIOC2 (66)
|
||||
#define F1C100S_GPIOC3 (67)
|
||||
|
||||
#define F1C100S_GPIOD0 (96)
|
||||
#define F1C100S_GPIOD1 (97)
|
||||
#define F1C100S_GPIOD2 (98)
|
||||
#define F1C100S_GPIOD3 (99)
|
||||
#define F1C100S_GPIOD4 (100)
|
||||
#define F1C100S_GPIOD5 (101)
|
||||
#define F1C100S_GPIOD6 (102)
|
||||
#define F1C100S_GPIOD7 (103)
|
||||
#define F1C100S_GPIOD8 (104)
|
||||
#define F1C100S_GPIOD9 (105)
|
||||
#define F1C100S_GPIOD10 (106)
|
||||
#define F1C100S_GPIOD11 (107)
|
||||
#define F1C100S_GPIOD12 (108)
|
||||
#define F1C100S_GPIOD13 (109)
|
||||
#define F1C100S_GPIOD14 (110)
|
||||
#define F1C100S_GPIOD15 (111)
|
||||
#define F1C100S_GPIOD16 (112)
|
||||
#define F1C100S_GPIOD17 (113)
|
||||
#define F1C100S_GPIOD18 (114)
|
||||
#define F1C100S_GPIOD19 (115)
|
||||
#define F1C100S_GPIOD20 (116)
|
||||
#define F1C100S_GPIOD21 (117)
|
||||
|
||||
#define F1C100S_GPIOE0 (128)
|
||||
#define F1C100S_GPIOE1 (129)
|
||||
#define F1C100S_GPIOE2 (130)
|
||||
#define F1C100S_GPIOE3 (131)
|
||||
#define F1C100S_GPIOE4 (132)
|
||||
#define F1C100S_GPIOE5 (133)
|
||||
#define F1C100S_GPIOE6 (134)
|
||||
#define F1C100S_GPIOE7 (135)
|
||||
#define F1C100S_GPIOE8 (136)
|
||||
#define F1C100S_GPIOE9 (137)
|
||||
#define F1C100S_GPIOE10 (138)
|
||||
#define F1C100S_GPIOE11 (139)
|
||||
#define F1C100S_GPIOE12 (140)
|
||||
|
||||
#define F1C100S_GPIOF0 (160)
|
||||
#define F1C100S_GPIOF1 (161)
|
||||
#define F1C100S_GPIOF2 (162)
|
||||
#define F1C100S_GPIOF3 (163)
|
||||
#define F1C100S_GPIOF4 (164)
|
||||
#define F1C100S_GPIOF5 (165)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __F1C100S_GPIO_H__ */
|
104
hw/mcu/allwinner/f1c100s/include/f1c100s-irq.h
Normal file
104
hw/mcu/allwinner/f1c100s/include/f1c100s-irq.h
Normal file
@ -0,0 +1,104 @@
|
||||
#ifndef __F1C100S_IRQ_H__
|
||||
#define __F1C100S_IRQ_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define F1C100S_IRQ_NMI (0)
|
||||
#define F1C100S_IRQ_UART0 (1)
|
||||
#define F1C100S_IRQ_UART1 (2)
|
||||
#define F1C100S_IRQ_UART2 (3)
|
||||
#define F1C100S_IRQ_SPDIF (5)
|
||||
#define F1C100S_IRQ_CIR (6)
|
||||
#define F1C100S_IRQ_I2C0 (7)
|
||||
#define F1C100S_IRQ_I2C1 (8)
|
||||
#define F1C100S_IRQ_I2C2 (9)
|
||||
#define F1C100S_IRQ_SPI0 (10)
|
||||
#define F1C100S_IRQ_SPI1 (11)
|
||||
#define F1C100S_IRQ_TIMER0 (13)
|
||||
#define F1C100S_IRQ_TIMER1 (14)
|
||||
#define F1C100S_IRQ_TIMER2 (15)
|
||||
#define F1C100S_IRQ_WDOG (16)
|
||||
#define F1C100S_IRQ_RSB (17)
|
||||
#define F1C100S_IRQ_DMA (18)
|
||||
#define F1C100S_IRQ_TP (20)
|
||||
#define F1C100S_IRQ_AUDIO (21)
|
||||
#define F1C100S_IRQ_LRADC (22)
|
||||
#define F1C100S_IRQ_MMC0 (23)
|
||||
#define F1C100S_IRQ_MMC1 (24)
|
||||
#define F1C100S_IRQ_USBOTG (26)
|
||||
#define F1C100S_IRQ_TVD (27)
|
||||
#define F1C100S_IRQ_TVE (28)
|
||||
#define F1C100S_IRQ_LCD (29)
|
||||
#define F1C100S_IRQ_DEFE (30)
|
||||
#define F1C100S_IRQ_DEBE (31)
|
||||
#define F1C100S_IRQ_CSI (32)
|
||||
#define F1C100S_IRQ_DEITLA (33)
|
||||
#define F1C100S_IRQ_VE (34)
|
||||
#define F1C100S_IRQ_I2S (35)
|
||||
#define F1C100S_IRQ_GPIOD (38)
|
||||
#define F1C100S_IRQ_GPIOE (39)
|
||||
#define F1C100S_IRQ_GPIOF (40)
|
||||
|
||||
#define F1C100S_IRQ_GPIOD0 (64)
|
||||
#define F1C100S_IRQ_GPIOD1 (65)
|
||||
#define F1C100S_IRQ_GPIOD2 (66)
|
||||
#define F1C100S_IRQ_GPIOD3 (67)
|
||||
#define F1C100S_IRQ_GPIOD4 (68)
|
||||
#define F1C100S_IRQ_GPIOD5 (69)
|
||||
#define F1C100S_IRQ_GPIOD6 (70)
|
||||
#define F1C100S_IRQ_GPIOD7 (71)
|
||||
#define F1C100S_IRQ_GPIOD8 (72)
|
||||
#define F1C100S_IRQ_GPIOD9 (73)
|
||||
#define F1C100S_IRQ_GPIOD10 (74)
|
||||
#define F1C100S_IRQ_GPIOD11 (75)
|
||||
#define F1C100S_IRQ_GPIOD12 (76)
|
||||
#define F1C100S_IRQ_GPIOD13 (77)
|
||||
#define F1C100S_IRQ_GPIOD14 (78)
|
||||
#define F1C100S_IRQ_GPIOD15 (79)
|
||||
#define F1C100S_IRQ_GPIOD17 (80)
|
||||
#define F1C100S_IRQ_GPIOD18 (81)
|
||||
#define F1C100S_IRQ_GPIOD19 (82)
|
||||
#define F1C100S_IRQ_GPIOD20 (83)
|
||||
#define F1C100S_IRQ_GPIOD21 (84)
|
||||
|
||||
#define F1C100S_IRQ_GPIOE0 (96)
|
||||
#define F1C100S_IRQ_GPIOE1 (97)
|
||||
#define F1C100S_IRQ_GPIOE2 (98)
|
||||
#define F1C100S_IRQ_GPIOE3 (99)
|
||||
#define F1C100S_IRQ_GPIOE4 (100)
|
||||
#define F1C100S_IRQ_GPIOE5 (101)
|
||||
#define F1C100S_IRQ_GPIOE6 (102)
|
||||
#define F1C100S_IRQ_GPIOE7 (103)
|
||||
#define F1C100S_IRQ_GPIOE8 (104)
|
||||
#define F1C100S_IRQ_GPIOE9 (105)
|
||||
#define F1C100S_IRQ_GPIOE10 (106)
|
||||
#define F1C100S_IRQ_GPIOE11 (107)
|
||||
#define F1C100S_IRQ_GPIOE12 (108)
|
||||
|
||||
#define F1C100S_IRQ_GPIOF0 (128)
|
||||
#define F1C100S_IRQ_GPIOF1 (129)
|
||||
#define F1C100S_IRQ_GPIOF2 (130)
|
||||
#define F1C100S_IRQ_GPIOF3 (131)
|
||||
#define F1C100S_IRQ_GPIOF4 (132)
|
||||
#define F1C100S_IRQ_GPIOF5 (133)
|
||||
|
||||
typedef void (*IRQHandleTypeDef)(void);
|
||||
|
||||
uint8_t f1c100s_intc_get_nirq(void);
|
||||
void f1c100s_intc_dispatch(uint8_t nIRQ);
|
||||
void f1c100s_intc_set_isr(uint8_t nIRQ, IRQHandleTypeDef handle);
|
||||
void f1c100s_intc_enable_irq(uint8_t nIRQ);
|
||||
void f1c100s_intc_disable_irq(uint8_t nIRQ);
|
||||
void f1c100s_intc_unmask_irq(uint8_t nIRQ);
|
||||
void f1c100s_intc_mask_irq(uint8_t nIRQ);
|
||||
void f1c100s_intc_force_irq(uint8_t nIRQ);
|
||||
void f1c100s_intc_clear_pend(uint8_t nIRQ);
|
||||
void f1c100s_intc_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __F1C100S_IRQ_H__ */
|
39
hw/mcu/allwinner/f1c100s/include/f1c100s-reset.h
Normal file
39
hw/mcu/allwinner/f1c100s/include/f1c100s-reset.h
Normal file
@ -0,0 +1,39 @@
|
||||
#ifndef __F1C100S_RESET_H__
|
||||
#define __F1C100S_RESET_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define F1C100S_RESET_DMA (6)
|
||||
#define F1C100S_RESET_SD0 (8)
|
||||
#define F1C100S_RESET_SD1 (9)
|
||||
#define F1C100S_RESET_SDRAM (14)
|
||||
#define F1C100S_RESET_SPI0 (20)
|
||||
#define F1C100S_RESET_SPI1 (21)
|
||||
#define F1C100S_RESET_USB_OTG (24)
|
||||
#define F1C100S_RESET_VE (32)
|
||||
#define F1C100S_RESET_LCD (36)
|
||||
#define F1C100S_RESET_DEINTERLACE (37)
|
||||
#define F1C100S_RESET_CSI (40)
|
||||
#define F1C100S_RESET_TVD (41)
|
||||
#define F1C100S_RESET_TVE (42)
|
||||
#define F1C100S_RESET_DEBE (44)
|
||||
#define F1C100S_RESET_DEFE (46)
|
||||
#define F1C100S_RESET_ADDA (64)
|
||||
#define F1C100S_RESET_SPDIF (65)
|
||||
#define F1C100S_RESET_CIR (66)
|
||||
#define F1C100S_RESET_RSB (67)
|
||||
#define F1C100S_RESET_DAUDIO (76)
|
||||
#define F1C100S_RESET_I2C0 (80)
|
||||
#define F1C100S_RESET_I2C1 (81)
|
||||
#define F1C100S_RESET_I2C2 (82)
|
||||
#define F1C100S_RESET_UART0 (84)
|
||||
#define F1C100S_RESET_UART1 (85)
|
||||
#define F1C100S_RESET_UART2 (86)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __F1C100S_RESET_H__ */
|
139
hw/mcu/allwinner/f1c100s/include/f1c100s-util.h
Normal file
139
hw/mcu/allwinner/f1c100s/include/f1c100s-util.h
Normal file
@ -0,0 +1,139 @@
|
||||
// Designed by Hong Xuyao
|
||||
|
||||
#ifndef __TARGET_H__
|
||||
#define __TARGET_H__
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#include <stdint.h>
|
||||
typedef unsigned long ubase_t;
|
||||
|
||||
#define MEM_PI_SRAM __attribute__((section("SRAM")))
|
||||
|
||||
#define MEM_PI_SUMMARY __attribute__((section("SUMMARY")))
|
||||
|
||||
#define MEM_PI_NOINIT __attribute__((section("NOINIT"),zero_init))
|
||||
|
||||
#define MEM_PI_CPUONLY __attribute__((section("CPUONLY"),zero_init))
|
||||
|
||||
#define MEM_PI_HARDWARE __attribute__((section("HARDWARE"),zero_init,aligned(32)))
|
||||
|
||||
#define MEM_PI_NCNB __attribute__((section("NCNB"),zero_init,aligned(32)))
|
||||
|
||||
#define MEM_PI_STACK __attribute__((section("STACK"),zero_init,aligned(8)))
|
||||
|
||||
#define CACHE_ALIGNED __attribute__((aligned(32)))
|
||||
|
||||
#ifndef INLINE
|
||||
#define INLINE __attribute__((always_inline))
|
||||
#endif
|
||||
|
||||
#ifndef NOINLINE
|
||||
#define NOINLINE __attribute__((noinline))
|
||||
#endif
|
||||
|
||||
#ifndef NOINLINE_FUNC
|
||||
#define NOINLINE_FUNC __attribute__((noinline))
|
||||
#endif
|
||||
|
||||
#ifndef ALIGN
|
||||
#define ALIGN(n) __attribute__((aligned(n)))
|
||||
#endif
|
||||
|
||||
#define CPU_SR_DECL ubase_t cpu_sr
|
||||
|
||||
#ifdef __thumb__
|
||||
#define __SWITCH_TO_ARM__
|
||||
#pragma arm
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#define CPU_ENTER_CRITICAL() do{cpu_sr = util_enter_critical();}while(0)
|
||||
#else
|
||||
#define CPU_ENTER_CRITICAL() do{cpu_sr = __fast_enter_critical();}while(0)
|
||||
static inline ubase_t __fast_enter_critical(void)
|
||||
{
|
||||
ubase_t cpu_sr, tmp_sr;
|
||||
__asm volatile {
|
||||
MRS cpu_sr, CPSR
|
||||
ORR tmp_sr, cpu_sr, #0xC0
|
||||
MSR CPSR_c, tmp_sr
|
||||
}
|
||||
return cpu_sr;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#define CPU_EXIT_CRITICAL() do{util_exit_critical(cpu_sr);}while(0)
|
||||
#else
|
||||
#define CPU_EXIT_CRITICAL() do{__fast_exit_critical(cpu_sr);}while(0)
|
||||
static inline void __fast_exit_critical(ubase_t cpu_sr)
|
||||
{
|
||||
__asm volatile {
|
||||
MSR CPSR_c, cpu_sr
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline unsigned CPU_CLZ16(uint16_t val)
|
||||
{
|
||||
__asm volatile {
|
||||
CLZ val, val
|
||||
}
|
||||
return (val - 16);
|
||||
}
|
||||
|
||||
static inline uint8_t __swap_byte(uint8_t newval, uint8_t volatile* pmem)
|
||||
{
|
||||
uint8_t oldval;
|
||||
__asm volatile {
|
||||
SWPB oldval, newval, [pmem]
|
||||
};
|
||||
return oldval;
|
||||
}
|
||||
|
||||
static inline uint32_t UTL_REV32(uint32_t val)
|
||||
{
|
||||
uint32_t tmpval;
|
||||
__asm volatile {
|
||||
EOR tmpval, val, val, ROR #16
|
||||
MOV tmpval, tmpval, LSR #8
|
||||
BIC tmpval, tmpval, #0xFF00
|
||||
EOR val, tmpval, val, ROR #8
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline uint16_t UTL_REV16(uint16_t val)
|
||||
{
|
||||
uint32_t tmpval;
|
||||
__asm volatile {
|
||||
LSR tmpval, val, #8
|
||||
ORR val, tmpval, val, LSL #8
|
||||
BIC val, val, #0xFF0000
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
#ifdef __SWITCH_TO_ARM__
|
||||
#undef __SWITCH_TO_ARM__
|
||||
#pragma thumb
|
||||
#endif
|
||||
|
||||
#ifndef COUNTOF
|
||||
#define COUNTOF(ar) (sizeof(ar)/sizeof(ar[0]))
|
||||
#endif
|
||||
/*
|
||||
void util_halt(void);
|
||||
void util_fastloop(ubase_t n);
|
||||
ubase_t util_getCPSR(void);
|
||||
ubase_t util_enter_critical(void);
|
||||
void util_exit_critical(ubase_t sr);
|
||||
void util_enable_interrupt(void);
|
||||
void util_disable_interrupt(void);
|
||||
|
||||
void target_wdt_setup(void);
|
||||
void target_wdt_feed(void);
|
||||
void target_reset(void);
|
||||
*/
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* __TARGET_H__ */
|
||||
|
55
hw/mcu/allwinner/f1c100s/include/f1c100s/reg-ccu.h
Normal file
55
hw/mcu/allwinner/f1c100s/include/f1c100s/reg-ccu.h
Normal file
@ -0,0 +1,55 @@
|
||||
#ifndef __F1C100S_REG_CCU_H__
|
||||
#define __F1C100S_REG_CCU_H__
|
||||
|
||||
#define F1C100S_CCU_BASE (0x01c20000)
|
||||
|
||||
#define CCU_PLL_CPU_CTRL (0x000)
|
||||
#define CCU_PLL_AUDIO_CTRL (0x008)
|
||||
#define CCU_PLL_VIDEO_CTRL (0x010)
|
||||
#define CCU_PLL_VE_CTRL (0x018)
|
||||
#define CCU_PLL_DDR_CTRL (0x020)
|
||||
#define CCU_PLL_PERIPH_CTRL (0x028)
|
||||
#define CCU_CPU_CFG (0x050)
|
||||
#define CCU_AHB_APB_CFG (0x054)
|
||||
|
||||
#define CCU_BUS_CLK_GATE0 (0x060)
|
||||
#define CCU_BUS_CLK_GATE1 (0x064)
|
||||
#define CCU_BUS_CLK_GATE2 (0x068)
|
||||
|
||||
#define CCU_SDMMC0_CLK (0x088)
|
||||
#define CCU_SDMMC1_CLK (0x08c)
|
||||
#define CCU_DAUDIO_CLK (0x0b0)
|
||||
#define CCU_SPDIF_CLK (0x0b4)
|
||||
#define CCU_I2S_CLK (0x0b8)
|
||||
#define CCU_USBPHY_CFG (0x0cc)
|
||||
#define CCU_DRAM_CLK_GATE (0x100)
|
||||
#define CCU_DEBE_CLK (0x104)
|
||||
#define CCU_DEFE_CLK (0x10c)
|
||||
#define CCU_LCD_CLK (0x118)
|
||||
#define CCU_DEINTERLACE_CLK (0x11c)
|
||||
#define CCU_TVE_CLK (0x120)
|
||||
#define CCU_TVD_CLK (0x124)
|
||||
#define CCU_CSI_CLK (0x134)
|
||||
#define CCU_VE_CLK (0x13c)
|
||||
#define CCU_ADDA_CLK (0x140)
|
||||
#define CCU_AVS_CLK (0x144)
|
||||
|
||||
#define CCU_PLL_STABLE_TIME0 (0x200)
|
||||
#define CCU_PLL_STABLE_TIME1 (0x204)
|
||||
#define CCU_PLL_CPU_BIAS (0x220)
|
||||
#define CCU_PLL_AUDIO_BIAS (0x224)
|
||||
#define CCU_PLL_VIDEO_BIAS (0x228)
|
||||
#define CCU_PLL_VE_BIAS (0x22c)
|
||||
#define CCU_PLL_DDR0_BIAS (0x230)
|
||||
#define CCU_PLL_PERIPH_BIAS (0x234)
|
||||
#define CCU_PLL_CPU_TUN (0x250)
|
||||
#define CCU_PLL_DDR_TUN (0x260)
|
||||
#define CCU_PLL_AUDIO_PAT (0x284)
|
||||
#define CCU_PLL_VIDEO_PAT (0x288)
|
||||
#define CCU_PLL_DDR0_PAT (0x290)
|
||||
|
||||
#define CCU_BUS_SOFT_RST0 (0x2c0)
|
||||
#define CCU_BUS_SOFT_RST1 (0x2c4)
|
||||
#define CCU_BUS_SOFT_RST3 (0x2d0)
|
||||
|
||||
#endif /* __F1C100S_REG_CCU_H__ */
|
39
hw/mcu/allwinner/f1c100s/include/f1c100s/reg-dram.h
Normal file
39
hw/mcu/allwinner/f1c100s/include/f1c100s/reg-dram.h
Normal file
@ -0,0 +1,39 @@
|
||||
#ifndef __F1C100S_REG_DRAM_H__
|
||||
#define __F1C100S_REG_DRAM_H__
|
||||
|
||||
#define F1C100S_DRAM_BASE (0x01c01000)
|
||||
|
||||
#define DRAM_SCONR (0x00)
|
||||
#define DRAM_STMG0R (0x04)
|
||||
#define DRAM_STMG1R (0x08)
|
||||
#define DRAM_SCTLR (0x0c)
|
||||
#define DRAM_SREFR (0x10)
|
||||
#define DRAM_SEXTMR (0x14)
|
||||
#define DRAM_DDLYR (0x24)
|
||||
#define DRAM_DADRR (0x28)
|
||||
#define DRAM_DVALR (0x2c)
|
||||
#define DRAM_DRPTR0 (0x30)
|
||||
#define DRAM_DRPTR1 (0x34)
|
||||
#define DRAM_DRPTR2 (0x38)
|
||||
#define DRAM_DRPTR3 (0x3c)
|
||||
#define DRAM_SEFR (0x40)
|
||||
#define DRAM_MAE (0x44)
|
||||
#define DRAM_ASPR (0x48)
|
||||
#define DRAM_SDLY0 (0x4C)
|
||||
#define DRAM_SDLY1 (0x50)
|
||||
#define DRAM_SDLY2 (0x54)
|
||||
#define DRAM_MCR0 (0x100)
|
||||
#define DRAM_MCR1 (0x104)
|
||||
#define DRAM_MCR2 (0x108)
|
||||
#define DRAM_MCR3 (0x10c)
|
||||
#define DRAM_MCR4 (0x110)
|
||||
#define DRAM_MCR5 (0x114)
|
||||
#define DRAM_MCR6 (0x118)
|
||||
#define DRAM_MCR7 (0x11c)
|
||||
#define DRAM_MCR8 (0x120)
|
||||
#define DRAM_MCR9 (0x124)
|
||||
#define DRAM_MCR10 (0x128)
|
||||
#define DRAM_MCR11 (0x12c)
|
||||
#define DRAM_BWCR (0x140)
|
||||
|
||||
#endif /* __F1C100S_REG_DRAM_H__ */
|
57
hw/mcu/allwinner/f1c100s/include/io.h
Normal file
57
hw/mcu/allwinner/f1c100s/include/io.h
Normal file
@ -0,0 +1,57 @@
|
||||
#ifndef __IO_H__
|
||||
#define __IO_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <types.h>
|
||||
|
||||
static inline u8_t read8(virtual_addr_t addr)
|
||||
{
|
||||
return( *((volatile u8_t *)(addr)) );
|
||||
}
|
||||
|
||||
static inline u16_t read16(virtual_addr_t addr)
|
||||
{
|
||||
return( *((volatile u16_t *)(addr)) );
|
||||
}
|
||||
|
||||
static inline u32_t read32(virtual_addr_t addr)
|
||||
{
|
||||
return( *((volatile u32_t *)(addr)) );
|
||||
}
|
||||
|
||||
static inline u64_t read64(virtual_addr_t addr)
|
||||
{
|
||||
return( *((volatile u64_t *)(addr)) );
|
||||
}
|
||||
|
||||
static inline void write8(virtual_addr_t addr, u8_t value)
|
||||
{
|
||||
*((volatile u8_t *)(addr)) = value;
|
||||
}
|
||||
|
||||
static inline void write16(virtual_addr_t addr, u16_t value)
|
||||
{
|
||||
*((volatile u16_t *)(addr)) = value;
|
||||
}
|
||||
|
||||
static inline void write32(virtual_addr_t addr, u32_t value)
|
||||
{
|
||||
*((volatile u32_t *)(addr)) = value;
|
||||
}
|
||||
|
||||
static inline void write64(virtual_addr_t addr, u64_t value)
|
||||
{
|
||||
*((volatile u64_t *)(addr)) = value;
|
||||
}
|
||||
|
||||
virtual_addr_t phys_to_virt(physical_addr_t phys);
|
||||
physical_addr_t virt_to_phys(virtual_addr_t virt);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __IO_H__ */
|
104
hw/mcu/allwinner/f1c100s/include/irqflags.h
Normal file
104
hw/mcu/allwinner/f1c100s/include/irqflags.h
Normal file
@ -0,0 +1,104 @@
|
||||
#ifndef __ARM32_IRQFLAGS_H__
|
||||
#define __ARM32_IRQFLAGS_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#if __ARM32_ARCH__ == 5
|
||||
|
||||
static inline void arch_local_irq_enable(void)
|
||||
{
|
||||
irq_flags_t temp;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"mrs %0, cpsr\n"
|
||||
"bic %0, %0, #(1<<7)\n"
|
||||
"msr cpsr_c, %0"
|
||||
: "=r" (temp)
|
||||
:
|
||||
: "memory", "cc");
|
||||
}
|
||||
|
||||
static inline void arch_local_irq_disable(void)
|
||||
{
|
||||
irq_flags_t temp;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"mrs %0, cpsr\n"
|
||||
"orr %0, %0, #(1<<7)\n"
|
||||
"msr cpsr_c, %0"
|
||||
: "=r" (temp)
|
||||
:
|
||||
: "memory", "cc");
|
||||
}
|
||||
|
||||
static inline irq_flags_t arch_local_irq_save(void)
|
||||
{
|
||||
irq_flags_t flags, temp;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"mrs %0, cpsr\n"
|
||||
"orr %1, %0, #(1<<7)\n"
|
||||
"msr cpsr_c, %1"
|
||||
: "=r" (flags), "=r" (temp)
|
||||
:
|
||||
: "memory", "cc");
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static inline void arch_local_irq_restore(irq_flags_t flags)
|
||||
{
|
||||
__asm__ __volatile__(
|
||||
"msr cpsr_c, %0"
|
||||
:
|
||||
: "r" (flags)
|
||||
: "memory", "cc");
|
||||
}
|
||||
#else
|
||||
static inline void arch_local_irq_enable(void)
|
||||
{
|
||||
__asm__ __volatile__("cpsie i" ::: "memory", "cc");
|
||||
}
|
||||
|
||||
static inline void arch_local_irq_disable(void)
|
||||
{
|
||||
__asm__ __volatile__("cpsid i" ::: "memory", "cc");
|
||||
}
|
||||
|
||||
static inline irq_flags_t arch_local_irq_save(void)
|
||||
{
|
||||
irq_flags_t flags;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"mrs %0, cpsr\n"
|
||||
"cpsid i"
|
||||
: "=r" (flags)
|
||||
:
|
||||
: "memory", "cc");
|
||||
return flags;
|
||||
}
|
||||
|
||||
static inline void arch_local_irq_restore(irq_flags_t flags)
|
||||
{
|
||||
__asm__ __volatile__(
|
||||
"msr cpsr_c, %0"
|
||||
:
|
||||
: "r" (flags)
|
||||
: "memory", "cc");
|
||||
}
|
||||
#endif
|
||||
|
||||
#define local_irq_enable() do { arch_local_irq_enable(); } while(0)
|
||||
#define local_irq_disable() do { arch_local_irq_disable(); } while(0)
|
||||
#define local_irq_save(flags) do { flags = arch_local_irq_save(); } while(0)
|
||||
#define local_irq_restore(flags) do { arch_local_irq_restore(flags); } while(0)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ARM32_IRQFLAGS_H__ */
|
35
hw/mcu/allwinner/f1c100s/include/malloc.h
Normal file
35
hw/mcu/allwinner/f1c100s/include/malloc.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef __MALLOC_H__
|
||||
#define __MALLOC_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <types.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
void * mm_create(void * mem, size_t bytes);
|
||||
void mm_destroy(void * mm);
|
||||
void * mm_get_pool(void * mm);
|
||||
void * mm_add_pool(void * mm, void * mem, size_t bytes);
|
||||
void mm_remove_pool(void * mm, void * pool);
|
||||
void * mm_malloc(void * mm, size_t size);
|
||||
void * mm_memalign(void * mm, size_t align, size_t size);
|
||||
void * mm_realloc(void * mm, void * ptr, size_t size);
|
||||
void mm_free(void * mm, void * ptr);
|
||||
|
||||
void * malloc(size_t size);
|
||||
void * memalign(size_t align, size_t size);
|
||||
void * realloc(void * ptr, size_t size);
|
||||
void * calloc(size_t nmemb, size_t size);
|
||||
void free(void * ptr);
|
||||
|
||||
void do_init_mem_pool(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __MALLOC_H__ */
|
99
hw/mcu/allwinner/f1c100s/include/printf.h
Normal file
99
hw/mcu/allwinner/f1c100s/include/printf.h
Normal file
@ -0,0 +1,99 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// \author (c) Marco Paland (info@paland.com)
|
||||
// 2014-2018, PALANDesign Hannover, Germany
|
||||
//
|
||||
// \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.
|
||||
//
|
||||
// \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on
|
||||
// embedded systems with a very limited resources.
|
||||
// Use this instead of bloated standard/newlib printf.
|
||||
// These routines are thread safe and reentrant!
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _PRINTF_H_
|
||||
#define _PRINTF_H_
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Output a character to a custom device like UART, used by the printf() function
|
||||
* This function is declared here only. You have to write your custom implementation somewhere
|
||||
* \param character Character to output
|
||||
*/
|
||||
void _putchar(char character);
|
||||
|
||||
|
||||
/**
|
||||
* Tiny printf implementation
|
||||
* You have to implement _putchar if you use printf()
|
||||
* \param format A string that specifies the format of the output
|
||||
* \return The number of characters that are written into the array, not counting the terminating null character
|
||||
*/
|
||||
int printf(const char* format, ...);
|
||||
|
||||
|
||||
/**
|
||||
* Tiny sprintf implementation
|
||||
* Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD!
|
||||
* \param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output!
|
||||
* \param format A string that specifies the format of the output
|
||||
* \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
|
||||
*/
|
||||
int sprintf(char* buffer, const char* format, ...);
|
||||
|
||||
|
||||
/**
|
||||
* Tiny snprintf/vsnprintf implementation
|
||||
* \param buffer A pointer to the buffer where to store the formatted string
|
||||
* \param count The maximum number of characters to store in the buffer, including a terminating null character
|
||||
* \param format A string that specifies the format of the output
|
||||
* \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
|
||||
* If the formatted string is truncated the buffer size (count) is returned
|
||||
*/
|
||||
int snprintf(char* buffer, size_t count, const char* format, ...);
|
||||
int vsnprintf(char* buffer, size_t count, const char* format, va_list va);
|
||||
|
||||
|
||||
/**
|
||||
* printf with output function
|
||||
* You may use this as dynamic alternative to printf() with its fixed _putchar() output
|
||||
* \param out An output function which takes one character and an argument pointer
|
||||
* \param arg An argument pointer for user data passed to output function
|
||||
* \param format A string that specifies the format of the output
|
||||
* \return The number of characters that are sent to the output function, not counting the terminating null character
|
||||
*/
|
||||
int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif // _PRINTF_H_
|
42
hw/mcu/allwinner/f1c100s/include/sizes.h
Normal file
42
hw/mcu/allwinner/f1c100s/include/sizes.h
Normal file
@ -0,0 +1,42 @@
|
||||
#ifndef __SIZES_H__
|
||||
#define __SIZES_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SZ_16 (0x00000010)
|
||||
#define SZ_256 (0x00000100)
|
||||
#define SZ_512 (0x00000200)
|
||||
|
||||
#define SZ_1K (0x00000400)
|
||||
#define SZ_4K (0x00001000)
|
||||
#define SZ_8K (0x00002000)
|
||||
#define SZ_16K (0x00004000)
|
||||
#define SZ_32K (0x00008000)
|
||||
#define SZ_64K (0x00010000)
|
||||
#define SZ_128K (0x00020000)
|
||||
#define SZ_256K (0x00040000)
|
||||
#define SZ_512K (0x00080000)
|
||||
|
||||
#define SZ_1M (0x00100000)
|
||||
#define SZ_2M (0x00200000)
|
||||
#define SZ_4M (0x00400000)
|
||||
#define SZ_8M (0x00800000)
|
||||
#define SZ_16M (0x01000000)
|
||||
#define SZ_32M (0x02000000)
|
||||
#define SZ_64M (0x04000000)
|
||||
#define SZ_128M (0x08000000)
|
||||
#define SZ_256M (0x10000000)
|
||||
#define SZ_512M (0x20000000)
|
||||
|
||||
#define SZ_1G (0x40000000)
|
||||
#define SZ_2G (0x80000000)
|
||||
|
||||
#define ARRAY_SIZE(array) ( sizeof(array) / sizeof((array)[0]) )
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __SIZES_H__ */
|
55
hw/mcu/allwinner/f1c100s/include/types.h
Normal file
55
hw/mcu/allwinner/f1c100s/include/types.h
Normal file
@ -0,0 +1,55 @@
|
||||
#ifndef __ARM32_TYPES_H__
|
||||
#define __ARM32_TYPES_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef signed char s8_t;
|
||||
typedef unsigned char u8_t;
|
||||
|
||||
typedef signed short s16_t;
|
||||
typedef unsigned short u16_t;
|
||||
|
||||
typedef signed int s32_t;
|
||||
typedef unsigned int u32_t;
|
||||
|
||||
typedef signed long long s64_t;
|
||||
typedef unsigned long long u64_t;
|
||||
|
||||
typedef signed long long intmax_t;
|
||||
typedef unsigned long long uintmax_t;
|
||||
|
||||
typedef signed int ptrdiff_t;
|
||||
typedef signed int intptr_t;
|
||||
typedef unsigned int uintptr_t;
|
||||
|
||||
typedef unsigned int size_t;
|
||||
typedef signed int ssize_t;
|
||||
|
||||
// typedef signed int off_t;
|
||||
typedef signed long long loff_t;
|
||||
|
||||
typedef signed int bool_t;
|
||||
|
||||
typedef signed int register_t;
|
||||
typedef unsigned int irq_flags_t;
|
||||
|
||||
typedef unsigned int virtual_addr_t;
|
||||
typedef unsigned int virtual_size_t;
|
||||
typedef unsigned int physical_addr_t;
|
||||
typedef unsigned int physical_size_t;
|
||||
|
||||
typedef struct {
|
||||
volatile long counter;
|
||||
} atomic_t;
|
||||
|
||||
typedef struct {
|
||||
volatile long lock;
|
||||
} spinlock_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ARM32_TYPES_H__ */
|
834
hw/mcu/allwinner/f1c100s/lib/malloc.c
Normal file
834
hw/mcu/allwinner/f1c100s/lib/malloc.c
Normal file
@ -0,0 +1,834 @@
|
||||
/*
|
||||
* lib/libc/malloc/malloc.c
|
||||
*/
|
||||
|
||||
#include <malloc.h>
|
||||
|
||||
static void * __heap_pool = NULL;
|
||||
|
||||
/*
|
||||
* Some 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 assert
|
||||
#define tlsf_insist(x) { tlsf_assert(x); if (!(x)) { status--; } }
|
||||
|
||||
#if defined(__ARM64__) || defined(__X64__)
|
||||
# define TLSF_64BIT
|
||||
#else
|
||||
# undef TLSF_64BIT
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Public constants
|
||||
*/
|
||||
enum tlsf_public
|
||||
{
|
||||
/*
|
||||
* log2 of number of linear subdivisions of block sizes
|
||||
*/
|
||||
SL_INDEX_COUNT_LOG2 = 5,
|
||||
};
|
||||
|
||||
/*
|
||||
* Private constants
|
||||
*/
|
||||
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),
|
||||
|
||||
#if defined(TLSF_64BIT)
|
||||
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),
|
||||
};
|
||||
|
||||
/*
|
||||
* Block header structure
|
||||
*/
|
||||
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;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/*
|
||||
* Associated constants
|
||||
*/
|
||||
static const size_t block_header_free_bit = 1 << 0;
|
||||
static const size_t block_header_prev_free_bit = 1 << 1;
|
||||
static const size_t block_header_overhead = sizeof(size_t);
|
||||
static const size_t block_start_offset = offsetof(block_header_t, size) + sizeof(size_t);
|
||||
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;
|
||||
|
||||
#if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) && defined(__GNUC_PATCHLEVEL__)
|
||||
static int tlsf_ffs(unsigned int word)
|
||||
{
|
||||
return __builtin_ffs(word) - 1;
|
||||
}
|
||||
|
||||
static int tlsf_fls(unsigned int word)
|
||||
{
|
||||
const int bit = word ? 32 - __builtin_clz(word) : 0;
|
||||
return bit - 1;
|
||||
}
|
||||
#else
|
||||
static 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;
|
||||
}
|
||||
|
||||
static int tlsf_ffs(unsigned int word)
|
||||
{
|
||||
return tlsf_fls_generic(word & (~word + 1)) - 1;
|
||||
}
|
||||
|
||||
static int tlsf_fls(unsigned int word)
|
||||
{
|
||||
return tlsf_fls_generic(word) - 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(TLSF_64BIT)
|
||||
static 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
|
||||
|
||||
static size_t block_get_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 (0 == block_get_size(block));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wcast-align"
|
||||
static block_header_t * block_from_ptr(void * ptr)
|
||||
{
|
||||
return tlsf_cast(block_header_t *, tlsf_cast(unsigned char*, ptr) - block_start_offset);
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
static void * block_to_ptr(block_header_t * block)
|
||||
{
|
||||
return tlsf_cast(void *, tlsf_cast(unsigned char*, block) + block_start_offset);
|
||||
}
|
||||
|
||||
static block_header_t * offset_to_block(void * ptr, size_t size)
|
||||
{
|
||||
return tlsf_cast(block_header_t *, tlsf_cast(tlsfptr_t, ptr) + size);
|
||||
}
|
||||
|
||||
static block_header_t * block_prev(block_header_t * block)
|
||||
{
|
||||
return block->prev_phys_block;
|
||||
}
|
||||
|
||||
static block_header_t * block_next(block_header_t * block)
|
||||
{
|
||||
block_header_t * next = offset_to_block(block_to_ptr(block), block_get_size(block) - block_header_overhead);
|
||||
tlsf_assert(!block_is_last(block));
|
||||
return next;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
static size_t adjust_request_size(size_t size, size_t align)
|
||||
{
|
||||
size_t adjust = 0;
|
||||
if (size && size < block_size_max)
|
||||
{
|
||||
const size_t aligned = align_up(size, align);
|
||||
adjust = tlsf_max(aligned, block_size_min);
|
||||
}
|
||||
return adjust;
|
||||
}
|
||||
|
||||
static void mapping_insert(size_t size, int * fli, int * sli)
|
||||
{
|
||||
int fl, sl;
|
||||
if (size < SMALL_BLOCK_SIZE)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
static void mapping_search(size_t size, int * fli, int * sli)
|
||||
{
|
||||
if (size >= (1 << SL_INDEX_COUNT_LOG2))
|
||||
{
|
||||
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;
|
||||
|
||||
unsigned int sl_map = control->sl_bitmap[fl] & (~0U << sl);
|
||||
if (!sl_map)
|
||||
{
|
||||
const unsigned int fl_map = control->fl_bitmap & (~0U << (fl + 1));
|
||||
if (!fl_map)
|
||||
{
|
||||
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 control->blocks[fl][sl];
|
||||
}
|
||||
|
||||
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 (control->blocks[fl][sl] == block)
|
||||
{
|
||||
control->blocks[fl][sl] = next;
|
||||
|
||||
if (next == &control->block_null)
|
||||
{
|
||||
control->sl_bitmap[fl] &= ~(1 << sl);
|
||||
|
||||
if (!control->sl_bitmap[fl])
|
||||
{
|
||||
control->fl_bitmap &= ~(1 << fl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
control->blocks[fl][sl] = block;
|
||||
control->fl_bitmap |= (1 << fl);
|
||||
control->sl_bitmap[fl] |= (1 << sl);
|
||||
}
|
||||
|
||||
static void block_remove(control_t * control, block_header_t * block)
|
||||
{
|
||||
int fl, sl;
|
||||
mapping_insert(block_get_size(block), &fl, &sl);
|
||||
remove_free_block(control, block, fl, sl);
|
||||
}
|
||||
|
||||
static void block_insert(control_t * control, block_header_t * block)
|
||||
{
|
||||
int fl, sl;
|
||||
mapping_insert(block_get_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_get_size(block) >= sizeof(block_header_t) + size;
|
||||
}
|
||||
|
||||
static block_header_t * block_split(block_header_t * block, size_t size)
|
||||
{
|
||||
block_header_t* remaining = offset_to_block(block_to_ptr(block), size - block_header_overhead);
|
||||
const size_t remain_size = block_get_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_get_size(block) == remain_size + size + block_header_overhead);
|
||||
block_set_size(remaining, remain_size);
|
||||
tlsf_assert(block_get_size(remaining) >= block_size_min && "block split with invalid size");
|
||||
|
||||
block_set_size(block, size);
|
||||
block_mark_as_free(remaining);
|
||||
|
||||
return remaining;
|
||||
}
|
||||
|
||||
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!");
|
||||
prev->size += block_get_size(block) + block_header_overhead;
|
||||
block_link_next(prev);
|
||||
return prev;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
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))
|
||||
{
|
||||
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);
|
||||
block = search_suitable_block(control, &fl, &sl);
|
||||
}
|
||||
|
||||
if (block)
|
||||
{
|
||||
tlsf_assert(block_get_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)
|
||||
{
|
||||
block_trim_free(control, block, size);
|
||||
block_mark_as_used(block);
|
||||
p = block_to_ptr(block);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void * tlsf_add_pool(void * tlsf, void * mem, size_t bytes)
|
||||
{
|
||||
block_header_t * block;
|
||||
block_header_t * next;
|
||||
const size_t pool_overhead = 2 * block_header_overhead;
|
||||
const size_t pool_bytes = align_down(bytes - pool_overhead, ALIGN_SIZE);
|
||||
|
||||
if (((ptrdiff_t)mem % ALIGN_SIZE) != 0)
|
||||
return 0;
|
||||
|
||||
if (pool_bytes < block_size_min || pool_bytes > block_size_max)
|
||||
return 0;
|
||||
|
||||
block = offset_to_block(mem, -(tlsfptr_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);
|
||||
|
||||
next = block_link_next(block);
|
||||
block_set_size(next, 0);
|
||||
block_set_used(next);
|
||||
block_set_prev_free(next);
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
static inline void tlsf_remove_pool(void * tlsf, void * pool)
|
||||
{
|
||||
control_t * control = tlsf_cast(control_t *, tlsf);
|
||||
block_header_t * block = offset_to_block(pool, -(int)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_get_size(block_next(block)) == 0 && "next block size should be zero");
|
||||
|
||||
mapping_insert(block_get_size(block), &fl, &sl);
|
||||
remove_free_block(control, block, fl, sl);
|
||||
}
|
||||
|
||||
static inline void * tlsf_create(void * mem)
|
||||
{
|
||||
if (((tlsfptr_t)mem % ALIGN_SIZE) != 0)
|
||||
return 0;
|
||||
|
||||
control_construct(tlsf_cast(control_t *, mem));
|
||||
return tlsf_cast(void *, mem);
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Warray-bounds"
|
||||
static inline void * tlsf_create_with_pool(void * mem, size_t bytes)
|
||||
{
|
||||
void * tlsf = tlsf_create(mem);
|
||||
tlsf_add_pool(tlsf, (char *)mem + sizeof(control_t), bytes - sizeof(control_t));
|
||||
return tlsf;
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
|
||||
static inline void tlsf_destroy(void * tlsf)
|
||||
{
|
||||
(void)tlsf;
|
||||
}
|
||||
|
||||
static inline void * tlsf_get_pool(void * tlsf)
|
||||
{
|
||||
return tlsf_cast(void *, (char *)tlsf + sizeof(control_t));
|
||||
}
|
||||
|
||||
static inline void * tlsf_malloc(void * 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);
|
||||
}
|
||||
|
||||
static inline void * tlsf_memalign(void * 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);
|
||||
|
||||
const size_t gap_minimum = sizeof(block_header_t);
|
||||
const size_t size_with_gap = adjust_request_size(adjust + align + gap_minimum, align);
|
||||
|
||||
const size_t aligned_size = (align <= ALIGN_SIZE) ? adjust : size_with_gap;
|
||||
|
||||
block_header_t* block = block_locate_free(control, aligned_size);
|
||||
|
||||
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 && 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);
|
||||
}
|
||||
|
||||
static inline void tlsf_free(void * tlsf, void * ptr)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void * tlsf_realloc(void * tlsf, void * ptr, size_t size)
|
||||
{
|
||||
control_t * control = tlsf_cast(control_t *, tlsf);
|
||||
void * p = 0;
|
||||
|
||||
if (ptr && size == 0)
|
||||
{
|
||||
tlsf_free(tlsf, ptr);
|
||||
}
|
||||
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_get_size(block);
|
||||
const size_t combined = cursize + block_get_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 (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
|
||||
{
|
||||
if (adjust > cursize)
|
||||
{
|
||||
block_merge_next(control, block);
|
||||
block_mark_as_used(block);
|
||||
}
|
||||
|
||||
block_trim_used(control, block, adjust);
|
||||
p = ptr;
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void * mm_create(void * mem, size_t bytes)
|
||||
{
|
||||
return tlsf_create_with_pool(mem, bytes);
|
||||
}
|
||||
|
||||
void mm_destroy(void * mm)
|
||||
{
|
||||
tlsf_destroy(mm);
|
||||
}
|
||||
|
||||
void * mm_get_pool(void * mm)
|
||||
{
|
||||
return tlsf_get_pool(mm);
|
||||
}
|
||||
|
||||
void * mm_add_pool(void * mm, void * mem, size_t bytes)
|
||||
{
|
||||
return tlsf_add_pool(mm, mem, bytes);
|
||||
}
|
||||
|
||||
void mm_remove_pool(void * mm, void * pool)
|
||||
{
|
||||
tlsf_remove_pool(mm, pool);
|
||||
}
|
||||
|
||||
void * mm_malloc(void * mm, size_t size)
|
||||
{
|
||||
return tlsf_malloc(mm, size);
|
||||
}
|
||||
|
||||
void * mm_memalign(void * mm, size_t align, size_t size)
|
||||
{
|
||||
return tlsf_memalign(mm, align, size);
|
||||
}
|
||||
|
||||
void * mm_realloc(void * mm, void * ptr, size_t size)
|
||||
{
|
||||
return tlsf_realloc(mm, ptr, size);
|
||||
}
|
||||
|
||||
void mm_free(void * mm, void * ptr)
|
||||
{
|
||||
tlsf_free(mm, ptr);
|
||||
}
|
||||
|
||||
void * malloc(size_t size)
|
||||
{
|
||||
return tlsf_malloc(__heap_pool, size);
|
||||
}
|
||||
|
||||
void * memalign(size_t align, size_t size)
|
||||
{
|
||||
return tlsf_memalign(__heap_pool, align, size);
|
||||
}
|
||||
|
||||
void * realloc(void * ptr, size_t size)
|
||||
{
|
||||
return tlsf_realloc(__heap_pool, ptr, size);
|
||||
}
|
||||
|
||||
void * calloc(size_t nmemb, size_t size)
|
||||
{
|
||||
void * ptr;
|
||||
|
||||
if((ptr = malloc(nmemb * size)))
|
||||
memset(ptr, 0, nmemb * size);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void free(void * ptr)
|
||||
{
|
||||
tlsf_free(__heap_pool, ptr);
|
||||
}
|
||||
|
||||
void do_init_mem_pool(void)
|
||||
{
|
||||
#ifndef __SANDBOX__
|
||||
extern unsigned char __heap_start;
|
||||
extern unsigned char __heap_end;
|
||||
__heap_pool = tlsf_create_with_pool((void *)&__heap_start, (size_t)(&__heap_end - &__heap_start));
|
||||
#else
|
||||
static char __heap_buf[SZ_16M];
|
||||
__heap_pool = tlsf_create_with_pool((void *)__heap_buf, (size_t)(sizeof(__heap_buf)));
|
||||
#endif
|
||||
}
|
404
hw/mcu/allwinner/f1c100s/lib/memcpy.S
Normal file
404
hw/mcu/allwinner/f1c100s/lib/memcpy.S
Normal file
@ -0,0 +1,404 @@
|
||||
/*
|
||||
* memcpy.S
|
||||
*/
|
||||
.text
|
||||
|
||||
.global memcpy
|
||||
.type memcpy, %function
|
||||
.align 4
|
||||
|
||||
memcpy:
|
||||
/* determine copy direction */
|
||||
cmp r1, r0
|
||||
bcc .Lmemcpy_backwards
|
||||
|
||||
moveq r0, #0 /* quick abort for len=0 */
|
||||
moveq pc, lr
|
||||
|
||||
stmdb sp!, {r0, lr} /* memcpy() returns dest addr */
|
||||
subs r2, r2, #4
|
||||
blt .Lmemcpy_fl4 /* less than 4 bytes */
|
||||
ands r12, r0, #3
|
||||
bne .Lmemcpy_fdestul /* oh unaligned destination addr */
|
||||
ands r12, r1, #3
|
||||
bne .Lmemcpy_fsrcul /* oh unaligned source addr */
|
||||
|
||||
.Lmemcpy_ft8:
|
||||
/* we have aligned source and destination */
|
||||
subs r2, r2, #8
|
||||
blt .Lmemcpy_fl12 /* less than 12 bytes (4 from above) */
|
||||
subs r2, r2, #0x14
|
||||
blt .Lmemcpy_fl32 /* less than 32 bytes (12 from above) */
|
||||
stmdb sp!, {r4} /* borrow r4 */
|
||||
|
||||
/* blat 32 bytes at a time */
|
||||
.Lmemcpy_floop32:
|
||||
ldmia r1!, {r3, r4, r12, lr}
|
||||
stmia r0!, {r3, r4, r12, lr}
|
||||
ldmia r1!, {r3, r4, r12, lr}
|
||||
stmia r0!, {r3, r4, r12, lr}
|
||||
subs r2, r2, #0x20
|
||||
bge .Lmemcpy_floop32
|
||||
|
||||
cmn r2, #0x10
|
||||
ldmgeia r1!, {r3, r4, r12, lr} /* blat a remaining 16 bytes */
|
||||
stmgeia r0!, {r3, r4, r12, lr}
|
||||
subge r2, r2, #0x10
|
||||
ldmia sp!, {r4} /* return r4 */
|
||||
|
||||
.Lmemcpy_fl32:
|
||||
adds r2, r2, #0x14
|
||||
|
||||
/* blat 12 bytes at a time */
|
||||
.Lmemcpy_floop12:
|
||||
ldmgeia r1!, {r3, r12, lr}
|
||||
stmgeia r0!, {r3, r12, lr}
|
||||
subges r2, r2, #0x0c
|
||||
bge .Lmemcpy_floop12
|
||||
|
||||
.Lmemcpy_fl12:
|
||||
adds r2, r2, #8
|
||||
blt .Lmemcpy_fl4
|
||||
|
||||
subs r2, r2, #4
|
||||
ldrlt r3, [r1], #4
|
||||
strlt r3, [r0], #4
|
||||
ldmgeia r1!, {r3, r12}
|
||||
stmgeia r0!, {r3, r12}
|
||||
subge r2, r2, #4
|
||||
|
||||
.Lmemcpy_fl4:
|
||||
/* less than 4 bytes to go */
|
||||
adds r2, r2, #4
|
||||
ldmeqia sp!, {r0, pc} /* done */
|
||||
|
||||
/* copy the crud byte at a time */
|
||||
cmp r2, #2
|
||||
ldrb r3, [r1], #1
|
||||
strb r3, [r0], #1
|
||||
ldrgeb r3, [r1], #1
|
||||
strgeb r3, [r0], #1
|
||||
ldrgtb r3, [r1], #1
|
||||
strgtb r3, [r0], #1
|
||||
ldmia sp!, {r0, pc}
|
||||
|
||||
/* erg - unaligned destination */
|
||||
.Lmemcpy_fdestul:
|
||||
rsb r12, r12, #4
|
||||
cmp r12, #2
|
||||
|
||||
/* align destination with byte copies */
|
||||
ldrb r3, [r1], #1
|
||||
strb r3, [r0], #1
|
||||
ldrgeb r3, [r1], #1
|
||||
strgeb r3, [r0], #1
|
||||
ldrgtb r3, [r1], #1
|
||||
strgtb r3, [r0], #1
|
||||
subs r2, r2, r12
|
||||
blt .Lmemcpy_fl4 /* less the 4 bytes */
|
||||
|
||||
ands r12, r1, #3
|
||||
beq .Lmemcpy_ft8 /* we have an aligned source */
|
||||
|
||||
/* erg - unaligned source */
|
||||
/* This is where it gets nasty ... */
|
||||
.Lmemcpy_fsrcul:
|
||||
bic r1, r1, #3
|
||||
ldr lr, [r1], #4
|
||||
cmp r12, #2
|
||||
bgt .Lmemcpy_fsrcul3
|
||||
beq .Lmemcpy_fsrcul2
|
||||
cmp r2, #0x0c
|
||||
blt .Lmemcpy_fsrcul1loop4
|
||||
sub r2, r2, #0x0c
|
||||
stmdb sp!, {r4, r5}
|
||||
|
||||
.Lmemcpy_fsrcul1loop16:
|
||||
mov r3, lr, lsr #8
|
||||
ldmia r1!, {r4, r5, r12, lr}
|
||||
orr r3, r3, r4, lsl #24
|
||||
mov r4, r4, lsr #8
|
||||
orr r4, r4, r5, lsl #24
|
||||
mov r5, r5, lsr #8
|
||||
orr r5, r5, r12, lsl #24
|
||||
mov r12, r12, lsr #8
|
||||
orr r12, r12, lr, lsl #24
|
||||
stmia r0!, {r3-r5, r12}
|
||||
subs r2, r2, #0x10
|
||||
bge .Lmemcpy_fsrcul1loop16
|
||||
ldmia sp!, {r4, r5}
|
||||
adds r2, r2, #0x0c
|
||||
blt .Lmemcpy_fsrcul1l4
|
||||
|
||||
.Lmemcpy_fsrcul1loop4:
|
||||
mov r12, lr, lsr #8
|
||||
ldr lr, [r1], #4
|
||||
orr r12, r12, lr, lsl #24
|
||||
str r12, [r0], #4
|
||||
subs r2, r2, #4
|
||||
bge .Lmemcpy_fsrcul1loop4
|
||||
|
||||
.Lmemcpy_fsrcul1l4:
|
||||
sub r1, r1, #3
|
||||
b .Lmemcpy_fl4
|
||||
|
||||
.Lmemcpy_fsrcul2:
|
||||
cmp r2, #0x0c
|
||||
blt .Lmemcpy_fsrcul2loop4
|
||||
sub r2, r2, #0x0c
|
||||
stmdb sp!, {r4, r5}
|
||||
|
||||
.Lmemcpy_fsrcul2loop16:
|
||||
mov r3, lr, lsr #16
|
||||
ldmia r1!, {r4, r5, r12, lr}
|
||||
orr r3, r3, r4, lsl #16
|
||||
mov r4, r4, lsr #16
|
||||
orr r4, r4, r5, lsl #16
|
||||
mov r5, r5, lsr #16
|
||||
orr r5, r5, r12, lsl #16
|
||||
mov r12, r12, lsr #16
|
||||
orr r12, r12, lr, lsl #16
|
||||
stmia r0!, {r3-r5, r12}
|
||||
subs r2, r2, #0x10
|
||||
bge .Lmemcpy_fsrcul2loop16
|
||||
ldmia sp!, {r4, r5}
|
||||
adds r2, r2, #0x0c
|
||||
blt .Lmemcpy_fsrcul2l4
|
||||
|
||||
.Lmemcpy_fsrcul2loop4:
|
||||
mov r12, lr, lsr #16
|
||||
ldr lr, [r1], #4
|
||||
orr r12, r12, lr, lsl #16
|
||||
str r12, [r0], #4
|
||||
subs r2, r2, #4
|
||||
bge .Lmemcpy_fsrcul2loop4
|
||||
|
||||
.Lmemcpy_fsrcul2l4:
|
||||
sub r1, r1, #2
|
||||
b .Lmemcpy_fl4
|
||||
|
||||
.Lmemcpy_fsrcul3:
|
||||
cmp r2, #0x0c
|
||||
blt .Lmemcpy_fsrcul3loop4
|
||||
sub r2, r2, #0x0c
|
||||
stmdb sp!, {r4, r5}
|
||||
|
||||
.Lmemcpy_fsrcul3loop16:
|
||||
mov r3, lr, lsr #24
|
||||
ldmia r1!, {r4, r5, r12, lr}
|
||||
orr r3, r3, r4, lsl #8
|
||||
mov r4, r4, lsr #24
|
||||
orr r4, r4, r5, lsl #8
|
||||
mov r5, r5, lsr #24
|
||||
orr r5, r5, r12, lsl #8
|
||||
mov r12, r12, lsr #24
|
||||
orr r12, r12, lr, lsl #8
|
||||
stmia r0!, {r3-r5, r12}
|
||||
subs r2, r2, #0x10
|
||||
bge .Lmemcpy_fsrcul3loop16
|
||||
ldmia sp!, {r4, r5}
|
||||
adds r2, r2, #0x0c
|
||||
blt .Lmemcpy_fsrcul3l4
|
||||
|
||||
.Lmemcpy_fsrcul3loop4:
|
||||
mov r12, lr, lsr #24
|
||||
ldr lr, [r1], #4
|
||||
orr r12, r12, lr, lsl #8
|
||||
str r12, [r0], #4
|
||||
subs r2, r2, #4
|
||||
bge .Lmemcpy_fsrcul3loop4
|
||||
|
||||
.Lmemcpy_fsrcul3l4:
|
||||
sub r1, r1, #1
|
||||
b .Lmemcpy_fl4
|
||||
|
||||
.Lmemcpy_backwards:
|
||||
add r1, r1, r2
|
||||
add r0, r0, r2
|
||||
subs r2, r2, #4
|
||||
blt .Lmemcpy_bl4 /* less than 4 bytes */
|
||||
ands r12, r0, #3
|
||||
bne .Lmemcpy_bdestul /* oh unaligned destination addr */
|
||||
ands r12, r1, #3
|
||||
bne .Lmemcpy_bsrcul /* oh unaligned source addr */
|
||||
|
||||
.Lmemcpy_bt8:
|
||||
/* we have aligned source and destination */
|
||||
subs r2, r2, #8
|
||||
blt .Lmemcpy_bl12 /* less than 12 bytes (4 from above) */
|
||||
stmdb sp!, {r4, lr}
|
||||
subs r2, r2, #0x14 /* less than 32 bytes (12 from above) */
|
||||
blt .Lmemcpy_bl32
|
||||
|
||||
/* blat 32 bytes at a time */
|
||||
.Lmemcpy_bloop32:
|
||||
ldmdb r1!, {r3, r4, r12, lr}
|
||||
stmdb r0!, {r3, r4, r12, lr}
|
||||
ldmdb r1!, {r3, r4, r12, lr}
|
||||
stmdb r0!, {r3, r4, r12, lr}
|
||||
subs r2, r2, #0x20
|
||||
bge .Lmemcpy_bloop32
|
||||
|
||||
.Lmemcpy_bl32:
|
||||
cmn r2, #0x10
|
||||
ldmgedb r1!, {r3, r4, r12, lr} /* blat a remaining 16 bytes */
|
||||
stmgedb r0!, {r3, r4, r12, lr}
|
||||
subge r2, r2, #0x10
|
||||
adds r2, r2, #0x14
|
||||
ldmgedb r1!, {r3, r12, lr} /* blat a remaining 12 bytes */
|
||||
stmgedb r0!, {r3, r12, lr}
|
||||
subge r2, r2, #0x0c
|
||||
ldmia sp!, {r4, lr}
|
||||
|
||||
.Lmemcpy_bl12:
|
||||
adds r2, r2, #8
|
||||
blt .Lmemcpy_bl4
|
||||
subs r2, r2, #4
|
||||
ldrlt r3, [r1, #-4]!
|
||||
strlt r3, [r0, #-4]!
|
||||
ldmgedb r1!, {r3, r12}
|
||||
stmgedb r0!, {r3, r12}
|
||||
subge r2, r2, #4
|
||||
|
||||
.Lmemcpy_bl4:
|
||||
/* less than 4 bytes to go */
|
||||
adds r2, r2, #4
|
||||
moveq pc, lr
|
||||
|
||||
/* copy the crud byte at a time */
|
||||
cmp r2, #2
|
||||
ldrb r3, [r1, #-1]!
|
||||
strb r3, [r0, #-1]!
|
||||
ldrgeb r3, [r1, #-1]!
|
||||
strgeb r3, [r0, #-1]!
|
||||
ldrgtb r3, [r1, #-1]!
|
||||
strgtb r3, [r0, #-1]!
|
||||
mov pc, lr
|
||||
|
||||
/* erg - unaligned destination */
|
||||
.Lmemcpy_bdestul:
|
||||
cmp r12, #2
|
||||
|
||||
/* align destination with byte copies */
|
||||
ldrb r3, [r1, #-1]!
|
||||
strb r3, [r0, #-1]!
|
||||
ldrgeb r3, [r1, #-1]!
|
||||
strgeb r3, [r0, #-1]!
|
||||
ldrgtb r3, [r1, #-1]!
|
||||
strgtb r3, [r0, #-1]!
|
||||
subs r2, r2, r12
|
||||
blt .Lmemcpy_bl4 /* less than 4 bytes to go */
|
||||
ands r12, r1, #3
|
||||
beq .Lmemcpy_bt8 /* we have an aligned source */
|
||||
|
||||
/* erg - unaligned source */
|
||||
/* This is where it gets nasty ... */
|
||||
.Lmemcpy_bsrcul:
|
||||
bic r1, r1, #3
|
||||
ldr r3, [r1, #0]
|
||||
cmp r12, #2
|
||||
blt .Lmemcpy_bsrcul1
|
||||
beq .Lmemcpy_bsrcul2
|
||||
cmp r2, #0x0c
|
||||
blt .Lmemcpy_bsrcul3loop4
|
||||
sub r2, r2, #0x0c
|
||||
stmdb sp!, {r4, r5, lr}
|
||||
|
||||
.Lmemcpy_bsrcul3loop16:
|
||||
mov lr, r3, lsl #8
|
||||
ldmdb r1!, {r3-r5, r12}
|
||||
orr lr, lr, r12, lsr #24
|
||||
mov r12, r12, lsl #8
|
||||
orr r12, r12, r5, lsr #24
|
||||
mov r5, r5, lsl #8
|
||||
orr r5, r5, r4, lsr #24
|
||||
mov r4, r4, lsl #8
|
||||
orr r4, r4, r3, lsr #24
|
||||
stmdb r0!, {r4, r5, r12, lr}
|
||||
subs r2, r2, #0x10
|
||||
bge .Lmemcpy_bsrcul3loop16
|
||||
ldmia sp!, {r4, r5, lr}
|
||||
adds r2, r2, #0x0c
|
||||
blt .Lmemcpy_bsrcul3l4
|
||||
|
||||
.Lmemcpy_bsrcul3loop4:
|
||||
mov r12, r3, lsl #8
|
||||
ldr r3, [r1, #-4]!
|
||||
orr r12, r12, r3, lsr #24
|
||||
str r12, [r0, #-4]!
|
||||
subs r2, r2, #4
|
||||
bge .Lmemcpy_bsrcul3loop4
|
||||
|
||||
.Lmemcpy_bsrcul3l4:
|
||||
add r1, r1, #3
|
||||
b .Lmemcpy_bl4
|
||||
|
||||
.Lmemcpy_bsrcul2:
|
||||
cmp r2, #0x0c
|
||||
blt .Lmemcpy_bsrcul2loop4
|
||||
sub r2, r2, #0x0c
|
||||
stmdb sp!, {r4, r5, lr}
|
||||
|
||||
.Lmemcpy_bsrcul2loop16:
|
||||
mov lr, r3, lsl #16
|
||||
ldmdb r1!, {r3-r5, r12}
|
||||
orr lr, lr, r12, lsr #16
|
||||
mov r12, r12, lsl #16
|
||||
orr r12, r12, r5, lsr #16
|
||||
mov r5, r5, lsl #16
|
||||
orr r5, r5, r4, lsr #16
|
||||
mov r4, r4, lsl #16
|
||||
orr r4, r4, r3, lsr #16
|
||||
stmdb r0!, {r4, r5, r12, lr}
|
||||
subs r2, r2, #0x10
|
||||
bge .Lmemcpy_bsrcul2loop16
|
||||
ldmia sp!, {r4, r5, lr}
|
||||
adds r2, r2, #0x0c
|
||||
blt .Lmemcpy_bsrcul2l4
|
||||
|
||||
.Lmemcpy_bsrcul2loop4:
|
||||
mov r12, r3, lsl #16
|
||||
ldr r3, [r1, #-4]!
|
||||
orr r12, r12, r3, lsr #16
|
||||
str r12, [r0, #-4]!
|
||||
subs r2, r2, #4
|
||||
bge .Lmemcpy_bsrcul2loop4
|
||||
|
||||
.Lmemcpy_bsrcul2l4:
|
||||
add r1, r1, #2
|
||||
b .Lmemcpy_bl4
|
||||
|
||||
.Lmemcpy_bsrcul1:
|
||||
cmp r2, #0x0c
|
||||
blt .Lmemcpy_bsrcul1loop4
|
||||
sub r2, r2, #0x0c
|
||||
stmdb sp!, {r4, r5, lr}
|
||||
|
||||
.Lmemcpy_bsrcul1loop32:
|
||||
mov lr, r3, lsl #24
|
||||
ldmdb r1!, {r3-r5, r12}
|
||||
orr lr, lr, r12, lsr #8
|
||||
mov r12, r12, lsl #24
|
||||
orr r12, r12, r5, lsr #8
|
||||
mov r5, r5, lsl #24
|
||||
orr r5, r5, r4, lsr #8
|
||||
mov r4, r4, lsl #24
|
||||
orr r4, r4, r3, lsr #8
|
||||
stmdb r0!, {r4, r5, r12, lr}
|
||||
subs r2, r2, #0x10
|
||||
bge .Lmemcpy_bsrcul1loop32
|
||||
ldmia sp!, {r4, r5, lr}
|
||||
adds r2, r2, #0x0c
|
||||
blt .Lmemcpy_bsrcul1l4
|
||||
|
||||
.Lmemcpy_bsrcul1loop4:
|
||||
mov r12, r3, lsl #24
|
||||
ldr r3, [r1, #-4]!
|
||||
orr r12, r12, r3, lsr #8
|
||||
str r12, [r0, #-4]!
|
||||
subs r2, r2, #4
|
||||
bge .Lmemcpy_bsrcul1loop4
|
||||
|
||||
.Lmemcpy_bsrcul1l4:
|
||||
add r1, r1, #1
|
||||
b .Lmemcpy_bl4
|
79
hw/mcu/allwinner/f1c100s/lib/memset.S
Normal file
79
hw/mcu/allwinner/f1c100s/lib/memset.S
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* memcpy.S
|
||||
*/
|
||||
.text
|
||||
|
||||
.global memset
|
||||
.type memset, %function
|
||||
.align 4
|
||||
|
||||
memset:
|
||||
stmfd sp!, {r0} /* remember address for return value */
|
||||
and r1, r1, #0x000000ff /* we write bytes */
|
||||
|
||||
cmp r2, #0x00000004 /* do we have less than 4 bytes */
|
||||
blt .Lmemset_lessthanfour
|
||||
|
||||
/* first we will word align the address */
|
||||
ands r3, r0, #0x00000003 /* get the bottom two bits */
|
||||
beq .Lmemset_addraligned /* the address is word aligned */
|
||||
|
||||
rsb r3, r3, #0x00000004
|
||||
sub r2, r2, r3
|
||||
cmp r3, #0x00000002
|
||||
strb r1, [r0], #0x0001 /* set 1 byte */
|
||||
strgeb r1, [r0], #0x0001 /* set another byte */
|
||||
strgtb r1, [r0], #0x0001 /* and a third */
|
||||
|
||||
cmp r2, #0x00000004
|
||||
blt .Lmemset_lessthanfour
|
||||
|
||||
/* now we must be word aligned */
|
||||
.Lmemset_addraligned:
|
||||
orr r3, r1, r1, lsl #8 /* repeat the byte into a word */
|
||||
orr r3, r3, r3, lsl #16
|
||||
|
||||
/* we know we have at least 4 bytes ... */
|
||||
cmp r2, #0x00000020 /* if less than 32 then use words */
|
||||
blt .Lmemset_lessthan32
|
||||
|
||||
/* we have at least 32 so lets use quad words */
|
||||
stmfd sp!, {r4-r6} /* store registers */
|
||||
mov r4, r3 /* duplicate data */
|
||||
mov r5, r3
|
||||
mov r6, r3
|
||||
|
||||
.Lmemset_loop16:
|
||||
stmia r0!, {r3-r6} /* store 16 bytes */
|
||||
sub r2, r2, #0x00000010 /* adjust count */
|
||||
cmp r2, #0x00000010 /* still got at least 16 bytes ? */
|
||||
bgt .Lmemset_loop16
|
||||
|
||||
ldmfd sp!, {r4-r6} /* restore registers */
|
||||
|
||||
/* do we need to set some words as well ? */
|
||||
cmp r2, #0x00000004
|
||||
blt .Lmemset_lessthanfour
|
||||
|
||||
/* have either less than 16 or less than 32 depending on route taken */
|
||||
.Lmemset_lessthan32:
|
||||
|
||||
/* we have at least 4 bytes so copy as words */
|
||||
.Lmemset_loop4:
|
||||
str r3, [r0], #0x0004
|
||||
sub r2, r2, #0x0004
|
||||
cmp r2, #0x00000004
|
||||
bge .Lmemset_loop4
|
||||
|
||||
.Lmemset_lessthanfour:
|
||||
cmp r2, #0x00000000
|
||||
ldmeqfd sp!, {r0}
|
||||
moveq pc, lr /* zero length so exit */
|
||||
|
||||
cmp r2, #0x00000002
|
||||
strb r1, [r0], #0x0001 /* set 1 byte */
|
||||
strgeb r1, [r0], #0x0001 /* set another byte */
|
||||
strgtb r1, [r0], #0x0001 /* and a third */
|
||||
|
||||
ldmfd sp!, {r0}
|
||||
mov pc, lr /* exit */
|
757
hw/mcu/allwinner/f1c100s/lib/printf.c
Normal file
757
hw/mcu/allwinner/f1c100s/lib/printf.c
Normal file
@ -0,0 +1,757 @@
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// \author (c) Marco Paland (info@paland.com)
|
||||
// 2014-2018, PALANDesign Hannover, Germany
|
||||
//
|
||||
// \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.
|
||||
//
|
||||
// \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for speed on
|
||||
// embedded systems with a very limited resources. These routines are thread
|
||||
// safe and reentrant!
|
||||
// Use this instead of the bloated standard/newlib printf cause these use
|
||||
// malloc for printf (and may not be thread safe).
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <stdint.h>
|
||||
#include "printf.h"
|
||||
|
||||
|
||||
// ntoa conversion buffer size, this must be big enough to hold
|
||||
// one converted numeric number including padded zeros (dynamically created on stack)
|
||||
// 32 byte is a good default
|
||||
#define PRINTF_NTOA_BUFFER_SIZE 32U
|
||||
|
||||
// ftoa conversion buffer size, this must be big enough to hold
|
||||
// one converted float number including padded zeros (dynamically created on stack)
|
||||
// 32 byte is a good default
|
||||
#define PRINTF_FTOA_BUFFER_SIZE 32U
|
||||
|
||||
// define this to support floating point (%f)
|
||||
#define PRINTF_SUPPORT_FLOAT
|
||||
|
||||
// define this to support long long types (%llu or %p)
|
||||
#define PRINTF_SUPPORT_LONG_LONG
|
||||
|
||||
// define this to support the ptrdiff_t type (%t)
|
||||
// ptrdiff_t is normally defined in <stddef.h> as long or long long type
|
||||
#define PRINTF_SUPPORT_PTRDIFF_T
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// 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)
|
||||
|
||||
typedef unsigned char bool;
|
||||
#ifndef false
|
||||
#define false 0
|
||||
#endif
|
||||
#ifndef true
|
||||
#define true (!false)
|
||||
#endif
|
||||
extern void sys_uart_putc(char c);
|
||||
static char last_ch;
|
||||
void _putchar(char character)
|
||||
{
|
||||
if(character == 0x0a && last_ch != 0x0d)
|
||||
{
|
||||
sys_uart_putc(0x0d);
|
||||
}
|
||||
sys_uart_putc(character);
|
||||
|
||||
}
|
||||
|
||||
// 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_fct_wrap_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_null(char character, void* buffer, size_t idx, size_t maxlen)
|
||||
{
|
||||
(void)character; (void)buffer; (void)idx; (void)maxlen;
|
||||
}
|
||||
|
||||
|
||||
// internal _putchar wrapper
|
||||
static inline void _out_char(char character, void* buffer, size_t idx, size_t maxlen)
|
||||
{
|
||||
(void)buffer; (void)idx; (void)maxlen;
|
||||
if (character) {
|
||||
_putchar(character);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// internal output function wrapper
|
||||
static inline void _out_fct(char character, void* buffer, size_t idx, size_t maxlen)
|
||||
{
|
||||
(void)idx; (void)maxlen;
|
||||
// buffer is the output fct pointer
|
||||
((out_fct_wrap_type*)buffer)->fct(character, ((out_fct_wrap_type*)buffer)->arg);
|
||||
}
|
||||
|
||||
|
||||
// internal strlen
|
||||
// \return The length of the string (excluding the terminating 0)
|
||||
static inline unsigned int _strlen(const char* str)
|
||||
{
|
||||
const char* s;
|
||||
for (s = str; *s; ++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;
|
||||
}
|
||||
|
||||
|
||||
// internal itoa format
|
||||
static size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len, bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags)
|
||||
{
|
||||
const size_t start_idx = idx;
|
||||
|
||||
// pad leading zeros
|
||||
while (!(flags & FLAGS_LEFT) && (len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
while (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
|
||||
// handle hash
|
||||
if (flags & FLAGS_HASH) {
|
||||
if (!(flags & FLAGS_PRECISION) && len && ((len == prec) || (len == width))) {
|
||||
len--;
|
||||
if (len && (base == 16U)) {
|
||||
len--;
|
||||
}
|
||||
}
|
||||
if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = 'x';
|
||||
}
|
||||
else if ((base == 16U) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = 'X';
|
||||
}
|
||||
else if ((base == 2U) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = 'b';
|
||||
}
|
||||
if (len < PRINTF_NTOA_BUFFER_SIZE) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
// handle sign
|
||||
if (len && (len == width) && (negative || (flags & FLAGS_PLUS) || (flags & FLAGS_SPACE))) {
|
||||
len--;
|
||||
}
|
||||
if (len < PRINTF_NTOA_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++] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
for (size_t i = 0U; i < len; i++) {
|
||||
out(buf[len - i - 1U], 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;
|
||||
}
|
||||
|
||||
|
||||
// internal itoa for 'long' type
|
||||
static size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, unsigned int prec, unsigned int width, unsigned int flags)
|
||||
{
|
||||
char buf[PRINTF_NTOA_BUFFER_SIZE];
|
||||
size_t len = 0U;
|
||||
|
||||
// no hash for 0 values
|
||||
if (!value) {
|
||||
flags &= ~FLAGS_HASH;
|
||||
}
|
||||
|
||||
// write if precision != 0 and value is != 0
|
||||
if (!(flags & FLAGS_PRECISION) || value) {
|
||||
do {
|
||||
const char digit = (char)(value % base);
|
||||
buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
|
||||
value /= base;
|
||||
} while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
|
||||
}
|
||||
|
||||
return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags);
|
||||
}
|
||||
|
||||
|
||||
// internal itoa for 'long long' type
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
static size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags)
|
||||
{
|
||||
char buf[PRINTF_NTOA_BUFFER_SIZE];
|
||||
size_t len = 0U;
|
||||
|
||||
// no hash for 0 values
|
||||
if (!value) {
|
||||
flags &= ~FLAGS_HASH;
|
||||
}
|
||||
|
||||
// write if precision != 0 and value is != 0
|
||||
if (!(flags & FLAGS_PRECISION) || value) {
|
||||
do {
|
||||
const char digit = (char)(value % base);
|
||||
buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
|
||||
value /= base;
|
||||
} while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
|
||||
}
|
||||
|
||||
return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags);
|
||||
}
|
||||
#endif // PRINTF_SUPPORT_LONG_LONG
|
||||
|
||||
|
||||
#if defined(PRINTF_SUPPORT_FLOAT)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
|
||||
static size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags)
|
||||
{
|
||||
const size_t start_idx = idx;
|
||||
|
||||
char buf[PRINTF_FTOA_BUFFER_SIZE];
|
||||
size_t len = 0U;
|
||||
double diff = 0.0;
|
||||
|
||||
// if input is larger than thres_max, revert to exponential
|
||||
const double thres_max = (double)0x7FFFFFFF;
|
||||
|
||||
// powers of 10
|
||||
static const double pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
|
||||
|
||||
// test for negative
|
||||
bool negative = false;
|
||||
if (value < 0) {
|
||||
negative = true;
|
||||
value = 0 - value;
|
||||
}
|
||||
|
||||
// set default precision to 6, if not set explicitly
|
||||
if (!(flags & FLAGS_PRECISION)) {
|
||||
prec = 6U;
|
||||
}
|
||||
// limit precision to 9, cause a prec >= 10 can lead to overflow errors
|
||||
while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) {
|
||||
buf[len++] = '0';
|
||||
prec--;
|
||||
}
|
||||
|
||||
int whole = (int)value;
|
||||
double tmp = (value - whole) * pow10[prec];
|
||||
unsigned long frac = (unsigned long)tmp;
|
||||
diff = tmp - frac;
|
||||
|
||||
if (diff > 0.5l) {
|
||||
++frac;
|
||||
// handle rollover, e.g. case 0.99 with prec 1 is 1.0
|
||||
if (frac >= pow10[prec]) {
|
||||
frac = 0;
|
||||
++whole;
|
||||
}
|
||||
}
|
||||
else if ((diff == 0.5l) && ((frac == 0U) || (frac & 1U))) {
|
||||
// if halfway, round up if odd, OR if last digit is 0
|
||||
++frac;
|
||||
}
|
||||
|
||||
// TBD: for very large numbers switch back to native sprintf for exponentials. Anyone want to write code to replace this?
|
||||
// Normal printf behavior is to print EVERY whole number digit which can be 100s of characters overflowing your buffers == bad
|
||||
if (value > thres_max) {
|
||||
return 0U;
|
||||
}
|
||||
|
||||
if (prec == 0U) {
|
||||
diff = value - (double)whole;
|
||||
if (diff > 0.5l) {
|
||||
// greater than 0.5, round up, e.g. 1.6 -> 2
|
||||
++whole;
|
||||
}
|
||||
else if ((diff == 0.5l) && (whole & 1)) {
|
||||
// exactly 0.5 and ODD, then round up
|
||||
// 1.5 -> 2, but 2.5 -> 2
|
||||
++whole;
|
||||
}
|
||||
}
|
||||
else {
|
||||
unsigned int count = prec;
|
||||
// now do fractional part, as an unsigned number
|
||||
while (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
--count;
|
||||
buf[len++] = (char)(48U + (frac % 10U));
|
||||
if (!(frac /= 10U)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// add extra 0s
|
||||
while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
if (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
// add decimal
|
||||
buf[len++] = '.';
|
||||
}
|
||||
}
|
||||
|
||||
// do whole part, number is reversed
|
||||
while (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
buf[len++] = (char)(48 + (whole % 10));
|
||||
if (!(whole /= 10)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// pad leading zeros
|
||||
while (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
|
||||
// handle sign
|
||||
if ((len == width) && (negative || (flags & FLAGS_PLUS) || (flags & FLAGS_SPACE))) {
|
||||
len--;
|
||||
}
|
||||
if (len < PRINTF_FTOA_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++] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
for (size_t i = 0U; i < len; i++) {
|
||||
out(buf[len - i - 1U], 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;
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
#endif // PRINTF_SUPPORT_FLOAT
|
||||
|
||||
|
||||
// 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_null;
|
||||
}
|
||||
|
||||
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 prec = (int)va_arg(va, int);
|
||||
precision = prec > 0 ? (unsigned int)prec : 0U;
|
||||
format++;
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
#if defined(PRINTF_SUPPORT_PTRDIFF_T)
|
||||
case 't' :
|
||||
flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
|
||||
format++;
|
||||
break;
|
||||
#endif
|
||||
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;
|
||||
}
|
||||
|
||||
// evaluate specifier
|
||||
switch (*format) {
|
||||
case 'd' :
|
||||
case 'i' :
|
||||
case 'u' :
|
||||
case 'x' :
|
||||
case 'X' :
|
||||
case 'o' :
|
||||
case 'b' : {
|
||||
// set the base
|
||||
unsigned int base;
|
||||
if (*format == 'x' || *format == 'X') {
|
||||
base = 16U;
|
||||
}
|
||||
else if (*format == 'o') {
|
||||
base = 8U;
|
||||
}
|
||||
else if (*format == 'b') {
|
||||
base = 2U;
|
||||
}
|
||||
else {
|
||||
base = 10U;
|
||||
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 defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
const long long value = va_arg(va, long long);
|
||||
idx = _ntoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
|
||||
#endif
|
||||
}
|
||||
else if (flags & FLAGS_LONG) {
|
||||
const long value = va_arg(va, long);
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
|
||||
}
|
||||
else {
|
||||
const int value = (flags & FLAGS_CHAR) ? (char)va_arg(va, int) : (flags & FLAGS_SHORT) ? (short int)va_arg(va, int) : va_arg(va, int);
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// unsigned
|
||||
if (flags & FLAGS_LONG_LONG) {
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
idx = _ntoa_long_long(out, buffer, idx, maxlen, va_arg(va, unsigned long long), false, base, precision, width, flags);
|
||||
#endif
|
||||
}
|
||||
else if (flags & FLAGS_LONG) {
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, 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 = _ntoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags);
|
||||
}
|
||||
}
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
#if defined(PRINTF_SUPPORT_FLOAT)
|
||||
case 'f' :
|
||||
case 'F' :
|
||||
idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);
|
||||
format++;
|
||||
break;
|
||||
#endif // PRINTF_SUPPORT_FLOAT
|
||||
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;
|
||||
}
|
||||
|
||||
case 's' : {
|
||||
char* p = va_arg(va, char*);
|
||||
unsigned int l = _strlen(p);
|
||||
// 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;
|
||||
}
|
||||
|
||||
case 'p' : {
|
||||
width = sizeof(void*) * 2U;
|
||||
flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE;
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
const bool is_ll = sizeof(uintptr_t) == sizeof(long long);
|
||||
if (is_ll) {
|
||||
idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void*), false, 16U, precision, width, flags);
|
||||
}
|
||||
else {
|
||||
#endif
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void*)), false, 16U, precision, width, flags);
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
}
|
||||
#endif
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
|
||||
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 printf(const char* format, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
char buffer[1];
|
||||
const int ret = _vsnprintf(_out_char, buffer, (size_t)-1, format, va);
|
||||
va_end(va);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int sprintf(char* buffer, const char* format, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
const int ret = _vsnprintf(_out_buffer, buffer, (size_t)-1, format, va);
|
||||
va_end(va);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int snprintf(char* buffer, size_t count, const char* format, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
const int ret = _vsnprintf(_out_buffer, buffer, count, format, va);
|
||||
va_end(va);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int vsnprintf(char* buffer, size_t count, const char* format, va_list va)
|
||||
{
|
||||
return _vsnprintf(_out_buffer, buffer, count, format, va);
|
||||
}
|
||||
|
||||
|
||||
int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
out_fct_wrap_type out_fct_wrap = { out, arg };
|
||||
const int ret = _vsnprintf(_out_fct, (char*)&out_fct_wrap, (size_t)-1, format, va);
|
||||
va_end(va);
|
||||
return ret;
|
||||
}
|
76
hw/mcu/allwinner/f1c100s/machine/exception.c
Normal file
76
hw/mcu/allwinner/f1c100s/machine/exception.c
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* exception.c
|
||||
*
|
||||
* Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com>
|
||||
* Official site: http://xboot.org
|
||||
* Mobile phone: +86-18665388956
|
||||
* QQ: 8192542
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <arm32.h>
|
||||
#include <string.h>
|
||||
|
||||
static void show_regs(struct arm_regs_t * regs)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("pc : [<%08lx>] lr : [<%08lx>] cpsr: %08lx\r\n", regs->pc, regs->lr, regs->cpsr);
|
||||
printf("sp : %08lx\r\n", regs->sp);
|
||||
for(i = 12; i >= 0; i--)
|
||||
{
|
||||
printf("r%-2d: %08lx ", i, regs->r[i]);
|
||||
if(i % 2 == 0)
|
||||
printf("\r\n");
|
||||
}
|
||||
printf("\r\n");
|
||||
}
|
||||
|
||||
void arm32_do_undefined_instruction(struct arm_regs_t * regs)
|
||||
{
|
||||
//gdbserver_handle_exception(regs);
|
||||
}
|
||||
|
||||
void arm32_do_software_interrupt(struct arm_regs_t * regs)
|
||||
{
|
||||
show_regs(regs);
|
||||
regs->pc += 4;
|
||||
}
|
||||
|
||||
void arm32_do_prefetch_abort(struct arm_regs_t * regs)
|
||||
{
|
||||
show_regs(regs);
|
||||
regs->pc += 4;
|
||||
}
|
||||
|
||||
void arm32_do_data_abort(struct arm_regs_t * regs)
|
||||
{
|
||||
show_regs(regs);
|
||||
regs->pc += 4;
|
||||
}
|
||||
|
||||
_Noreturn void __fatal_error(const char *msg) {
|
||||
printf("%s\n", msg);
|
||||
while (1);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
_Noreturn void __assert_func(const char *file, int line, const char *func, const char *expr) {
|
||||
//printf("Assertion '%s' failed, at file %s:%d\n", expr, file, line);
|
||||
__fatal_error("Assertion failed");
|
||||
}
|
||||
#endif
|
173
hw/mcu/allwinner/f1c100s/machine/f1c100s-intc.c
Normal file
173
hw/mcu/allwinner/f1c100s/machine/f1c100s-intc.c
Normal file
@ -0,0 +1,173 @@
|
||||
// Originally designed by Hong Xuyao
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <f1c100s-irq.h>
|
||||
#include <arm32.h>
|
||||
|
||||
#define __irq __attribute__ ((interrupt ("IRQ")))
|
||||
|
||||
#ifndef __IO
|
||||
#define __IO volatile
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
__IO uint32_t INTC_VECTOR_REG; // 0x00
|
||||
__IO uint32_t INTC_BASE_ADDR_REG; // 0x04
|
||||
uint32_t resv1[1]; // 0x08
|
||||
__IO uint32_t NMI_INT_CTRL_REG; // 0x0c
|
||||
__IO uint32_t INTC_PEND_REG[2]; // 0x10
|
||||
uint32_t resv2[2]; // 0x18
|
||||
__IO uint32_t INTC_EN_REG[2]; // 0x20
|
||||
uint32_t resv3[2]; // 0x28
|
||||
__IO uint32_t INTC_MASK_REG[2]; // 0x30
|
||||
uint32_t resv4[2]; // 0x38
|
||||
__IO uint32_t INTC_RESP_REG[2]; // 0x40
|
||||
uint32_t resv5[2]; // 0x48
|
||||
__IO uint32_t INTC_FF_REG[2]; // 0x50
|
||||
uint32_t resv6[2]; // 0x58
|
||||
__IO uint32_t INTC_PRIO_REG[4]; // 0x60
|
||||
} INTC_TypeDef;
|
||||
|
||||
#ifndef COUNTOF
|
||||
#define COUNTOF(ar) (sizeof(ar)/sizeof(ar[0]))
|
||||
#endif
|
||||
|
||||
#define INTC ((INTC_TypeDef*)0x01C20400)
|
||||
|
||||
static IRQHandleTypeDef irq_table[64] __attribute__((used, aligned(32)));
|
||||
|
||||
void arm32_do_irq(struct arm_regs_t * regs)
|
||||
{
|
||||
uint8_t nIRQ = f1c100s_intc_get_nirq();
|
||||
|
||||
// ForceIRQ flag must be cleared by ISR
|
||||
// Otherwise ISR will be entered repeatedly
|
||||
INTC->INTC_FF_REG[nIRQ / 32] &= ~(1 << nIRQ);
|
||||
// Call the drivers ISR
|
||||
f1c100s_intc_dispatch(nIRQ);
|
||||
// Clear pending at the end of ISR
|
||||
f1c100s_intc_clear_pend(nIRQ);
|
||||
}
|
||||
|
||||
void arm32_do_fiq(struct arm_regs_t * regs)
|
||||
{
|
||||
// Call the drivers ISR
|
||||
f1c100s_intc_dispatch(0);
|
||||
// Clear pending at the end of ISR.
|
||||
f1c100s_intc_clear_pend(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read active IRQ number
|
||||
* @return: none
|
||||
*/
|
||||
uint8_t f1c100s_intc_get_nirq(void)
|
||||
{
|
||||
return ((INTC->INTC_VECTOR_REG >> 2) & 0x3F);
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute ISR corresponding to IRQ number
|
||||
* @nIRQ: IRQ number
|
||||
* @return: none
|
||||
*/
|
||||
void f1c100s_intc_dispatch(uint8_t nIRQ)
|
||||
{
|
||||
IRQHandleTypeDef handle = irq_table[nIRQ];
|
||||
if (handle)
|
||||
handle();
|
||||
}
|
||||
|
||||
/*
|
||||
* Set handler function for specified IRQ
|
||||
* @nIRQ: IRQ number
|
||||
* @handle: Handle function
|
||||
* @return: none
|
||||
*/
|
||||
void f1c100s_intc_set_isr(uint8_t nIRQ, IRQHandleTypeDef handle)
|
||||
{
|
||||
if (nIRQ < COUNTOF(irq_table)) {
|
||||
irq_table[nIRQ] = handle;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable IRQ
|
||||
* @nIRQ: IRQ number
|
||||
* @return: none
|
||||
*/
|
||||
void f1c100s_intc_enable_irq(uint8_t nIRQ)
|
||||
{
|
||||
INTC->INTC_EN_REG[nIRQ / 32] |= (1 << (nIRQ % 32));
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable IRQ
|
||||
* @nIRQ: IRQ number
|
||||
* @return: none
|
||||
*/
|
||||
void f1c100s_intc_disable_irq(uint8_t nIRQ)
|
||||
{
|
||||
INTC->INTC_EN_REG[nIRQ / 32] &= ~(1 << (nIRQ % 32));
|
||||
}
|
||||
|
||||
/*
|
||||
* Mask IRQ
|
||||
* @nIRQ: IRQ number
|
||||
* @return: none
|
||||
*/
|
||||
void f1c100s_intc_mask_irq(uint8_t nIRQ)
|
||||
{
|
||||
INTC->INTC_MASK_REG[nIRQ / 32] |= (1 << (nIRQ % 32));
|
||||
}
|
||||
|
||||
/*
|
||||
* Unmask IRQ
|
||||
* @nIRQ: IRQ number
|
||||
* @return: none
|
||||
*/
|
||||
void f1c100s_intc_unmask_irq(uint8_t nIRQ)
|
||||
{
|
||||
INTC->INTC_MASK_REG[nIRQ / 32] &= ~(1 << (nIRQ % 32));
|
||||
}
|
||||
|
||||
/*
|
||||
* Immediately trigger IRQ
|
||||
* @nIRQ: IRQ number
|
||||
* @return: none
|
||||
*/
|
||||
void f1c100s_intc_force_irq(uint8_t nIRQ)
|
||||
{
|
||||
// This bit is to be cleared in IRQ handler
|
||||
INTC->INTC_FF_REG[nIRQ / 32] = (1 << (nIRQ % 32));
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear pending flag
|
||||
* @nIRQ: IRQ number
|
||||
* @return: none
|
||||
*/
|
||||
void f1c100s_intc_clear_pend(uint8_t nIRQ)
|
||||
{
|
||||
INTC->INTC_PEND_REG[nIRQ / 32] = (1 << (nIRQ % 32));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialize IRQ module
|
||||
* @return: none
|
||||
*/
|
||||
void f1c100s_intc_init(void)
|
||||
{
|
||||
INTC->INTC_EN_REG[0] = INTC->INTC_EN_REG[1] = 0;
|
||||
INTC->INTC_MASK_REG[0] = INTC->INTC_MASK_REG[1] = 0;
|
||||
INTC->INTC_FF_REG[0] = INTC->INTC_FF_REG[1] = 0;
|
||||
INTC->INTC_RESP_REG[0] = INTC->INTC_RESP_REG[1] = 0;
|
||||
INTC->INTC_PEND_REG[0] = INTC->INTC_PEND_REG[1] = ~0UL;
|
||||
INTC->INTC_BASE_ADDR_REG = 0;
|
||||
INTC->NMI_INT_CTRL_REG = 0;
|
||||
for (unsigned int i = 0; i < COUNTOF(irq_table); i++) {
|
||||
irq_table[i] = 0;
|
||||
}
|
||||
}
|
313
hw/mcu/allwinner/f1c100s/machine/start.S
Normal file
313
hw/mcu/allwinner/f1c100s/machine/start.S
Normal file
@ -0,0 +1,313 @@
|
||||
/*
|
||||
* start.S
|
||||
*
|
||||
* Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com>
|
||||
* Official site: http://xboot.org
|
||||
* Mobile phone: +86-18665388956
|
||||
* QQ: 8192542
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Exception vector table
|
||||
*/
|
||||
.text
|
||||
.arm
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
/* Boot head information for BROM */
|
||||
.long 0xea000016
|
||||
.byte 'e', 'G', 'O', 'N', '.', 'B', 'T', '0'
|
||||
.long 0, __bootloader_size
|
||||
.byte 'S', 'P', 'L', 2
|
||||
.long 0, 0
|
||||
.long 0, 0, 0, 0, 0, 0, 0, 0
|
||||
.long 0, 0, 0, 0, 0, 0, 0, 0 /* 0x40 - boot params, 0x58 - fel boot type, 0x5c - dram size */
|
||||
|
||||
_vector:
|
||||
b reset
|
||||
ldr pc, _undefined_instruction
|
||||
ldr pc, _software_interrupt
|
||||
ldr pc, _prefetch_abort
|
||||
ldr pc, _data_abort
|
||||
ldr pc, _not_used
|
||||
ldr pc, _irq
|
||||
ldr pc, _fiq
|
||||
|
||||
_undefined_instruction:
|
||||
.word undefined_instruction
|
||||
_software_interrupt:
|
||||
.word software_interrupt
|
||||
_prefetch_abort:
|
||||
.word prefetch_abort
|
||||
_data_abort:
|
||||
.word data_abort
|
||||
_not_used:
|
||||
.word not_used
|
||||
_irq:
|
||||
.word irq
|
||||
_fiq:
|
||||
.word fiq
|
||||
|
||||
/*
|
||||
* The actual reset code
|
||||
*/
|
||||
reset:
|
||||
/* Save boot params to 0x00000040 */
|
||||
ldr r0, =0x00000040
|
||||
str sp, [r0, #0]
|
||||
str lr, [r0, #4]
|
||||
mrs lr, cpsr
|
||||
str lr, [r0, #8]
|
||||
mrc p15, 0, lr, c1, c0, 0
|
||||
str lr, [r0, #12]
|
||||
mrc p15, 0, lr, c1, c0, 0
|
||||
str lr, [r0, #16]
|
||||
|
||||
/* Check boot type just for fel */
|
||||
mov r0, #0x0
|
||||
ldr r1, [r0, #8]
|
||||
ldr r2, =0x4c45462e
|
||||
cmp r1, r2
|
||||
bne 1f
|
||||
ldr r1, =0x1
|
||||
str r1, [r0, #0x58]
|
||||
1: nop
|
||||
|
||||
/* Enter svc mode and mask interrupts */
|
||||
mrs r0, cpsr
|
||||
bic r0, r0, #0x1f
|
||||
orr r0, r0, #0xd3
|
||||
msr cpsr, r0
|
||||
|
||||
/* Set vector to the low address */
|
||||
mrc p15, 0, r0, c1, c0, 0
|
||||
bic r0, #(1<<13)
|
||||
mcr p15, 0, r0, c1, c0, 0
|
||||
|
||||
/* Copy vector to the correct address */
|
||||
adr r0, _vector
|
||||
mrc p15, 0, r2, c1, c0, 0
|
||||
ands r2, r2, #(1 << 13)
|
||||
ldreq r1, =0x00000000
|
||||
ldrne r1, =0xffff0000
|
||||
ldmia r0!, {r2-r8, r10}
|
||||
stmia r1!, {r2-r8, r10}
|
||||
ldmia r0!, {r2-r8, r10}
|
||||
stmia r1!, {r2-r8, r10}
|
||||
|
||||
/* Initial system clock, ddr add uart */
|
||||
bl sys_clock_init
|
||||
bl sys_dram_init
|
||||
bl sys_uart_init
|
||||
|
||||
/* Boot speed up, leave slower sram */
|
||||
adr r0, _start
|
||||
ldr r1, =_start
|
||||
cmp r0, r1
|
||||
beq _speedup
|
||||
ldr r0, =0x81f80000
|
||||
adr r1, _start
|
||||
mov r2, #0x4000
|
||||
bl memcpy
|
||||
ldr r0, =_speedup
|
||||
ldr r1, =_start
|
||||
sub r0, r0, r1
|
||||
ldr r1, =0x81f80000
|
||||
add r0, r0, r1
|
||||
mov pc, r0
|
||||
_speedup:
|
||||
nop
|
||||
|
||||
/* Copyself to link address */
|
||||
adr r0, _start
|
||||
ldr r1, =_start
|
||||
cmp r0, r1
|
||||
beq 1f
|
||||
bl sys_copyself
|
||||
1: nop
|
||||
|
||||
/* Initialize stacks */
|
||||
mrs r0, cpsr
|
||||
bic r0, r0, #0x1f
|
||||
orr r1, r0, #0x1b
|
||||
msr cpsr_cxsf, r1
|
||||
ldr sp, _stack_und_end
|
||||
|
||||
bic r0, r0, #0x1f
|
||||
orr r1, r0, #0x17
|
||||
msr cpsr_cxsf, r1
|
||||
ldr sp, _stack_abt_end
|
||||
|
||||
bic r0, r0, #0x1f
|
||||
orr r1, r0, #0x12
|
||||
msr cpsr_cxsf, r1
|
||||
ldr sp, _stack_irq_end
|
||||
|
||||
bic r0, r0, #0x1f
|
||||
orr r1, r0, #0x11
|
||||
msr cpsr_cxsf, r1
|
||||
ldr sp, _stack_fiq_end
|
||||
|
||||
bic r0, r0, #0x1f
|
||||
orr r1, r0, #0x13
|
||||
msr cpsr_cxsf, r1
|
||||
ldr sp, _stack_srv_end
|
||||
|
||||
/* Copy data section */
|
||||
ldr r0, _data_start
|
||||
ldr r1, _data_shadow_start
|
||||
ldr r2, _data_shadow_end
|
||||
sub r2, r2, r1
|
||||
bl memcpy
|
||||
|
||||
/* Clear bss section */
|
||||
ldr r0, _bss_start
|
||||
ldr r2, _bss_end
|
||||
sub r2, r2, r0
|
||||
mov r1, #0
|
||||
bl memset
|
||||
|
||||
/* Call _main */
|
||||
ldr r1, =_main
|
||||
mov pc, r1
|
||||
_main:
|
||||
bl main
|
||||
b _main
|
||||
|
||||
.global return_to_fel
|
||||
return_to_fel:
|
||||
mov r0, #0x4
|
||||
mov r1, #'e'
|
||||
strb r1, [r0, #0]
|
||||
mov r1, #'G'
|
||||
strb r1, [r0, #1]
|
||||
mov r1, #'O'
|
||||
strb r1, [r0, #2]
|
||||
mov r1, #'N'
|
||||
strb r1, [r0, #3]
|
||||
mov r1, #'.'
|
||||
strb r1, [r0, #4]
|
||||
mov r1, #'F'
|
||||
strb r1, [r0, #5]
|
||||
mov r1, #'E'
|
||||
strb r1, [r0, #6]
|
||||
mov r1, #'L'
|
||||
strb r1, [r0, #7]
|
||||
ldr r0, =0x00000040
|
||||
ldr sp, [r0, #0]
|
||||
ldr lr, [r0, #4]
|
||||
ldr r1, [r0, #16]
|
||||
mcr p15, 0, r1, c1, c0, 0
|
||||
ldr r1, [r0, #12]
|
||||
mcr p15, 0, r1, c1, c0, 0
|
||||
ldr r1, [r0, #8]
|
||||
msr cpsr, r1
|
||||
bx lr
|
||||
|
||||
/*
|
||||
* Exception handlers
|
||||
*/
|
||||
.align 5
|
||||
undefined_instruction:
|
||||
b .
|
||||
|
||||
.align 5
|
||||
software_interrupt:
|
||||
b .
|
||||
|
||||
.align 5
|
||||
prefetch_abort:
|
||||
b .
|
||||
|
||||
.align 5
|
||||
data_abort:
|
||||
b .
|
||||
|
||||
.align 5
|
||||
not_used:
|
||||
b .
|
||||
|
||||
.align 5
|
||||
irq:
|
||||
ldr sp, _stack_irq_end
|
||||
sub sp, sp, #72
|
||||
stmia sp, {r0 - r12}
|
||||
add r8, sp, #60
|
||||
stmdb r8, {sp, lr}^
|
||||
str lr, [r8, #0]
|
||||
mrs r6, spsr
|
||||
str r6, [r8, #4]
|
||||
str r0, [r8, #8]
|
||||
mov r0, sp
|
||||
bl arm32_do_irq
|
||||
ldmia sp, {r0 - lr}^
|
||||
mov r0, r0
|
||||
ldr lr, [sp, #60]
|
||||
add sp, sp, #72
|
||||
subs pc, lr, #4
|
||||
|
||||
.align 5
|
||||
fiq:
|
||||
ldr sp, _stack_irq_end
|
||||
sub sp, sp, #72
|
||||
stmia sp, {r0 - r12}
|
||||
add r8, sp, #60
|
||||
stmdb r8, {sp, lr}^
|
||||
str lr, [r8, #0]
|
||||
mrs r6, spsr
|
||||
str r6, [r8, #4]
|
||||
str r0, [r8, #8]
|
||||
mov r0, sp
|
||||
bl arm32_do_fiq
|
||||
ldmia sp, {r0 - lr}^
|
||||
mov r0, r0
|
||||
ldr lr, [sp, #60]
|
||||
add sp, sp, #72
|
||||
subs pc, lr, #4
|
||||
|
||||
/*
|
||||
* The location of section
|
||||
*/
|
||||
.align 4
|
||||
_image_start:
|
||||
.long __image_start
|
||||
_image_end:
|
||||
.long __image_end
|
||||
_data_shadow_start:
|
||||
.long __data_shadow_start
|
||||
_data_shadow_end:
|
||||
.long __data_shadow_end
|
||||
_data_start:
|
||||
.long __data_start
|
||||
_data_end:
|
||||
.long __data_end
|
||||
_bss_start:
|
||||
.long __bss_start
|
||||
_bss_end:
|
||||
.long __bss_end
|
||||
_stack_und_end:
|
||||
.long __stack_und_end
|
||||
_stack_abt_end:
|
||||
.long __stack_abt_end
|
||||
_stack_irq_end:
|
||||
.long __stack_irq_end
|
||||
_stack_fiq_end:
|
||||
.long __stack_fiq_end
|
||||
_stack_srv_end:
|
||||
.long __stack_srv_end
|
124
hw/mcu/allwinner/f1c100s/machine/sys-clock.c
Normal file
124
hw/mcu/allwinner/f1c100s/machine/sys-clock.c
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* sys-clock.c
|
||||
*
|
||||
* Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com>
|
||||
* Official site: http://xboot.org
|
||||
* Mobile phone: +86-18665388956
|
||||
* QQ: 8192542
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
//#include <xboot.h>
|
||||
#include <stdint.h>
|
||||
#include <f1c100s/reg-ccu.h>
|
||||
#include <io.h>
|
||||
|
||||
static inline void sdelay(int loops)
|
||||
{
|
||||
__asm__ __volatile__ ("1:\n" "subs %0, %1, #1\n"
|
||||
"bne 1b":"=r" (loops):"0"(loops));
|
||||
}
|
||||
|
||||
static void wait_pll_stable(uint32_t base)
|
||||
{
|
||||
uint32_t rval = 0;
|
||||
uint32_t time = 0xfff;
|
||||
|
||||
do {
|
||||
rval = read32(base);
|
||||
time--;
|
||||
} while(time && !(rval & (1 << 28)));
|
||||
}
|
||||
|
||||
static void clock_set_pll_cpu(uint32_t clk)
|
||||
{
|
||||
uint32_t n, k, m, p;
|
||||
uint32_t rval = 0;
|
||||
uint32_t div = 0;
|
||||
|
||||
if(clk > 720000000)
|
||||
clk = 720000000;
|
||||
|
||||
if((clk % 24000000) == 0)
|
||||
{
|
||||
div = clk / 24000000;
|
||||
n = div - 1;
|
||||
k = 0;
|
||||
m = 0;
|
||||
p = 0;
|
||||
}
|
||||
else if((clk % 12000000) == 0)
|
||||
{
|
||||
m = 1;
|
||||
div = clk / 12000000;
|
||||
if((div % 3) == 0)
|
||||
k = 2;
|
||||
else if((div % 4) == 0)
|
||||
k = 3;
|
||||
else
|
||||
k = 1;
|
||||
n = (div / (k + 1)) - 1;
|
||||
p = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
div = clk / 24000000;
|
||||
n = div - 1;
|
||||
k = 0;
|
||||
m = 0;
|
||||
p = 0;
|
||||
}
|
||||
|
||||
rval = read32(F1C100S_CCU_BASE + CCU_PLL_CPU_CTRL);
|
||||
rval &= ~((0x3 << 16) | (0x1f << 8) | (0x3 << 4) | (0x3 << 0));
|
||||
rval |= (1U << 31) | (p << 16) | (n << 8) | (k << 4) | m;
|
||||
write32(F1C100S_CCU_BASE + CCU_PLL_CPU_CTRL, rval);
|
||||
wait_pll_stable(F1C100S_CCU_BASE + CCU_PLL_CPU_CTRL);
|
||||
}
|
||||
|
||||
void sys_clock_init(void)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
write32(F1C100S_CCU_BASE + CCU_PLL_STABLE_TIME0, 0x1ff);
|
||||
write32(F1C100S_CCU_BASE + CCU_PLL_STABLE_TIME1, 0x1ff);
|
||||
|
||||
val = read32(F1C100S_CCU_BASE + CCU_CPU_CFG);
|
||||
val &= ~(0x3 << 16);
|
||||
val |= (0x1 << 16);
|
||||
write32(F1C100S_CCU_BASE + CCU_CPU_CFG, val);
|
||||
sdelay(100);
|
||||
|
||||
write32(F1C100S_CCU_BASE + CCU_PLL_VIDEO_CTRL, 0x81004107);
|
||||
sdelay(100);
|
||||
write32(F1C100S_CCU_BASE + CCU_PLL_PERIPH_CTRL, 0x80041800);
|
||||
sdelay(100);
|
||||
write32(F1C100S_CCU_BASE + CCU_AHB_APB_CFG, 0x00003180);
|
||||
sdelay(100);
|
||||
|
||||
val = read32(F1C100S_CCU_BASE + CCU_DRAM_CLK_GATE);
|
||||
val |= (0x1 << 26) | (0x1 << 24);
|
||||
write32(F1C100S_CCU_BASE + CCU_DRAM_CLK_GATE, val);
|
||||
sdelay(100);
|
||||
|
||||
clock_set_pll_cpu(408000000);
|
||||
val = read32(F1C100S_CCU_BASE + CCU_CPU_CFG);
|
||||
val &= ~(0x3 << 16);
|
||||
val |= (0x2 << 16);
|
||||
write32(F1C100S_CCU_BASE + CCU_CPU_CFG, val);
|
||||
sdelay(100);
|
||||
}
|
111
hw/mcu/allwinner/f1c100s/machine/sys-copyself.c
Normal file
111
hw/mcu/allwinner/f1c100s/machine/sys-copyself.c
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* sys-copyself.c
|
||||
*
|
||||
* Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com>
|
||||
* Official site: http://xboot.org
|
||||
* Mobile phone: +86-18665388956
|
||||
* QQ: 8192542
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
#include <stdint.h>
|
||||
|
||||
extern unsigned char __image_start;
|
||||
extern unsigned char __image_end;
|
||||
extern void return_to_fel(void);
|
||||
extern void sys_mmu_init(void);
|
||||
extern void sys_uart_putc(char c);
|
||||
extern void sys_spi_flash_init(void);
|
||||
extern void sys_spi_flash_exit(void);
|
||||
extern void sys_spi_flash_read(int addr, void * buf, int count);
|
||||
|
||||
enum {
|
||||
BOOT_DEVICE_FEL = 0,
|
||||
BOOT_DEVICE_SPI = 1,
|
||||
BOOT_DEVICE_MMC = 2,
|
||||
};
|
||||
|
||||
static int get_boot_device(void)
|
||||
{
|
||||
uint32_t * t = (void *)0x00000058;
|
||||
|
||||
if(t[0] == 0x1)
|
||||
return BOOT_DEVICE_FEL;
|
||||
return BOOT_DEVICE_SPI;
|
||||
}
|
||||
|
||||
void sys_copyself(void)
|
||||
{
|
||||
int d = get_boot_device();
|
||||
void * mem;
|
||||
uint32_t size;
|
||||
|
||||
if(d == BOOT_DEVICE_FEL)
|
||||
{
|
||||
sys_uart_putc('B');
|
||||
sys_uart_putc('o');
|
||||
sys_uart_putc('o');
|
||||
sys_uart_putc('t');
|
||||
sys_uart_putc(' ');
|
||||
sys_uart_putc('t');
|
||||
sys_uart_putc('o');
|
||||
sys_uart_putc(' ');
|
||||
sys_uart_putc('F');
|
||||
sys_uart_putc('E');
|
||||
sys_uart_putc('L');
|
||||
sys_uart_putc(' ');
|
||||
sys_uart_putc('m');
|
||||
sys_uart_putc('o');
|
||||
sys_uart_putc('d');
|
||||
sys_uart_putc('e');
|
||||
sys_uart_putc('\r');
|
||||
sys_uart_putc('\n');
|
||||
return_to_fel();
|
||||
}
|
||||
else if(d == BOOT_DEVICE_SPI)
|
||||
{
|
||||
sys_uart_putc('B');
|
||||
sys_uart_putc('o');
|
||||
sys_uart_putc('o');
|
||||
sys_uart_putc('t');
|
||||
sys_uart_putc(' ');
|
||||
sys_uart_putc('t');
|
||||
sys_uart_putc('o');
|
||||
sys_uart_putc(' ');
|
||||
sys_uart_putc('S');
|
||||
sys_uart_putc('P');
|
||||
sys_uart_putc('I');
|
||||
sys_uart_putc(' ');
|
||||
sys_uart_putc('m');
|
||||
sys_uart_putc('o');
|
||||
sys_uart_putc('d');
|
||||
sys_uart_putc('e');
|
||||
sys_uart_putc('\r');
|
||||
sys_uart_putc('\n');
|
||||
mem = (void *)&__image_start;
|
||||
size = &__image_end - &__image_start;
|
||||
sys_mmu_init();
|
||||
|
||||
sys_spi_flash_init();
|
||||
sys_spi_flash_read(0, mem, size);
|
||||
sys_spi_flash_exit();
|
||||
}
|
||||
else if(d == BOOT_DEVICE_MMC)
|
||||
{
|
||||
mem = (void *)&__image_start;
|
||||
size = (&__image_end - &__image_start + 512) >> 9;
|
||||
}
|
||||
}
|
506
hw/mcu/allwinner/f1c100s/machine/sys-dram.c
Normal file
506
hw/mcu/allwinner/f1c100s/machine/sys-dram.c
Normal file
@ -0,0 +1,506 @@
|
||||
/*
|
||||
* sys-dram.c
|
||||
*
|
||||
* Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com>
|
||||
* Official site: http://xboot.org
|
||||
* Mobile phone: +86-18665388956
|
||||
* QQ: 8192542
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <f1c100s/reg-ccu.h>
|
||||
#include <f1c100s/reg-dram.h>
|
||||
#include <io.h>
|
||||
|
||||
#define PLL_DDR_CLK (156000000)
|
||||
#define SDR_T_CAS (0x2)
|
||||
#define SDR_T_RAS (0x8)
|
||||
#define SDR_T_RCD (0x3)
|
||||
#define SDR_T_RP (0x3)
|
||||
#define SDR_T_WR (0x3)
|
||||
#define SDR_T_RFC (0xd)
|
||||
#define SDR_T_XSR (0xf9)
|
||||
#define SDR_T_RC (0xb)
|
||||
#define SDR_T_INIT (0x8)
|
||||
#define SDR_T_INIT_REF (0x7)
|
||||
#define SDR_T_WTR (0x2)
|
||||
#define SDR_T_RRD (0x2)
|
||||
#define SDR_T_XP (0x0)
|
||||
|
||||
enum dram_type_t
|
||||
{
|
||||
DRAM_TYPE_SDR = 0,
|
||||
DRAM_TYPE_DDR = 1,
|
||||
DRAM_TYPE_MDDR = 2,
|
||||
};
|
||||
|
||||
struct dram_para_t
|
||||
{
|
||||
uint32_t base; /* dram base address */
|
||||
uint32_t size; /* dram size (unit: MByte) */
|
||||
uint32_t clk; /* dram work clock (unit: MHz) */
|
||||
uint32_t access_mode; /* 0: interleave mode 1: sequence mode */
|
||||
uint32_t cs_num; /* dram chip count 1: one chip 2: two chip */
|
||||
uint32_t ddr8_remap; /* for 8bits data width DDR 0: normal 1: 8bits */
|
||||
enum dram_type_t sdr_ddr;
|
||||
uint32_t bwidth; /* dram bus width */
|
||||
uint32_t col_width; /* column address width */
|
||||
uint32_t row_width; /* row address width */
|
||||
uint32_t bank_size; /* dram bank count */
|
||||
uint32_t cas; /* dram cas */
|
||||
};
|
||||
|
||||
static inline void sdelay(int loops)
|
||||
{
|
||||
__asm__ __volatile__ ("1:\n" "subs %0, %1, #1\n"
|
||||
"bne 1b":"=r" (loops):"0"(loops));
|
||||
}
|
||||
|
||||
static void dram_delay(int ms)
|
||||
{
|
||||
sdelay(ms * 2 * 1000);
|
||||
}
|
||||
|
||||
static int dram_initial(void)
|
||||
{
|
||||
unsigned int time = 0xffffff;
|
||||
|
||||
write32(F1C100S_DRAM_BASE + DRAM_SCTLR, read32(F1C100S_DRAM_BASE + DRAM_SCTLR) | 0x1);
|
||||
while((read32(F1C100S_DRAM_BASE + DRAM_SCTLR) & 0x1) && time--)
|
||||
{
|
||||
if(time == 0)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dram_delay_scan(void)
|
||||
{
|
||||
unsigned int time = 0xffffff;
|
||||
|
||||
write32(F1C100S_DRAM_BASE + DRAM_DDLYR, read32(F1C100S_DRAM_BASE + DRAM_DDLYR) | 0x1);
|
||||
while((read32(F1C100S_DRAM_BASE + DRAM_DDLYR) & 0x1) && time--)
|
||||
{
|
||||
if(time == 0)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void dram_set_autofresh_cycle(uint32_t clk)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
uint32_t row = 0;
|
||||
uint32_t temp = 0;
|
||||
|
||||
row = read32(F1C100S_DRAM_BASE + DRAM_SCONR);
|
||||
row &= 0x1e0;
|
||||
row >>= 0x5;
|
||||
|
||||
if(row == 0xc)
|
||||
{
|
||||
if(clk >= 1000000)
|
||||
{
|
||||
temp = clk + (clk >> 3) + (clk >> 4) + (clk >> 5);
|
||||
while(temp >= (10000000 >> 6))
|
||||
{
|
||||
temp -= (10000000 >> 6);
|
||||
val++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
val = (clk * 499) >> 6;
|
||||
}
|
||||
}
|
||||
else if(row == 0xb)
|
||||
{
|
||||
if(clk >= 1000000)
|
||||
{
|
||||
temp = clk + (clk >> 3) + (clk >> 4) + (clk >> 5);
|
||||
while(temp >= (10000000 >> 7))
|
||||
{
|
||||
temp -= (10000000 >> 7);
|
||||
val++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
val = (clk * 499) >> 5;
|
||||
}
|
||||
}
|
||||
write32(F1C100S_DRAM_BASE + DRAM_SREFR, val);
|
||||
}
|
||||
|
||||
static int dram_para_setup(struct dram_para_t * para)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
|
||||
val = (para->ddr8_remap) |
|
||||
(0x1 << 1) |
|
||||
((para->bank_size >> 2) << 3) |
|
||||
((para->cs_num >> 1) << 4) |
|
||||
((para->row_width - 1) << 5) |
|
||||
((para->col_width - 1) << 9) |
|
||||
((para->sdr_ddr ? (para->bwidth >> 4) : (para->bwidth >> 5)) << 13) |
|
||||
(para->access_mode << 15) |
|
||||
(para->sdr_ddr << 16);
|
||||
|
||||
write32(F1C100S_DRAM_BASE + DRAM_SCONR, val);
|
||||
write32(F1C100S_DRAM_BASE + DRAM_SCTLR, read32(F1C100S_DRAM_BASE + DRAM_SCTLR) | (0x1 << 19));
|
||||
return dram_initial();
|
||||
}
|
||||
|
||||
static uint32_t dram_check_delay(uint32_t bwidth)
|
||||
{
|
||||
uint32_t dsize;
|
||||
uint32_t i,j;
|
||||
uint32_t num = 0;
|
||||
uint32_t dflag = 0;
|
||||
|
||||
dsize = ((bwidth == 16) ? 4 : 2);
|
||||
for(i = 0; i < dsize; i++)
|
||||
{
|
||||
if(i == 0)
|
||||
dflag = read32(F1C100S_DRAM_BASE + DRAM_DRPTR0);
|
||||
else if(i == 1)
|
||||
dflag = read32(F1C100S_DRAM_BASE + DRAM_DRPTR1);
|
||||
else if(i == 2)
|
||||
dflag = read32(F1C100S_DRAM_BASE + DRAM_DRPTR2);
|
||||
else if(i == 3)
|
||||
dflag = read32(F1C100S_DRAM_BASE + DRAM_DRPTR3);
|
||||
|
||||
for(j = 0; j < 32; j++)
|
||||
{
|
||||
if(dflag & 0x1)
|
||||
num++;
|
||||
dflag >>= 1;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
static int sdr_readpipe_scan(void)
|
||||
{
|
||||
uint32_t k = 0;
|
||||
|
||||
for(k = 0; k < 32; k++)
|
||||
{
|
||||
write32(0x80000000 + 4 * k, k);
|
||||
}
|
||||
for(k = 0; k < 32; k++)
|
||||
{
|
||||
if(read32(0x80000000 + 4 * k) != k)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint32_t sdr_readpipe_select(void)
|
||||
{
|
||||
uint32_t value = 0;
|
||||
uint32_t i = 0;
|
||||
for(i = 0; i < 8; i++)
|
||||
{
|
||||
write32(F1C100S_DRAM_BASE + DRAM_SCTLR, (read32(F1C100S_DRAM_BASE + DRAM_SCTLR) & (~(0x7 << 6))) | (i << 6));
|
||||
if(sdr_readpipe_scan())
|
||||
{
|
||||
value = i;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static uint32_t dram_check_type(struct dram_para_t * para)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
uint32_t times = 0;
|
||||
uint32_t i;
|
||||
|
||||
for(i = 0; i < 8; i++)
|
||||
{
|
||||
val = read32(F1C100S_DRAM_BASE + DRAM_SCTLR);
|
||||
val &= ~(0x7 << 6);
|
||||
val |= (i << 6);
|
||||
write32(F1C100S_DRAM_BASE + DRAM_SCTLR, val);
|
||||
|
||||
dram_delay_scan();
|
||||
if(read32(F1C100S_DRAM_BASE + DRAM_DDLYR) & 0x30)
|
||||
times++;
|
||||
}
|
||||
|
||||
if(times == 8)
|
||||
{
|
||||
para->sdr_ddr = DRAM_TYPE_SDR;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
para->sdr_ddr = DRAM_TYPE_DDR;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t dram_scan_readpipe(struct dram_para_t * para)
|
||||
{
|
||||
uint32_t i, rp_best = 0, rp_val = 0;
|
||||
uint32_t val = 0;
|
||||
uint32_t readpipe[8];
|
||||
|
||||
if(para->sdr_ddr == DRAM_TYPE_DDR)
|
||||
{
|
||||
for(i = 0; i < 8; i++)
|
||||
{
|
||||
val = read32(F1C100S_DRAM_BASE + DRAM_SCTLR);
|
||||
val &= ~(0x7 << 6);
|
||||
val |= (i << 6);
|
||||
write32(F1C100S_DRAM_BASE + DRAM_SCTLR, val);
|
||||
dram_delay_scan();
|
||||
readpipe[i] = 0;
|
||||
if((((read32(F1C100S_DRAM_BASE + DRAM_DDLYR) >> 4) & 0x3) == 0x0) &&
|
||||
(((read32(F1C100S_DRAM_BASE + DRAM_DDLYR) >> 4) & 0x1) == 0x0))
|
||||
{
|
||||
readpipe[i] = dram_check_delay(para->bwidth);
|
||||
}
|
||||
if(rp_val < readpipe[i])
|
||||
{
|
||||
rp_val = readpipe[i];
|
||||
rp_best = i;
|
||||
}
|
||||
}
|
||||
val = read32(F1C100S_DRAM_BASE + DRAM_SCTLR);
|
||||
val &= ~(0x7 << 6);
|
||||
val |= (rp_best << 6);
|
||||
write32(F1C100S_DRAM_BASE + DRAM_SCTLR, val);
|
||||
dram_delay_scan();
|
||||
}
|
||||
else
|
||||
{
|
||||
val = read32(F1C100S_DRAM_BASE + DRAM_SCONR);
|
||||
val &= (~(0x1 << 16));
|
||||
val &= (~(0x3 << 13));
|
||||
write32(F1C100S_DRAM_BASE + DRAM_SCONR, val);
|
||||
rp_best = sdr_readpipe_select();
|
||||
val = read32(F1C100S_DRAM_BASE + DRAM_SCTLR);
|
||||
val &= ~(0x7 << 6);
|
||||
val |= (rp_best << 6);
|
||||
write32(F1C100S_DRAM_BASE + DRAM_SCTLR, val);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t dram_get_dram_size(struct dram_para_t * para)
|
||||
{
|
||||
uint32_t colflag = 10, rowflag = 13;
|
||||
uint32_t i = 0;
|
||||
uint32_t val1 = 0;
|
||||
uint32_t count = 0;
|
||||
uint32_t addr1, addr2;
|
||||
|
||||
para->col_width = colflag;
|
||||
para->row_width = rowflag;
|
||||
dram_para_setup(para);
|
||||
dram_scan_readpipe(para);
|
||||
for(i = 0; i < 32; i++)
|
||||
{
|
||||
*((uint32_t *)(0x80000200 + i)) = 0x11111111;
|
||||
*((uint32_t *)(0x80000600 + i)) = 0x22222222;
|
||||
}
|
||||
for(i = 0; i < 32; i++)
|
||||
{
|
||||
val1 = *((uint32_t *)(0x80000200 + i));
|
||||
if(val1 == 0x22222222)
|
||||
count++;
|
||||
}
|
||||
if(count == 32)
|
||||
{
|
||||
colflag = 9;
|
||||
}
|
||||
else
|
||||
{
|
||||
colflag = 10;
|
||||
}
|
||||
count = 0;
|
||||
para->col_width = colflag;
|
||||
para->row_width = rowflag;
|
||||
dram_para_setup(para);
|
||||
if(colflag == 10)
|
||||
{
|
||||
addr1 = 0x80400000;
|
||||
addr2 = 0x80c00000;
|
||||
}
|
||||
else
|
||||
{
|
||||
addr1 = 0x80200000;
|
||||
addr2 = 0x80600000;
|
||||
}
|
||||
for(i = 0; i < 32; i++)
|
||||
{
|
||||
*((uint32_t *)(addr1 + i)) = 0x33333333;
|
||||
*((uint32_t *)(addr2 + i)) = 0x44444444;
|
||||
}
|
||||
for(i = 0; i < 32; i++)
|
||||
{
|
||||
val1 = *((uint32_t *)(addr1 + i));
|
||||
if(val1 == 0x44444444)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if(count == 32)
|
||||
{
|
||||
rowflag = 12;
|
||||
}
|
||||
else
|
||||
{
|
||||
rowflag = 13;
|
||||
}
|
||||
para->col_width = colflag;
|
||||
para->row_width = rowflag;
|
||||
if(para->row_width != 13)
|
||||
{
|
||||
para->size = 16;
|
||||
}
|
||||
else if(para->col_width == 10)
|
||||
{
|
||||
para->size = 64;
|
||||
}
|
||||
else
|
||||
{
|
||||
para->size = 32;
|
||||
}
|
||||
dram_set_autofresh_cycle(para->clk);
|
||||
para->access_mode = 0;
|
||||
dram_para_setup(para);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dram_init(struct dram_para_t * para)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
uint32_t i;
|
||||
|
||||
write32(0x01c20800 + 0x24, read32(0x01c20800 + 0x24) | (0x7 << 12));
|
||||
dram_delay(5);
|
||||
if(((para->cas) >> 3) & 0x1)
|
||||
{
|
||||
write32(0x01c20800 + 0x2c4, read32(0x01c20800 + 0x2c4) | (0x1 << 23) | (0x20 << 17));
|
||||
}
|
||||
if((para->clk >= 144) && (para->clk <= 180))
|
||||
{
|
||||
write32(0x01c20800 + 0x2c0, 0xaaa);
|
||||
}
|
||||
if(para->clk >= 180)
|
||||
{
|
||||
write32(0x01c20800 + 0x2c0, 0xfff);
|
||||
}
|
||||
if((para->clk) <= 96)
|
||||
{
|
||||
val = (0x1 << 0) | (0x0 << 4) | (((para->clk * 2) / 12 - 1) << 8) | (0x1u << 31);
|
||||
}
|
||||
else
|
||||
{
|
||||
val = (0x0 << 0) | (0x0 << 4) | (((para->clk * 2) / 24 - 1) << 8) | (0x1u << 31);
|
||||
}
|
||||
|
||||
if(para->cas & (0x1 << 4))
|
||||
{
|
||||
write32(F1C100S_CCU_BASE + CCU_PLL_DDR0_PAT, 0xd1303333);
|
||||
}
|
||||
else if(para->cas & (0x1 << 5))
|
||||
{
|
||||
write32(F1C100S_CCU_BASE + CCU_PLL_DDR0_PAT, 0xcce06666);
|
||||
}
|
||||
else if(para->cas & (0x1 << 6))
|
||||
{
|
||||
write32(F1C100S_CCU_BASE + CCU_PLL_DDR0_PAT, 0xc8909999);
|
||||
}
|
||||
else if(para->cas & (0x1 << 7))
|
||||
{
|
||||
write32(F1C100S_CCU_BASE + CCU_PLL_DDR0_PAT, 0xc440cccc);
|
||||
}
|
||||
if(para->cas & (0xf << 4))
|
||||
{
|
||||
val |= 0x1 << 24;
|
||||
}
|
||||
write32(F1C100S_CCU_BASE + CCU_PLL_DDR_CTRL, val);
|
||||
write32(F1C100S_CCU_BASE + CCU_PLL_DDR_CTRL, read32(F1C100S_CCU_BASE + CCU_PLL_DDR_CTRL) | (0x1 << 20));
|
||||
while((read32(F1C100S_CCU_BASE + CCU_PLL_DDR_CTRL) & (1 << 28)) == 0);
|
||||
dram_delay(5);
|
||||
write32(F1C100S_CCU_BASE + CCU_BUS_CLK_GATE0, read32(F1C100S_CCU_BASE + CCU_BUS_CLK_GATE0) | (0x1 << 14));
|
||||
write32(F1C100S_CCU_BASE + CCU_BUS_SOFT_RST0, read32(F1C100S_CCU_BASE + CCU_BUS_SOFT_RST0) & ~(0x1 << 14));
|
||||
for(i = 0; i < 10; i++)
|
||||
continue;
|
||||
write32(F1C100S_CCU_BASE + CCU_BUS_SOFT_RST0, read32(F1C100S_CCU_BASE + CCU_BUS_SOFT_RST0) | (0x1 << 14));
|
||||
|
||||
val = read32(0x01c20800 + 0x2c4);
|
||||
(para->sdr_ddr == DRAM_TYPE_DDR) ? (val |= (0x1 << 16)) : (val &= ~(0x1 << 16));
|
||||
write32(0x01c20800 + 0x2c4, val);
|
||||
|
||||
val = (SDR_T_CAS << 0) | (SDR_T_RAS << 3) | (SDR_T_RCD << 7) | (SDR_T_RP << 10) | (SDR_T_WR << 13) | (SDR_T_RFC << 15) | (SDR_T_XSR << 19) | (SDR_T_RC << 28);
|
||||
write32(F1C100S_DRAM_BASE + DRAM_STMG0R, val);
|
||||
val = (SDR_T_INIT << 0) | (SDR_T_INIT_REF << 16) | (SDR_T_WTR << 20) | (SDR_T_RRD << 22) | (SDR_T_XP << 25);
|
||||
write32(F1C100S_DRAM_BASE + DRAM_STMG1R, val);
|
||||
dram_para_setup(para);
|
||||
dram_check_type(para);
|
||||
|
||||
val = read32(0x01c20800 + 0x2c4);
|
||||
(para->sdr_ddr == DRAM_TYPE_DDR) ? (val |= (0x1 << 16)) : (val &= ~(0x1 << 16));
|
||||
write32(0x01c20800 + 0x2c4, val);
|
||||
|
||||
dram_set_autofresh_cycle(para->clk);
|
||||
dram_scan_readpipe(para);
|
||||
dram_get_dram_size(para);
|
||||
|
||||
for(i = 0; i < 128; i++)
|
||||
{
|
||||
*((volatile uint32_t *)(para->base + 4 * i)) = para->base + 4 * i;
|
||||
}
|
||||
|
||||
for(i = 0; i < 128; i++)
|
||||
{
|
||||
if(*((volatile uint32_t *)(para->base + 4 * i)) != (para->base + 4 * i))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void sys_dram_init(void)
|
||||
{
|
||||
struct dram_para_t para;
|
||||
uint32_t * dsz = (void *)0x0000005c;
|
||||
|
||||
para.base = 0x80000000;
|
||||
para.size = 32;
|
||||
para.clk = PLL_DDR_CLK / 1000000;
|
||||
para.access_mode = 1;
|
||||
para.cs_num = 1;
|
||||
para.ddr8_remap = 0;
|
||||
para.sdr_ddr = DRAM_TYPE_DDR;
|
||||
para.bwidth = 16;
|
||||
para.col_width = 10;
|
||||
para.row_width = 13;
|
||||
para.bank_size = 4;
|
||||
para.cas = 0x3;
|
||||
|
||||
if((dsz[0] >> 24) == 'X')
|
||||
return;
|
||||
if(dram_init(¶))
|
||||
dsz[0] = (((uint32_t)'X') << 24) | (para.size << 0);
|
||||
}
|
57
hw/mcu/allwinner/f1c100s/machine/sys-mmu.c
Normal file
57
hw/mcu/allwinner/f1c100s/machine/sys-mmu.c
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* sys-mmu.c
|
||||
*
|
||||
* Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com>
|
||||
* Official site: http://xboot.org
|
||||
* Mobile phone: +86-18665388956
|
||||
* QQ: 8192542
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <io.h>
|
||||
#include <sizes.h>
|
||||
#include <arm32.h>
|
||||
|
||||
static void map_l1_section(uint32_t * ttb, virtual_addr_t virt, physical_addr_t phys, physical_size_t size, int type)
|
||||
{
|
||||
physical_size_t i;
|
||||
|
||||
virt >>= 20;
|
||||
phys >>= 20;
|
||||
size >>= 20;
|
||||
type &= 0x3;
|
||||
|
||||
for(i = size; i > 0; i--, virt++, phys++)
|
||||
ttb[virt] = (phys << 20) | (0x3 << 10) | (0x0 << 5) | (type << 2) | (0x2 << 0);
|
||||
}
|
||||
|
||||
void sys_mmu_init(void)
|
||||
{
|
||||
uint32_t * ttb = (uint32_t *)(0x80000000 + SZ_1M * 31);
|
||||
|
||||
map_l1_section(ttb, 0x00000000, 0x00000000, SZ_2G, 0);
|
||||
map_l1_section(ttb, 0x80000000, 0x80000000, SZ_2G, 0);
|
||||
map_l1_section(ttb, 0x80000000, 0x80000000, SZ_1M * 32, 3);
|
||||
|
||||
arm32_ttb_set((uint32_t)(ttb));
|
||||
arm32_tlb_invalidate();
|
||||
arm32_domain_set(0x3);
|
||||
arm32_mmu_enable();
|
||||
arm32_icache_enable();
|
||||
arm32_dcache_enable();
|
||||
}
|
204
hw/mcu/allwinner/f1c100s/machine/sys-spi-flash.c
Normal file
204
hw/mcu/allwinner/f1c100s/machine/sys-spi-flash.c
Normal file
@ -0,0 +1,204 @@
|
||||
/*
|
||||
* sys-spi-flash.c
|
||||
*
|
||||
* Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com>
|
||||
* Official site: http://xboot.org
|
||||
* Mobile phone: +86-18665388956
|
||||
* QQ: 8192542
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <types.h>
|
||||
#include <string.h>
|
||||
#include <io.h>
|
||||
|
||||
enum {
|
||||
SPI_GCR = 0x04,
|
||||
SPI_TCR = 0x08,
|
||||
SPI_IER = 0x10,
|
||||
SPI_ISR = 0x14,
|
||||
SPI_FCR = 0x18,
|
||||
SPI_FSR = 0x1c,
|
||||
SPI_WCR = 0x20,
|
||||
SPI_CCR = 0x24,
|
||||
SPI_MBC = 0x30,
|
||||
SPI_MTC = 0x34,
|
||||
SPI_BCC = 0x38,
|
||||
SPI_TXD = 0x200,
|
||||
SPI_RXD = 0x300,
|
||||
};
|
||||
|
||||
void sys_spi_flash_init(void)
|
||||
{
|
||||
virtual_addr_t addr;
|
||||
uint32_t val;
|
||||
|
||||
/* Config GPIOC0, GPIOC1, GPIOC2 and GPIOC3 */
|
||||
addr = 0x01c20848 + 0x00;
|
||||
val = read32(addr);
|
||||
val &= ~(0xf << ((0 & 0x7) << 2));
|
||||
val |= ((0x2 & 0x7) << ((0 & 0x7) << 2));
|
||||
write32(addr, val);
|
||||
|
||||
val = read32(addr);
|
||||
val &= ~(0xf << ((1 & 0x7) << 2));
|
||||
val |= ((0x2 & 0x7) << ((1 & 0x7) << 2));
|
||||
write32(addr, val);
|
||||
|
||||
val = read32(addr);
|
||||
val &= ~(0xf << ((2 & 0x7) << 2));
|
||||
val |= ((0x2 & 0x7) << ((2 & 0x7) << 2));
|
||||
write32(addr, val);
|
||||
|
||||
val = read32(addr);
|
||||
val &= ~(0xf << ((3 & 0x7) << 2));
|
||||
val |= ((0x2 & 0x7) << ((3 & 0x7) << 2));
|
||||
write32(addr, val);
|
||||
|
||||
/* Deassert spi0 reset */
|
||||
addr = 0x01c202c0;
|
||||
val = read32(addr);
|
||||
val |= (1 << 20);
|
||||
write32(addr, val);
|
||||
|
||||
/* Open the spi0 bus gate */
|
||||
addr = 0x01c20000 + 0x60;
|
||||
val = read32(addr);
|
||||
val |= (1 << 20);
|
||||
write32(addr, val);
|
||||
|
||||
/* Set spi clock rate control register, divided by 4 */
|
||||
addr = 0x01c05000;
|
||||
write32(addr + SPI_CCR, 0x00001001);
|
||||
|
||||
/* Enable spi0 and do a soft reset */
|
||||
addr = 0x01c05000;
|
||||
val = read32(addr + SPI_GCR);
|
||||
val |= (1 << 31) | (1 << 7) | (1 << 1) | (1 << 0);
|
||||
write32(addr + SPI_GCR, val);
|
||||
while(read32(addr + SPI_GCR) & (1 << 31));
|
||||
|
||||
val = read32(addr + SPI_TCR);
|
||||
val &= ~(0x3 << 0);
|
||||
val |= (1 << 6) | (1 << 2);
|
||||
write32(addr + SPI_TCR, val);
|
||||
|
||||
val = read32(addr + SPI_FCR);
|
||||
val |= (1 << 31) | (1 << 15);
|
||||
write32(addr + SPI_FCR, val);
|
||||
}
|
||||
|
||||
void sys_spi_flash_exit(void)
|
||||
{
|
||||
virtual_addr_t addr = 0x01c05000;
|
||||
uint32_t val;
|
||||
|
||||
/* Disable the spi0 controller */
|
||||
val = read32(addr + SPI_GCR);
|
||||
val &= ~((1 << 1) | (1 << 0));
|
||||
write32(addr + SPI_GCR, val);
|
||||
}
|
||||
|
||||
static void sys_spi_select(void)
|
||||
{
|
||||
virtual_addr_t addr = 0x01c05000;
|
||||
uint32_t val;
|
||||
|
||||
val = read32(addr + SPI_TCR);
|
||||
val &= ~((0x3 << 4) | (0x1 << 7));
|
||||
val |= ((0 & 0x3) << 4) | (0x0 << 7);
|
||||
write32(addr + SPI_TCR, val);
|
||||
}
|
||||
|
||||
static void sys_spi_deselect(void)
|
||||
{
|
||||
virtual_addr_t addr = 0x01c05000;
|
||||
uint32_t val;
|
||||
|
||||
val = read32(addr + SPI_TCR);
|
||||
val &= ~((0x3 << 4) | (0x1 << 7));
|
||||
val |= ((0 & 0x3) << 4) | (0x1 << 7);
|
||||
write32(addr + SPI_TCR, val);
|
||||
}
|
||||
|
||||
static void sys_spi_write_txbuf(uint8_t * buf, int len)
|
||||
{
|
||||
virtual_addr_t addr = 0x01c05000;
|
||||
int i;
|
||||
|
||||
if(!buf)
|
||||
len = 0;
|
||||
|
||||
write32(addr + SPI_MTC, len & 0xffffff);
|
||||
write32(addr + SPI_BCC, len & 0xffffff);
|
||||
for(i = 0; i < len; ++i)
|
||||
write8(addr + SPI_TXD, *buf++);
|
||||
}
|
||||
|
||||
static int sys_spi_transfer(void * txbuf, void * rxbuf, int len)
|
||||
{
|
||||
virtual_addr_t addr = 0x01c05000;
|
||||
int count = len;
|
||||
uint8_t * tx = txbuf;
|
||||
uint8_t * rx = rxbuf;
|
||||
uint8_t val;
|
||||
unsigned int n, i;
|
||||
|
||||
while(count > 0)
|
||||
{
|
||||
n = (count <= 64) ? count : 64;
|
||||
write32(addr + SPI_MBC, n);
|
||||
sys_spi_write_txbuf(tx, n);
|
||||
write32(addr + SPI_TCR, read32(addr + SPI_TCR) | (1 << 31));
|
||||
|
||||
while((read32(addr + SPI_FSR) & 0xff) < n);
|
||||
for(i = 0; i < n; i++)
|
||||
{
|
||||
val = read8(addr + SPI_RXD);
|
||||
if(rx)
|
||||
*rx++ = val;
|
||||
}
|
||||
|
||||
if(tx)
|
||||
tx += n;
|
||||
count -= n;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static int sys_spi_write_then_read(void * txbuf, int txlen, void * rxbuf, int rxlen)
|
||||
{
|
||||
if(sys_spi_transfer(txbuf, NULL, txlen) != txlen)
|
||||
return -1;
|
||||
if(sys_spi_transfer(NULL, rxbuf, rxlen) != rxlen)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sys_spi_flash_read(int addr, void * buf, int count)
|
||||
{
|
||||
uint8_t tx[4];
|
||||
|
||||
tx[0] = 0x03;
|
||||
tx[1] = (uint8_t)(addr >> 16);
|
||||
tx[2] = (uint8_t)(addr >> 8);
|
||||
tx[3] = (uint8_t)(addr >> 0);
|
||||
sys_spi_select();
|
||||
sys_spi_write_then_read(tx, 4, buf, count);
|
||||
sys_spi_deselect();
|
||||
}
|
83
hw/mcu/allwinner/f1c100s/machine/sys-uart.c
Normal file
83
hw/mcu/allwinner/f1c100s/machine/sys-uart.c
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* sys-uart.c
|
||||
*
|
||||
* Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com>
|
||||
* Official site: http://xboot.org
|
||||
* Mobile phone: +86-18665388956
|
||||
* QQ: 8192542
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <types.h>
|
||||
#include <stdint.h>
|
||||
#include <io.h>
|
||||
|
||||
void sys_uart_init(void)
|
||||
{
|
||||
virtual_addr_t addr;
|
||||
uint32_t val;
|
||||
|
||||
/* Config GPIOE1 and GPIOE0 to txd0 and rxd0 */
|
||||
addr = 0x01c20890 + 0x00;
|
||||
val = read32(addr);
|
||||
val &= ~(0xf << ((1 & 0x7) << 2));
|
||||
val |= ((0x5 & 0x7) << ((1 & 0x7) << 2));
|
||||
write32(addr, val);
|
||||
|
||||
val = read32(addr);
|
||||
val &= ~(0xf << ((0 & 0x7) << 2));
|
||||
val |= ((0x5 & 0x7) << ((0 & 0x7) << 2));
|
||||
write32(addr, val);
|
||||
|
||||
/* Open the clock gate for uart0 */
|
||||
addr = 0x01c20068;
|
||||
val = read32(addr);
|
||||
val |= 1 << 20;
|
||||
write32(addr, val);
|
||||
|
||||
/* Deassert uart0 reset */
|
||||
addr = 0x01c202d0;
|
||||
val = read32(addr);
|
||||
val |= 1 << 20;
|
||||
write32(addr, val);
|
||||
|
||||
/* Config uart0 to 115200-8-1-0 */
|
||||
addr = 0x01c25000;
|
||||
write32(addr + 0x04, 0x0);
|
||||
write32(addr + 0x08, 0xf7);
|
||||
write32(addr + 0x10, 0x0);
|
||||
val = read32(addr + 0x0c);
|
||||
val |= (1 << 7);
|
||||
write32(addr + 0x0c, val);
|
||||
write32(addr + 0x00, 0x36 & 0xff);
|
||||
write32(addr + 0x04, (0x36 >> 8) & 0xff);
|
||||
val = read32(addr + 0x0c);
|
||||
val &= ~(1 << 7);
|
||||
write32(addr + 0x0c, val);
|
||||
val = read32(addr + 0x0c);
|
||||
val &= ~0x1f;
|
||||
val |= (0x3 << 0) | (0 << 2) | (0x0 << 3);
|
||||
write32(addr + 0x0c, val);
|
||||
}
|
||||
|
||||
void sys_uart_putc(char c)
|
||||
{
|
||||
virtual_addr_t addr = 0x01c25000;
|
||||
|
||||
while((read32(addr + 0x7c) & (0x1 << 1)) == 0);
|
||||
write32(addr + 0x00, c);
|
||||
}
|
@ -4,6 +4,7 @@
|
||||
#include <f1c100s-irq.h>
|
||||
#include <device/dcd.h>
|
||||
#include "musb_def.h"
|
||||
#include "bsp/board.h"
|
||||
|
||||
typedef uint32_t u32;
|
||||
typedef uint16_t u16;
|
||||
@ -69,8 +70,8 @@ static void usb_phy_write(int addr, int data, int len)
|
||||
static void delay_ms(uint32_t ms)
|
||||
{
|
||||
#if CFG_TUSB_OS == OPT_OS_NONE
|
||||
int cnt = ms * 1000 * 1000 / 2;
|
||||
while (cnt--) asm("nop");
|
||||
int now = board_millis();
|
||||
while (board_millis() - now <= ms) asm("nop");
|
||||
#else
|
||||
osal_task_delay(ms);
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user